Page 1 of 2

Game Rules scripting entry point

Posted: 2014-08-30, 03:21
by SoulRider
Hi Carsten,

While I am making slow progress with the C++ side of things, I thought I'd get started at the same time implementing some lua code, as this will take a lot less time for me.

The only problem I am having is that I can't work out the entry point for lua code. I will have some code I would want run only on server, some only on client and some on both. Do you have a server and client entry point where I can begin to load the relevant lua files?

Re: Game Rules scripting entry point

Posted: 2014-08-30, 15:26
by Carsten
SoulRider wrote:The only problem I am having is that I can't work out the entry point for lua code. I will have some code I would want run only on server, some only on client and some on both. Do you have a server and client entry point where I can begin to load the relevant lua files?
Well... the key idea is to have map designers, script authors etc. look at the entities or in fact the entire game world as if the split into client and server did not exist, i.e. have the same natural attitude as you would have if this were a single-player game only.

To achieve this, what you actually do in Lua scripts is implementing callback functions. That is, you write the functions (their implementations), and the Cafu Engine -- the client and/or the server -- call your functions whenever they deem it right.

It's not much, but the reference documentation has a page Event Handlers about this, with the mentioned WindowT class of the GuiSys being a good generic example.

(I just realize that not all of these callbacks are mentioned in the Lua reference documentation... will try to fix that later today.)

