Author Topic: Lua Extensions  (Read 6681 times)

hailstone

  • Local Moderator
  • Battle Machine
  • ********
  • Posts: 1,568
    • View Profile
Lua Extensions
« on: 26 August 2009, 09:27:34 »
I've added some new lua functions, quite a verbose process, using GameSettings. I'm not sure if I should commit to trunk or create a new branch since these are untested features, what do people think?

string playerName( faction )
string factionTypeName( faction )
string scenarioDir()

So you can use everyone's favourite string concatenation operator '..' when using dofile.

Code: [Select]
dofile(scenarioDir() .. "/startup.lua")
« Last Edit: 6 September 2009, 11:12:38 by hailstone »
Glest Advanced Engine - Admin/Programmer
https://sourceforge.net/projects/glestae/

silnarm

  • Local Moderator
  • Behemoth
  • ********
  • Posts: 1,373
    • View Profile
Re: GameSettings class and Lua
« Reply #1 on: 26 August 2009, 12:09:14 »
Coolio, I was going to say those could probably just go straight into trunk... but it seems you have more plans for new LUA functionality... maybe a branch is called for?
Glest Advanced Engine - Code Monkey

Timeline | Downloads

John.d.h

  • Moderator
  • Airship
  • ********
  • Posts: 3,757
  • I have to go now. My planet needs me.
    • View Profile
Re: GameSettings class and Lua
« Reply #2 on: 3 September 2009, 02:14:46 »
string playerName( faction )
So, this is for naming a specific player something instead of "Player 1", right?  I was just thinking that we needed something like that but I thought maybe it had already been done.  (As it stands, I know approximately nothing about Lua.)

Omega

  • MegaGlest Team
  • Dragon
  • ********
  • Posts: 6,167
  • Professional bug writer
    • View Profile
    • Personal site
Re: GameSettings class and Lua
« Reply #3 on: 3 September 2009, 05:30:16 »
Although in order to declare something in a message box, etc; we MUST remove the question marks for something not found in the lng.

I say change the language parsers code. It normally returns '???'+s+'???' if not found. This should be removed, or set as s debug feature. Simply changing it to return s will do.
Edit the MegaGlest wiki: http://docs.megaglest.org/

My personal projects: http://github.com/KatrinaHoffert

hailstone

  • Local Moderator
  • Battle Machine
  • ********
  • Posts: 1,568
    • View Profile
Re: GameSettings class and Lua
« Reply #4 on: 3 September 2009, 06:57:37 »
This is a query to get the player's name. The player would set their name in glestadv.ini (or in options eventually). I don't know if it's actually setup though, there isn't anywhere calling setPlayerName(...).
Glest Advanced Engine - Admin/Programmer
https://sourceforge.net/projects/glestae/

silnarm

  • Local Moderator
  • Behemoth
  • ********
  • Posts: 1,373
    • View Profile
Re: GameSettings class and Lua
« Reply #5 on: 3 September 2009, 10:09:15 »
This is a query to get the player's name. The player would set their name in glestadv.ini (or in options eventually). I don't know if it's actually setup though, there isn't anywhere calling setPlayerName(...).

Hooked up, and added an optional 'name' attribute to the player node in the XML, this will be used if present, else it will be 'CPU Player' or the human's name, as pulled from 'NetPlayerName' in the ini file.

Test Rig:
Code: [Select]
<?xml version="1.0" standalone="yes" ?>
<scenario>
 
<difficulty value="2"/>
<players>
<player control="human" faction="tech" team="1"/>
<player control="cpu" faction="tech" team="1" name="Bob the AI"/>
<player control="cpu" faction="magic" team="2" />
<player control="cpu-ultra" faction="magic" team="2" name="Merlin" />
</players>
<map value="conflict"/>
<tileset value="dark_forest"/>
<tech-tree value="magitech"/>
<default-resources value="false"/>
<default-units value="false"/>
<default-victory-conditions value="false"/>
<scripts>

<startup>
  setTimer ( 'summary', 'real', 2, false )

</startup>
 
<timer name="summary">
  showMessage ( "Human: " .. playerName(0) .. "[" .. factionTypeName(0) .. "]"
           .. ", CPU 1: " .. playerName(1) .. "[" .. factionTypeName(1) .. "]"
           .. ", CPU 2: " .. playerName(2) .. "[" .. factionTypeName(2) .. "]"
           .. ", CPU 3: " .. playerName(3) .. "[" .. factionTypeName(3) .. "]"
              , "..."  )

  createUnit ( "farm", 0, startLocation(0) )
  setTimer ( 'machine', 'game', 40*5, true )
  setTimer ( 'stopMachines', 'game', 40*21, false )
