GameMonkey Script

GameMonkey Script Forums
It is currently Tue Oct 23, 2018 3:54 pm

All times are UTC




Post new topic Reply to topic  [ 9 posts ] 
Author Message
PostPosted: Sat Aug 01, 2009 7:25 am 
Offline

Joined: Fri Jul 24, 2009 1:09 pm
Posts: 27
Currently in my game, all entities and resources that the script should be dealing with have unique identifiers, so the script only needs to pass this ID to the function it's calling and it can work on the data of that entity/resource:
Code:
set_current_level_tile(6, 8, `OBJECT_LAYER`, 57);


However, I'm guessing that providing a free function for every possible operation on a C++ type might become tedious. Is this the case? I read somewhere (perhaps on this forum or an article or something) that keeping C++ objects out of script is a good thing. Is this the case?

I haven't bound any C++ objects to GM script yet, purely because my game isn't that complex yet. However, soon I will need the script to access several different data members of objects and I'm wondering if I should stop providing free functions and go straight to binding these objects for GM to work with.

Also, once the script has done all it needs to with a C++ type, how does it send the changes back to C++? E.g. would a script look something like this:
Code:
player = get_player();
if(player.x == 6 && player.y == 8)
{ // Stepped on lava!
    player.health = player.health - 1;
}

set_player(player);
Or is there a way to get a reference to the player so that changes are directly reflected back to the C++ object? Feel free point me to the documentation and call me a dick if it's there haha...

Cheers.


Top
 Profile  
Reply with quote  
PostPosted: Sun Aug 02, 2009 3:07 pm 
Offline

Joined: Thu Jan 01, 2004 4:31 pm
Posts: 307
For this you'd want to create a user type (call it player/entity, etc), then in your get_player() function, return a gmUserObject of this type that holds the pointer to your player (or the id/hanlde of your player). On the user type, bind the get/set dot operators to functions which, when called, will receive gmUserObject as one of the operands - you can then resolve this to your C++ object and then do what you need to.

My GM Article part 2 (see resources) will show some of this using the example of a vector. If you need a hand, shout back on this forum.


Top
 Profile  
Reply with quote  
PostPosted: Sun Aug 02, 2009 11:53 pm 
Offline

Joined: Fri Jul 24, 2009 1:09 pm
Posts: 27
Hey downgraded. Thanks for the reply.

Now I understand how to do it, but I'm still curious as to whether you think it is advisable to do it this way, or keep using free functions.


Top
 Profile  
Reply with quote  
PostPosted: Mon Aug 03, 2009 5:21 am 
Offline

Joined: Sat Apr 25, 2009 1:40 am
Posts: 66
One thing you need to remember when binding objects that will be handled by the game and by the scripting engine is to only ever allow it to be freed by the Game Monkey GC. That means if you want to make a user type that wraps around the "Player" object than the only place in your entire source code that you will ever see:

delete (Player*)blah;

is in the Gamemonkey Destruct callback for that type.


Top
 Profile  
Reply with quote  
PostPosted: Mon Aug 03, 2009 8:13 pm 
Offline

Joined: Fri Jan 14, 2005 2:28 am
Posts: 439
I would say the opposite. Any game objects your bind directly to the scripting system should NOT be given ownership to the scripting system. This means that it doesn't matter what references the object, the GC will never attempt to delete the object it is bound to. You are asking for trouble if you allow the GC to manage lifetime of your game objects.


Top
 Profile  
Reply with quote  
PostPosted: Tue Aug 04, 2009 8:32 am 
Offline

Joined: Sat Apr 25, 2009 1:40 am
Posts: 66
DrEvil-OB wrote:
I would say the opposite. Any game objects your bind directly to the scripting system should NOT be given ownership to the scripting system. This means that it doesn't matter what references the object, the GC will never attempt to delete the object it is bound to. You are asking for trouble if you allow the GC to manage lifetime of your game objects.


...Then what if the object is stored in a global variable or is being referenced in a running thread and then the game decides to delete that object (like if the player left the game, the game might try to delete the object)

This is what i do for objects that is both being used by the game engine and the script engine:

-When the game engine wants to create a new instance of "Player", it creates it and also it creates the gmUserObject for it and binds them together. It then calls gmMachine::AddCPPOwnedObject() on the new object.

-Now both can access the object and won't have to worry about wether or not that object has been deleted.

-When the game wants to remove that object, call gmMachine::RemoveCPPOwnedObject() on the gmUserObject and set a member called "exists" to false, but don't do any actual deleting. Now the object will only really be deleted if there is no script reference to it.


