Lua unit scripting - Page 2

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

Tobi
Spring Developer
Posts: 4598
Joined: 01 Jun 2005, 11:36

Re: Lua unit scripting

Post by Tobi »

That's what I thought at first too, but that is NOT what smoothAnim=1 does.

What it does is exactly the following:

While executing COB code, any move-now and turn-now that is encountered is stored in a list.

When the thread stops executing because it calls wait-for-move or wait-for-turn for a move/turn that is not finished yet, or because the outermost function returned, this list is flushed: all the move-now and turn-now are executed, as-is, without any extra interpolation.

However, when the thread stops executing because of a sleep more than 30 ms and less than 300 ms, the moves and turns in the list are 'converted' from move-now to move and turn-now to turn, with a speed calculated so the move/turn will finish just before the sleep ends.

For other amounts of sleep nothing special happens.


tl;dr: smoothAnim=1 only converts sequences of move-now/turn-now before a sleep > 30 ms and < 300 ms to move/turn with a speed calculated so they finish just before the sleep ends.


EDIT: wikified
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Re: Lua unit scripting

Post by Argh »

Yeah, I remember when that change was put in. Originally, it was implemented as I described. However, it was changed because of a bunch of whining about certain OTA scripts going bonkers, because they were written so poorly and nobody wanted to fix them.

I'm just asking if it might be possible, with a brand-new system (where backwards compatibility is no longer a concern, yay), to not follow that precedent. It's such a huge performance boost, and for well-written scripts that do not use wait-for-turn, but instead use sleep timing... it's totally free.
User avatar
zwzsg
Kernel Panic Co-Developer
Posts: 7052
Joined: 16 Nov 2004, 13:08

Re: Lua unit scripting

Post by zwzsg »

I'm pretty sure Tobi said already that internally, Spring use radian for angles. So by having directly radian in the lua, you'd remove one multiplication step from the BOS system, not add one.
If piece position now == piece position linear * constant + / - some value * constant, that's fairly lengthy float math in Lua.

If you don't get why that has some fairly serious performance ramifications, that's not my problem.
Until you have some repeatable measure about those imagnied performance problem, I will not believe that one or two multiplications per animation are going to have any measurable effect. I think you greatly underestimate the amount of multiplication a simple c<->lua interface will already have.


And let's stop talking about SmoothAnim, I just wish SmoothAnim never existed, it's an hacky engine-side hack attempting to fix broken scripts that result in breaking well-made scripts, and shouldn't enter in any discussion about a clean new animation system.
Yeah, I remember when that change was put in. Originally, it was implemented as I described. However, it was changed because of a bunch of whining about certain OTA scripts going bonkers, because they were written so poorly and nobody wanted to fix them.
:roll: Other way around. Sheesh, you're unbelievable. SmoothAnim was written because most TA script, including Cavedog's ones, were written poorly, and a S.Y. found it easier to write one engine hack than to hope for thousands of scattered scripts to ever get fixed.
It's such a huge performance boost, and for well-written scripts that do not use wait-for-turn, but instead use sleep timing... it's totally free.
:roll: You can use turn .. speed; and sleep ..; to have perfect scripts you know. Without SmoothAnim I mean.
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Re: Lua unit scripting

Post by Argh »

I'm pretty sure Tobi said already that internally, Spring use radian for angles. So by having directly radian in the lua, you'd remove one multiplication step from the BOS system, not add one.
You're quite right, but the idea of writing scripts with radians is pretty icky. Degrees are a lot easier to visualize.

I guess I can wrote every turn command as 1*z, where z is that constant, since Lua will optimize it correctly, though. Just seems like that should be done.



As for SmoothAnim, you're getting it backwards, lol.

What Tobi just reminded me was that SmoothAnim=0 does not operate the way that I originally requested (originally, SmoothAnim was required, but we had a long thread about it at some point years ago).

I am well aware that it was a hack to put interpolation into the engine and keep OTA scripts looking as good as modern ones. I'm saying, "don't implement the current SmoothAnim behavior, do what we originally wanted, which performs a lot better".

You can use turn .. speed; and sleep ..; to have perfect scripts you know. Without SmoothAnim I mean.
I think you need to re-read Tobi's post.

Or watch a P.U.R.E. Unit with a walk-cycle, which uses exactly the method you're describing, walk with the engine speed down.

Let's just say that you will not suddenly see really jerky animation.

For example... where RUN_SPEED_FAST = 3

Code: Select all

