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

Calling script functions from code

Post by Stoo » 2012-06-16, 03:45

I'm working on making an RPG, and I'd like to move the code that processes attacks in Lua, to make it easier to play around with different damage models. I've seen a couple of examples of how to call an entity's methods from Lua, but the only example I've seen of entities calling Lua code is the 3D GUI objects, which are... difficult to follow :oops:

Is there a straightforward way to, for instance, find the currently running map script and call a function on it from the HumanPlayer entity? Would it make more sense to have the "main" Lua script track and poll the HumanPlayer entities to gather input states? Is there some other way to feed inputs from the entities (key commands, physics, etc.) into Lua?
HWGuy
Posts: 95
Joined: 2011-05-31, 07:37

Re: Calling script functions from code

Post by HWGuy » 2012-06-16, 03:54

Well if you have weapon stats set to vars you could simply have the vars changed on the fly in console and with Lua.
User avatar
Carsten
Site Admin
Posts: 2145
Joined: 2004-08-19, 13:46
Location: Germany
Contact:

Re: Calling script functions from code

Post by Carsten » 2012-06-16, 11:58

Hi Stoo,
Stoo wrote:Is there a straightforward way to, for instance, find the currently running map script and call a function on it from the HumanPlayer entity?
yes, use ScriptStateT::CallEntityMethod():

Declaration with documentation:
http://trac.cafu.de/browser/cafu/trunk/ ... ev=546#L91

More about the Signature parameter (the GuiSys implements a very similar concept, and the documentation for CallLuaFunc() applies here as well):
http://trac.cafu.de/browser/cafu/trunk/ ... v=546#L113

An example:
http://trac.cafu.de/browser/cafu/trunk/ ... ev=546#L96

Note that in the related Lua map script, entities are called by name. For human players, the name is "Player%lu", i.e. Player1 for the first player:
http://trac.cafu.de/browser/cafu/trunk/ ... ev=546#L96

Thus, for your purposes it would probably be better to call a global Lua function with the human player entity as the first parameter rather than a method of Lua entity "Player1", but I just realize that this seems not yet to be implemented in ScriptStateT.
I can look into it, but it would take until next week. Using Player1 in the meanwhile should however get you started as well. :up:
Best regards,
Carsten
Stoo
Posts: 42
Joined: 2012-05-11, 00:28

Re: Calling script functions from code

Post by Stoo » 2012-06-16, 17:22

HWGuy wrote:Well if you have weapon stats set to vars you could simply have the vars changed on the fly in console and with Lua.
For this one piece, that could work; but I'd still want to be able to adjust it for the particular target's armor skill level, any potential dodge ability, ECM effects, etc. Besides, if I can get this to work, then I can use it as a model to implement dialog, trading, and all that other fun RPG business :D

Carsten wrote: ...
An example:
http://trac.cafu.de/browser/cafu/trunk/ ... ev=546#L96
...
I think that trigger code does what I was trying to do... but like you said, the comments for CallEntityMethod says that it's not actually implemented yet. Does this mean the triggers don't work yet? I've seen references to them, but haven't played with them much so far...
Carsten wrote: Thus, for your purposes it would probably be better to call a global Lua function with the human player entity as the first parameter
So what makes a Lua function/method "global", in the context of CallEntityMethod? Does it just need to be defined in the global scope of any active Lua script? I'm still getting familiar with Lua as well...
Carsten wrote:...rather than a method of Lua entity "Player1" ... Using Player1 in the meanwhile should however get you started as well. :up:
I'll have to dig more into the pros and cons of running it from a HumanPlayer script rather than a global script - like I mentioned earlier, I'm hoping to have similar functions to cover a variety of actions, so it might make sense to have them grouped into an object rather than defined in a global function.
User avatar
Carsten
Site Admin
Posts: 2145
Joined: 2004-08-19, 13:46
Location: Germany
Contact:

Re: Calling script functions from code

Post by Carsten » 2012-06-16, 21:39

Stoo wrote:I think that trigger code does what I was trying to do... but like you said, the comments for CallEntityMethod says that it's not actually implemented yet. Does this mean the triggers don't work yet?
They work as documented, e.g. as in the trigger example or as described in the comment for the CallEntityMethod() method:

Code: Select all

/// Example: If Ent is a BaseEntityT object and Ent->Name=="Barney",
/// then   CallEntityMethod(Ent, "OnTrigger", "f", 1.0);
/// calls the script method   Barney:OnTrigger(value)
/// where value is a number with value 1.0.
What does not yet work is using NULL instead of Ent in the example above to have it call global function (in this example, OnTrigger()) instead of Barney's OnTrigger() method.
So what makes a Lua function/method "global", in the context of CallEntityMethod? Does it just need to be defined in the global scope of any active Lua script? I'm still getting familiar with Lua as well...
Have a look at http://trac.cafu.de/browser/cafu/trunk/ ... ua?rev=546

