Calling script functions from code

Get technical support about the C++ source code and about Lua scripts for maps, entities, GUIs, the console, materials, etc. Also covered are the Cafu libraries and APIs, as well as compiling, linking, and the build system.
User avatar
Carsten
Site Admin
Posts:2170
Joined:2004-08-19, 13:46
Location:Germany
Contact:
Re: Calling script functions from code

Post by Carsten » 2012-09-21, 21:58

Did you add the ScriptTracker to the AllTypeInfos list in file GameImpl.cpp?

This is the result of a very unfortunate technical problem, as the comment above the AllTypeInfos list explains, and I just realize that we really need better diagnostics for this case.

(Your post just gave me some inspiration for something... I'll try it out.)
Best regards,
Carsten
Stoo
Posts:42
Joined:2012-05-11, 00:28

Re: Calling script functions from code

Post by Stoo » 2012-09-25, 13:22

Carsten wrote:Did you add the ScriptTracker to the AllTypeInfos list in file GameImpl.cpp?

This is the result of a very unfortunate technical problem, as the comment above the AllTypeInfos list explains, and I just realize that we really need better diagnostics for this case.
Didn't know about that one... that did make it visible to the map script. The GUI still doesn't see it though... I'm running

Code: Select all

    if ScriptTracker_001 then
        Console.Print("Found ScriptTracker instance from GUI!\n")
    else
        Console.Print("Could not find ScriptTracker instance\n")
    end
on both the map script and GUI script (well, the map says "from Map!"); the map takes the first branch, and the GUI the second.

The more I think about this, the more sense it makes to integrate this into the HumanPlayerEntity code, as part of the UI portion. This would also allow script information to be filtered by who should be able to "see" it (team-based info, for instance). Only issue with that is, the GUI script can't see Player1 either! :lol:

Is this an easier problem if the class that launches the GUI is the only one that needs to be visible from the GUI script?
User avatar
Carsten
Site Admin
Posts:2170
Joined:2004-08-19, 13:46
Location:Germany
Contact:

Re: Calling script functions from code

Post by Carsten » 2012-09-25, 22:41

Ok, that sounds good.
For the first half of the problem, I've just created this ticket that I intend to implement very soon:
http://trac.cafu.de/ticket/123


About the second half, if I understand your problem correctly, you want an augmented version of the human players GuiHUD, right?

Well, I have a "solution" for you, but it's downright ugly, more a work-around than a solution, and I'm somewhat ashamed of it: :oops:

1. In the HumanPlayer entity code, you learn the data that is relevant for you from the ScriptTracker entity. (Btw., with the new DoSerialize() and DoDeserialize() code it would even be possible to store the data in the HumanPlayer entity directly, in each of them, bypassing the ScriptTracker entity. Just a thought.)

2. Then, still in the HumanPlayer entity code, you would update your augmented version of the GuiHUD analogously as the existing sample code does: GuiHUD->GetScriptState().Call(...);

3. The only problem is that you cannot easily react on events that occur in the GuiHUD in the HumanPlayer code: with things as they are, we have no callback from the GuiHUD into the HumanPlayer.
And this is where things get ugly: You could implement a polling mechanism. For example, as long as

Code: Select all

std::string result;
GuiHUD->GetScriptState().Call("GetSomeChoice", ">S", &result);   // S, not s
yields result == "" (checked each frame), the player made no choice, otherwise, a choice was clicked.


Well, as I said, neither can I see if that actually helps your problem (did I understand it right?), nor is this a particularly elegant solution.

Better solutions would register callback functions to the GuiHUD script state, and/or bind the HumanPlayer instance to it (hey I like this one!), but for that I needed more time than I have tonight, and more thorough understanding of your problem, and possibly some sample code.

Hope this helps anyway! :up:
Best regards,
Carsten
Stoo
Posts:42
Joined:2012-05-11, 00:28

Re: Calling script functions from code

Post by Stoo » 2012-09-27, 01:33

Carsten wrote:Ok, that sounds good.
For the first half of the problem, I've just created this ticket that I intend to implement very soon:
http://trac.cafu.de/ticket/123
That would be helpful; though for me it was more of a gotcha than anything else... especially since my vehicle code didn't need to be added to it! (Presumably because it's non-static?) It would definitely help the moddability, though.
Carsten wrote: About the second half, if I understand your problem correctly, you want an augmented version of the human players GuiHUD, right?