turn toe_f_r to x-axis <15> speed <5>*RUN_SPEED_FAST;
sleep 1000 / RUN_SPEED_FAST;
This should result in obvious stepping issues, when the engine's slowed down a lot... but it doesn't. Which is why I'm bringing this up. If we're going to use this, I want to get that huge speedup again, since it'll offset any other cause of slowdown by huge margins.
User avatar
smoth
Posts: 22309
Joined: 13 Jan 2005, 00:46

Re: Lua unit scripting

Post by smoth »

You're quite right, but the idea of writing scripts with radians is pretty icky. Degrees are a lot easier to visualize.
FFS
Image
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Re: Lua unit scripting

Post by Argh »

Which is easier to remember and mentally convert and work with? 32768, or 180?

For me, it's definitely 180. I do not relate to radians, and neither do most people, especially artists, for whom "radian" is a foreign word.

At any rate, that's a very minor side issue.
User avatar
smoth
Posts: 22309
Joined: 13 Jan 2005, 00:46

Re: Lua unit scripting

Post by smoth »

You are the one who is on about efficiency, having the engine do the math for you is adding cost for the end user. As a programmer you are to take on all of that burden.
User avatar
FLOZi
MC: Legacy & Spring 1944 Developer
Posts: 6241
Joined: 29 Apr 2005, 01:14

Re: Lua unit scripting

Post by FLOZi »

If you want to use degrees, that's fine. Just use math.rad(my_angle_in_degrees) to convert. Minimal CPU cost.
(Ok, maybe not that minimal, but easy enough to use other simple methods to optimise it)

And the only COB call-in that Spring requires (or at least did require at some point, sorry Tobi, Argh was at least passingly right) was Create().


Might it not be neater for all the weapon-related callins to provide the weapon number rather than have AimWeapon1 etc?

Is there really a need for seperate HitByWeapon and HitByWeaponID callins?
User avatar
SpliFF
Posts: 1224
Joined: 28 Jul 2008, 06:51

Re: Lua unit scripting

Post by SpliFF »

I'm very excited about this but I have some concerns about the current implementation:

SetDirection-> WindDirectionChange
SetSpeed -> WindSpeedChange / ExtractorAmountChange

Otherwise the name implies it is a mobile unit changing direction/speed.

setSFXoccupy -> TerrainChange

If this stays TerrainChange is a clearer name.

Go() is a vague and confusing name. It also seems totally unnessesary:

Go -> ExtractorStart
-- or preferably --
ExtractorMetalChange( unit_id ) do
if IsUnitActive(unit_id) do something end
end

UNIT DEF INFO

Most traditional unit callbacks pass unitDef / targetUnitDef arguments as well as unitID. I would prefer a little extra overhead in the callback initialisation over having to probe for the unitdef since the former can be done in C++.

BUILDERS

Please be explicit when a callback has different arguments and behaviour based on type:

StartBuilding -> MobileStartBuilding / FactoryStartBuilding
QueryBuildInfo -> FactoryBuildInfo

This change makes it clearer the functions have different behavior. It may even be possible that one day a unit can have both properties (like the Fatboy in Supreme Commander but with a nanolathe insted of guns)

WEAPONS

I'd also prefer to see the numbered weapon callbacks change format:

AimWeapon1( ... ) -> AimWeapon( weaponID, weaponDefID, ... )

This will allow behaviours to be shared between common weapons (consider a large tank with 10 turretted machineguns). This way you'd only need a single function and you can call specific behaviours with a comparison, switch or array lookup.

TRANSPORTS

I'm not convinced about air and ground transports sharing a callback name when different behaviour is implied. It would be better as:

TransportDrop -> AirTransportDrop / GroundTransportDrop

If nothing else this should make documentation clearer.

Passenger Falling() should have a StartFalling() callback as well since I suspect it will be common to test for this event and doing so in Falling() would require setting up vars and if statements.

I accept many of these issues above are a legacy of COB and changing them would make conversion from COB slightly harder but these changes are clearer and more consistent with other callbacks. Best to fix COB's mistakes now before any serious Lua development takes place.
Last edited by SpliFF on 26 Aug 2009, 04:32, edited 1 time in total.
User avatar
smoth
Posts: 22309
Joined: 13 Jan 2005, 00:46

Re: Lua unit scripting

Post by smoth »

SpliFF wrote:Best to fix COB's mistakes now before any serious Lua development takes place.
+2
User avatar
FLOZi
MC: Legacy & Spring 1944 Developer
Posts: 6241
Joined: 29 Apr 2005, 01:14

Re: Lua unit scripting

Post by FLOZi »