The OnTrigger() methods you see their are specific to their entity object, whereas LightBlinkThread() is a global function not specific to any entity.
I'll have to dig more into the pros and cons of running it from a HumanPlayer script rather than a global script - like I mentioned earlier, I'm hoping to have similar functions to cover a variety of actions, so it might make sense to have them grouped into an object rather than defined in a global function.
No problem, both will work. That is, whether you put your code into a Lua script method like

Code: Select all

 Player1:myCode(...) 
or into a global function

Code: Select all

 myCode(myEntity, ...) 
both will work.
Normally (with non-player entities defined in the map file), the former is preferable, but as you want to have script functions on the human player(s), the latter may be the better (more flexible) choice. But as said, I think that both will work.
Best regards,
Carsten
Stoo
Posts: 42
Joined: 2012-05-11, 00:28

Re: Calling script functions from code

Post by Stoo » 2012-06-20, 03:01

Okay... it almost works :lol:

It won't load a map.lua file with a Player1:<functionname> defined, because Player1 isn't defined before anybody connects. Works fine if I get it to reload the map script after I've spawned, though :cheesy:

What I'd really like to do is add the attack processing code to every player object (along with the bot objects) in Lua. The "classname" on new Player%lu entities looks like it's supposed to be set to "HumanPlayer", and it looks like ScriptState tries to add in any "inherited" functions that a new entity should know about, but I'm not able to find a HumanPlayer object in Lua for Player1 to copy functions from. Am I missing a step or something, or do player entities not actually inherit from anything right now? In which case, is that something I'd just implement in EntityClassDefs.lua?
User avatar
Carsten
Site Admin
Posts: 2145
Joined: 2004-08-19, 13:46
Location: Germany
Contact:

Re: Calling script functions from code

Post by Carsten » 2012-06-20, 22:56

Hi Stoo,

the entity inheritance is fully functional, but it is intended so that Lua methods that are implemented in C++ can be used in Lua with entities of derived classes.

For example, the C++ BaseEntityT class implements Lua methods GetName() and GetOrigin(), and the inheritance code makes sure that in Lua, if myBot is an instance of EntCompanyBotT, you can call myBot:GetOrigin() etc.

You can not define Lua methods for BaseEntityT in Lua unfortunately (although I agree that the idea is appealing). However, as a side note, Lua's understanding of "object oriented" programming makes this very simple to overcome. For example, to add a common method to myBot (made up but working example):

Code: Select all

d:\Dev\Cafu> ExtLibs\lua\build\win32\vc10\x86\debug\lua.exe
Lua 5.1.4  Copyright (C) 1994-2008 Lua.org, PUC-Rio

> myBot = {}

> shared_entity_method = function (self, param1, param2) print(param1 + param2) end

> myBot.myMethod = shared_entity_method

> myBot:myMethod(2, 3)
5
This solves the problem with Lua-scripted inherited functions, but not with the fact that Player1 is only available after the map script has been loaded...


Would it help you (if I understood your message right) if you had a Lua function like this:

Code: Select all

function HandleAttack(my_HP_or_Bot)
    -- somehow handle the attack, e.g.:
    print(my_HP_or_Bot:GetName() .. " has been attacked\n")
end
?

If so, all that would be required was calling the HandleAttack() function from the C++'s EntHumanPlayerT::Think() or EntHumanPlayerT::TakeDamage() methods (same for EntCompanyBotT).

If that and my understanding of your goal is right, I'll then look into over the weekend that the required call

Code: Select all

ScriptState->CallEntityMethod(NULL, "HandleAttack", "E", this);
actually works. :up:

If you want to achieve something entirely else, please let me know as well. :cheesy:
Best regards,
Carsten
Stoo
Posts: 42
Joined: 2012-05-11, 00:28

Re: Calling script functions from code

Post by Stoo » 2012-06-22, 02:25

Carsten wrote:the entity inheritance is fully functional, but it is intended so that Lua methods that are implemented in C++ can be used in Lua with entities of derived classes.

For example, the C++ BaseEntityT class implements Lua methods GetName() and GetOrigin(), and the inheritance code makes sure that in Lua, if myBot is an instance of EntCompanyBotT, you can call myBot:GetOrigin() etc.
I guess I'm still confused about how the Lua BaseEntityT types work - does Lua handle C++ based objects differently? Like I said, I'm still figuring it out, but I was under the impression that Lua objects could be assigned "inheritance" after they were created, and even after they're instanced...