Well, I have a "solution" for you, but it's downright ugly, more a work-around than a solution, and I'm somewhat ashamed of it: :oops:

1. In the HumanPlayer entity code, you learn the data that is relevant for you from the ScriptTracker entity. (Btw., with the new DoSerialize() and DoDeserialize() code it would even be possible to store the data in the HumanPlayer entity directly, in each of them, bypassing the ScriptTracker entity. Just a thought.)

2. Then, still in the HumanPlayer entity code, you would update your augmented version of the GuiHUD analogously as the existing sample code does: GuiHUD->GetScriptState().Call(...);

3. The only problem is that you cannot easily react on events that occur in the GuiHUD in the HumanPlayer code: with things as they are, we have no callback from the GuiHUD into the HumanPlayer.
And this is where things get ugly: You could implement a polling mechanism. For example, as long as
Code:
std::string result;
GuiHUD->GetScriptState().Call("GetSomeChoice", ">S", &result); // S, not s
yields result == "" (checked each frame), the player made no choice, otherwise, a choice was clicked.
That's actually not bad at all... My intention was to just dump anything that the UI might need into the HumanPlayerEntity, since it's already handling a lot of the networked UI pieces anyway (health, etc.). Do/DeSerialize also look very easy to use! (Is there any backend work to avoid sending the same data repeatedly; or will I need to work out some caching system to keep from sending long tables of script values every frame?) I've already got the HumanPlayerEntity launching the GUI and updating a value and polling for a response; at this point I'm just trying to work out how to tie a script function to a GUI button to generate said response :P
Carsten wrote:Better solutions would register callback functions to the GuiHUD script state, and/or bind the HumanPlayer instance to it (hey I like this one!), but for that I needed more time than I have tonight, and more thorough understanding of your problem, and possibly some sample code.
It would be nice to get a callback (and I can see registering the calling entity as well), but I'm not too worried about it at this point. Right now, I'm just structuring the code so I can go from a polling system to a callback system once I know how to do that. It might help that right now, it only calls to update the menu when the player isn't active (ie, not in the Alive state).
Carsten wrote:Hope this helps anyway! :up:
It does! Made a far bit of progress, actually :thx:

Like you said, it's not *ideal*, but it'll keep me going on this until I can rework it. I'm very much in the "write now, optimize later" mode! :lol:
User avatar
Carsten
Site Admin
Posts:2170
Joined:2004-08-19, 13:46
Location:Germany
Contact:

Re: Calling script functions from code

Post by Carsten » 2012-09-30, 21:58

Hi Stoo,
Stoo wrote:That would be helpful; though for me it was more of a gotcha than anything else... especially since my vehicle code didn't need to be added to it! (Presumably because it's non-static?)
The vehicle didn't need to be added (only) because it was referenced from something else that was, so in general, all entity classes should still be added to that list. ;-)
Do/DeSerialize also look very easy to use! (Is there any backend work to avoid sending the same data repeatedly; or will I need to work out some caching system to keep from sending long tables of script values every frame?)
Yes, there is a powerful backend that handles all caching and compression. Writing the same data twice essentially sends no bytes at all across the wire, no matter how large the data written in DoSerialize() is (within limits).
That's the real beauty of these methods. :cheesy:
I've already got the HumanPlayerEntity launching the GUI and updating a value and polling for a response; at this point I'm just trying to work out how to tie a script function to a GUI button to generate said response :P
[...]
It would be nice to get a callback (and I can see registering the calling entity as well), but I'm not too worried about it at this point. Right now, I'm just structuring the code so I can go from a polling system to a callback system once I know how to do that.
As I indicated in my previous post, last night I tried binding the HumanPlayer entity to the GuiHUD script's state directly. It's actually pretty easy, and I have it running here with very nice results, but there is still one problem to solve before I can post it: Having the HumanPlayer entity holding the GuiHUD which in turn holds a reference (IntrusivePtrT<>) back to the HumanPlayer creates a circular reference that prevents the HumanPlayer from being properly deleted when the map is quit.
Will report back when I got it done. :up:
Best regards,
Carsten
Stoo
Posts:42
Joined:2012-05-11, 00:28

Re: Calling script functions from code

