• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.
  • 💡 We're thrilled to announce that our upcoming texturing contest is in the works, and we're eager to hear your suggestions! Please take this opportunity to share your ideas in this theme discussion thread for the Texturing Contest #34!
  • 🏆 Hive's 7th HD Modeling Contest: Icecrown Creature is now open! The frozen wastes of Icecrown are home to some of Azeroth’s most terrifying and resilient creatures. For this contest, your challenge is to design and model a HD 3D monster that embodies the cold, undead, and sinister essence of Icecrown! 📅 Submissions close on April 13, 2025. Don't miss this opportunity to let your creativity shine! Enter now and show us your frozen masterpiece! 🔗 Click here to enter!

Desync Debugging

Status
Not open for further replies.
Level 4
Joined
Mar 8, 2006
Messages
27
Is there any effective way to debug desyncs? Like having a breakpoint before the desync or saved logs or something?

I have a fairly non-deterministic and unusual desync, where myself and a friend of mine (and my other account on a VM) never desync (or at least very rarely), but everyone else in the game tends to nearly immediately after the map loads (tested about 3 times).

I've tried removing various parts of the code and trying to narrow down the cause, and tried bisecting it to a specific version via source control but neither have proven to be very successful due to the random nature of the desync. I suspect versions which we deem to be "good" and don't desync were actually bad, just didn't hit whatever weird edge case causes the desync, which leads me even further off track.

Does anyone have any advice around this? I've written everything in lua if it helps. How do people usually go about solving these kind of random, inconsistent desyncs?

Is it possible that people with slower PCs are not able to keep up with the tight loops running on the host (I have a couple of 0.0078125s loops) and therefore fall behind in execution and desync? If this is the case, how would anyone guarantee people not to fall behind? I'd imagine WC3 would somehow ensure each players loops are synced? Maybe slowing down the fastest loop to match the slowest player?

How do triggers actually get synced between players? Is order guaranteed (I expect it has to be, or else we'd see many more desyncs across the board)? Are timers synced & guaranteed to be the same?

For example, if I have a trigger that when a player presses "Q", I create a unit and start a timer for 5 sec, but if the timer has any duration left I don't create the unit, is there a race condition where one player can enter the loop and think the timer is not finished, but another player can enter and think the timer is finished?
 
It is always difficult to debug such issues. Here are all the causes I know for desync.

I am in the same situation as you, trying to debug my desync issues. I think I'll add hooks (=user callbacks on-before a native function is executed):

JASS:
hook <native name> <my log function name>
Where my log function must have the same arguments and return type than the native.

And each time I'll add logs only for player whose name is "Ricola3D". I started it as below. To be continued...

JASS:
library DesyncCheck
    globals
        public integer getLocalPlayerExecCount = 0
        public integer getLocationZExecCount = 0
        public integer smartCameraPanBJExecCount = 0
        public integer getPlayerSlotStateExecCount = 0
        public integer getPlayerControllerExecCount = 0
    endglobals

    private function DebugUserFilter takes nothing returns boolean
        // Filter only players whose user name is a developer
        return ( GetPlayerName(GetEnumPlayer()) == "Ricola3D" )
    endfunction

    private function DebugLog takes string message returns nothing
        local force debugForce = GetPlayersMatching(Condition(function DebugUserFilter))
        call DisplayTimedTextToForce( debugForce, 10.00, message )
        call DestroyForce(debugForce)
        set debugForce = null
    endfunction

    public function onGetLocalPlayer takes nothing returns nothing
        set getLocalPlayerExecCount = getLocalPlayerExecCount + 1
        call DebugLog("getLocalPlayer call number "+I2S(getLocalPlayerExecCount))
    endfunction

    public function onGetLocationZ takes location whichLocation returns nothing
        set getLocationZExecCount = getLocationZExecCount + 1
        call DebugLog("getLocationZ call number "+I2S(getLocationZExecCount))
    endfunction

    public function onSmartCameraPanBJ takes player whichPlayer, location loc, real duration returns nothing
        set smartCameraPanBJExecCount = smartCameraPanBJExecCount + 1
        call DebugLog("SmartCameraPanBJ call number "+I2S(smartCameraPanBJExecCount))
    endfunction

    public function onGetPlayerSlotState takes player whichPlayer returns playerslotstate
        set getPlayerSlotStateExecCount = getPlayerSlotStateExecCount + 1
        call DebugLog("GetPlayerSlotState call number "+I2S(getPlayerSlotStateExecCount))
        return PLAYER_SLOT_STATE_EMPTY
    endfunction

    public function onGetPlayerController takes player whichPlayer returns mapcontrol
        set getPlayerControllerExecCount = getPlayerControllerExecCount + 1
        call DebugLog("GetPlayerController call number "+I2S(getPlayerControllerExecCount))
        return MAP_CONTROL_NONE
    endfunction

    hook GetLocalPlayer onGetLocalPlayer
    hook GetLocationZ onGetLocationZ
    hook SmartCameraPanBJ onSmartCameraPanBJ
    hook GetPlayerSlotState onGetPlayerSlotState
    hook GetPlayerController onGetPlayerController
endlibrary
 
Level 4
Joined
Mar 8, 2006
Messages
27
Thanks for the list - I was aware of most of those things and don't see anything obvious that I've hit (except maybe unit selection, which I'll test).

Just displaying some text won't really work though, once you desync you immediately disconnect and so you won't be able to see it in time. Unless those logs are saved somewhere on disk each game?
 
Just displaying some text won't really work though, once you desync you immediately disconnect and so you won't be able to see it in time. Unless those logs are saved somewhere on disk each game?

I think there is a IO File system made by Nestharus years ago, that can save & read local files, but I never tried it.
Printed text will be visible from the players that are not kicked by the desync, I'm counting of that to the last functions executed before someone desyncs^^
 
Status
Not open for further replies.
Top