Lua in SpringRTS/Gadgets

Gadgets are script files that must be present from all players. That's the reason gadgets are used in mods and maps as those should always have exactly the same data. Gadgets can use callins and callouts from both synced and unsynced mode but you need a special way to let synced and unsynced code to communicate with each other.

When making a gadget, always separate synced code from the unsynced code. That can be done with using:

if (gadgetHandler:IsSyncedCode()) then
           --  Synced code here --
else
           -- Unsynced code here --
end


That makes sure that the code blocks are in the right place. Not using the gadgetHandler:IsSyncedCode() will result in executing the code in both synced and unsynced mode. That in many occasions will create errors so it's not wise to do so. Specify whether the code should be used in synced mode or unsynced.
When making a gadget you should always place the game events(UnitCreated(), UnitDestroyed(), ...) in the synced block of code and the events that just has with Lua graphic to do should be placed in the unsynced block of code.
An easy way to determine if something should be placed in unsynced or synced is to determine if the code should have the same effect on all users or only you. The reason Lua graphics are placed in the unsynced code is that even if one user doesn't get the right graphics it doesn't mean that other players are having the same issues. So doing so makes the gameflow go smooth. Think if UnitDestroyed() for example was in the unsynced code. Then a player with a slower computer would probably get the event a bit slower thus not making the game playable for him as he would get events a bit delayed.

Sync/Unsynced communication

edit

Using globals:

edit

One way to communicate between synced and unsynced code is to use globals. We use the _G table from Lua to add a variable as global:

_G.variable=variable --we assign variable to the global table


Here follows a demonstration of synced/unsynced communication via globals:

--SYNCED CODE
if (gadgetHandler:IsSyncedCode()) then
   local number = 10                        -- declaring local variable 'number'
   function gadget:SomeSyncedCallin(...)
      number=number+1                       -- increment variable's value by one
      _G.number=number                      -- save the new value into a global variable
   end
else

--UNSYNCED CODE
   function gadget:Update(...)              -- here goes some unsynced callin. we use Update to see the result in real time
      Spring.Echo(SYNCED.number)            -- print the global variable's value on screen
   end
end

In the example we declare a local variable in the synced part of the code and try to change the value of it while still in synced mode. Then we save the value as a global. After that if we want to read the value in the unsynced code we just use the "SYNCED." table.

Using SendToUnsynced() function

edit

A second way to do this is to use the SendToUnsynced() function.