</timer>

<timer name="swordman">
  createUnit ( "swordman", 0, startLocation(0) );
</timer>

<timer name="stopSwords">
  stopTimer ( 'swordman' );
</timer>
 
<timer name="machine">
  createUnit ( "battle_machine", 0, startLocation(0) );
</timer>

<timer name="stopMachines">
  stopTimer ( 'machine' );

  setTimer ( 'stopSwords', 'real', 12, false )
  setTimer ( 'swordman', 'real', 3, true )
</timer>
 
</scripts> 
</scenario>



Oh, the timers are all fixed up too :)
Glest Advanced Engine - Code Monkey

Timeline | Downloads

hailstone

  • Local Moderator
  • Battle Machine
  • ********
  • Posts: 1,568
    • View Profile
Re: GameSettings class and Lua
« Reply #6 on: 4 September 2009, 01:29:41 »
Should we combine the two lua topics to be about lua extensions in general?

I think location based events might be the next step. Eg. a unit walks to a location then an event happens.

Or maybe it should be more general. Eg. fire event when unit location is equal to a location. setCompareEventVec2i( 'name', unitPosition( unitId ), {12, 12} )
« Last Edit: 4 September 2009, 01:35:16 by hailstone »
Glest Advanced Engine - Admin/Programmer
https://sourceforge.net/projects/glestae/

silnarm

  • Local Moderator
  • Behemoth
  • ********
  • Posts: 1,373
    • View Profile
Re: GameSettings class and Lua
« Reply #7 on: 4 September 2009, 02:08:32 »
Should we combine the two lua topics to be about lua extensions in general?

I think location based events might be the next step. Eg. a unit walks to a location then an event happens.

Or maybe it should be more general. Eg. fire event when unit location is equal to a location. setCompareEventVec2i( 'name', unitPosition( unitId ), {12, 12} )

Yep, one topic would be good :) I say just rename this one 'New Moon' and away we go...

'Triggers' for arrival at a location (better an 'area') would be very cool, I'll let you mull that one over for a little bit :) I'm going to hook up the rest of the commands to the existing givePositionCommand() and giveProduceCommand(), then add any new functions needed for 'left over' commands that don't fit either of those.

To try and appease titi, I was also thinking of another optional attribute in the player XML node, if control == 'cpu-ultra', then there can be an optional 'resource-multiplier', it will be stored in the game settings, and could be added to the regular 'new game' & 'host game' menus later.

Edit:
'harvest' is now accepted by givePositionCommand(), and giveProductionCommand() now also looks at morph commands.

Code: [Select]
<?xml version="1.0" standalone="yes" ?>
<scenario>
 
<difficulty value="2"/>
<players>
<player control="human" faction="tech" team="1"/>
<player control="cpu-ultra" faction="magic" team="2" name="Merlin" />
<player control="cpu" faction="tech" team="1" name="Bob the AI"/>
<player control="cpu" faction="magic" team="2" />
</players>
<map value="conflict"/>
<tileset value="dark_forest"/>
<tech-tree value="magitech"/>
<default-resources value="false"/>
<default-units value="false"/>
<default-victory-conditions value="false"/>
<scripts>

<startup>
    setTimer ( 'trymorph', 'game', 40*2, false );
    disableAi ( 1 );
    createUnit ( "mage_tower", 1, startLocation(1) );
    createUnit ( "initiate", 1, startLocation(1) );
    morpher = lastCreatedUnit ();
    setCameraPosition ( startLocation (1) );
</startup>

<timer name="trymorph">
  giveProductionCommand  ( morpher, "battlemage" ); -- fail, no resources
  setTimer ( 'handOut', 'game', 40*2, false );
</timer> 
 
<timer name="handOut">
  giveResource ( "gold", 1, 150 );
  giveResource ( "energy", 1, 5 );
  setTimer ( 'domorph', 'game', 40*2, false );
</timer> 

<timer name="domorph">
  giveProductionCommand  ( morpher, "battlemage" );
  --[[ This will succeed,
       morph skill speed == 500, battlemage produce time == 75
       Glest's 'speedModifier' is 1/4000
       So this morph will be complete after 75 / ( 500 / 4000 ) == 600 frames
       However... the command will get queued, until the current command can be
       stopped (after a skill cycle), so some leeway is required...
       in this case, he'll just be standing about, executing the stop command,
       so +100 should be fine.. ]]
  setTimer ( 'attack', 'game', 700, false );
  setTimer ( 'positionCommands', 'game', 40*2, false );