Oh and ovcourse all other objects that are referencing the player object, and is also accessible by GM must include the player object in the Trace callback


Top
 Profile  
Reply with quote  
PostPosted: Tue Aug 04, 2009 7:48 pm 
Offline

Joined: Fri Jan 14, 2005 2:28 am
Posts: 439
39ster wrote:
...Then what if the object is stored in a global variable or is being referenced in a running thread and then the game decides to delete that object (like if the player left the game, the game might try to delete the object)


Agreed, that's a problem. However I consider that a weakness of GM. Squirrel for example, and perhaps lua. Support the concept of weak references. Weak references mean you can give a weak reference to the scripting system, and if you delete that object on the c++ side, that reference becomes invalid, and anyone holding that reference in the script would effectively be holding a 'null' basically.

I have a simple emulation of weak references in my project. I pass script objects to script representing the 'bot' in my FPS bot project. Scripts use the 'bot' reference all the time in many different ways. If a bot is kicked from the game, obviously that bot reference becomes invalid, and any number of scripts may still be referencing it, I have no way of knowing. What I do in the destructor to my bot class, is get the gmUserObject, and null out the pointer that would normally point to the memory that is to be deleted. This means that if anyone attempts to access something on that user object from script after it is deleted, the game doesn't crash, it just throws a script exceptions and the game continues, just as if those scripts attempted to call a function or access a variable from a null variable. My binding class simply verifies that the pointer to the actual object is not null. It's not perfect, but it works. One of these days I'm going to try to think of a more proper 'weak reference' implementation and see if it's doable in GM.

39ster wrote:
This is what i do for objects that is both being used by the game engine and the script engine:

-When the game engine wants to create a new instance of "Player", it creates it and also it creates the gmUserObject for it and binds them together. It then calls gmMachine::AddCPPOwnedObject() on the new object.


Yep I do this too.

39ster wrote:
-When the game wants to remove that object, call gmMachine::RemoveCPPOwnedObject() on the gmUserObject and set a member called "exists" to false, but don't do any actual deleting. Now the object will only really be deleted if there is no script reference to it.


I see. I don't trust the GC to do the deleting of all my objects that I bind to script. The GC is my least favorite part of GM. As it is, it already builds up too much memory usage before it starts deleting stuff, and I prefer the object deletion not to be deferred some unknown duration.


Top
 Profile  
Reply with quote  
PostPosted: Wed Dec 16, 2009 2:34 pm 
Offline

Joined: Fri Jun 19, 2009 12:39 pm
Posts: 31
39ster wrote:
...Then what if the object is stored in a global variable or is being referenced in a running thread and then the game decides to delete that object (like if the player left the game, the game might try to delete the object)

This is what i do for objects that is both being used by the game engine and the script engine:


I think this is where it comes down to having good, consistent programming practices, both in your C++ code and in script code itself.

My take on this is that I never rely on global variables in script to hold a reference to a game object. I would never do this in C++, so why would I do it in script?

There's also the case of using one system to manage your objects or another system, but not both at the same time. The choices I made were that my object manager and lower level code beneath that are totally responsible for managing an objects life time. Game Monkey is used only as an external access point to my architecture, where I can implicitly use it to create and destroy objects.

But I never, ever use GM as a garbage collector. I do that myself by using smart objects with smart pointers, and knowing that the LAST place an objects ref count will reach zero is when it is explicitly removed from my system.

And this sort of follows on to something very important about how you design your systems. My first rule in writing a framework is "you should ALWAYS know the life time of an object". There's the question of do you allow dynamic allocation of object during a game frame too, but that's something for the gamedev.net or gamasutra forums and depends on your platform :)


Top
 Profile  
Reply with quote  
PostPosted: Thu Dec 17, 2009 6:22 pm 
Offline

Joined: Fri Jan 14, 2005 2:28 am
Posts: 439
Just to add, even if you are completely sure about what system is responsible for creating and deleting your game objects, the references you pass to script are out of your control, expecially if you will be taking advantage of gm threads, coroutines, etc. This basically means you have to emulate weak references in some way, because threads can be blocked or sleeping or otherwise referencing your object when you delete them. I generally have most of my objects maintain a list of thread ids they will kill when they get destroyed, but that's not a complete solution. The worst case is that if a thread wakes up with a reference to a deleted object it will cause an exception on the gm thread, thereby killing the thread and printing a message "script function on null object"


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 9 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB® Forum Software © phpBB Group