Best to fix COB's mistakes now before any serious Lua development takes place.
I tend to agree with this mindset. :-)
User avatar
Caydr
Omnidouche
Posts: 7179
Joined: 16 Oct 2004, 19:40

Re: Lua unit scripting

Post by Caydr »

Cob was flawless and any changes are heresy and admittance of self-gay.
User avatar
AF
AI Developer
Posts: 20687
Joined: 14 Sep 2004, 11:32

Re: Lua unit scripting

Post by AF »

Caydr wrote:Cob was flawless and any changes are heresy and admittance of self-gay.
I loo forward to this outcome

I dont think it's a good idea ot put Air and ground into the names since they both have different uses that could just as easily be used in an aircraft and a ground based unit.

Instead I would prefer the two to be broken down into their constituent parts for greater flexibility
User avatar
KaiserJ
Community Representative
Posts: 3113
Joined: 08 Sep 2008, 22:59

Re: Lua unit scripting

Post by KaiserJ »

smoth wrote:*FRUMPLE*
smelling pretty colors is the best game
Tobi
Spring Developer
Posts: 4598
Joined: 01 Jun 2005, 11:36

Re: Lua unit scripting

Post by Tobi »

SpliFF wrote:SetDirection-> WindDirectionChange
SetSpeed -> WindSpeedChange / ExtractorAmountChange

Otherwise the name implies it is a mobile unit changing direction/speed.

setSFXoccupy -> TerrainChange

If this stays TerrainChange is a clearer name.

Go() is a vague and confusing name. It also seems totally unnessesary:

Go -> ExtractorStart
-- or preferably --
ExtractorMetalChange( unit_id ) do
if IsUnitActive(unit_id) do something end
end
I agree with this yeah, personally I prefer just getting rid of setSFXOccupy and Go as both are trivial to emulate without the extra call-in.

UNIT DEF INFO

Most traditional unit callbacks pass unitDef / targetUnitDef arguments as well as unitID. I would prefer a little extra overhead in the callback initialisation over having to probe for the unitdef since the former can be done in C++.
I don't agree with this for two reasons:

1) Conceptually this call-in mechanism is already quite some different from traditional unit callbacks, as the actual Lua functions that are called are stored per unit instead of globally.

2) Because of 1) and how the framework is implemented, you can just have the unitDef available by doing somewhere at the top of the script:

Code: Select all

local unitDef = UnitDefs[Spring.GetUnitDefID(unitID)]
and have the unitDef available as non-local value (upvalue) in all functions.

I'm actually considering dropping unitID too, after all, because the same thing applies to this. (And having the unitID as function argument seems to only be an advantage when you have scripts that have no need for a separate closure per unit. In other words, when the same function object is reused by different units. I haven't found a script yet to which this really applies.)

SpliFF wrote: BUILDERS

Please be explicit when a callback has different arguments and behaviour based on type:

StartBuilding -> MobileStartBuilding / FactoryStartBuilding
QueryBuildInfo -> FactoryBuildInfo

This change makes it clearer the functions have different behavior. It may even be possible that one day a unit can have both properties (like the Fatboy in Supreme Commander but with a nanolathe insted of guns)
First thing may be an idea, although what about StopBuilding? For consistency also two variants, or inconsistent but save on the number of call-ins?

I think QueryBuildInfo has the right name now, at best I'd consider QueryFactoryBuildInfo, because the 'Query' prefix is quite consistently used already for functions that should just return some piece number. I don't want to break this convention.

SpliFF wrote:WEAPONS

I'd also prefer to see the numbered weapon callbacks change format:

AimWeapon1( ... ) -> AimWeapon( weaponID, weaponDefID, ... )

This will allow behaviours to be shared between common weapons (consider a large tank with 10 turretted machineguns). This way you'd only need a single function and you can call specific behaviours with a comparison, switch or array lookup.
Hmm, good point.

What do others think about this?

SpliFF wrote:TRANSPORTS
I'm not convinced about air and ground transports sharing a callback name when different behaviour is implied. It would be better as:

TransportDrop -> AirTransportDrop / GroundTransportDrop

If nothing else this should make documentation clearer.
I'd be the first to admit that the transport code in the engine is an epic mess, when I was documenting these call-ins my WTF/min rate raised to extraordinary heights. ;-)

