Lua unit scripting - Page 3

Lua unit scripting

Discuss the source code and development of Spring Engine in general from a technical point of view. Patches go here too.

Moderator: Moderators

User avatar
FLOZi
MC: Legacy & Spring 1944 Developer
Posts: 6242
Joined: 29 Apr 2005, 01:14

Re: Lua unit scripting

Post by FLOZi »

bah, so there is, I looked at the wiki and managed to completely miss them. :cry: :oops:
User avatar
SpliFF
Posts: 1224
Joined: 28 Jul 2008, 06:51

Re: Lua unit scripting

Post by SpliFF »

Would moving unit gadget callins to this new interface increase or decrease performance? It would be sensible to have all unit callins in one place.
User avatar
FLOZi
MC: Legacy & Spring 1944 Developer
Posts: 6242
Joined: 29 Apr 2005, 01:14

Re: Lua unit scripting

Post by FLOZi »

Might it not be nicer for explode to take the form

Explode(unitID, piece, {table_of_flags}) -> Nil

And have the engine do the bitwise OR of the flags? Maybe not. I dunno. As for the symbolic constants, a global SFX table seems the obvious answer. e.g. SFX.FALL, SFX.SHATTER etc. which would also contain the wakes and VTOL trail fx.
imbaczek
Posts: 3629
Joined: 22 Aug 2006, 16:19

Re: Lua unit scripting

Post by imbaczek »

flag1 + flag2 == flag1 | flag2 unless any of the flags have more than one bit set, so not a problem in practice.
User avatar
lurker
Posts: 3842
Joined: 08 Jan 2007, 06:13

Re: Lua unit scripting

Post by lurker »

I looked though some S44 scripts, and it is a problem in practice. Unless I confused myself.
User avatar
jK
Spring Developer
Posts: 2299
Joined: 28 Jun 2007, 07:30

Re: Lua unit scripting

Post by jK »

User avatar
lurker
Posts: 3842
Joined: 08 Jan 2007, 06:13

Re: Lua unit scripting

Post by lurker »

Yes, but that gets into the slow territory... wait, flozi actually suggested making tables, nevermind..
Tobi wrote:An example of a clash: you can now override engine damage using the UnitPreDamaged gadget call-in, or using the HitByWeaponId unit script call-in. (And if you use both the new damage of one of them will override the new damage of the other of course.)
Err, one of those calls comes first. If the other doesn't get the real damage number that's been changed it sounds like a bug.
User avatar
FLOZi
MC: Legacy & Spring 1944 Developer
Posts: 6242
Joined: 29 Apr 2005, 01:14

Re: Lua unit scripting

Post by FLOZi »

So I threw together a non-working example script based on ARMSTUMP.BOS, with the suggested FX table, weapon call-in changes, and relying on RockUnit and HitByWeapon libraries. :roll:

http://pastebin.com/m6f3579aa
User avatar
FLOZi
MC: Legacy & Spring 1944 Developer
Posts: 6242
Joined: 29 Apr 2005, 01:14

Re: Lua unit scripting

Post by FLOZi »

Tobi continues the awesome:
http://github.com/spring/spring/commit/ ... 3e943bfa89
lua unit script: added GetPieceTranslation, GetPieceRotation, GetPiecePosDir
User avatar
FLOZi
MC: Legacy & Spring 1944 Developer
Posts: 6242
Joined: 29 Apr 2005, 01:14

Re: Lua unit scripting

Post by FLOZi »

Triple post:
unit script: removed Create (framework handles it)
edit1: Does that mean it's still useable in exactly the same way, just the implementation has moved from the engine to the framework?

edit2: yeah, having actually bothered to examine the code, that's what the change was. :lol:

Also I think FX might be a better name for the table than SFX, but maybe that's just me. Not terribly important.
Tobi
Spring Developer
Posts: 4598
Joined: 01 Jun 2005, 11:36

Re: Lua unit scripting

Post by Tobi »

FLOZi wrote:Triple post:
unit script: removed Create (framework handles it)
edit1: Does that mean it's still useable in exactly the same way, just the implementation has moved from the engine to the framework?

edit2: yeah, having actually bothered to examine the code, that's what the change was. :lol:

Also I think FX might be a better name for the table than SFX, but maybe that's just me. Not terribly important.
Yeah, the framework already handled it before, and framework explicitly nilled the Create function before passing script to engine, because there was a bit of an order of initialization problem. (When engine calls Create it runs too early for framework to be able to properly handle calls to e.g. Sleep or WaitForTurn from inside Create..) Indeed for the scripts nothing changes.