</timer> 

<timer name="attack">
   givePositionCommand ( morpher, 'attack', startLocation(0) );
</timer>
 
<timer name="positionCommands">
  createUnit ( "castle", 0, startLocation(0) )
  createUnit ( "farm", 0, { startLocation(0)[1] - 10, startLocation(0)[2] - 10 } )
  setTimer ( 'worker', 'game', 40*3, true )
  workers = 0;
</timer> 
 
<timer name="worker">
  createUnit ( "worker", 0, startLocation(0) );
  if ( workers == 0 ) then setCameraPosition ( startLocation (0) ); end
  if ( workers % 3 == 0 ) then
    givePositionCommand ( lastCreatedUnit(), "harvest", { 115,91 } ); -- Gold
  elseif ( workers % 3 == 1 ) then
    givePositionCommand ( lastCreatedUnit(), "harvest", { 113,77 } ); -- Wood
  elseif ( workers % 3 == 2 ) then
    givePositionCommand ( lastCreatedUnit(), "harvest", { 98,85 } ); -- Stone
  end
  workers = workers + 1;
  if ( workers > 5 ) then
    stopTimer ( 'worker' );
  end
</timer>

</scripts> 
</scenario>
« Last Edit: 4 September 2009, 06:28:42 by silnarm »
Glest Advanced Engine - Code Monkey

Timeline | Downloads

silnarm

  • Local Moderator
  • Behemoth
  • ********
  • Posts: 1,373
    • View Profile
Re: GameSettings class and Lua
« Reply #8 on: 5 September 2009, 13:30:39 »
I've added giveTargetCommand() to give 'attack' and 'repair' commands, and giveStopCommand() for 'stop' and 'attack-stopped'.

I've also starting working on the error handling problem, but there's plenty more to do there unfortunately :(

current test rig:

xml
Code: [Select]
<?xml version="1.0" standalone="yes" ?>
<scenario>
 
<difficulty value="2"/>
<players>
<player control="human" faction="tech" team="1"/>
<player control="cpu-ultra" faction="magic" team="2" name="Merlin" />
<player control="cpu" faction="tech" team="1" name="Bob the AI"/>
<player control="cpu" faction="magic" team="2" />
</players>
<map value="conflict"/>
<tileset value="dark_forest"/>
<tech-tree value="magitech"/>
<default-resources value="false"/>
<default-units value="false"/>
<default-victory-conditions value="false"/>
<scripts>

<startup>
  dofile ( scenarioDir() .. "/test.lua" );
</startup>

</scripts> 
</scenario>

lua (test.lua)
Code: [Select]
----------------------------------------------------------------------------
--                Unit Creation and Group Management                      --
----------------------------------------------------------------------------

-- creates a unit and puts its id in group
function createAndGroup ( group, type, faction, pos )
   createUnit ( type, faction, pos );
   group[#group+1] = lastCreatedUnit ();
end
-- create a group of num units of a single unit type
function groupOfType ( group, type, faction, num, pos )
   for i=1,num do createAndGroup ( group, type, faction, pos ) end
end

----------------------------------------------------------------------------
--                          Group Commands                                --
----------------------------------------------------------------------------

-- give a group of units attack commands to location
function groupAttackPos ( units, pos )
   for i=1,#units do givePositionCommand ( units[i], "attack", pos ) end
end
-- give a group of units attack commands targeting a unit
function groupAttackUnit ( units, target )
   for i=1,#units do giveTargetCommand ( units[i], "attack", target ) end
end

-----------------------------------------------------------------------------------------
--                                  Start-Up                                           --
-----------------------------------------------------------------------------------------

disableAi ( 1 );
createUnit ( "mage_tower", 1, startLocation(1) );
createUnit ( "initiate", 1, startLocation(1) );
morpher = lastCreatedUnit ();
setTimer ( 'trymorph', 'game', 40*2, false );

-- ERROR
setTimer ( 'boo', 'game', 'forty', false );

giveResource ( "energy", 1, 6 );

initiates = {};
location = startLocation(1);
location[1] = location[1] - 20;
location[2] = location[2] + 10;
groupOfType ( initiates, "initiate", 1, 5, location );

-- for every group (or part of) of 5, send the first three to gold, one to stone, one to wood
for i=1, #initiates do
   if ( (i-1) % 5 < 3 ) then givePositionCommand ( initiates[i], "harvest", {115,101} ); -- gold
   elseif ( (i-1)%5==3 ) then givePositionCommand ( initiates[i], "harvest", {98,109} ); -- stone
   elseif ( (i-1)%5==4 ) then givePositionCommand ( initiates[i], "harvest", {116,117} ); -- wood
   end
end

setCameraPosition ( startLocation (0) );
createUnit ( "castle", 0, startLocation(0) )
createUnit ( "farm", 0, { startLocation(0)[1] - 10, startLocation(0)[2] - 10 } )
setTimer ( 'worker', 'game', 40*3, true )
workers = 0;

createUnit ( "worker", 0, { startLocation(0)[1] - 5, startLocation(0)[2] + 10 } );
givePositionCommand ( lastCreatedUnit(), "harvest", { 115,91 } ); -- Gold

createUnit ( "worker", 0, startLocation(0) );
givePositionCommand ( lastCreatedUnit(), "harvest", { 113,77 } ); -- Wood

createUnit ( "worker", 0, startLocation(0) );
givePositionCommand ( lastCreatedUnit(), "harvest", { 98,85 } ); -- Stone

-----------------------------------------------------------------------------------------
--                                Event Handlers                                       --
-----------------------------------------------------------------------------------------

function timer_trymorph ()
  giveProductionCommand  ( morpher, "battlemage" ); -- fail, no resources
  setTimer ( 'handOut', 'game', 40*2, false );
end

function timer_handOut ()
   giveResource ( "gold", 1, 150 );
   giveResource ( "energy", 1, 5 );
   setTimer ( 'domorph', 'game', 40*2, false );
end

function timer_domorph ()
   giveProductionCommand  ( morpher, "battlemage" );
   --[[ morph skill speed == 500, battlemage produce time == 75, speedModifier == 1/4000
       So this morph will be complete after 75 / ( 500 / 4000 ) == 600 frames ]]
   setTimer ( 'attack', 'game', 700, false );
end

function timer_attack ()
   createUnit ( "swordman", 0, { startLocation(0)[1], startLocation(0)[2] + 5 } );
   sword = lastCreatedUnit ();
   givePositionCommand ( sword, 'move', { startLocation(0)[1] - 15, startLocation(0)[2] - 30 } );
   giveTargetCommand ( morpher, 'attack', sword );
end

function unitDied ()
   local deadId = lastDeadUnit ();
   local deadType = lastDeadUnitName ();
   
   if ( deadId == sword ) then
      army = {};
      groupOfType ( army, "archer", 0, 3, startLocation(0) );
      groupAttackUnit ( army, morpher );
   elseif ( deadId == morpher ) then
      createUnit ( "golem", 1, { startLocation(1)[1], startLocation(1)[2] - 10 } );
      golem = lastCreatedUnit ();
      groupAttackUnit ( army, golem );
      setTimer ( "dorepair", "game", 40*20, false );
   end
end

function timer_dorepair ()
  for i=1, #initiates do giveTargetCommand ( initiates[i], "repair", golem ); end
end
Glest Advanced Engine - Code Monkey

Timeline | Downloads

hailstone

  • Local Moderator
  • Battle Machine
  • ********
  • Posts: 1,568
    • View Profile
Re: Lua Extensions
« Reply #9 on: 6 September 2009, 11:13:21 »
Not sure what you mean by "new moon" but I've renamed the topic now.
Glest Advanced Engine - Admin/Programmer
https://sourceforge.net/projects/glestae/

silnarm

  • Local Moderator
  • Behemoth
  • ********
  • Posts: 1,373
    • View Profile
Re: Lua Extensions
« Reply #10 on: 6 September 2009, 22:18:01 »
Not sure what you mean by "new moon" but I've renamed the topic now.

Lua nova!
Lua is the Portuguese word for 'moon' :)

I've added the 'resource-multiplier' attribute for 'cpu-ultra' players.

New things for the wish-list:
- Command callbacks, execute a function after a command has completed (will remove the need for the ugly frame counting math in the current test rig)
- Queries for HP, Energy, other things...
- Callbacks for events, things like 'damaged' or 'enemySpotted' etc [possible performance concern...]

Location Triggers...
I've been giving this some thought, here's how I think maybe it work:
setLocationTrigger ( trigger, location, entity );

'trigger' is much like the name of our timers, gives us 'handle' to call the LUA function from C++, and to cancel the trigger from the LUA side.
'location', either a point or rectangle (or 'circle'?) [Tables with 2, 4, (or 3) elements]
'entity', the ID of a unit we are interested in, or a table of unit IDs, or a table with a unit type and faction index, or possibly other things as well!
Glest Advanced Engine - Code Monkey

Timeline | Downloads

Omega

  • MegaGlest Team
  • Dragon
  • ********
  • Posts: 6,167
  • Professional bug writer
    • View Profile
    • Personal site
Re: Lua Extensions
« Reply #11 on: 8 September 2009, 01:51:41 »
I wasn't thinking when I made a new topic, but here's some ideas from another topic:

Quote from: Me, myself, and I
1. Way to get the typed text (needs hotkeys disabled while typing), as well as team/all. From when we press enter and type, normally meant for multiplayer.

2. Way to display text in the console. Errors are displayed in the console, but what about Lua messages?

3. Way to instantly give an upgrade to a faction. Now THIS is vital. Not sure why it's been overlooked.

4. Way to check if faction has an upgrade. Goes hand in hand with the last one.

5. Way to force unit location (no 2 space around sides). For precise placement. Should be done with an extra optional value in the createUnit(), such as createUnit('name', 0, startLocation(0), true).

6. Return true for button pressed on showMessage(), so to exectute AFTER all messages viewed, so we can get when the person has finished looking at the message. For example: myvariable = showMessage('xxx','xxx'), and my variable is false until the message 'ok' box is pressed.

7. Hold Position command. Simple nuf. Just perhaps holdPosition('unit').

I've added the 'resource-multiplier' attribute for 'cpu-ultra' players.
What's this?
Edit the MegaGlest wiki: http://docs.megaglest.org/

My personal projects: http://github.com/KatrinaHoffert

silnarm

  • Local Moderator
  • Behemoth
  • ********
  • Posts: 1,373
    • View Profile
Re: Lua Extensions
« Reply #12 on: 28 September 2009, 22:49:15 »
Ok, I think we should pump out some more lua extensions for 0.2.13

So, Omega's list,
1. Maybe later
2. Already done
3. Will do
4. Will do
5. Yeah, but later... and this one will have to return success or failure, and YOU will have have to handle failure.
6. I don't see the need, we now have timers (in game time or real time) and Hailstone fixed it up to pause while the message box is displayed.
7. Already done

More queries (like #4) would be easy and potentially useful and the command callbacks I mentioned shouldn't be too much of a problem... (famous last words?)

Not so easy, the location triggers as discussed would be very nice, I think we should at least put in a hack version, the lua interface need not change, we can make it efficient later, as long as it works people can start playing with it.

I've added the 'resource-multiplier' attribute for 'cpu-ultra' players.
What's this?
A custom resource multiplier for cpu-ultras in scenarios...
Glest Advanced Engine - Code Monkey

Timeline | Downloads

silnarm

  • Local Moderator
  • Behemoth
  • ********
  • Posts: 1,373
    • View Profile
Re: Lua Extensions
« Reply #13 on: 6 October 2009, 09:34:05 »
Location triggers are in. They require you to first register a region and an event, which will no doubt seem superfluous for the current use, I am however thinking for the future... regions will be useful for other things, and you may want more than trigger for an event. Hence the seemingly awkward approach I've taken.

XML
Code: [Select]
<?xml version="1.0" standalone="yes" ?>
<scenario> 
<difficulty value="2"/>
<players>
<player control="human" faction="magic" team="1" />
<player control="cpu-ultra" faction="magic" team="2" name="Merlin" resource-multiplier="3.5" />
<player control="cpu" faction="tech" team="1" name="Bob the AI" />
<player control="cpu" faction="magic" team="2" />
</players>
<map value="conflict"/>
<tileset value="dark_forest"/>
<tech-tree value="magitech"/>
<default-resources value="false"/>
<default-units value="false"/>
<default-victory-conditions value="false"/>
<scripts>

<startup>
  dofile ( scenarioDir() .. "/foo.lua" );
</startup>

</scripts> 
</scenario>

Lua:
Code: [Select]

createUnit( "initiate", 0, startLocation(0) );
id = lastCreatedUnit();
giveResource( "energy", 0, 1 );

registerRegion( "centre", {56,56,11,11} );
registerRegion( "nespot", {80,40,20,20} );
registerRegion( "swspot", {25,70,25,20} );

registerEvent( "inMiddle", "region=centre" );
registerEvent( "atNorthEast", "region=nespot" );
registerEvent( "atSouthWest", "region=swspot" );

setUnitTrigger( id, "inMiddle" );
setFactionTrigger( 0, "atNorthEast" );
setTeamTrigger( 0, "atSouthWest" );

function trigger_inMiddle()
showMessage( "Middle", "..." );
end

function trigger_atNorthEast()
showMessage( "North-East expansion spot", "..." );
end

function trigger_atSouthWest()
showMessage( "South-West expansion spot", "..." );
end

NB: I don't like XML, so I put all the lua in a lua file.
Code: [Select]
function trigger_boo ()
  -- some lua code
end

Is equivalent (as in, indentical) to having this in the XML:
Code: [Select]
<trigger name="boo">
  -- some lua code
</trigger>
Glest Advanced Engine - Code Monkey

Timeline | Downloads

daniel.santos

  • Guest
Re: Lua Extensions
« Reply #14 on: 6 October 2009, 21:43:46 »
Christ!  I'm really behind on this, you guys are doing some cool stuff! :)

OK, so some of this relates back to what I wrote in the GLgooey thread, we need a nice cute little mechanism to expose all game data to Lua -- and not too fat, slow and bloaty.  But first, I want you guys to see the new GameSettings from the network branch.  I don't have it 100% working yet, but I should later 2nite and will commit them (so the network branch is currently broken).  So this is what the GameSettings looks like when rendered as XML (I just grabbed this out of a saved game):
Code: [Select]
    <settings>
        <players>
            <player>
                <id value="0" />
                <name value="Player" />
                <type value="0" />
                <autoRepairEnabled value="false" />
                <autoReturnEnabled value="false" />
                <spectator value="false" />
                <networkInfo>
                    <ipAddress value="127.0.1.1" />
                    <port value="61357" />
                    <localHostName value="Ivory" />
                    <resolvedHostName value="" />
                    <gameVersion>
                        <major value="0" />
                        <minor value="2" />
                        <revision value="12" />
                        <bugFix value="" />
                        <wip value="true" />
                    </gameVersion>
                    <protocolVersion>
                        <major value="0" />
                        <minor value="2" />
                        <revision value="12" />
                        <bugFix value="" />
                        <wip value="true" />
                    </protocolVersion>
                    <uid value="0" />
                </networkInfo>
            </player>
            <player>
                <id value="10001" />
                <name value="AI Player" />
                <type value="1" />
                <autoRepairEnabled value="true" />
                <autoReturnEnabled value="false" />
                <ultra value="false" />
            </player>
            <player>
                <id value="10002" />
                <name value="AI Player" />
                <type value="1" />
                <autoRepairEnabled value="true" />
                <autoReturnEnabled value="false" />
                <ultra value="true" />
            </player>
        </players>
        <teams>
            <team>
                <id value="0" />
                <name value="" />
            </team>
            <team>
                <id value="1" />
                <name value="" />
            </team>
            <team>
                <id value="2" />
                <name value="" />
            </team>
            <team>
                <id value="3" />
                <name value="" />
            </team>
        </teams>
        <factions>
            <faction>
                <id value="0" />
                <name value="Faction 0" />
                <teamId value="0" />
                <typeName value="magic" />
                <randomType value="false" />
                <mapSlot value="0" />
                <resourceMultiplier value="1.00" />
                <players>
                    <player id="0" />
                </players>
            </faction>
            <faction>
                <id value="1" />
                <name value="Faction 1" />
                <teamId value="1" />
                <typeName value="tech" />
                <randomType value="false" />
                <mapSlot value="1" />
                <resourceMultiplier value="1.00" />
                <players>
                    <player id="10001" />
                </players>
            </faction>
            <faction>
                <id value="2" />
                <name value="Faction 2" />
                <teamId value="2" />
                <typeName value="magic" />
                <randomType value="false" />
                <mapSlot value="2" />
                <resourceMultiplier value="3.00" />
                <players>
                    <player id="10002" />
                </players>
            </faction>
        </factions>
        <description value="Island Siege" />
        <mapPath value="maps/island_siege.gbm" />
        <mapSlots value="4" />
        <tilesetPath value="tilesets/winter_forest" />
        <techPath value="techs/magitech" />
        <scenarioPath value="" />
        <thisFactionId value="0" />
        <autoRepairAllowed value="true" />
        <autoReturnAllowed value="false" />
        <dayTime value="1000.00" />
        <fogOfWarEnabled value="true" />
        <randStartLocs value="false" />
        <pauseAllowed value="false" />
        <changeSpeedAllowed value="false" />
        <speedFastest value="2.00" />
        <speedSlowest value="0.50" />
        <worldUpdateFps value="40" />
        <commandDelay value="10" />
    </settings>

My thought is that we need a nice generic mechanism to expose objects to Lua.  I don't like the idea of each of these being a method of ScriptManager.  Instead of ScriptManager::getPlayerName(), I want to have functions like ScriptManager::getWorld(), which returns a reference to the world object which with methods like getFactions() which returns all of the factions or even getFaction(int id), etc.  In other words, I want to create a direct mapping between C++ objects and Lua objects to the greatest degree possible (and feasible, of course).  The optimal solution will no doubt involve templates, possibly even std::tr1::function (or boost::function, same thing).  The same mechanism can be used for exposing these data values to the GUI layer, where XML specifies a Lua snippet to populate a GUI component from internal GAE objects.

silnarm

  • Local Moderator
  • Behemoth
  • ********
  • Posts: 1,373
    • View Profile
Re: Lua Extensions
« Reply #15 on: 6 October 2009, 22:27:51 »
I've been getting concerned with the ScriptManager 'solution', though I plan to address the messy error handling soon, which should cut a lot of the rot.  Even so, the collection of functions making up the Lua interface is getting large, and still growing... So I think you're right...

We need luabind.  But we also need to use it wisely, at least with scenarios, to avoid copying excessive amounts of data to and from the lua state.
http://www.rasterbar.com/products/luabind.html

The new game-settings look good, I even noticed a resource-multiplier in there ;)
Glest Advanced Engine - Code Monkey

Timeline | Downloads

daniel.santos

  • Guest
Re: Lua Extensions
« Reply #16 on: 6 October 2009, 22:55:21 »
ooh, luabind sounds VERY f**king cool!  Yea, I want data only moved when it's requested from Lua.  When an object is requested, I want some type of reference to that object returned, not the entire object.  Then when an accessor is called from Lua, it can access the actual data of that field.  If this is an ugly thing (requiring lots of work), then we can pass smaller objects by value and large ones (like Unit) by reference.  As far as ScriptManager, this can be cleaned up a lot with IoC (Inversion of Control).  You just have to have some mechanism to abstract the actual Lua call and then you have a common function that does all of the error handling, even if you just pass a function pointer or std::tr1::function object to it (which, in turn, calls some function to perform the Lua expression, but that calling function (or even class) handles all error conditions.

I've also seen this tolua++ package, although it doesn't appear (at first glance) as slick as luabind.

daniel.santos

  • Guest
Re: Lua Extensions
« Reply #17 on: 7 October 2009, 00:31:04 »
The new game-settings look good, I even noticed a resource-multiplier in there ;)

