Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Messages - Crimson Wizard

#2281
Please tell, where exactly did you put this code: which script, and which function?

EDIT: after checking your edits in the first post, which kind of a problem do you actually have: your script does not compile, or it runs but nothing happens in game?
#2282
Please tell some details about your room, does it have walkable areas, is the NPC standing on the walkable area?
What is your goal exactly, making it walk from point A to point B, or keep walking along some path, or walk between two places repeatedly? anything else?

Please post the code you are using, it's difficult to tell something without it.
#2283
Hello, this is literally a AGS HELP WANTED, in the sense that we need help for the AGS itself.

The AGS manual is lacking many topics, and some existing ones are not complete or not very well done overall. Unfortunately, there have been very little volunteers to help with it over the years.

I cannot remember if I did this before on Recruitment board, but I decided to do now (again?).

We are looking for a person which is:
- Good with writing in English;
- Good with explaining things to people, especially to those who might have less technical knowledge about the topic;
- Good with AGS, of course (you must know the subject well).

Our manual (source) repository is here:
https://github.com/adventuregamestudio/ags-manual
The manual may be edited as a Wiki, using Markdown language:
https://github.com/adventuregamestudio/ags-manual/wiki
There are basic guidelines for working with it:
https://github.com/adventuregamestudio/ags-manual/blob/master/CONTRIBUTING.md
I think the Tutorial pages may be used as an example of a "tone" that we'd like to have, that is not overly encyclopedic, and easy enough to understand for a non-technical person or a kid:
https://github.com/adventuregamestudio/ags-manual/wiki/acintro1
https://github.com/adventuregamestudio/ags-manual/wiki/acintro2
https://github.com/adventuregamestudio/ags-manual/wiki/acintro3


Currently this may be edited by anyone who has a Github account, although the dev team retains a right to edit or even reset your changes if you do something weird there. TBH I was about to discuss setting permissions differently with our dev team, but that's a separate question.

You may look for the list of tasks in the repository's issue tracker:
https://github.com/adventuregamestudio/ags-manual/issues
you may open ones too if you feel the need to



The tasks we are primarily interested in are:
1) Enhancing description of the Editor and editing various items in the project. Issue: https://github.com/adventuregamestudio/ags-manual/issues/218
2) Writing thorough explanation of Game Features, basically, explaining the logic of how things work in game, how they are set up and how they behave. Issue: https://github.com/adventuregamestudio/ags-manual/issues/209
3) Expanding tutorials, explaining solutions to most typical problems (say, run continuous state update in repeatedly_execute, and other).


If you have questions or suggestions, please contact us in this forum thread, at the issue tracker or AGS Discord (there's a channel dedicated to documentation). You may also send me a PM, although I'd prefer to keep the discussion public.
#2284
Quote from: eri0o on Tue 25/04/2023 17:49:29I kinda want to figure out a very simple actual game I can use this to add a bit motivation.

What about a color-match game, but with physics? Colored squares fall from above and player must move them sideways or drop fast. If same-colored squares are close enough and join by sides, they will despawn.

But everything works with physics, so slightest mistake may create a mess.

Option 2:
a cannon shooting a castle made of blocks. Castles may be of different shape, and you only have limited shots.
#2285
Code: ags
surface.DrawImage(info.X, info.Y, 1097, 10);

This is wrong; info.X and Y tell the coordinates of a surface on screen, but since you are drawing on surface itself, you should be using relative coordinates, just like you do with DrawStringWrapped (you don't draw string at info.X + 5, but simply at 5).

Code: ags
surface.DrawImage(0, 0, 1097, 10);
#2286
Updated to v0.9.4, fixed a crash upon restoring a saved game where some of the objects had Parents; and couple other minor fixes.

For Windows: https://github.com/ivan-mogilko/ags-spritevideo/releases/download/v0.9.4/win_ags_spritevideo.zip
For Linux (debian-based): https://github.com/ivan-mogilko/ags-spritevideo/releases/download/v0.9.4/libags_spritevideo.tar.xz
#2287
So, from what I understand, the primary goal of this is to have a cleaner and stricter translation source format, which is

- is a widespread standard, which can be viewed and edited by multiple tools;
- not breaking easily like TRS, if you add or misplace a line somewhere;
- provides extra fields that may potentially be utilized in the future for more translation fixes and features.

I guess that additional features, like contexts, is more of a job for Editor/Engine rather than the PO format. The format itself only provides an option to store extra data, but the problem remains how to generate and use that data in game.


I propose to separate two kinds of features:
- The tasks of generating and updating a translation source, which involve only parsing game and generating PO file.
- The features that require engine to treat translations differently (contexts, plurals, etc).

This is for organizational purposes, as former kind may be done easier than the latter.
#2288
The big issue with the manual right now is that it has dedicated pages for editors and script commands, but does not have these for the basic features. You often have to go through all the "tutorials" or scripting section in order to find out that AGS can do something.

For the same reason, whenever I'd like to refer to how particular feature works in AGS (like speech, animation, dialog options), I cannot simply give a link to an article, and have to explain everything over again.

I opened a task ticket about it once: https://github.com/adventuregamestudio/ags-manual/issues/209
#2289
The updated version, with some fixes related to game saves, and plugins which create their own objects:
https://cirrus-ci.com/task/5586565305466880
I made a comment about performance:
https://github.com/adventuregamestudio/ags/pull/1923#issuecomment-1519166283

In summary, it reduces slightly, but for me it was only noticeable in script-heavy games when running in "unlimited fps" mode. But I have not tested anything "heavy" that would have objects (cross-)referencing objects, simply because I don't have a ready game with that.

Still, some things in this branch were done as a quick first attempt, and there's room for improvement. Some optimization may be done quicker, other would require a redesign of e.g. managed object storage internally.



Quote from: eri0o on Sun 23/04/2023 23:13:05Hey, after applying this, would pursuing a refactor to port the script rewrite idea from Nick's branch much harder or the same difficulty?

No, I do not think that it makes it more difficult, as the main principles of the script executor's and managed pool's work were not changed.
The biggest changes are related to
* generating extra data (rtti) as a post-step in script compiling;
* loading extra data (rtti), and generating helper data from it;
* disposing user structs and dynamic arrays (changes are contained within Dispose method);
* garbage collector was practically correctly written now.
#2290
Hmm... if I remember correctly, the speech is always displayed in relation to the first visible viewport/camera pair. So if your primary viewport is still on the screen, the it will be displayed in its coordinates.

EDIT: OR, the first viewport where character is visible.

Note that its considered to be "visible" even if there's another viewport overlaying it. You'd have to disable it by setting Screen.Viewport.Visible = false temporarily.

But, if you do not need original camera to be seen at this time, then you do not have to create new viewport/camera pair, and may adjust existing ones instead. They are accessible as Screen.Viewport and Game.Camera.

I recall this was an issue before because the manual had examples with unnecessary camera creations, so people copied them. These examples were changed since:
https://adventuregamestudio.github.io/ags-manual/Camera.html
https://adventuregamestudio.github.io/ags-manual/Viewport.html
#2291
Engine Development / Re: Why is AGS slow?
Sat 22/04/2023 16:44:03
Quote from: Crimson Wizard on Thu 13/10/2022 22:05:15One major reason this was written in the first place was because AGS compiled script assumes 32-bit pointer size, so it won't work with 64-bit systems. Couple of people have suggested to implement a virtual memory instead, and use virtual 32-bit addresses instead of the real ones, which might fix this issue.
I suppose this is what Nick Sonneveld started to write in one of his experimental branches few years ago.

I've been testing a couple of script-heavy games with a Nick Sonneveld's script interpreter's rewrite
https://github.com/sonneveld/ags/commits/ags--script
using "infinite fps mode" (where the game runs as fast as possible without frame delays) and depending on a game and situation it gives about 20-25% improvement in fps, compared to the 3.5.0 engine it was based on. In one game it raised from 70 fps to around 84 fps, in another - from 330 to 400+ fps.

Code-wise it's bit dirty in places, and I don't know if it's fully feature complete.
There are few things that it probably does not do, which current engine does, like being able to address explicit variables from the engine structs exposed to script instead of letting interpreter read/write memory raw without knowing where it reads or writes to (which may be dangerous), but maybe it uses an alternate safety mechanism which I have not understood yet.

It also does very little safechecks, which is a very good thing for performance, but may make debugging for mistake harder. If it had these checks under some compilation flag, - that could improve debugging too.

Implementation-wise, it solves the memory issue by having a joint virtual/real memory mapper. Whenever possible the script data is allocated on the virtual memory "heap", which size is limited by 32-bit, which lets to reference it by using 32-bit offsets instead of real addresses. But when not possible (or not wanted for some reasons) it uses the virtual-to-real mem map (so it translates 32-bit handles to whatever-bit addresses). The latter is like the classic managed objects handles, except it seem to be able to work for anything. I haven't looked too deep into this, but I may imagine this mem map could be used for plugins too, which can allocate on their own and thus cannot be restricted to a virtual heap.

I actually wonder why we haven't tried at least this virtual-to-real map mechanism back in 2012/13, it alone might have been more performant than the solution that I did. It seems a quite logical thing to try.




Separately, I'd like to re-visit two my past comments in this thread:

Quote from: Crimson Wizard on Fri 24/09/2021 17:49:06Personally I would speculate that most games created with AGS so far may fit into 32-bit memory, and those which don't likely are overusing memory due to low optimization.

So, in the recent year it's been found that Dave Gilbert's new full-HD game actually goes above 32-bit RAM limit, but this was mostly due to the graphics. We did number of memory optimizations, which reduced the RAM usage by few hundreds MBs, but apparently reaching the limit is realistic. If this becomes a problem again, we might use 64-bit engine which has a much much more RAM support.


Quote from: Crimson Wizard on Fri 24/09/2021 17:49:06most of the mem is likely to be taken by resources (sprites, sounds), and these are not exposed into script VM, so not part of this address issue. What is left for VM addresses is: script variables and managed objects. Most managed objects are merely "wrappers" which contain ID of an actual object in the engine. So probably most managed script memory goes to: dynamic containers (arrays, etc), and dynamic sprites.

I must correct the last statement here: dynamic sprites do not store the image data in the script memory, it's being stored inside the sprite storage (aka sprite cache), and therefore this data does not have to be restricted by the size or address. The script's memory only stores minimal reference info.
#2292
@glurex: you can use GetTranslation instead, that automatically returns the line in the current language:

Code: ags
player.SayBubble(GetTranslation("original text goes here"));

I think, this call to GetTranslation could be done right inside SayBubble. The problem here is that the message could be made using String.Format, and therefore not translatable. So it's a question of how to design the module...

Maybe there could be separate functions for automatically translated messages and not.

EDIT: you may write a helper function yourself:
Code: ags
void SayBubbleTra(this Character*, String message, GUI* bubbleGui)
{
  this.SayBubble(GetTranslation(message), bubbleGui);
}
and then use it like
Code: ags
player.SayBubbleTra("original text goes here");
#2293
Quote from: Snarky on Fri 21/04/2023 17:33:28As for the rest, it depends on which character code is actually stored in the string at string manipulation time. If it is always LF, then things are simple and it is clear what to do.

AFAIK all the true escape sequences ('\\', '\n', '\r', '\t' and so forth) are dealt with at compilation time, and all the '\n' in the string you typed in the Editor will be LF in the compiled data.

What engine does at runtime is converting '[' into '\n'. This is where it tests for any backslashes before the '['.
This is done just before the string wrapping algorithm, so that the latter could work strictly with '\n's.

So, at the time when engine is drawing the line of text, it has to be either "\n" or "\\[". I suppose it's best to just replace everything with '\n' in script.
How to treat the "\\[" and "[\\" in otherwise reverse text case in script, - that is indeed open for interpretations...
One solution is to ignore these completely, and suggest users to use '\n' in their texts where they want a manual linebreak, because '\n' always becomes a single character. Then they will be dealt with by a compiler. Although, I don't know how it will be displayed if you type real Unicode text in RTL mode.
#2294
Quote from: Snarky on Fri 21/04/2023 15:05:23One question: how will manual linebreaks made using "/n" appear in the reversed "RTL" string? As "/n", as "n/", or already converted to a newline code? (Actually, it might be best to optionally support all of these as well as the old ']', using some kind of configuration bit field.)

No, the line breaking chars do not need to be reversed, that makes no sense whatsoever. The `\n` (escaped 'n') is not treated as two characters, it's processed as a  single special character called LF (ascii code 10).
Converting '[' to ']' will only make sense if that's a displayed character, but won't if it's a special break character, in which case it must retain its code.
Both '\n' and '[' are treated by AGS during wrapped string drawing (I think it converts one to another for consistency, but I forgot the details); if they will be reversed, then nothing will work.
#2295
Something has to write a script module for handling these special cases.

I think what is required is this:
* a function that calculates width of drawn text (given string, font and width limit) and inserts linebreaks in it.
* a special handling for the case when the text has to be read Right-to-left. Probably this means that either the splitting has to be done in reverse, or the text has to be reversed char by char twice: first before the splitting and then each separate part (between the linebreaks) is reversed on its own again.


For the reference, I had a function that splits text written long time ago for the TypedText module:
https://github.com/ivan-mogilko/ags-script-modules/blob/f55bc9015f6e6443de7f4d293b5b199779b79e88/scripts/gui/TypedText/TypedText.asc#L41
but it actually had a bug, mentioned here, with a proposed fix:
https://github.com/ivan-mogilko/ags-script-modules/issues/5

I had plans to pick this function out as a separate module, but never had found time to do this.

Or it could be rewritten from scratch.
#2296
Alright, I wrote something, based on Python's idea:
https://github.com/adventuregamestudio/ags/pull/1923#issuecomment-1515510131
Test build:
https://cirrus-ci.com/task/6681544534786048

It seems working using the simple script test:
Spoiler
Code: ags
managed struct ListItem
{
    ListItem* prev;
    ListItem* next;
    
    String name;
    int data;
};

managed struct LinkedList
{
    ListItem* first;
    ListItem* last;
};

import ListItem* newItem(ListItem* add_after, String name, int data);
import void      detachItem(ListItem* item);
import ListItem* findNthItem(ListItem* first, int n);
import void      printItems(ListItem* first, ListBox* lb);

import ListItem* addItem(this LinkedList*, String name, int data);
import ListItem* remItem(this LinkedList*, ListItem* item);
import ListItem* remItemN(this LinkedList*, int index);
import void      clear(this LinkedList*);

Code: ags

ListItem* newItem(ListItem* add_after, String name, int data)
{
    ListItem* item = new ListItem;
    item.name = name;
    item.data = data;
    if (add_after != null)
    {
        ListItem* next = add_after.next;
        add_after.next = item;
        item.prev = add_after;
        if (next != null)
        {
            next.prev = item;
            item.next = next;
        }
    }
    return item;
}

void detachItem(ListItem* item)
{
    if (item.prev != null)
        item.prev.next = item.next;
    if (item.next != null)
        item.next.prev = item.prev;
    item.next = null;
    item.prev = null;
}

ListItem* findNthItem(ListItem* first, int n)
{
    ListItem* item = first;
    for (int i = 0; i < n; i++)
    {
        if (item.next == null)
            return null;
        item = item.next;
    }
    return item;
}

void printItems(ListItem* first, ListBox* lb)
{
    lb.Clear();
    if (first == null)
        return;
    ListItem* item = first;
    do
    {
        lb.AddItem(String.Format("%s : %d", item.name, item.data));
        item = item.next;
    }
    while (item != null);
}

ListItem* addItem(this LinkedList*, String name, int data)
{
    ListItem* item = newItem(this.last, TextBox1.Text, Random(32000));
    if (this.first == null)
        this.first = item;
    this.last = item;
    return item;
}

ListItem* remItem(this LinkedList*, ListItem* item)
{
    if (item == this.first)
        this.first = item.next;
    if (item == this.last)
        this.last = item.prev;
    detachItem(item);
    return item;
}

ListItem* remItemN(this LinkedList*, int index)
{
    ListItem* item = findNthItem(this.first, ListBox1.SelectedIndex);
    if (item == null)
        return null;
    this.remItem(item);
    return item;
}

void clear(this LinkedList*)
{
    this.first = null;
    this.last = null;
}
[close]
#2297
The "Mark & Sweep" is probably the method which I described earlier, but, from what I understood, it requires to have a "root" reference which AGS does not have. This could be worked around by generating script reflection.

Comparing these two, I'd rather first try the one that does not require this.
#2298
Alright, after reading this article, I can see that Python's gc has an opposite approach, where it does not check which pointers exist in script, instead it checks only the pointers in the "managed objects", to speak in AGS terms.

In a nutshell, there's a separate "reference counter" meant only for GC. It's initialized with real "reference counter" at the start. Then GC scans all the managed objects, and subrefs the objects it references, but it changes the "gc ref count" (not the real one). After that the objects that have 0 ref counts remaining are the ones that do not have link from the script memory.

Then it does a second pass, restoring "gc ref counts", but only starting at the objects that still kept positive "gc ref count" (these are ones that have a link from the script memory).

Finally in the end only the completely unattached objects remain with "gc ref count" = 0.

This is all really clever!, and this is possible to do in AGS without adding anything extra to script format, or checking internal engine refs; because this algorithm does not care about all that, it only cares to find out which refs come from withing the managed objects themselves.
#2299
Quote from: eri0o on Tue 18/04/2023 22:27:49Not sure if it's because I am doing a lot of python recently, but the first result for garbage collection in Google for me was this: https://devguide.python.org/internals/garbage-collector/

Alright, I will read this, maybe this will give ideas how to optimize the whole thing...

Previously I found this funny article about how to write a GC memory in C language:
https://maplant.com/gc.html
#2300
Quote from: Crimson Wizard on Tue 18/04/2023 20:27:50If the script memory would have contained hints on the data types in it, we could know where are "dynamic object handles" among it.

In regards to this: as the RTTI feature is already merged to ags4, it's potentially possible to expand and generate a script global variables table, which would have a structure similar to RTTI tables.

RTTI already has a Field type, which may as well be reused here.
It may contain even variable names, but that's not essential, and may be skipped for now.

To summarize, the necessary changes for GC would require:
1) compilers generating a reflection table for script's global variables (each script); the table is saved as another extension to script format, similar to how RTTI table is saved now.
2) writing a search algorithm that finds managed handles in the script memory.
3) figuring out a good trigger condition for running GC.


PS. I'd need to write a proper ticket for this; imo it's better to do this separately, and prior to the task of supporting nested managed pointers.
SMF spam blocked by CleanTalk