Post by Stoo » 2012-09-30, 22:13

Carsten wrote: Yes, there is a powerful backend that handles all caching and compression. Writing the same data twice essentially sends no bytes at all across the wire, no matter how large the data written in DoSerialize() is (within limits).
That's the real beauty of these methods. :cheesy:
Ooh, that'll be handy! How lazy does it let me get? Will it let me cram all the script variables into one string and only send across changes to that string, or do I still need to break them out into a list or something for it to detect which ones need updated? I'll be seperating it some anyway; just want to know what the limits are :P
Carsten wrote: As I indicated in my previous post, last night I tried binding the HumanPlayer entity to the GuiHUD script's state directly. It's actually pretty easy, and I have it running here with very nice results, but there is still one problem to solve before I can post it: Having the HumanPlayer entity holding the GuiHUD which in turn holds a reference (IntrusivePtrT<>) back to the HumanPlayer creates a circular reference that prevents the HumanPlayer from being properly deleted when the map is quit.
Will report back when I got it done. :up:
Didn't realize that might be an issue... not sure if it's crossed your radar yet, but the vehicle code I put in does the same thing. No idea how your garbage collection works (I assume that's where this is tripping up?), but that could be an issue there as well.

Look forward to seeing what you come up with!
User avatar
Carsten
Site Admin
Posts:2170
Joined:2004-08-19, 13:46
Location:Germany
Contact:

Re: Calling script functions from code

Post by Carsten » 2012-10-07, 23:44

Stoo wrote:Ooh, that'll be handy! How lazy does it let me get? Will it let me cram all the script variables into one string and only send across changes to that string, or do I still need to break them out into a list or something for it to detect which ones need updated? I'll be seperating it some anyway; just want to know what the limits are :P
Well, the EntHumanPlayerT::Do(De)Serialize() methods give a pretty good example of what it can do and how it is supposed to be used; also check out their documentation.

You can use strings, or individual variables as required.

At this time though, there is a limit on the maximum amount of data that you can write (though it is difficult to provide hard numbers right now), so try to keep things small. I'd say that roughly twice of what the EntHumanPlayerT is sending right now should not be exceeded. (In the average case, compression reduces it to almost zero, this is just a worst case estimate that can occur if on level start, the entity is initialized with all non-zero data.)
Didn't realize that might be an issue... not sure if it's crossed your radar yet, but the vehicle code I put in does the same thing. No idea how your garbage collection works (I assume that's where this is tripping up?), but that could be an issue there as well.
Not a problem here: The

Code: Select all

IntrusivePtrT<EntVehicleT> PilotedVehicle;
member of EntHumanPlayerT indeed prevents the vehicle from leaving the map as long as the player is referring to it, but when the player leaves, it automatically frees the vehicle as well.

Look forward to seeing what you come up with!
I got it working, see http://trac.cafu.de/changeset/647 for the required details. :-D
(You have to upgrade everything else to r647 for this to work as well. If this is not an option for you, at least the Libs/UniScriptState.* files must be updated, but I've not checked if that's truly all (compared to r625).)

With this, you can write e.g.

Code: Select all

 x, y, z = Player:GetOrigin()
in the HUD GUI script code.
It works really nice, but I'm sorry to say that I've not yet been able to provide some concrete example usage code as well. Will do so however as soon as I can (I toyed a bit too much with Mercurial and Git these days, so everything else got temporarily stalled. ;-) )
Best regards,
Carsten
User avatar
Carsten
Site Admin
Posts:2170
Joined:2004-08-19, 13:46
Location:Germany
Contact:

Re: Calling script functions from code

Post by Carsten » 2012-10-25, 23:02

Hi Stoo,

I'm sorry that it took me so horribly long to complete this, but I've just finished a series of changes that show how you can very nicely "communicate" between the EntHumanPlayerT code and its HUD script code: see HUD_main.cgui for the updated example.

As explained in the comments, note that it works, if desired, in a "bi-directional" manner: You can easily call from the HUD script into the EntHumanPlayerT C++ code, and vice versa!

In order for this to work, you also have to upgrade the C++ code to the current SVN head revision r654, but that should not be a problem, as the changes are relatively few and (as I hope) clear.

Hope this helps! :up:
Best regards,
Carsten
Post Reply

Who is online

Users browsing this forum: No registered users and 6 guests