In accordance with bug #31 I should probably also add the starting resources to the GameSettings::Faction.

hailstone

  • Local Moderator
  • Battle Machine
  • ********
  • Posts: 1,568
    • View Profile
Re: Lua Extensions
« Reply #18 on: 11 October 2009, 01:28:11 »
I think it would be good to have the lua callbacks in the class that it relates to.

Such as having getPlayerName in GameSettings and use a macro to register it with Lua.

Code: [Select]
REGISTER_LUA_FUNC(getPlayerName)

int GameSettings::getPlayerName(LuaHandle* luaHandle){
LuaArguments luaArguments(luaHandle);
string playerName = this->getPlayerName(luaArguments.getInt(-1));
luaArguments.returnString(playerName);
return luaArguments.getReturnCount();
}

That eliminates the wrapper function since it is used directly in the Lua callback function.

Or maybe since a lot of them have very similar callbacks
Code: [Select]
REGISTER_LUA_QUERY(string, getPlayerName, int) // return type, function name, parameter types
REGISTER_LUA_COMMAND(createUnit, string, int, Vec2i) // function name, parameter types

I haven't looked at luabind yet.
« Last Edit: 11 October 2009, 01:33:11 by hailstone »
Glest Advanced Engine - Admin/Programmer
https://sourceforge.net/projects/glestae/