That being said, making a conscious distinction between client and server should not be necessary in the Lua scripts. (However, in some situations involving technical subtleties I've found myself confronted with the issue, but usually only because this entire subject was addressed totally differently in pre-component-system times, where game programmers were heavily burdened with all the related and often very complicated details.)

Thus, could you please provide more details on the goal that you wish to achieve with client- and server-specific script code?

Re: Game Rules scripting entry point

Posted: 2014-08-30, 17:47
by SoulRider
It is with game code, some logic I want to keep on the server, and some I want to keep only on the client. For example, post map load, I want the server to populate a couple of arrays holding spawn point info, I don't need or want this on the client side.

The question is really about where I start the code. For example, I create a file called gamerules, which is used to define the conditions which start and end the game. How would I get that file to launch post map load? I can create the files I need, but I need a way to launch my code that doesn't have entities attached to it.

Re: Game Rules scripting entry point

Posted: 2014-08-31, 14:58
by Carsten
Ok, I think that in the other thread, you said that the problem is solved.

For completeness, let me still add two thoughts, though:

First, the best (and simplest) way to run "map-wide" init code is to create a new entity, name it e.g. "my_map_initializer", add a Script component to it, and point the Script component to a custom Lua script that contains the desired code, which you would typically put into the component's OnInit() callback. I think there are examples for this in Games/DeathMatch/Scripts/.

Second, regarding client and server, you really should not think as complicated as that. Think of the game world as "one", as if this was a single-player game only. This is especially important because the clients(!) can run (some of) the server side's logic, e.g. in order to implement the "prediction" feature that is paramount to hiding the network latency from the player.

While the prediction feature is very complicated underneath, and hiding the distinction between client and server from the scripting API (that you use) is not always entirely possible despite the underlying code goes to great length to achieve this, the desired ideal (and one of the goals of the Cafu Engine software design) is still to create a game as of the difference did not exists.

The same issue, but from a different perspective, is to consider entities and their components as "service providers". That is, by implementing the C++ methods and Lua callbacks of the components, you "teach" them how to render themselves, how to interact with others, and how to "behave" (or "think", i.e. change their internal state from one frame to the next). But essentially, components do nothing by themselves until they are asked to run their functionality, and when this happens, they just do it (render, think, ...) without caring if it was a client, a server, a Map Editor, a client's prediction run, or whatever else that asked for the task.

Re: Game Rules scripting entry point

Posted: 2014-08-31, 18:04
by SoulRider
The method I came up with was to create a 'GameType' entity which is placed in the map and links to the GameType script, looks like your suggestion is the same.

I do have a related problem though, and that is creating and using non-entity code. I have my TeamNumber component, I have a team player start, but I want to create logic that controls teams.

This Team.lua is not an entity, it would normally be a new base class, and it would be used to create and manage all of the team information - Create each team with TeamName and Number, add playerID's to an array, remove from array when they leave team, etc. It would need to be called by entities and other game logic, how would I do this? I can't seem to create a class as it isn't accessible by entites, even though I am using dofile to load the team.lua script.

I don't think creating an entity to control teams would be right, but then again, this whole process is new to me, so maybe I am overlooking something.

Re: Game Rules scripting entry point

Posted: 2014-09-01, 03:20
by SoulRider
Ok, I am almost there, I am trying different solutions but I'm not quite there. I am trying to call a function within a file called Team.lua. Here is the Team.lua file, it is currently only a simple file -

Code: Select all

local Team = {}

function Team:OnInit(teamName, teamNumber)
    Self.teamName = teamName
    Self.teamNumber = teamNumber

function Team:GetTeamNumber()
    return Self.teamNumber
This file is being called from the GameType.lua file. GameType is a mapper placeable entity. It will be eventually made as a mapping compile requirement. Currently the code is simple in the file. I am trying to call the OnInit function in the team file from the GameType OnInit function.

Here is the GameType.lua code:

Code: Select all


local GameType = ...   -- Retrieve the ComponentScriptT instance that is responsible for this script.

function GameType:OnInit()
	--Create Playing Teams
	Team:OnInit("Team1", kTeam1)
	Team:OnInit("Team2", kTeam2)
When I run the game I get the an error in console - Pointing to line 9 of GameType.lua, which is the line -

Code: Select all

Team:OnInit("Team1", kTeam1)
The error message is:
'attempt to call method 'OnInit' (a nil value)

This indicates that the Team.lua file is being loaded, but the function can't be found. Any pointers? This is basically the programming concept issue which is stopping me from getting on with programming the Duel game code. Once I understand how to call functions from other files correctly, I can develop the Duel Cafu Demo :)

Re: Game Rules scripting entry point

Posted: 2014-09-01, 05:29
by SoulRider
Ignore my previous posts, I am getting there through experimentation. I am also trying out a simple class system I got from the internet, I look like I may be making some progress, but we'll see!!

Re: Game Rules scripting entry point

Posted: 2014-09-02, 19:16
by SoulRider
Ok, so I have files linked and working, I can call functions and everything is great. However, I am trying to do a bit of a shortcut, as I want the players to spawn with a 9mmAR.

I did a dofile in human player, and in a new OnInit() I tried to call AR.PickedUp(). However ,the script fails at AR:GetEntity() as local AR is nil.

I set AR = {...}

However, when the code tries to run it returns - attempt to call method 'GetEntity'(a nil value).

This is obviously because GetEntity() is not defined in AR. Is there anyway I can make a call into a component script to call a function?

If there is some way of making the components work within a lua table, it will make game development a lot easier :D

Re: Game Rules scripting entry point

Posted: 2014-09-02, 21:28
by Carsten
I'm not entirely sure if I understood your description: Did you try to "dofile" the cw_9mmAR.lua script?
If so, this cannot work, because it is a script intended to be loaded by the CarriedWeapon component, and it will likely not work in a "general" case.

Generally, and also to address the last statement in your post, you can deal with components as if they were ordinary Lua tables (in fact, they are): In Lua, we have access to the same entity hierarchy and each entity's components as in C++.

This is valid in general, but as an example, let's get back to your concrete problem:

Consider the HumanPlayer.lua script. The variable PlayerScript is the component that loaded this very script, and variable Entity references that component's entity -- the human player.
As you can see elsewhere in the same script file, with

Code: Select all

        local cw = Entity:GetComponent("CarriedWeapon", i)
you can obtain the human player's i-th CarriedWeapon component. You could iterate over them to find the one with label "9mmAR", or you could figure from ServerWorld.cpp that is has index 4.

Therefore, a call like

Code: Select all

        Entity:GetComponent("CarriedWeapon", 4):PickedUp()
should assign the 9mmAR to the human player as desired. (I have not tested this, and it must probably be put into the PlayerScript:OnInit() callback. Or, looking at the end of CaServerWorldT::InsertHumanPlayerEntityForNextFrame(), maybe you even have to add another callback such as OnInit2() at very end, and put the above line there.)

Does this work?

Re: Game Rules scripting entry point

Posted: 2014-09-02, 22:28
by SoulRider
Looking at the code, i noticed that the OnInit for HumanPlayer script is called before CarriedWeapon is initialised. I edited ServerWorld.cpp -

Code: Select all

    // As we're inserting a new entity into a live map, post-load stuff must be run here.
    ScriptComp->CallLuaMethod("OnInit", 0);

    for (unsigned int i = 0; i < 99; i++)
        IntrusivePtrT<cf::GameSys::ComponentCarriedWeaponT> CompCW =
            dynamic_pointer_cast<cf::GameSys::ComponentCarriedWeaponT>(NewEnt->GetComponent("CarriedWeapon", i));

        if (CompCW == NULL) break;

        CompCW->CallLuaMethod("OnInit", 0);
	// The OnInit() call to HumanPlayer script is run before the CarriedWeapon component is loaded.
	// As a result, we need to run a CWInit() if we want to init anything involving CarriedWeapon.
	ScriptComp->CallLuaMethod("CWInit", 0);

    return CreateNewEntityFromBasicInfo(GameEnt, m_ServerFrameNr + 1);
I added the same comment and the following code to the HumanPlayer script -

Code: Select all

function PlayerScript:CWInit()
	Entity:GetComponent("CarriedWeapon", 4):PickedUp()
This worked perfectly. :) Well almost...

