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

Topics - Monsieur OUXX

I remember CW saying that one of the obstacles of easily "managing" managed objects inside the AGS virtual machine is that they share the same address space as basic pointers. I don't remember exactly which kind of difficulties it was causing but I clearly remember that it was creating a technical glass ceiling -- because in the end everything is a pointer. So this limitation was indirectly impeding some glorious steps towards engine modernity and dynamic objects. 

This message is not to ask "what is the problem exactly" but to suggest a solution. Maybe what I'm about to write is dumb and has nothing to do with the issue, but here goes nothing. I've done that successfully in some pseudo-VM I was writing in AGS :

Split the pointers address range in two. I mean, a pair of completely artificial "fake" addresses ranges. For example :
0x0000 --> 0xFFFF = old-style pointers, nothing changed.
0x10000 --> 0x1FFFF = managed objects. You generate those exactly like you used to (values from 0x0000 to 0xFFFF), but you immediately add 0x10000 for as long as they're passed around as value from C++ function to C++ function-

With a simple binary mask you can tell which value represents which type. <= 0xFFFF = regular pointer. >=0x10000 = managed pointer.
Whenever you need to actually read/write to memory, just remove the bogus offset : For example, convert managed pointer 0x100AA to 00AA, then do whatever you would normally do (pointers arithmetic, real address in memory, etc.)

Food for thought.

Engine Development / Why is AGS slow?
21 Sep 2021, 12:50
I sometimes ask myself why AGS is slow, or at least not lightning fast.
Having very little knowledge of the engine's code, I can't seem to come up with a reason :
- It uses SDL, which is very close to the hardware. If not the fastest possible option, it's pretty close.
- It's written in C/C++
- The virtual machine is running pre-compiled code, literally just byte code.

So, what is slow in all this?
Is it that the VM's instructions are not mapped directly to the underlying CPU instructions? Is it that the engine uses simple data structures with a lot of overhead and lookups? Etc.

I want to add a new sort of "Component" in the AGS project tree.

- I duplicated "ScriptsComponent" and named it "FooComponent".
- I replaced the word Script/script/Scripts everywhere relevant.
- I did "AddComponent" in ApplicationController.cs
- Finally, I duplicated "scripts.ico" and "script.ico" in the Resources folder and named the new files "foos.ico" and "foo.ico".
- I added those files to the Resources folder in the project ("Add existing item").

Everything compiles, but when the Editor starts, ResourceManager.GetIcon crashes. It says that "System.ArgumentException: 'Resource 'foo.ico' cannot be found in class 'AGS.Editor.Resources.ResourceManager'.'

Again, I did everything like ScriptsComponent does it, except with "Foo" in place of "Script".

So, my question : Do new resources (icons) need to be added explicitly to some sort of Resources manifest file or some list that I failed to locate?
Why are the new icons not found? Not found in what? (in the file system? In some list?)

I don't have a specific situation on mind, I'm asking about general best practice.

Let's say you have this :
Code: ags

    File* f = File.Open("file.txt", eFileRead);
    while (!f.EOF) {
      String s = f.ReadRawLineBack();

Notice the line "EVENT HAPPENS HERE". I'm talking about random events that almost never happen but could happen.

Two scenarios :
a) On that line, this game gets saved (e.g. through "SaveGameSlot" in another script) and then instantly quits (the player closed the game in Windows).
b) On that line, another game gets restored (e.g. through "RestoreGameSlot" in another script). As a mental exercise we imagine that we restore a previous occurrence of scenario "a".

If "a" just happened, then do I just have to accept that the file is not entirely loaded into the game's VM, and deal with it next time it gets loaded?

If "b" just happened, then
1) Is f in an undefined state? I guess I can't just continue reading from it.
2) What should I do? Just scrap it and have a mechanism to restart reading the file from the top?

Fact : AGS script is VERY inspired by C. It's the archaic side to AGS.

Don't get me wrong. C is a fine language, and it works.

But nowadays, who declares a class as "struct"? Who uses so-called "pointers" in a high-level scripting language?
The only reason why AGS still offers both managed and unmanaged is because until the latest versions dynamic structures were not fully implemented. And this is on the verge of being fixed.

Here is my suggestion :
1. Accept to break (a tiny bit of) script retro-compatibility upgrading when from AGS 3 to AGS4.
2. Replace keyword "struct" with "class"
3. Make *all* structs managed.
4. Get rid of the "asterisk" ( * ) when dealing with managed objects.
This would effectively make AGS move to the age of References rather than pointers.