silnarm

  • Local Moderator
  • Behemoth
  • ********
  • Posts: 1,373
    • View Profile
Re: Lua Extensions
« Reply #19 on: 12 October 2009, 03:50:16 »
I think it would be good to have the lua callbacks in the class that it relates to.

Such as having getPlayerName in GameSettings and use a macro to register it with Lua.

This would be nice, unfortunately it wouldn't work ;)

A Lua call back must have the signature int callback( LuaHandle* ). So it would have to be static int callback(LuaHandle*) in GameSettings, not int callback(LuaHandle *lh) which is really int callback(GameSettings *this, LuaHandle *lh).

That's why all the callbacks are in ScriptManager, and why all the wrappers existed (Note that they don't exist anymore, I made the ScriptManager class static, which is arguably just as ugly, but it got rid of the need for the wrappers.
Glest Advanced Engine - Code Monkey

Timeline | Downloads

daniel.santos

  • Guest
Re: Lua Extensions
« Reply #20 on: 13 October 2009, 21:32:00 »
I know I should probably be reading instead of just asking this question here, but can we have variables in Lua that are references to objects?  Example:
Code: [Select]
FactionVariableType faction = currentFaction; // (or something)
string playerName = faction.getPlayer().getName();

Sorry, I haven't learned Lua enough to give a more vague accurate example.