I have no weapon HUD, and I can't fire the weapon.... I'll have a look at some other way of calling the appropriate function and get it working :D

Now if you could explain the table situation.... :D

Re: Game Rules scripting entry point

Posted: 2014-09-02, 23:33
by SoulRider
If I select 3, then everything appears, the hud appears and the weapon works, although I can't seem to get the ChangeWeapon() function work by calling it in the CWInit().

Re: Game Rules scripting entry point

Posted: 2014-09-03, 00:04
by Carsten
SoulRider wrote:Now if you could explain the table situation.... :D
Uh, ahm, could you please say again what exactly the question was? :oops:

Entities and components are, in Lua, just represented by tables (augmented with metamethods etc.), and the table elements are the functions that we either provide in C++ or implement in Lua (the "callbacks"). That's all. :cheesy:

(The C++ bindings implementation is in fact quite complicated in its details, but the above is the gist.)
I can't seem to get the ChangeWeapon() function work
Are you passing the proper parameter? (It's the weapons "group" number, not the weapon index that was earlier used for the 9mmAR.)
Did you beforehand call PickedUp() for another weapon (the one you're changing to)?

Re: Game Rules scripting entry point

Posted: 2014-09-03, 01:24
by SoulRider
The only weapon I have is the AR I gave my self in the code. The gun is displayed and running idle animation, but it is not active. I have to press number 3 to activate the weapon and the hud.

I wasn't passing the group number, I need to check that..

Re: Game Rules scripting entry point

Posted: 2014-09-03, 13:53
by SoulRider
I tried passing the group number, which is 3 for this weapon, but it still wouldn't change. I had to do it manually by pressing 3 once the game had started.

I think it may have something to do with the HumanPlayer not getting a call to PickUpItem(). But then I can't really see the issue..

Re: Game Rules scripting entry point

Posted: 2014-09-06, 11:47
by Carsten
I'm not sure what exactly you're trying to achieve, but if ChangeWeapon() doesn't work (and inserting some Console.Print(...) statements doesn't help either), you could also call method [url=]SelectWeapon()[/url] directly.

Also, see page Carried Weapons Overview, which may provide helpful information.