Plugin API: Managed Objects - huh?

Started by edmundito, Mon 10/10/2005 02:43:07

Previous topic - Next topic

edmundito

Can someone explain and give out some examples on the API Functions RegisterManagedObject, AddManagedObjectReader, and so on? I keep scratching my head when I read Plugin API doc.  ???

Yep, I'm a total n00b at plugins.

scotch

#1
The documentation is fairly unclear on the subject, and I'd like to make an OO interface to my plugin, so I tried to work out how to use them, here is what I have gathered...

Managed objects are objects created in the plugin that the script can manipulate using a pointer, the pointer is reference counted, so your plugin will be notified when the object is no longer needed by the script and you can delete it.

A managed object type needs a couple of classes implemented for it and passed to the runtime so that AGS can use it -
IAGSScriptManagedObject ( which is responsible for destroying objects that aren't needed, and serializing them for when the game is saved) and IAGSManagedObjectReader (which is responsible for rebuilding objects from the saved data).

The interface that the managed object uses should be declared in the script header for your plugin using a struct definition, in my test I had an object called Circle, and the header was like this -
Code: ags
managed struct Circle {
		import attribute int radius;
		import int getArea();
		import static Circle* create();
Ã,  };
import Circle* CreateCircle();


The "managed" keyword makes it impossible to declare a struct in the script, which would not do what you wanted, you can only manipulate it with a pointer that you get from a function, such as the CreateCircle one I put there.
All the members should be declared with "import" so that the engine looks for them in your plugin.
The "attribute" thing is needed on member variables that you want to be able to get from the object in the plugin, when you specify a member variable as an attribute then you need to create get_name and set_name member functions and tell the engine about them.Ã,  In that case I had to make "Circle::get_radius" and "Circle::set_radius".
Now, this worked fine with int parameters, but I couldn't get the get_radius function to work with a float return type, not sure what I was doing wrong yet.

I could write more, but it's probably more confusing than showing some code, so here:

http://caverider.com/ags_managedtest.cpp

With that you can create and manipulate Circle objects.

CJ, would it not be possible to register member variables in a quicker way, saving the get/set functions, by using something like
engine->RegisterManagedObjectMember("Circle", "float radius", offsetof(Circle, radius));
that'd give you the byte offset of the variable in the object so AGS can manipulate it directly.Ã,  Just an idea... the get/set method has its advantages also.

All in all ManagedObjects seem really useful, I'll use them for my game.


EDIT: found this thread http://www.adventuregamestudio.co.uk/yabb/index.php?topic=22628.0 which covers some of the stuff, still, could anyone answer the question about returning floats, or does it work for everyone else?

Pumaman

scotch has given a nice introduction to using managed types from plugins. As he's also pointed out, there is more information in this thread:
http://www.adventuregamestudio.co.uk/yabb/index.php?topic=22628.0

QuoteCJ, would it not be possible to register member variables in a quicker way, saving the get/set functions, by using something like
engine->RegisterManagedObjectMember("Circle", "float radius", offsetof(Circle, radius));
that'd give you the byte offset of the variable in the object so AGS can manipulate it directly.  Just an idea... the get/set method has its advantages also.

Well, property accesses are generated as function calls by the script compiler, so AGS would have to effectively generate a wrapper get/setter in this situation anyway. Also, generally you'd want to do some sort of validation in the setter. However I see what you're saying, and it would perhaps simplify the process of creating plugins.

Quotecould anyone answer the question about returning floats, or does it work for everyone else?

Floats are a bit special in the AGS scripting system. This is because most compilers such as GCC and MSVC always convert floats to doubles (64-bit) when passing to and from functions, whereas the AGS script actually uses them as 32-bit floats.

This is an extract from the AGS Source Code on how the engine deals with this problem. It's not pretty.

#define SCRIPT_FLOAT(x) long __script_float##x
#define INIT_SCRIPT_FLOAT(x) float x = *((float*)&__script_float##x)
#define FLOAT_RETURN_TYPE long
#define RETURN_FLOAT(x) return *((long*)&x)

int FloatToInt(SCRIPT_FLOAT(value), int roundDirection) {
  INIT_SCRIPT_FLOAT(value);

  int intval = (int)value;

  return intval;
}

FLOAT_RETURN_TYPE IntToFloat(int value) {
  float fval = value;

  RETURN_FLOAT(fval);
}


Above are some examples of a (stripped-down) version of FloatToInt and IntToFloat to demonstrate how the macros are used.

edmundito

#3
OMG! Teh Source has been leaked. Now everyone shall make their own AGS-clone!

Um, yeah, I looked at that older thread, but it just gave me a headache, because everyone talked assuming that they knew the whole managed objects stuff already.

Anyway, I think I'm starting to get it.

Kweepa

Quote from: Edmundo on Mon 10/10/2005 20:16:02
Um, yeah, I looked at that older thread, but it just gave me a headache, because everyone talked assuming that they knew the whole managed objects stuff already.

Yeah, what was that about? I was rather confused too. Managed? Where did that terminology come from and how come everyone was bandying it around like it was common knowledge?
Still waiting for Purity of the Surf II

edmundito

#5
Quote from: SteveMcCrea on Mon 10/10/2005 23:19:19
Quote from: Edmundo on Mon 10/10/2005 20:16:02
Um, yeah, I looked at that older thread, but it just gave me a headache, because everyone talked assuming that they knew the whole managed objects stuff already.

Yeah, what was that about? I was rather confused too. Managed? Where did that terminology come from and how come everyone was bandying it around like it was common knowledge?

Obviously, this is all one big joke between Scotch and Puma that they devised at Mittens last year to confuse everyone.  :=

Edit: Good example... now I pretty much understand it.

One weird thing, though, on AGS 2.71 RC (well who knows if it's 2.7 too): The little helper window that pops up with the member functions does not pop up for Circle or Circle's members, and I noticed that you indeed registered the names:

  engine->RegisterScriptFunction("Circle::create^0", CreateCircle);
  engine->RegisterScriptFunction("Circle::getArea^0", Circle_getArea);
  engine->RegisterScriptFunction("Circle::set_radius", Circle_set_radius);
  engine->RegisterScriptFunction("Circle::get_radius", Circle_get_radius);
  engine->RegisterScriptFunction("CreateCircle", CreateCircle);

scotch

#6
Thanks CJ!
Hm, you are right about the plugin's script header not being picked up by the autocomplete, Edmundo, not sure what's up there.
And I had no idea about managed objects either :P I had to work this out with trial and error, like struct member functions, CJ adds cool stuff, and doesn't even tell anyone how to use it!

Edit by strazer:

AGS v2.71 RC2:
* Fixed plugin headers not being parsed for autocomplete in RC 1.

edmundito

#7
Okay, say that you have this...

Struct A { MyManagedObj *B; }

and you have

A a;
a.B = createB();
MyManagedObj *C = a.B;

AGS says it's missing A::get_B. how do we get around this situation?

Pumaman

How exactly have you defined the struct? The "missing A::get_b" message will appear if you used "attribute" when declaring the variable, but didn't provide such an attribute definition in the plugin.

edmundito

#9
I got my problems fixed, and thanks to scotch I understand this stuff pretty well. However, there was still some problems passing objects to functions and changing the values, so the best way for me to tacle the problems were like:

Code: ags
MyManagedObj* f() {
  MyManagedObj *temp = MyManagedObj.new();
  temp.number = 5;
  return temp;
}


followed by:

Code: ags
MyManagedObj *a = f();


Instead of having:

Code: ags
function f(MyManagedObj *temp) {
  b.number = 5;
}


followed by:

Code: ags
MyManagedObj *a = MyManagedObj.new();
f(a);


I just forgot about making functions with a type (eg- MyManagedObj whatever() {})  on AGS since usually function whatever() can return a lot of the types that I usually need, you know? and there was no need for it with pre-2.7 scripting, anwyay.

scotch

Somewhat related, is it possible to take Strings as parameters to a plugin function? How would I do it, if it is?

Pumaman

#11
Yes, just declare the function as taking a "const string" parameter in the script header, and then in your plugin code declare it as a "const char*" and it'll be fine.

One thing you can't do at the moment though is return a String from a plugin function, which is something I should add.

Edit by strazer:

AGS v2.71 RC2:
* Added plugin API CreateScriptString method to allow plugins to return Strings.

edmundito

While we're on this topic of advanced stuff for AGS, I think there needs to be a programmer's manual for AGS featuring the unofficial support for stuff that is an optional download from the website. it would include information on the API functions as well and so on, but also on struct inheritance and other features not mentioned in the manual.

For example, I don't know if you can have private/protected functions on structs. Some guy claimed that you could, but he didn't know the syntax, so he was worthless.

Janik

Thanks for that sample code you posted, scotch - it was a great help for a plugin I am working on at the moment. I think it could be made part of the official plugin documentation.

Managed objects look like a very useful addition. They certainly made life easier for my plugin. I imagine that for the many people working on AGS RPGs, creating a custom object for a character's stats etc. would be a godsend.  :=
Play pen and paper D&D? Then try DM Genie - software for Dungeons and Dragons!

SMF spam blocked by CleanTalk