• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Consistent desync at 20 seconds game time.

Level 7
Joined
Aug 5, 2010
Messages
147
My map is consistently desyncing multiple players at 20 seconds of game time.

Ive gone through most of the known causes of desyncs and tried my best to change my triggers, i changed multiple triggers that were activating at the 20 second mark, mostly periodic events.

Some of these changes have resulted in no desync happening when i play the map again, only for the desync to happen once again after ive made further changes to the map.

Ive had no desyncs happen 2, maybe 3 times. so im either fixing one source of desyncs only for something else to desync or i got lucky sometimes and its not a 100% chance.

Both the map and the war3map.lua file is attached,
 

Attachments

  • Demon Circle TD - Hellforged TEST.w3x
    1.7 MB · Views: 9
  • war3map.lua
    168.8 KB · Views: 4
Last edited:
I also have inconsistent desyncs in my map always happening at the same time in the map progress. Any attempts to reliably reproduce them have failed.

One thing to keep in mind is that the time of the game desyncing doesn't necessarily have to be the exact time the event happened that caused the desync. I just did a test map where I do:

JASS:
	if GetLocalPlayer() == Player(0) then
		call Location(0,0)
	endif

And the game only desynced ~3 seconds later. The desync might be happening at 20 seconds consistently because that's where a lot of stuff is happening and one client receives instructions that don't make any sense, so this triggers them being kicked out of the game.

Since you don't have any GetLocalPlayer calls in your script, the culprit could be one of the GUI functions that are known to desync. The list of those should be somewhere here on hive.
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,543
I would change this to 0.50 seconds to allow enough time for everyone to properly load in:
  • Map Start
    • Events
      • Time - Elapsed game time is 0.00 seconds
Also, your For Loop logic is not a good idea and will bug out when players leave the game. You should instead use a Player Group and (Picked player) whenever you're doing something like this:
  • For each (Integer A) from 1 to Integer_PlayerCount, do (Actions)
    • Loop - Actions
      • Dialog - Hide Dialog_Difficulty for (Player((Integer A)))
1) You're assuming that Players 1 to X are playing the game. What if you're in a 2 player game and the second Player chose to play as player slot 5? You'd skip them when you loop from 1 to 2.

2) You subtract PlayerCount when someone leaves the game. What if you're in a 3 player game and Player 2 leaves the game? You're now looping from 1 to 2, thus skipping Player 3 who is still actively playing.

I've gone through most of your triggers and addressed the above issues and fixed anything else I could find. I added a few Player Group variables and replaced all of your For Loops with them. I also tried to make everything more efficient and bug free with the use of variables. I glossed over the triggers in the Custom Abilities folder and I imagine your culprit may be there, those triggers are doing some gnarly things.

I didn't test it, so apologies if I broke something. Unfortunately, I didn't see anything that jumped out as a "desync", but maybe I inadvertently fixed it?

Edit: Reuploaded map, forgot something. Make sure you have the newer version.
 

Attachments

  • Demon Circle TD - Hellforged TEST Unc3.w3x
    1.7 MB · Views: 4
Last edited:
Level 7
Joined
Aug 5, 2010
Messages
147
So after discovering that i can use LAN games to test for desyncs by launching war3 from battle net and worldedits test map function, ive done a bunch of testing and come to the conclusion that this timer is causing the desync.

As with my testing online where it didnt desync sometimes the same happened whilst i was testing on LAN.
  • Countdown Timer - Start Timer as a Repeating timer that will expire in 20.00 seconds
I created a new var for the timer, tested it and got a desync, changed to repeating, desync, tried 20 and 25 seconds, both desynced. Then when i disable the timer action no desync occurs.

The test map is attached. all other triggers are disabled along with all actions within the Map Start trigger where the timer action is located, all imports have been removed, custom game interface and constants have been disabled and some scenario settings have been set to default.

Could someone else test it in a LAN game? If it still desyncs then that would at least eliminate my war3 installation as the cause.

As for the desync itself, i just deleted all the timer actions and replaced them all with the trigger below. It starts turned off and is turned on as the final action in the map Start trigger, Integer_Time is reset back to 0 when each wave has been fully spawned.
  • Timer
    • Events
      • Time - Every 1.00 seconds of game time
    • Conditions
    • Actions
      • Set VariableSet Integer_Timer = (Integer_Timer + 1)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Integer_Timer Greater than or equal to (Integer(Real_WaveTimer))
        • Then - Actions
          • Trigger - Run Next Wave <gen> (ignoring conditions)
        • Else - Actions
As for the changes @Uncle made, much appreciated.

As for the notes you left, i havent encountered any crashes caused by my custom abilities nor desyncs or lag, all damage caused within them use dummy units to deal damage to avoid triggering them infinitely, the only infinite damage loop i encounted was because i forgot the casting time on shadow strike is its damage interval. The custom values of units is only used for 1 tower so i have no real need for a unit indexer and have no plans to make further use of them. I checked the Anomaly Tower trigger and yeh, am dumb i didnt need to have 2 sets of the same actions so i deleted 1 set and moved it out of the if/then/else statement. As for the rest of the abilities some of them are in their current form because im lazy and havent changed them like i have the others, but they still function correctly.

Ill eventually make a post in the Map Dev section for the map so people can tell me how shit my triggers are and how i can improve things.
 

Attachments

  • Demon Circle TD - Hellforged TEST.w3x
    148.6 KB · Views: 4
Last edited:

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,543
A timer would cause a crash if it's set to Repeat at 0 seconds. Maybe that was the issue? Also, perhaps a bad string in the Timer Window that's paired with it? Then of course there's the trigger(s) that run when the timer expires which could contain the crash (or desync).

Here's my attempt at fixing it, I added a 0.01 second Wait in NextRound as well as some other little tweaks to it and the WaveReal/TW_NextRound variables.
 

Attachments

  • Demon Circle TD - Hellforged TEST Unc4.w3x
    1.7 MB · Views: 5
Last edited:
Level 7
Joined
Aug 5, 2010
Messages
147
None of those things apply to the map in my previous post, the timer is set to 20 not 0 and it desyncs as both a One-shot timer and repeating timer, their is no timer window paired with the timer, the triggers that are activated by the timer expiring are disabled and it always desynced before the timer ended and never desynced when the timer ended.

Regardless, as stated in my previous post i fixed the desync by removing all timer actions and replacing it with what i already posted.

Edit: I tested the map you posted as is 3 times, got no desyncs. I then changed the timer back to a 30 seconds instead of being Real_WaveTimer, tested 3 times and got no desyncs. I then disabled the 0.01 second wait you put in the Next Round triggers then tested 4 times and got 2 desyncs. The sample size is obviously tiny in comparison to what it would need to be to conclude that timers desync, but as far as im aware in the case of my map the timer is causing the desync.
 
Last edited:

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,543
None of those things apply to the map in my previous post, the timer is set to 20 not 0 and it desyncs as both a One-shot timer and repeating timer, their is no timer window paired with the timer, the triggers that are activated by the timer expiring are disabled and it always desynced before the timer ended and never desynced when the timer ended.

Regardless, as stated in my previous post i fixed the desync by removing all timer actions and replacing it with what i already posted.
Okay, I found the main source of the problem. It's because you're using Lua as your scripting language. By switching back to Jass the crash goes away, regardless of whether you're using Timers or any other alternative solution.

What that means I'm not too sure... I deleted all of the Custom Script while in Lua mode thinking that may be related and the crash still occurred.
 
Okay, I found the main source of the problem. It's because you're using Lua as your scripting language. By switching back to Jass the crash goes away, regardless of whether you're using Timers or any other alternative solution.

What that means I'm not too sure... I deleted all of the Custom Script while in Lua mode thinking that may be related and the crash still occurred.
Is something like this common? :pshock: Are there problems with the Lua-GUI implementation?
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,543
Is something like this common? :pshock: Are there problems with the Lua-GUI implementation?
Seems like it, I know my own Lua/GUI hybrid map always had desyncs, although they weren't 100% consistent like this one (which made them worse since I couldn't properly recreate them). I wonder if there's problematic "ghost" code that is lingering in the map script file or something....