Anyway, it shouldn't be a big deal for what I'm doing - as long as I can call Lua functions in the global scope from a C++ entity, I should be fine. If I could call your HandleAttack() example from HumanPlayer.cpp, I think I can build a framework to handle the rest. In fact, the more I think about it, the more that way makes sense to me :P

(Incidently, while trying to limp my script along far enough to let it load with the map, I found that the code:

Code: Select all

if Player1 == nil then Player1 = {} end

function Player1:attack(target) 
    Console.Print("Attack called!\n") 
end
not only allowed the script to load, but was actually available for HumanPlayer to call! Not sure if this interferes with any other Player1-defined functionality, though... I assume this has something to do with the way pieces are extended, but I'm sure I'm missing something! :P)
User avatar
Carsten
Site Admin
Posts: 2145
Joined: 2004-08-19, 13:46
Location: Germany
Contact:

Re: Calling script functions from code

Post by Carsten » 2012-06-25, 12:01

Hi Stoo,
Stoo wrote:I guess I'm still confused about how the Lua BaseEntityT types work - does Lua handle C++ based objects differently? Like I said, I'm still figuring it out, but I was under the impression that Lua objects could be assigned "inheritance" after they were created, and even after they're instanced...
Well, yes and no: Both the C++-implemented functions that a Lua object can call, as well as the inheritance, are implemented with Lua's concept of metatables, which we have chosen to keep in the registry so that only C++ code can access and change them. If we kept the metatables elsewhere, e.g. as globals, you could manipulate the metatables directly in Lua to achieve the desired result.

Generally, for getting into the details, I highly recommend the "Programming in Lua" book:
http://www.lua.org/pil/

The current 2nd edition is aimed at Lua 5.1 (that we still use in Cafu), a 3rd edition addressing the new Lua 5.2 will appear sometime in the future. The book is very well written, and explains all the advanced concepts that we employ here in a very easy to comprehend manner.

Anyway, it shouldn't be a big deal for what I'm doing - as long as I can call Lua functions in the global scope from a C++ entity, I should be fine. If I could call your HandleAttack() example from HumanPlayer.cpp, I think I can build a framework to handle the rest. In fact, the more I think about it, the more that way makes sense to me :P
:cheesy: :up:
(Incidently, while trying to limp my script along far enough to let it load with the map, I found that the code:

Code: Select all

if Player1 == nil then Player1 = {} end

function Player1:attack(target) 
    Console.Print("Attack called!\n") 
end
not only allowed the script to load, but was actually available for HumanPlayer to call! Not sure if this interferes with any other Player1-defined functionality, though... I assume this has something to do with the way pieces are extended, but I'm sure I'm missing something! :P)
Good to hear that this works! ;-)

In my endeavor to improve the game and network code (which is making very good progress), I've now also progressed to and approached the map script handling from a different perspective, and am currently working on improving the ScriptStateT class and moving it into the engine core. Not much will change for the entity code (C++ or Lua), but I'll also fix the existing problems along the way. This will take a week or two, and will help in this context as well.
Best regards,
Carsten
Stoo
Posts: 42
Joined: 2012-05-11, 00:28

Re: Calling script functions from code

Post by Stoo » 2012-06-29, 01:03

Carsten wrote: Well, yes and no: Both the C++-implemented functions that a Lua object can call, as well as the inheritance, are implemented with Lua's concept of metatables, which we have chosen to keep in the registry so that only C++ code can access and change them. If we kept the metatables elsewhere, e.g. as globals, you could manipulate the metatables directly in Lua to achieve the desired result.
Okay, so the "parent class" piece points to something outside Lua - I can see how that would complicate inheritance.

I've been reading the online version of the pil book since I started messing with the scripting - so I probably know just enough to be dangerous :lol: The whole metatable-as-parent concept is why I was confused about why the player objects couldn't inherit; it seemed so flexible...
Carsten wrote: In my endeavor to improve the game and network code (which is making very good progress), I've now also progressed to and approached the map script handling from a different perspective, and am currently working on improving the ScriptStateT class and moving it into the engine core. Not much will change for the entity code (C++ or Lua), but I'll also fix the existing problems along the way. This will take a week or two, and will help in this context as well.
Yeah, I was looking forward to seeing what you updated! I'm just running from your last binary release though - how often do those come out?
User avatar
Carsten
Site Admin
Posts: 2145
Joined: 2004-08-19, 13:46
Location: Germany
Contact:

