Advertisement

A few questions about fundamentals

Started by January 14, 2011 01:10 PM
25 comments, last by WitchLord 13 years, 8 months ago
You can register the ADDREF and RELEASE behaviours with an empty function. As long as you guarantee the object will stay alive for as long as anyone might reference it, you will not have any problem. The risk is just if you do not have full control of where the scripts may or may not keep a reference, e.g. in global variables, or as members of another object, and so on.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Thanks. Clear.
The next one.
I coudn't figure out the proper way to create an object inside script to return it out.
I'd like to see correct script-side example for something like this:


PhysicalParamsHolder& test4()
{
int id = GetTypeIdByDecl("PhysicalParamsHolder");
PhysicalParamsHolder& pph = CreateScriptObject(id);
pph.setVisual(100);
return pph;
}

(PhysicalParamsHolder is refcounted with factory_func as in manual)
Advertisement

PhysicalParamsHolder@ test4() // Return a handle to PPH
{
PhysicalParamsHolder pph;
pph.setVisual(100);
return pph;
}


You may think of object handles as smart pointers. This article explains how they work on the application side, and this article explains how they work on the script side.

Regards,
Andreas

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game



PhysicalParamsHolder@ test4() // Return a handle to PPH
{
PhysicalParamsHolder pph;
pph.setVisual(100);
return pph;
}


You may think of object handles as smart pointers. This article explains how they work on the application side, and this article explains how they work on the script side.

Regards,
Andreas




[font="arial, verdana, tahoma, sans-serif"]Ok. Works fine.
Uhmmm, some more qs about handles. I want to make clear all the cases when I should explicitly call addRef/release. Just made a test


asWrapper.execute(*ch->context);
PhysicalParamsHolder* ph = *(PhysicalParamsHolder**) (ch->context->GetAddressOfReturnValue());
ph->addRef();
fid = asWrapper.getFucnId("test5", "modA");
asWrapper.setupScriptContext(*ch->context, fid);
ch->context->SetArgAddress(0, ph);
asWrapper.execute(*ch->context);

Without ph->addRef(); it crashes.
I suppose because of on the next call to setupScriptContext an implicit release() is called for PhysicalParamsHolder;
So, I personally have to intervene in reference handling if I want to keep holders alive out of their scope. Other cases?
Is there a case where I have to do it from scripts?
Your assumption is correct. If you do not call addRef on the object returned by the script function, the pointer may become invalid when the context is reused for the next call if the returned handle is the last reference to the object.

The articles I linked to in the previous post should explain most of the situations where you will need to manually call addref and release from the application side.

From the script side, there is no way to call the addref and release behaviours manually. It is all taken care of by the script engine.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Thanks, WitchLord. It's getting better.
The next ones.
1 - What do you think about shared_ptr+proxy / intrusive_ptr strategies? Currently in my project I use shared_ptr+proxy.
But after being writing another ProxyEntity to pass it to AS I became kinda annoyed. Maybe there's a sense to switch to intrusive,
while it's not too late, but I am hesitant, because it demands a lot of reworking and I'm afraid I will have to do addRef/release through
mutexes for it properly to work and MT-environment.
2 - I am not sure I have a right to complain, but is it possible to extend error handling a little further?
To be more concrete - I often get "Failed to prepare the context" and it literally may be anything. The last one happend cause I did a mistake registering enums(registered the same value twice). I spent a lot of time on commenting/uncommenting code to catch that mistake,
when I'd like to get messagelike "Enum X duplicate value attempt". I'd find it more valuable than even new features. So...?
3 - Another issue I'd like to ask. I just tried to create ObjectHolder on stack and pass it to AS, ObjHolder oh; setArg(as &oh); The script itself worked well, but in the end of execution it crashed severly. So I switched to heap-allocated holder and everything's fine. Can you explain what's going on there?
Advertisement
shared_ptr+proxy works great in C++ as the shared_ptr object can overload the -> operator to give the actual pointer to the class allowing you to call the class methods directly without awkward syntax. Unfortunately this doesn't let you take an address of the function that AngelScript can call directly.

If you use shared_ptr you will be forced to implement wrappers for all methods you want to expose to the script. This is not necessarily a bad thing, I do this in my own game engine. In the wrappers I also add logic to shield the script from objects that have been destroyed from the game engine itself. This makes it a lot easier for me to manage the memory in the game engine, as I don't have to worry about release all references to the object before I destroy it.

On the error handling side, it looks like you're not checking the return codes while registering the actual interface. RegisterEnumValue for example returns an error if you attempt to register the same name twice. Always check the return codes. At the very least add an assert so you can validate the registration in debug mode.

Please elaborate on the ObjectHolder problem. How did you implement this class? And how was it used when the application crashed? You may have encountered a bug in the script library, but I need more detail to determine what's going on.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game


shared_ptr+proxy works great in C++ as the shared_ptr object can overload the -> operator to give the actual pointer to the class allowing you to call the class methods directly without awkward syntax.


Wow, may be a code example?



On the error handling side, it looks like you're not checking the return codes while registering the actual interface. RegisterEnumValue for example returns an error if you attempt to register the same name twice. Always check the return codes. At the very least add an assert so you can validate the registration in debug mode.

Damn, I feel ashamed. I forgot to to assign value for assertion checker... Where can I read about return codes in detail?


Please elaborate on the ObjectHolder problem. How did you implement this class? And how was it used when the application crashed? You may have encountered a bug in the script library, but I need more detail to determine what's going on.

ObjectHolders are mostly non-instansiable references. AddRef/Release only

The calling code looks like this

method(boost::shared_ptr<Event> e, boost::shared_ptr<IEntity> reciever)
{
EventHolder eventH(e);
EntityHolder entH(reciever);
asIScriptContext* ctx = reciever->getScriptContext()->context;
asWrapper::Instance()->setupScriptContext(*ctx, mFuncId);
ctx->SetArgAddress(0, &eventH);
ctx->SetArgAddress(1, &entH);
asWrapper::Instance()->execute(*ctx);
}
It crashes after script execution goes to the end, unless you change it to a form of EventHolder* eventH = new EventHolder(e);
I did Print( event.getRefCount() ) at the end of script and it's == 1
The boost::shared_ptr implements the operator-> overload, so in your case you can access the members of the Event of IEntity objects directly with:

e->property;
receiver->Method();

I'm sure you already knew that.


The manual is a good place to look for details about return values. ;)


What is the signature of the script function called with this code? The SetArgAddress() method doesn't increase the ref count so if the script function takes a handle the reference will be decreased at the end of the function thus deleting the object. If the script function takes a reference, then the reference will not be decreased and all is fine. The SetArgObject() is probably a better choice for you, as it has the intelligence to increase the ref count for object handles, or copy the object if the function takes the object by value.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game


The boost::shared_ptr implements the operator-> overload, so in your case you can access the members of the Event of IEntity objects directly with:

e->property;
receiver->Method();

I'm sure you already knew that.
[size=2]

[size="1"]I mean... Ahh, I guess I'm drunk. it's Ok, I'll try that.


[size=2]

What is the signature of the script function called with this code? The SetArgAddress() method doesn't increase the ref count so if the script function takes a handle the reference will be decreased at the end of the function thus deleting the object. If the script function takes a reference, then the reference will not be decreased and all is fine. The SetArgObject() is probably a better choice for you, as it has the intelligence to increase the ref count for object handles, or copy the object if the function takes the object by value.



void func(EventHolder@ eh, IEntityHolder@ receiver) so the trouble is with the method... Yes I confirm. It works via [size=2]SetArgObject. Thank you.

This topic is closed to new replies.

Advertisement