Confusing Game Hacks bug with Strategic Tools mode (SOLVED!)

2 replies [Last post]
Wuzzy
Wuzzy's picture
User offline. Last seen 24 weeks 6 days ago. Offline
Joined: 2012-06-20
Posts: 1304

This one goes to the Lua / Hedgewars development gurus out there, it's about a tricky bug. Wink Smiley

I have lately made some testing and made bugfixes to my Game Hacks script (I have stopped adding new features for the moment, now I try to make my script as stable as possible).

And then I stumpled upon a really weird bug.

The strategic tools mode (script parameter: “strategictools=true”) broke between version 8 and version 9. To be precise, the timer is not set correctly after placing a girder or rubber (The idea is to end the turn when placing these, this also involves to set the turn time to emulate the get-away time).

Luckily Smile, I use Git since version 8 and found the first buggy commit with git bisect.

It is commit 27a4f7f975995051524de407f1dfc6c5b8ec1eca.

On first glance, there doesn't seem to be anything suspicios about this commit.

From my bugfixing attemts so far, my best guess is that all this is caused by onSetWeapon. A seemingly (?) totally unrelated function.

Now things are getting weird:

When I remove the function “onSetWeapon” (see here) entirely, strategic tools mode works agaim.
Okay, you might think this is caused by what is done in this function.
But then I discovered this:
When I commented out everything (well, just 1 line) in onSetWeapon, and just kept the function empty, strategic tools mode was still broken. But when I remove the empty function completely, then it works. WTF? Shocking

It seems to me as if the mere *existance* of that function is the “trigger” of the bug. I've already checked if I haven't accidentally defined this function twice or something, but nope.

The problem is, I can't just remove that function from the script, because the manual timer setups depend on it. Sad Smiley

More context for you:
Currently, onSetWeapon only does one variable change. This variable is used in order to show a caption in the next tick(s). This caption is used for weapons with manual timer setting enabled (i.e. it is possible to allow for setting the hellish handgrenade timer in-game, use “hellishtimer=manual” as script parameter). I intentionally wait for the next tick(s) because otherwise the caption will not be displayed correctly.

I would be very glad if someone would be able to help me.

Some questions I'd like to ask:

  • Could it be that the order in which I define the Lua callback functions matters? (note: I don't call onSetWeapon by myself)
  • Is there anything “special” about onSetWeapon which might cause this weird quirk?
  • Does defining onSetWeapon cause Hedgewars to use a different number of ticks than without it? I'm asking because correct timing is critical for strategic tools mode.

Here is the link to the most recent development stage of the script:
http://repo.or.cz/Hedgewars_Game_Hacks.git/blob_plain/918db1a08118dd7fbc0d74f589f613bf164c6604:/Game_Hacks_v10.lua

And here's the link to the first bad commit according to git bisect:
http://repo.or.cz/Hedgewars_Game_Hacks.git/blob/27a4f7f975995051524de407f1dfc6c5b8ec1eca:/Game_Hacks_v8.lua
(diff)

To reproduce my bug, do this:

  • Install dev version of script
  • Set script parameter to “strategictools=true”
  • Start a game with lots of girders
  • Place a girder anywhere

The turn should end and the timer should be set to a retreat time of 3 seconds (for 100% retreat time). But actually, the hog just goes into “gstAttacked” state (meaning that you can't use weapons or tools for this turn anymore) and shows the “Retreat!” message, but the turn timer does not change.

To reproduce my bug fixing attempt, just take the latest dev version, and experiment around with onSetWeapon (remove the function or make it empty).

If your test results differ from mine, please reply as well, even if you have no clue what is going on.

Hi, I am a Hedgewars developer. Smile

sheepluva
sheepluva's picture
User offline. Last seen 21 weeks 4 days ago. Offline
Joined: 2009-07-18
Posts: 563

I investigated this for you, the problem (and the fix) is actually quote trivial.

Cause

  • ScriptCall (so any lua hook, including SetWeapon()) will write all globals to lua - overwriting their exiting values.
  • TurnTimeLeft gets only read from Lua at the end of each hook call into Lua. So triggering a hook in a hook function itself will reset all changes made to globals in that hook function till that point.
  • After you set TurnTimeLeft = retreatTime you also call SetWeapon(amSkip) in the "girderhack" branch, resulting in the engine overwriting all globals, including TurnTimeLeft.

Solution
Move "TurnTimeLeft = retreat" to below the "end" of the "if girderHack" branch.

Notes
Yes, this is a shortcoming in the LUA-API.
In fact, TurnTimeLeft is the ONLY global that is being read and it shouldn't.
Instead all globals should be read-only and there should be a SetTurnTimeLeft() call that will change the value directly in engine and avoid issues like this entirely.

I'll put it on my TODO:
Changing globals (so TurnTimeLeft) in Lua will get deprecated (but supported further with its existing limitations) and instead a function will be introduced that reliably sets the value in engine.

EDIT: more correct description of when globals are read from Lua. + Typos

  sheepluva <- me  my code stats -> 
a Hedgewars Developer


   <- where I'm from  what I speak -> 

Wuzzy
Wuzzy's picture
User offline. Last seen 24 weeks 6 days ago. Offline
Joined: 2012-06-20
Posts: 1304

Thanks for your help.
Smile

An Game Hacks update will be released when I have done more testing.

Hi, I am a Hedgewars developer. Smile

User login

Copyright © 2004-2024 Hedgewars Project. All rights reserved. [ contact ]