Re: Calling script functions from code

Post by Carsten » 2012-07-01, 14:02

Hi Stoo,
Stoo wrote:Okay, so the "parent class" piece points to something outside Lua - I can see how that would complicate inheritance.
Well, yes and no: The metatables are in the registry (a part of the Lua script state), but the registry is only available via the C API.

The key idea is to prevent Lua code from accidentally tampering with the C++ controlled parts of the code. The flexibility is preserved, though: Simply assign data or methods to the entity instances directly (function myEntity:myNewMethod() ... end), and it should work.
I've been reading the online version of the pil book since I started messing with the scripting - so I probably know just enough to be dangerous :lol:
:cheesy:
The whole metatable-as-parent concept is why I was confused about why the player objects couldn't inherit; it seemed so flexible...
Well, I think it is, though I agree that on the C API side, things quickly tend to get ... involved. (On the one hand, I find it easy enough, but on the other hand, I also find myself re-reading the PiL2 book whenever I made a longer pause in using it.)
Yeah, I was looking forward to seeing what you updated!
My latest updates in the SVN head revision, though not yet completely implementing what I have in mind (see http://trac.cafu.de/browser/cafu/trunk/ ... tState.hpp for details), should solve the problems we discussed above:

You can now call methods on an entity (as before, from EntTriggerT):

Code: Select all

ScriptState->CallEntityMethod(this, "OnTrigger", "G", Activator->Name.c_str());
but now also call any global function, with input/output parameter passing:

Code: Select all

ScriptState->GetScriptState()->Call("functionname", Signature, ...);
and run arbitrary chunks of Lua code:

Code: Select all

ScriptState->GetScriptState()->Run("a = 1; b = 2; c();");
(The double "ScriptState" in ScriptState->GetScriptState() is one of the awkward things that will disappear again in one of the next revisions!)
Yeah, I was looking forward to seeing what you updated! I'm just running from your last binary release though - how often do those come out?
Binary??

Easiest and most up-to-date was if you used the SVN repository.
I also update the source code packages and binary release these days much more frequently than before -- I'll start another updates run later today.
Best regards,
Carsten
Stoo
Posts: 42
Joined: 2012-05-11, 00:28

Re: Calling script functions from code

Post by Stoo » 2012-07-03, 13:24

Carsten wrote:My latest updates in the SVN head revision, though not yet completely implementing what I have in mind (see http://trac.cafu.de/browser/cafu/trunk/ ... tState.hpp for details), should solve the problems we discussed above:
That sounds really promising... I'll have to look into it!
Carsten wrote:Hi Stoo,
Yeah, I was looking forward to seeing what you updated! I'm just running from your last binary release though - how often do those come out?
Binary??

Easiest and most up-to-date was if you used the SVN repository.
I also update the source code packages and binary release these days much more frequently than before -- I'll start another updates run later today.
...Yeah, I misspoke. I'm using the code from the May stable release :P
User avatar
Carsten
Site Admin
Posts: 2145
Joined: 2004-08-19, 13:46
Location: Germany
Contact:

Re: Calling script functions from code

Post by Carsten » 2012-07-04, 14:54

Sorry that I forgot it the other night:
Latest source code packages (at r561) are available at the downloads page now!
:up:
Best regards,
Carsten
User avatar
Carsten
Site Admin
Posts: 2145
Joined: 2004-08-19, 13:46
Location: Germany
Contact:

Re: Calling script functions from code

Post by Carsten » 2012-07-10, 22:53

Just for the records, here's what I've been up to recently:

http://thread.gmane.org/gmane.comp.lang ... eral/92550
http://thread.gmane.org/gmane.comp.lang ... eral/92555

Not trivial to get right, but the result will be worthwhile! :wohow:
Best regards,
Carsten
Stoo
Posts: 42
Joined: 2012-05-11, 00:28

Re: Calling script functions from code

Post by Stoo » 2012-07-10, 23:54

Sorry for the delay in response... casualty of the spare-time status of my project :P

[edit - Did post about missing files, realized I'd been getting an error while opening the downloaded archive... Redownloaded and all seems peachy now... :nerd: ]

Carsten wrote:Just for the records, here's what I've been up to recently:

http://thread.gmane.org/gmane.comp.lang ... eral/92550
http://thread.gmane.org/gmane.comp.lang ... eral/92555

Not trivial to get right, but the result will be worthwhile! :wohow:
That sort of thing is why I'm quite happy to let someone else write the engine... :P I think I'd actually seen some of the section you were referring to in the first link, and decided at that point it'd be far easier to work around the inheritance issue than try to change it :lol:
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest