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.
Stoo
Posts:42
Joined:2012-05-11, 00:28
Re: Calling script functions from code

Post by Stoo » 2012-08-03, 03:54

Well, run into another bit of a conundrum...

I got a very basic set of characters all set up in the map script, and was able to pick it up fine running commands through the console. Next step was to be able to select a character before spawning, so the game would associate character stats with the player's HumanPlayer instance. So, I made up a (very) quick GUI, adjusted the HumanPlayer.cpp code to show it when in the appropriate modes (dead, free spectator), and got ready to start pulling the list of characters in from the server.

Problem is, I don't see a good way to do that... I had assumed that I'd be able to do it using the ci object, but it looks like that only works for code-defined objects you've set up elsewhere (ClientStateInGame?). I can invoke runMapCmd through it, but I can't actually get anything back out of it that I can tell (since it goes through ci.RunCommand), unless there's a way to dig for map script values in ci.GetValue().

Is there some easy trick to pull map script objects across from the server? Even better, is there a way to add to the commands/objects ci can respond to with RunCommand and Get/SetValue?
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-08-04, 12:48

Hi Stoo,

I have to admit that I didn't fully understand what you want to accomplish (more about that in a moment), but before I attempt to make any suggestions:
What version of the code do you currently use?

Also, with all my heavy changes to the scripting (binding) code, I just realize that I still have to fix a few minor lose ends:
I removed runMapCmd recently, which is intended mostly for debugging but needs to be added back, and there is a something about calling Lua functions and methods from C++ that I want to improve. I also recently removed the (mis-)feature of loading games from DLLs -- games are now linked statically, and I still have to write and update some documentation about it.

But back to your question:
What do you mean by "character"? The player model, i.e. how the player looks?
If so, I'd not attempt to "pull the list of characters" from the server. As the list must be the same on the server and all clients anyway, why don't you just hard-code the list? (something similar is done already: the list of available player models is hard-coded in the DeathMatch code)

Or do you want to use scripting in order to assign player characteristics (such as initial amount of weapons, ammo, health, etc.)?
Best regards,
Carsten
Stoo
Posts:42
Joined:2012-05-11, 00:28

Re: Calling script functions from code

Post by Stoo » 2012-08-07, 01:53

Carsten wrote:Hi Stoo,

I have to admit that I didn't fully understand what you want to accomplish (more about that in a moment), but before I attempt to make any suggestions:
What version of the code do you currently use?
Yeah... I didn't really think about the fact that I was going to need this until I ran up against it either. I'm used to thinking about this sort of thing from a single user perspective, so it didn't occur to me that the client wouldn't be able to read everything in the map script. But after a moment's thought, I don't really want the clients to be able to run just *any* server command, either... at least, not automatically.

My current code base is from r561.
Carsten wrote:But back to your question:
What do you mean by "character"? The player model, i.e. how the player looks?
If so, I'd not attempt to "pull the list of characters" from the server. As the list must be the same on the server and all clients anyway, why don't you just hard-code the list? (something similar is done already: the list of available player models is hard-coded in the DeathMatch code)
I've been using the following terms:

- The Player sits behind the keyboard.

- The HumanPlayer entity (or just entity) runs around in the physics world, gets rendered, handles commands, etc. It holds location, orientation, (some) state, and network synchronization.

- The Character holds all the stats, inventory, abilities, etc. It runs (currently) in the map script, and is intended to stay in Lua (for ease of development). It stays on the server and determines what the HumanPlayer entity is allowed to do (run speed, attack stats, health, location, etc.) The Character will be updated as play progresses (new items, new abilities, leveling skills up, etc.), and is stored in a seperate file local to the server.

- Character attributes will be applied to the HumanPlayer entity by the Ruleset, which I'm also trying to put in the map script (and also want in script for ease of development). The Ruleset is what gets called, for instance, by the Attack code - comparing stats of the attacker and target, and changing the state of the target if need be.