About SFX vs FX, I thought SFX is consistent with EmitSfx, but otherwise I couldn't really find arguments in favour of one or the other ;-)

Thanks for the stumpy sample btw, I'll try to complete it and put it on wiki as example ASAP.
Tobi
Spring Developer
Posts: 4598
Joined: 01 Jun 2005, 11:36

Re: Lua unit scripting

Post by Tobi »

In between quite some changes I now changed weapon call-ins in master to take a weaponNumber, instead of existing for each weapon.

When changing the S44 GERTiger.lua script to use this however I can't really say it feels like a good interface, so I'm tempted to revert it or add compatibility layer to the framework (since in engine it resulted in cleaner code).

Consider what you get:

Code: Select all

function script.QueryWeapon(u, w)
  if (w == 3) then return coaxflare end
  return coaxflare
end
or

Code: Select all

local queryWeaponPieces = { flare, flare, coaxflare }
function script.QueryWeapon(u, w)
  return queryWeaponPieces[w]
end
Instead of the way less coupled:

Code: Select all

function script.QueryWeapon1() return flare end
function script.QueryWeapon2() return flare end
function script.QueryWeapon3() return coaxflare end
Similar for AimFromWeapon of course.

Also things like FireWeapon get patterns like:

Code: Select all

function script.FireWeapon(u, w)
  if (w <= 2) then
    -- main gun code
  else
    -- machine gun code
  end
end
All this increases the coupling between weapons incredibly. Unless you take care to always call into per weapon functions of course:

Code: Select all

function script.FireWeaponMainGun(u)
  --stuff
end

function script.FireWeaponMachineGun(u)
  -stuff
end

function script.FireWeapon(u, w)
  if (w <= 2) then
    return FireWeaponMainGun(u)
  else
    return FireWeaponMachineGun(u)
  end
end
But then, why do we have the weaponNum (w) argument anyway? We could as well have written:

Code: Select all

-- WEAPON 1
function script.FireWeapon1(u)  --FireWeaponMainGun
  --stuff for main gun
end

-- WEAPON 2
script.FireWeapon2 = script.FireWeapon1

-- WEAPON 3
function script.FireWeapon3(u)  --FireWeaponMachineGun
  --stuff for machine gun
end
So, in short, I think having a 'weaponNum' argument encourages lazy, coupled, unclean code, while having separate functions for each weapon encourages to keep weapon uncoupled. And it's still trivially easy to reuse common parts, as Lua has a thing called 'function'... ;-)

(Note that, whatever the engine does, the other behavior can always be faked either by the framework or by individual unit scripts.)


Opinions?
User avatar
SpliFF
Posts: 1224
Joined: 28 Jul 2008, 06:51

Re: Lua unit scripting

Post by SpliFF »

My only concern is will (does) the engine arbitrary enforce a limit on number of weapons due to this convention (or other legacy COB issues)? Will unit scripts provide AimFromWeapon50? I have a particular interest in building some very large and complex units.

Other than that I concede the old way is probably cleaner and faster for the common case (a unit of 1-5 weapons with different properties)

Another question. Does VFS.Include work with unit scripts? It seems there would be many cases where units share common code.
Tobi
Spring Developer
Posts: 4598
Joined: 01 Jun 2005, 11:36

Re: Lua unit scripting

Post by Tobi »

SpliFF wrote:My only concern is will (does) the engine arbitrary enforce a limit on number of weapons due to this convention (or other legacy COB issues)? Will unit scripts provide AimFromWeapon50? I have a particular interest in building some very large and complex units.
There is currently a limit of 32 weapons per unit. (MAX_WEAPONS_PER_UNIT in code)

This is used to know when to stop searching for weapon subtables. Also memory usage for COB files increases a bit when this is increased. Maybe worst effect is that COB's show uses an O(MAX_WEAPONS_PER_UNIT) algorithm for some weird hack...

Otherwise it can be bumped up easily.
SpliFF wrote: Other than that I concede the old way is probably cleaner and faster for the common case (a unit of 1-5 weapons with different properties)
Just added some compatibility 'dispatching' code to framework already ;-)