So INSTEAD of this :
Code: ags

managed struct A {
  int i;

function Foo(A* a)
   a.i = 777;

void game_start()
   A* a = new A;

...the new syntax would be this. And would look like most mainstream languages.
Code: ags

class A {
  int i;

function Foo(A a)
   a.i = 777;

void game_start()
   A a = new A;

The beauty of this is that almost everything is already there. It's only a matter of substituting some syntactic elements with other syntactic elements;
Advanced Technical Forum / Polymorphism
06 Sep 2021, 16:47
I'm experimenting with the old discovery of monkey0506 that polymorphism is somewhat possible. He explained it here : https://www.adventuregamestudio.co.uk/wiki/Extender_Methods_mean_Polymorphism!

What I've done :

Code: ags

managed struct Base {
import int GetSetting(this Base*);

managed struct A extends Base {
import int GetSetting(this A*);

managed struct B extends Base {
import int GetSetting(this B*);

Code: ags

int GetSetting(this Base*)
   AbortGame("You need to overwrite this function");

int GetSetting(this A*)
   return 666;

int GetSetting(this B*)
   return 777;

Then I do this :
Code: ags

Base* array[10];
array[0] = new A;
array[1] = new B;

So far so good. I've managed to store instances of both A and B into the same array of Base.

My issue is that I don't know how to cast back.

If I do this :
Code: ags

Base* o = array[0];
o.GetSetting(); //This causes AbortGame because it calls Base::GetSetting instead of A::GetSetting

And if I do this :
Code: ags

A* o = array[0]; //The compiler forbids this. It doesn't know how to cast back from Base* to A*

Do you have an idea to make polymorphism work? Something like GUIControl::AsLabel or GUIControl::AsButton.
If I try to write this I'll encounter the same issue as before :
Code: ags

A* AsA(this Base*)
    return this; //AGS won't know how to cast from Base to A.
As far as I can see, in AGS (patch9) : (September 2021)

This works and it's really cool :
Code: ags

managed struct A {  // <-- MANAGED
  int i;

struct B {  // <-- NOT MANAGED
  A* a; // <-- Pointer to managed.

This works and it's really cool too:
Code: ags
managed struct A
  int i;

struct B{
  A* array[];

Later :
Code: ags

   B b;
   b.array = new A[10];
   b.array[0] = new A;
   b.array[0].i= 666;

This does NOT work :
Code: ags

struct A {  // <-- NOT MANAGED
  int i;

struct B {  // <-- NOT MANAGED
  A a; // <-- Compiler error! Non-managed inside struct.

This does NOT work :
Code: ags

managed struct A {  // <-- MANAGED
  int i;

managed struct B {  // <-- MANAGED
  A* a; // <-- Compiler error! Pointer to managed inside a managed.

I want to build the SDL2 branch of the Engine on Windows 10.

I'm following those instructions : https://github.com/adventuregamestudio/ags/blob/master/Windows/README.md

Here is what I've tried :

1. Open Visual Studio 2019
2. Clone repository : https://github.com/adventuregamestudio/ags.git
3. VS asks me if I want to convert the project to VS2019. I say yes.
4. Switch to branch ags3--sdl2
4. Open solution 'Engine'
5. Download SDL2 from https://www.libsdl.org/download-2.0.php ( SDL2-2.0.16-win32-x86.zip ) , unzip it to a random folder
6. In project Engine.App, set the path to SDL2's include folder as shown here : https://lazyfoo.net/tutorials/SDL/01_hello_SDL/windows/msvc2019/index.php
7. In project Engine.App, set the path to SDL2's lib folder as shown here : https://lazyfoo.net/tutorials/SDL/01_hello_SDL/windows/msvc2019/index.php
8. Download glext.h from here ( https://www.khronos.org/registry/OpenGL/api/GL/glext.h ) and put it in SDL's include folder for convenience. EDIT: I don't know if it's still needed
9. Download SDL_sound from here ( https://hg.icculus.org/icculus/SDL_sound/archive/997e90562b35.tar.gz ). Unzipped it to a random folder. In project Engine.App, set up the path to SDL_Sound's include folder.

Clean the solution , rebuild the solution.

No compilation error, but linking error : SDL_sound.lib cannot be found.
It's not in the prebuilt package : https://www.dropbox.com/s/3vdq7qw01tdtfux/ags-prebuilt-libs-3.5.x.zip?dl=0

How do I get SDL_sound.lib ?
In the past I've built it myself but I cried so many tears of blood trying to download the dependency of the dependency of the dependency for whatever many libs that I'm not doing it again.
Hi everyone,

This topic is awfully specific and I'm totally OK to delete it if I get a few matches.
But I know that there are Point n click enthusiasts out there in Sweden, they're just hard to find. I found some in Stockholm, and I found some in Göteborg. But what about Örebro?
Drop me a private message if you're not too fond on giving away personal info publicly on this thread.
Version: AGS patched with latest build

- I had a 320x200 game.
- I changed the resolution to 640x400
- AGS asked me : "Do you want to automatically rescale the GUIs?" - I said no.
- I created a new room
- I set a 320x200 background
   So now I have a 640x400 game with a 320x200 background

- I run the game.
Now, this:
I see the 320x200 image fill only the top-left quarter of the screen. Why not, I'm not really shocked here I didn't expect AGS to upscale it for me.

Then I add this :
Code: ags

function room_RepExec()
  if (mouse.IsButtonDown(eMouseLeft)) {
    Display(String.Format("%d, %d", mouse.x,  mouse.y));

This way every time I click I see the mouse position in room coordinates.

To my great surprise when I click in the bottom right of the screen the coordinates are 320,200.

Can someone explain this contradiction?
- The actual background of this 320x200 room is rendered as a 320x200 image in the top-left quarter of the 640x400 game (in other words: no upscale)
- the room coordinates are upscaled so that room coordinates (320,200) match screen coordinates (640,400) (in other words: upscaled)

Is that expected behaviour?
Version : Using the Editor from this build (somewhere around 3.1.5.x EDIT: 3.5.1.x).

This doesn't really need to be fixed, just thought I'd let you know.

Scenario :
- 32-bit game, 640x400
- Open the Sprites "manager" from the AGS Editor
- Right-click : "Import new Sprite(s) from file"
- Select this PNG file
- First weird thing : The colors in the preview popup are broken
- Click "Import" anyway. Error popup :" Unknown pixel format".

The image doesn't have transparency, it's a very basic PNG file created using Paint.net 4.2.15

Note: No problem importing when I force Pant.Net to save it with 32-bit colors. The image that caused issues was saved with settings "auto-detect format". I don't know if it created it with a weird palette behind the scenes, I'm just curious why AGS (and its perfectly standard middleware, like LibPNG) fails to read that specific format.
AGS Same issue with (beta 5) and

I've never experienced that issue before in any of the thousands of lines of code that I've written.
Annoyingly, I didn't manage to isolate this issue in a simple piece of code. All I can do is provide the complicated AGS project (DOWNLOAD HERE).
I think the issue is in AGS' virtual machine, not in my code. A bug in the stack/heap or something.

Simply open it and run it. You will get "Error releasing pointer: Invalid handle".

This happens on the line containing a closing curly bracket ( } ) because I'm guessing that's where the engine frees local variables.
The issue is definitely with variable "keys" which contains the result of Dictionary.GetKeysAsArrays (i.e. a String[]), and here is how I know it : If you get rid of variable "memberName" and use "keys[ i]" instead directly, then you will get the same error ("invalid handle") on the line where you try to read keys[ i].

Interestingly the error does not happen in any of the subfunctions that have their own local versions of .GetKeysAsArrays (e.g. function ToConsole). It happens only in this block. So I suspect a weird obscure bug in the virtual machine.
I suspect that the handle to the pointer (I mean the handle that's local to this specific code block) becomes messed up when we call GetKeysAsArrays again on the same Dictionary but in another context (inside a subfunction or something) and then try to use the original handle. But it's just a theory.

I'll try with the new compiler, maybe it will help.
EDIT: I don't know how to get a built version of AGS 4.

Here I've rewritten the function without all the obscure code and macros, it's much easier to read:
Code: ags

void MyFunction()
        Dictionary* o = ...

        String keys[] = o.GetKeysAsArray();
        for (int i=0; i<o.ItemCount; i++) {
          o.ToConsole(); //This uses GetKeysAsArray to iterate on every key and write the vale into a file
          //AGS engine is having issues managing keys[i] all the way through. At some point it throws "invalid handle"
          String memberName = keys[i];
          String memberValue = o.Get(memberName); //You can try to use keys[i] instead of memberName and see what happens
          if (memberValue != "undefined") {
              o.Set(memberName, "undefined"); //You can try to use keys[i] instead of memberName and see what happens