I have some Character* variables in a module script that I need to expose, but that I would like to stay read-only outside of the script. To that end, instead of just exporting the variables globally, I'm trying to put them as static attributes inside of a struct, with getters that return the script-local values:
struct MyModule
{
import static readonly attribute Character* ActiveCharacter; // $AUTOCOMPLETESTATICONLY$
import static Character* get_ActiveCharacter(); // $AUTOCOMPLETEIGNORE$
};
Implemented in the script as:
Character* _activeCharacter;
static Character* MyModule::get_ActiveCharacter()
{
return _activeCharacter;
}
However, when I try to actually refer to this character, I get a compilation error:
MyModule.ActiveCharacter.Say("Blah blah"); // Fails to compile
"must have an instance of the struct to access a non-static member"
It works (or at least, it doesn't throw a compilation error: I haven't been able to test it live) if I instead write:
Character* c = MyModule.ActiveCharacter
c.Say("Blah blah");
However, that is massively less convenient, and makes the whole approach pretty much useless for me.
It seems to be related to this bug: http://www.adventuregamestudio.co.uk/forums/index.php?topic=32083.0
Is there any way around this or some way to fix it?
The only workaround presently is to not use static attributes.
struct MyModule_t // renamed, because we have to use an instance rather than statics
{
import readonly attribute Character* ActiveCharacter;
};
import MyModule_t MyModule; // import the instance
MyModule_t MyModule;
export MyModule;
Character *_activeCharacter;
Character* get_ActiveCharacter(this MyModule_t*) // switched to extender just to avoid having to rely on $AUTOCOMPLETEIGNORE$, functionally the same
{
return _activeCharacter;
}
MyModule.ActiveCharacter.Say("Blah blah");
This is the method I used in the latest ScrollingDialog module, for example, to achieve such feats as:
ScrollingDialog.ScrollArrows.Up.Padding.Bottom = 2;
It is a hassle to not be able to take full advantage of static attributes, but that's the current situation.
Thanks! That's essentially what I ended up doing, though your version is nicer, with the naming scheme mimicking a static class and the extender trick (I didn't know you could use extenders as attribute accessors).
Quote from: Snarky on Mon 16/10/2017 08:03:52the extender trick (I didn't know you could use extenders as attribute accessors).
Yeah, the way extender methods inject themselves means they are exactly the same as standard struct methods, even down to ridiculous and unnecessary definitions like:
import void Scream(this Character*); // imported using extender method syntax
void Character::Scream() // defined using standard method syntax
{
this.Say("AHHHHHH!");
}
The engine and compiler don't make any distinction between the two once the extender is imported. This makes it particularly useful when attributes are involved, so you don't have to clutter up your struct definition with a bunch of hidden accessor methods. If you did have a static attribute, you can use either an instance extender or a static extender -- either one will work. :=
Quote from: Snarky on Mon 16/10/2017 08:03:52
I didn't know you could use extenders as attribute accessors.
BTW, this also makes it possible to declare "overriding" property accessors for structs that extend parent structs (Or so I remember).