To use a tabletop game analogy, the Player sits in the chair, the Entity is on the game board, and the Character is the character sheet. The Ruleset is the set of rules :D (Well, and the DM.)

The intention is to eventually allow players to explore and play in a shared world cooperatively (or competitively), using characters and vehicles that they've designed. The first phase that I'm working on now is a simple arena-style mode, where players can create characters and play them against each other, or against other AI players. Right now, I'm taking the character creation as a given, and trying to let the player select from a set of predefined characters. Which, in a roundabout way, is why I can't just hardcode them - that would work for the immediate requirement, but is a dead end for my grand plan :P

What I'm after at the moment is a way to read a script-defined variable (in this case, a formatted list of the characters that the GUI can parse back into a viewable form) that's stored on the server from a client 2D GUI. Once that's done, the player can select a character, and then the GUI can call the RunScriptCommand, ci.RunCommand, or whatever to have the script on the server assign that character's attributes, model, etc. to the HumanPlayer, then switch the entity's state to Alive.

(...yeah, Player is pretty ambiguous. Maybe I should start calling the Player the User? :-| )
Carsten wrote: Also, with all my heavy changes to the scripting (binding) code, I just realize that I still have to fix a few minor lose ends:
I removed runMapCmd recently, which is intended mostly for debugging but needs to be added back, and there is a something about calling Lua functions and methods from C++ that I want to improve. I also recently removed the (mis-)feature of loading games from DLLs -- games are now linked statically, and I still have to write and update some documentation about it.
Yeah, I need to go back through and look at your new functions too, see what other options are available now.

[edit]Just reread your post - one of the big thiings I'm afer is "character persistence" - so if a character is disabled in the Arena, the player shouldn't be able to choose them again when they respawn! I'll also be needing a way to read stats, skills, etc. to put on a character sheet GUI, as well as inventory; so I'd like to be able to read dynamic values from the server.[/edit]
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-08-10, 11:04

Hi,

ok, it seems that I slowly start to understand what you want. ;-)
Stoo wrote:- Character attributes will be applied to the HumanPlayer entity by the Ruleset, which I'm also trying to put in the map script (and also want in script for ease of development). The Ruleset is what gets called, for instance, by the Attack code - comparing stats of the attacker and target, and changing the state of the target if need be.
As a technical detail, the character attributes could well be "member variables" of the HumanPlayer entity, right? Especially when we assume that they can be get and set from the map script?
What I'm after at the moment is a way to read a script-defined variable (in this case, a formatted list of the characters that the GUI can parse back into a viewable form) that's stored on the server from a client 2D GUI. Once that's done, the player can select a character, and then the GUI can call the RunScriptCommand, ci.RunCommand, or whatever to have the script on the server assign that character's attributes, model, etc. to the HumanPlayer, then switch the entity's state to Alive.
Ah! This seems to be the essence!

This is possible, but in a slightly different manner than you phrased it:
The script-defined variable that is stored on the server to be read by a client 2D GUI should in fact be a separate entity: imagine an invisible "manager" or "rulekeeper" entity, that keeps as members all the required information, i.e. currently available characters.

A 2D client GUI would query this manager entity for the available options, and issue the related command to the server.
Best regards,
Carsten
Stoo
Posts:42
Joined:2012-05-11, 00:28

Re: Calling script functions from code

Post by Stoo » 2012-08-13, 19:24

Carsten wrote: Ah! This seems to be the essence!

This is possible, but in a slightly different manner than you phrased it:
The script-defined variable that is stored on the server to be read by a client 2D GUI should in fact be a separate entity: imagine an invisible "manager" or "rulekeeper" entity, that keeps as members all the required information, i.e. currently available characters.

A 2D client GUI would query this manager entity for the available options, and issue the related command to the server.
Hmm... I'm still puzzling out how this "manager entity" would work. Are you saying the client UI would call it with, say "getMapValue(mapAttribute)" to have it retrieve the value of mapAttribute as defined in the running map script? Or are you saying more that anything that the client UI might need would need hard-coded into the manager entity; ie, it would have a hard-coded list that would be regularly updated with available character objects?

I'm not really clear how either would work - with the former, I would think you'd have to figure out how to handle the callbacks (and what to do in the meantime); and with the latter, I'm not sure how the code keeps everything synchronized at the moment (which would also be an issue with tracking things on the HumanPlayerEntity as well - what would I need to add to keep the new pieces sync'ed?)

I think the former matches the Lua design much better - you're responsible for keeping your own variable names straight - but I'm not real clear how your networking works either, so I'm not sure what sort of entity to use as a base. I was planning to just adjust the Chat function to assign values to the local script instance if a string started with a certain tag, which allowed a lot of this; but that also leaves it open for a lot of abuse from other players... figured I'd fix it once I had a better handle on things :P
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-08-15, 15:55

Stoo wrote:Hmm... I'm still puzzling out how this "manager entity" would work. Are you saying the client UI would call it with, say "getMapValue(mapAttribute)" to have it retrieve the value of mapAttribute as defined in the running map script?
My main point was that in Cafu you cannot (easily) "freely" communicate with the server, at least not - as far as I understood your posts - in a way you think you can. ;-)

However, the networking code automatically sync's the state of entities: The state that an entity has on the server is automatically sync'ed to all clients. Thus, it seems natural to keep a "manager" entity that knows which game resources are available for spawning players, rely on that entities state being sync'ed to all clients, and have your (client-local) 2D query the local (sync'ed) client entity for the data it needs.

(For completeness, let me mention that the networking system can of course be extended to deal with custom network messages for any purpose. The "chat" functionality is a good example for it. However, this is more complicated to get right. It very much depends on the intended purpose which kind of network communication is the better tool to solve the problem.)


I made very good progress with enhancing the code in these regards, and fixed a nasty problem in the networking code this morning. I'll upload the latest archives later today, even though the new way how your own MODs are linked to the Cafu core still needs some documentation.
Best regards,
Carsten
Stoo
Posts:42
Joined:2012-05-11, 00:28

Re: Calling script functions from code

Post by Stoo » 2012-08-18, 17:15

Carsten wrote:My main point was that in Cafu you cannot (easily) "freely" communicate with the server, at least not - as far as I understood your posts - in a way you think you can. ;-)

However, the networking code automatically sync's the state of entities: The state that an entity has on the server is automatically sync'ed to all clients. Thus, it seems natural to keep a "manager" entity that knows which game resources are available for spawning players, rely on that entities state being sync'ed to all clients, and have your (client-local) 2D query the local (sync'ed) client entity for the data it needs.

(For completeness, let me mention that the networking system can of course be extended to deal with custom network messages for any purpose. The "chat" functionality is a good example for it. However, this is more complicated to get right. It very much depends on the intended purpose which kind of network communication is the better tool to solve the problem.)
Had to think on this a bit - means I'll need to figure out what sort of data needs shared out to everyone to define on the "manager" entity, but that's not a huge deal. Does the network synchronization deal with all variables defined on the entity? That will make adding new entries pretty trivial, especially if it's just storing them for client scripts. What clues the network system in that it needs to keep something synchronized? Anything that inherits BaseEntity? Anything defined in the EntityClassDefs.Lua, or under the Code directory?

Now that I think of it, a lot of what I was talking about (inventory, etc) might be able to be passed across on the player directly. Like I said, I'll have to figure out what's needed where... I assume I still have to have a Manager entity actually defined in the map, even if it doesn't interact with the world directly; is there any way I can add it to the currently running world via script? Seems like I'll have to load a "master script" from the maps anyway, it'd be nice to just be able to throw it in that.
Carsten wrote: I made very good progress with enhancing the code in these regards, and fixed a nasty problem in the networking code this morning. I'll upload the latest archives later today, even though the new way how your own MODs are linked to the Cafu core still needs some documentation.
How nasty was it? I may wait a bit on this one... I'm finally making progress; and it took a while to reintegrate my mod with the last release!
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-08-20, 13:58