(ie. if AimWeapon doesn't exist but AimWeapon1 does exist, it generates dispatchers for all weapon funcs.)
SpliFF wrote:Another question. Does VFS.Include work with unit scripts? It seems there would be many cases where units share common code.
Yes, BUT, VFS.Include will load (that means decompress), parse and compile the Lua file each time it's run. That means each time a unit is created, double work is done.

That's why in master I added a memoized include function:

Code: Select all

include ( filename ) -> ...
Filename is relative to the script directory (UNITSCRIPT_DIR). It returns whatever is returned by the included file.

This works similar to the include function that is available to gadgets (that one just calls VFS.Include with the gadget environment), except this one is memoized, so only the first time it is called (over all units, until you either do '/luarules reload' or restart Spring) it will actually load, parse and compile the .lua file.

(Note that in 0.80.4 I had another approach, but I figured this new approach wouldn't have any performance impact and would be more standard. In other words, you need spring + base content from recent master to use this.)


EDIT:

Also I did some performance test again. The test counted number of times QueryWeapon1 can be called in 10 seconds, in chunks of 10k calls.

(This includes running the dispatching code in the Lua case!)

Results:

Code: Select all

COB  :    5130000 calls in 10016 ms ->    513000 calls/second
LUA  :   21450000 calls in 10001 ms ->   2145000 calls/second
none : 2430290000 calls in 10000 ms -> 243029000 calls/second
Tobi
Spring Developer
Posts: 4598
Joined: 01 Jun 2005, 11:36

Re: Lua unit scripting

Post by Tobi »

Just found some epic typo in the framework that broke Signal and made it leak threads (coroutines) like mad.

So if you want to experiment with this I recommend picking a recent development build.
User avatar
yuritch
Spring 1944 Developer
Posts: 1018
Joined: 11 Oct 2005, 07:18

Re: Lua unit scripting

Post by yuritch »

I have to say that while aimweapon1, aimweapon2, etc. approach is better for the Tiger (with 3 weapons total, only 2 of which operate the same barrel), units with more weapons are imo better scripted with aimweapon(n) approach. Consider the gbrmonitor from S44 for ex., it has 20 weapons, most of which operate similar turrets (so their aim scripts would be the same, only piece names differ). A piece array using weapon number as index would be right at home there.
Tobi
Spring Developer
Posts: 4598
Joined: 01 Jun 2005, 11:36

Re: Lua unit scripting

Post by Tobi »

Yeah I guess you are right, one approach is easier for certain kind of units, and the other one for other kinds of units.

They're both in the framework now so you're good to go :-)


In other news, I now also tested call-out speed (random series of 1000 moves and turns: 50/50 move/turn, 50/50 now/speed, random destinations, axes and speeds). The results:

Code: Select all

COB: 90000*1k calls in 10147 ms -> 8870000 calls/second
Lua: 40000*1k calls in 11754 ms -> 3403000 calls/second
So unfortunately COB is about 2.6x faster for practically infinitely long move/turn sequences. (On the other hand, Lua is about 4.2x faster for simple call-ins.)

(This isn't really surprising since Move/Turn in Lua are yet another call-out, while in COB move and turn have special opcodes and are implemented directly in the virtual machine.)

The question is now of course, how these ratios works out on a fully ported real mod or game :-)
User avatar
jK
Spring Developer
Posts: 2299
Joined: 28 Jun 2007, 07:30

Re: Lua unit scripting

Post by jK »

Tobi wrote:(This isn't really surprising since Move/Turn in Lua are yet another call-out, while in COB move and turn have special opcodes and are implemented directly in the virtual machine.)
did you localized those functions in lua?
Tobi
Spring Developer
Posts: 4598
Joined: 01 Jun 2005, 11:36

Re: Lua unit scripting

Post by Tobi »

Yes, all trivial optimization I know of applied.

I've attached scripts to this post in case people want to check :-)

(Btw the localization is done by the framework, a string with code like 'local Turn = ...' etc. is prepended before the script itself.)
Attachments
benchmark.zip
(25.79 KiB) Downloaded 21 times
Tobi
Spring Developer
Posts: 4598
Joined: 01 Jun 2005, 11:36

Re: Lua unit scripting

Post by Tobi »

In master, I removed unitID argument to all Lua unit script related call-ins and call-outs: it's available as upvalue anyway., and seeing "unitID unitID unitID" everywhere drives me crazy ;-)

If you already wrote some script, you can just remove the unitID argument from all call-ins and pretty much all Spring.UnitScript.* functions. (e.g. Turn, Move, etc.)

I'll try to remember updating the wiki shortly.
Post Reply

Return to “Engine”