silnarm

  • Local Moderator
  • Behemoth
  • ********
  • Posts: 1,373
    • View Profile
Re: Lua Extensions
« Reply #21 on: 15 October 2009, 11:07:49 »
LuaBind or something similar will make this easy.

The Lua would look something like,
Code: [Select]
local myFaction = getFaction(0); -- a callback to the engine
local playerName = myFaction:getName(); -- another callback to the engine
local numUnits = myFaction:getUnitCount(); -- and again
if numUnits < 15 then
    showMessage(playerName .. ", get cracking!");
elseif numUnits > 50 then
    if not getFaction(1):beenAttacked(0) then
        showMessage(playerName .. ", get over there already!");
    end
end

As far as 'aggregate' structures/objects goes, Lua has Tables.  Your one stop shop to everything, in essence an associative array, it is also how 'classes' are defined and instantiated. They are always passed by reference.  So myFaction.getName() is a legal function call, but that is just a function in the table, and that calls it with no parameters.  myFaction:getName() is syntactic sugar for myFaction.getName(myFaction), and takes care of the 'this' pointer equivalent, the self reference.
That's OO in Lua... it doesn't really offer proper OO out of the box, but you can construct your own inheritance system using 'fallbacks' if you really wanted to, LuaBind probably does this for us too, it can apparently even do classes in Lua, derived from C++ classes, so obviously it must include some more extensive OO system in Lua, got plenty more reading to do there.