The good news for you Geno, your map doesn't need Lua mode and you only have like 15 lines of Custom Script that need editing to make the switch back to Jass.
 
Last edited:
Level 7
Joined
Aug 5, 2010
Messages
147
The good news for you Geno, your map doesn't need Lua mode and you only have like 15 lines of Custom Script that need editing to make the switch back to Jass.
I will take that into consideration if i come across any other desyncs.

I haven't read any of the code yet but if you get are getting player states or slot states during initialization that will desync.
Only vars are setup in map ini trigger, player states and slot states are in the Map Start trigger which activates at 0.50 seconds game time.
 
Could the culprit be the % character?

From Eikonium's Lua tutorial:

"Don't use % in strings, it can crash your World Editor (WE bug).
Instead, use \x25, no matter the purpose (printing, string formatting, pattern matching).
Also don't use % within comments(!), for the same reason.
Instead, just type percent or use any other wording of your choice."

The bug doesn't apply only to WE if I understand him correctly.
 
GUI Countdown Timer - Start Timer will desync in Lua mode. The underlying function, StartTimerBJ, uses the timer variable bj_lastStartedTimer, which is set to a timer that is created in the Lua root beforehand.
Why does setting the variable to a new timer cause a desync and not the creation of the timer in the Lua root?
 
Level 20
Joined
Jul 10, 2009
Messages
478
GUI Countdown Timer - Start Timer will desync in Lua mode. The underlying function, StartTimerBJ, uses the timer variable bj_lastStartedTimer, which is set to a timer that is created in the Lua root beforehand.
If setting bj_lastStartedTimer to a new value causes the issue, CreateTimerBJ should be affected as well.
@Bribe might want to replace all occurances of bj_lastStartedTimer within StartTimerBJ, CreateTimerBJ and GetLastCreatedTimerBJ by a new global var for [Lua] - Lua-Infused GUI + Automatic Memory Leak prevention.
 
Last edited:

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,468
GUI Countdown Timer - Start Timer will desync in Lua mode. The underlying function, StartTimerBJ, uses the timer variable bj_lastStartedTimer, which is set to a timer that is created in the Lua root beforehand.
That doesn't make any sense, unless there are StartTimerBJ calls done uniquely per-player.
 
Level 20
Joined
Jul 10, 2009
Messages
478
That doesn't make any sense, unless there are StartTimerBJ calls done uniquely per-player.
@Bribe I think @Elprede was referring to line 478 of blizzard.j, which is part of the globals-block:
JASS:
timer              bj_lastStartedTimer         = CreateTimer()
If the Lua-version of blizzard.j also immediately initializes the variable like this, it would create a timer in the Lua root. Everything interacting with the object afterwards could then lead to a desync, including garbage collection after setting bj_lastStartedTimer to a new value, which happens in both StartTimerBJ and CreateTimerBJ.
If this is all true (I haven't checked), you could help Lua-GUI-Users by providing a safe version of these natives (plus GetLastCreatedTimerBJ) within your Lua-Infused GUI.
 
Level 20
Joined
Jul 10, 2009
Messages
478
From my perspective, not touching it at all would be the safest way. Gui-Users don't have direct access to bj_lastStartedTimer (unless queried via custom script), so overwriting the mentioned blizzard.j functions towards using a different variable would solve it.

Lua:
do
    --create new timer variable to replace bj_lastStartedTimer
    local lastStartedTimer

    --overwrite blizzard.j functions to use new variable
    function StartTimerBJ(t, periodic, timeout)
        lastStartedTimer = t
        TimerStart(t, timeout, periodic, nil)
        return lastStartedTimer
    end

    function CreateTimerBJ(periodic, timeout)
        lastStartedTimer = CreateTimer()
        TimerStart(lastStartedTimer, timeout, periodic, nil)
        return lastStartedTimer
    end

    function GetLastCreatedTimerBJ()
        return lastStartedTimer
    end
end
 
Last edited:

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,199
In my experience, the Lua root has strange behaviour with respect to object creation, such as object wrappers being subject to garbage collection despite wrapping persistent objects like trigger and event. These issues do not occur if the objects are created by the map initialization thread in a function.
 
Top