At some point I'll see how I can clean this up and make all loading behaviors consistent, but for that I'll first have to research the use patterns that are in use in BOS currently wrt these call-ins. (ie. whether lots of script depend on some WTF'ed behavior.)

Personally I'd rather work towards consistent behavior wrt call-ins for air and ground transports then to differentiate between the different behaviors by introducing more call-ins.
Passenger Falling() should have a StartFalling() callback as well since I suspect it will be common to test for this event and doing so in Falling() would require setting up vars and if statements.
I'm actually considering to make Falling being called only once. I haven't found a single script yet that depends on Falling being called every frame, and even if there is one it is trivially easy to emulate the current behavior by starting a thread executing something like this:

Code: Select all

while (!landed) do ... Sleep(unitID,30) end
SpliFF wrote:I accept many of these issues above are a legacy of COB and changing them would make conversion from COB slightly harder but these changes are clearer and more consistent with other callbacks. Best to fix COB's mistakes now before any serious Lua development takes place.
Yeah I totally agree. First milestone was just plain porting the COB engine and now my focus in this area will be removing the COB WTFs as soon as possible.

(Fixed axis directions, rotation directions already for example.)

Thanks SpliFF for your comments; this in particular are the type of comments I was hoping for :-)
User avatar
SpliFF
Posts: 1224
Joined: 28 Jul 2008, 06:51

Re: Lua unit scripting

Post by SpliFF »

Tobi wrote: 2) Because of 1) and how the framework is implemented, you can just have the unitDef available by doing somewhere at the top of the script:

Code: Select all

local unitDef = UnitDefs[Spring.GetUnitDefID(unitID)]
and have the unitDef available as non-local value (upvalue) in all functions.

I'm actually considering dropping unitID too, after all, because the same thing applies to this.
In that case it would be nice to see unit (pointer to unit table) unitDef (pointer to unitDef table) and unitDefID (uint) pushed into the state along with unitID or else many scripts will just end up with repetitive boilerplate code at the top setting these.

Great work on this btw. It looks like now there isn't much (anything?) left that you can't do in lua.

I'm also wondering wether it makes sense to keep refering to these scripts as 'Animations'. In truth they seem able to do a great deal more than that. Perhaps 'Unit Scripts' would be a better term. I had trouble find the info on the wiki because I was searching for 'unit' not 'animation'.

Final note: Keep documenting this stuff as best you can (i've seen the wiki page) as I'll be writing it all up in my Lua guide. I've recently completed a project that had me tied down all year which will give me back time to persue my own projects, namely the lua guide, mod guide, model importer (assimp) and Metalstorm mod. I'd prefer not to get tied down further digging info out of git changelogs (or the ether).
Tobi
Spring Developer
Posts: 4598
Joined: 01 Jun 2005, 11:36

Re: Lua unit scripting

Post by Tobi »

Replaced SetSpeed and SetDirection with a new WindChanged and ExtractionRateChanged. Removed Go.

Also I created a list of the differences between Lua and BOS here:
http://springrts.com/wiki/Animation-CobLuaDifferences
User avatar
jK
Spring Developer
Posts: 2299
Joined: 28 Jun 2007, 07:30

Re: Lua unit scripting

Post by jK »

Tobi wrote:
SpliFF wrote:setSFXoccupy -> TerrainChange

If this stays TerrainChange is a clearer name.
I agree with this yeah, personally I prefer just getting rid of setSFXOccupy and Go as both are trivial to emulate without the extra call-in.
I used it in COB, but with Lua you can either emulate it, or just use UnitEnteredAir/EnteredWater.
User avatar
FLOZi
MC: Legacy & Spring 1944 Developer
Posts: 6241
Joined: 29 Apr 2005, 01:14

Re: Lua unit scripting

Post by FLOZi »

What about transports? AFAIK you can query if a unit is being transported in lua, but there isn't a call-in to tell you when it is picked up - on the passenger side.

Something like

Loaded ( unitID, transporterID ) -> nil

to go along with Falling and Landed call-ins?
Or UnitEnteredTransport?
Tobi
Spring Developer
Posts: 4598
Joined: 01 Jun 2005, 11:36

Re: Lua unit scripting

Post by Tobi »

There exist UnitLoaded and UnitUnloaded in the Lua gadget interface.

I'm not entirely sure yet how to deal with the clash between the two interfaces. Should we strive to have every function only in one place, or to have two complete interfaces, that might overlap on a number of calls?

For example, UnitEnteredAir, UnitLeftAir, UnitEnteredWater, UnitLeftWater, UnitLoaded, UnitUnloaded, UnitFinished, UnitCloaked, UnitDecloaked and StockpileChanged would all be good candidates for call-ins for a unit script.

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.)
Post Reply

Return to “Engine”