I never liked 'loosely' typed languages myself (I notice it's in vogue to call them 'dynamically' typed these days, certainly sounds cooler...), but playing with Lua has been most enjoyable so far :)

I'm still not sure on how costly this will all be, in terms of overhead in passing stuff to and fro... if I understand LuaBind correctly, performance shouldn't be a problem, but our compile time may take a nasty hit :(
Glest Advanced Engine - Code Monkey

Timeline | Downloads

daniel.santos

  • Guest
Re: Lua Extensions
« Reply #22 on: 15 October 2009, 18:54:32 »
Yea, compile time will definitely rise substantially.  I don't personally mind that because I have a quad core processor.  Another thing that can help compile times is cleaning up our headers more so they are less dependant upon each other.  I don't mind changes in headers like util.h or patterns.h to cause the whole world to be re-built, but in general, these types of dependencies should be kept to a minimum.

So this sounds perfect!  I the way Lua implements OO seems perfectly fine to me.  Personally, I don't care how it passes this "this" pointer, as long as it has a mechanism for it.  And as far as polymorphism is concerned, I don't care too much about that either.  If we don't *need* the explicit sub-types in Lua, then we can just give Lua the interface to the C++ base class and let the Lua calls, make the C++ virtual calls to the sub-types.  For this, I'm mostly thinking of objects that wont be instantiated from Lua, just accessed (like getFaction()).

So back to LuaBind, from what I've read from it, performance should actually be either "absolutely as fast as possible" or *very* damn close to it.  The hit all comes at compile-time.  Also, if I understand the entirety of the mechanisms correctly (of both Lua and LuaBind) then the run-time overhead should also be minimal, since Lua has support for real object references.  Some interpreted languages implement this as a "copy a lot of stuff around but only return the field you requested" because they implemented objects/structs as an afterthought.
« Last Edit: 15 October 2009, 20:13:18 by daniel.santos »

hailstone

  • Local Moderator
  • Battle Machine
  • ********
  • Posts: 1,568
    • View Profile
Re: Lua Extensions
« Reply #23 on: 24 October 2009, 03:26:41 »
Here's another alternative for binding http://www.swig.org/
Glest Advanced Engine - Admin/Programmer
https://sourceforge.net/projects/glestae/

daniel.santos

  • Guest
Re: Lua Extensions
« Reply #24 on: 24 October 2009, 10:58:06 »
That seems like quite a powerful product.  Either way, I we don't want to export everything to Lua, so we'll want to mark up our header files with a lot of #ifs so that we only export the classes and methods we intend to, and I most certainly don't want to be maintaining interface files separate from our C++ header files (it looks like both SWIG and luabind will enable us to do it all in our own headers).  Good research Hailstone!  You're always finding cool stuff. :)