Stoo wrote:Had to think on this a bit - means I'll need to figure out what sort of data needs shared out to everyone to define on the "manager" entity, but that's not a huge deal. Does the network synchronization deal with all variables defined on the entity? That will make adding new entries pretty trivial, especially if it's just storing them for client scripts. What clues the network system in that it needs to keep something synchronized? Anything that inherits BaseEntity? Anything defined in the EntityClassDefs.Lua, or under the Code directory?
If you use r561, (only) the State structure (in r561 still a member of BaseEntityT) is sync'ed.
This is done in entity methods (Do)Serialize() and (Do)Deserialize(), which are defined in BaseEntityT and overridden in the concrete derived entity classes.

That is, for adding more variables (that are supposed to be sync'ed) you would (for future compatibility) normally not extend the State structure, but add normal members to EntHumanPlayerT and then add/update the DoSerialize() and DoDeserialize() methods appropriately.

Note that a lot of this has been refined in newer revisions, e.g. as cumulated in r611 (archives of which are available at http://www.cafu.de/downloads).
Now that I think of it, a lot of what I was talking about (inventory, etc) might be able to be passed across on the player directly. Like I said, I'll have to figure out what's needed where... I assume I still have to have a Manager entity actually defined in the map, even if it doesn't interact with the world directly; is there any way I can add it to the currently running world via script? Seems like I'll have to load a "master script" from the maps anyway, it'd be nice to just be able to throw it in that.
Yes, creating entities "manually" during the game is possible. (For example, the "Monster Maker" is an entity that dynamically creates other entities.)

The Monster Maker is not script controlled, but it should be easy enough to add a script function (either as a global function, or as a method of some entity instance) that dynamically creates new entities as well. If this is what you want, I'm happy to help you with it, just let me know.

In any case, the new entity would be created on the server (because the Think() and script functionality runs on the server), and the networking code of the Cafu core would automatically propagate the new entity to the clients, and sync its state.
How nasty was it? I may wait a bit on this one... I'm finally making progress; and it took a while to reintegrate my mod with the last release!
If you're still using r561, the problem does not affect you at all, it was only relevant in some of the newer revisions.

However, if anyhow possible with a reasonable effort, I'd recommend that you upgrade to r611.

If you use neither SVN nor Git, you should have a look at Beyond Compare, an incredibly good and helpful tool with which you can compare two entire directory trees (e.g. your code tree and r611), and conveniently copy or merge changes from one side to the other.
Best regards,
Carsten
Stoo
Posts:42
Joined:2012-05-11, 00:28

Re: Calling script functions from code

Post by Stoo » 2012-08-25, 01:40

Carsten wrote: If you use r561, (only) the State structure (in r561 still a member of BaseEntityT) is sync'ed.
This is done in entity methods (Do)Serialize() and (Do)Deserialize(), which are defined in BaseEntityT and overridden in the concrete derived entity classes.

That is, for adding more variables (that are supposed to be sync'ed) you would (for future compatibility) normally not extend the State structure, but add normal members to EntHumanPlayerT and then add/update the DoSerialize() and DoDeserialize() methods appropriately.
DoSerialize/DeSerialize sounds like what I was after. I'll have to look further into them; sounds like it'll be handy on both EntHumanPlayerT and the "MasterScriptState" piece.
Carsten wrote: Yes, creating entities "manually" during the game is possible. (For example, the "Monster Maker" is an entity that dynamically creates other entities.)
I'd forgotten all about the Monster Maker! Yeah, I should be able to figure something out, then...
Carsten wrote:If you're still using r561, the problem does not affect you at all, it was only relevant in some of the newer revisions.

However, if anyhow possible with a reasonable effort, I'd recommend that you upgrade to r611.

If you use neither SVN nor Git, you should have a look at Beyond Compare, an incredibly good and helpful tool with which you can compare two entire directory trees (e.g. your code tree and r611), and conveniently copy or merge changes from one side to the other.
Now that I've gotten the Vehicle code to a posteable state, I'm planning to look at updating again. I'm planning to move to Git soon (or something else, possibly SVN), I just wanted to get to a very basic playable state first.

We actually use Beyond Compare a lot at work; I'd forgotten that they seem to have a Linux port... I've been playing with some other compare tools, but I'm already familiar with (and pretty impressed by) BC...
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-08-28, 00:12

Stoo wrote:We actually use Beyond Compare a lot at work; I'd forgotten that they seem to have a Linux port...
Yep, and it works just as well as the Windows version! I too am very happy with it. :cheesy:
Best regards,
Carsten
Stoo
Posts:42
Joined:2012-05-11, 00:28

Re: Calling script functions from code

Post by Stoo » 2012-09-19, 13:13

Okay... finally got back to this piece again... and I'm stymied again :oops:

I have a data-tracking entity (ScriptTracker) defined and added to the map, but I can't figure out how to reference it from the GUI's Lua environment - I keep getting "attempt to index global 'ScriptTracker_001' (a nil value)" (or whatever else I try to reference it by).

Like I said, I've got an instance of the entity defined in the map, but don't otherwise interact with it before this point - do I need to have the HumanPlayer entity that launches the GUI grab/pass it somehow? Do I need to register the ScriptTracker object somewhere? The whole process works pretty smoothly from the server side, so it's throwing me for a loop when it doesn't "just work"! :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-20, 11:09

Hi Stoo,

does your entity have a name? (It probably has.) Only named entities have script instances.

Can you access it from the map script?

From which GUI script exactly do you want to access it?
Best regards,
Carsten
Stoo
Posts:42
Joined:2012-05-11, 00:28

Re: Calling script functions from code

Post by Stoo » 2012-09-20, 13:29

The instance I placed in the map file has a name, if I understand you right - if I select it in the map editor, the object properties window says

Code: Select all

Entity "ScriptTracker_001" of class "ScriptTracker" is selected.
Is there another name it needs to have?

I can't access it from the map script, either... I've got it defined in EntityClassDefs.lua, though; which is why it shows up as an option in the map editor. I've still got the map script interacting with Player1, and that's working fine, so I'm not sure what the issue is with the new entity. I did base it on the Speaker entity, since I assumed it would have all the script pieces already in place.

I'm trying to interact with it from a new character selection GUI that the HumanPlayerEntity calls whenever it's in Dead or FrozenSpectator mode. I suppose I could try calling it from an existing GUI first; but I'm not sure what GUI screens come and go during gameplay like this... I guess the quit menu?
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-20, 22:32

Ok, the name "ScriptTracker_001" is looking good.

I think we should divide the problem into two steps:
  1. Accessing the entity from the map script.
  2. Accessing the entity from a "foreign" (some other entities) GUI script.
About 1.:
Do you see in the game console (or the Linux command console) any error messes regarding entity instantiation, e.g. one of the messages mentioned in CaServerWorldT::CreateNewEntityFromBasicInfo() ?

If not, what do you see if in the map script you insert something like

Code: Select all

Console.Print(ScriptTracker_001)
?

If these steps don't succeed (e.g. the above prints "nil"), we probably should add some debug output to the code starting at http://trac.cafu.de/browser/cafu/trunk/ ... v=625#L112 to see why the script instance of that entity is not generated (although it's obsolete, you could use the EnqueueString() function that is also used elsewhere in that file for this purpose)...
Best regards,
Carsten
Stoo
Posts:42
Joined:2012-05-11, 00:28

Re: Calling script functions from code

Post by Stoo » 2012-09-21, 03:48

Ah! Not sure how I missed this... I do have a warning:

Code: Select all

Warning: No type info found for entity class "ScriptTracker" with C++ class name "EntScriptTrackerT".
Where would this type info be? Like I said, I've got it in the EntityClassDefs.lua, and I've got all the speaker refs switched over to ScriptTracker in the .cpp and .hpp files...
Post Reply

Who is online

Users browsing this forum: No registered users and 4 guests