HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Asychronous Lag - Comments

01-22-2010, 05:42 AM#1
Strilanc
Hostbots can set the maximum time a player can lag well past what wc3 defaults to. This causes the lag screen to show up much less often, which is great, but it reduces the understanding that a player is lagging.

So I wrote this library. It will show timer dialogs containing the total time a player has been lagging, once a player has lagged for more than 2 seconds. Perhaps more importantly, it also supports a command '-wait', which sends a signal bots can catch in order to trigger the lag screen earlier than they would normally do.

The map only has to include the following script in order to support async lag:

*Warning: This has not been extensively tested. Could conceivably contain a desync.*
Collapse JASS:
library HostBotAsyncLag initializer init
    globals
        private constant string WAIT_COMMAND = "-wait"
        private constant integer PERIOD = 500 //ms
        private constant integer MAX_DELAY = 2000 //ms

        private gamecache gc
        private timer array timers
        private timerdialog array dialogs
        private integer time = 0
        private string array colorCodes
        
        private constant string GAME_CACHE_FILENAME = "HostBot.AsyncLag"
        private constant string GAME_CACHE_TICK_KEY = "tick"
        private constant string GAME_CACHE_WAIT_KEY = "wait"
    endglobals
    
    private function OnCommand takes nothing returns nothing
        //signal the bot
        call StoreInteger(gc, GAME_CACHE_WAIT_KEY, GAME_CACHE_WAIT_KEY, 0)
        call SyncStoredInteger(gc, GAME_CACHE_WAIT_KEY, GAME_CACHE_WAIT_KEY)
    endfunction
    
    private function OnTick takes nothing returns nothing
        local integer dt
        local integer i
        
        //check for players' sync times falling behind
        set i = 0
        loop
            exitwhen i >= 12
            call TimerDialogDisplay(dialogs[i], false)
            if GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING and GetPlayerController(Player(i)) == MAP_CONTROL_USER then
                set dt = time - GetStoredInteger(gc, GAME_CACHE_TICK_KEY, I2S(i))
                if dt > MAX_DELAY then
                    //player is lagging
                    call TimerDialogSetTitle(dialogs[i], "("+WAIT_COMMAND+") |cFF"+colorCodes[i]+GetPlayerName(Player(i))+"|r lag")
                    call TimerStart(timers[i], dt/1000.0, false, null)
                    call PauseTimer(timers[i])
                    call TimerDialogDisplay(dialogs[i], true)
                endif
            endif
            set i = i + 1
        endloop
        
        //increase the local player's sync time
        set time = time + PERIOD
        set i = GetPlayerId(GetLocalPlayer())
        call StoreInteger(gc, GAME_CACHE_TICK_KEY, I2S(i), time)
        call SyncStoredInteger(gc, GAME_CACHE_TICK_KEY, I2S(i))
    endfunction
    
    private function init takes nothing returns nothing
        local trigger t
        local integer i
        
        //tick
        set t = CreateTrigger()
        call TriggerAddAction(t, function OnTick)
        call TriggerRegisterTimerEvent(t, PERIOD/1000.0, true)
        
        //command
        set t = CreateTrigger()
        call TriggerAddAction(t, function OnCommand)
        set i = 0
        loop
            exitwhen i >= 12
            call TriggerRegisterPlayerChatEvent(t, Player(i), WAIT_COMMAND, true)
            set i = i + 1
        endloop
        
        //construct timers and dialogs
        set i = 0
        loop
            exitwhen i >= 12
            set timers[i] = CreateTimer()
            set dialogs[i] = CreateTimerDialog(timers[i])
            set i = i + 1
        endloop

        //communication cache
        call FlushGameCache(InitGameCache(GAME_CACHE_FILENAME))
        set gc = InitGameCache(GAME_CACHE_FILENAME)
        
        //color codes
        set colorCodes[0] = "FF0303" //red
        set colorCodes[1] = "0042FF" //blue
        set colorCodes[2] = "1CE6B9" //teal
        set colorCodes[3] = "540081" //purple
        set colorCodes[4] = "FFFC01" //yellow
        set colorCodes[5] = "FEBA0E" //orange
        set colorCodes[6] = "20C000" //green
        set colorCodes[7] = "FF00FF" //pink
        set colorCodes[8] = "808080" //grey
        set colorCodes[9] = "0080FF" //light blue
        set colorCodes[10] = "008000" //dark green
        set colorCodes[11] = "800000" //brown

        set t = null
    endfunction
endlibrary

Essentially it works like this:
- Each player tracks the total elapsed game time, stores it in game cache using their id as a key, and syncs that value every 500 game milliseconds.
- The bot knows the map supports async lag when it sees one of those syncs, and ignores its normal lag limit.
- When a player notices another player's synced game time is more than 2s behind the current time, they know that player must be lagging and a timer dialog is shown.
- If a player enters the command '-wait' then a value called "wait" is synced, which the bot catches causing it to show the lag screen.

I've implemented this for Tinker, and Varlock will implement it for GHost. We tried it out using Tinker and it worked!
01-22-2010, 09:13 PM#2
Ammorth
When I'm hosting with a bot, I usually will up the latency for the map, even if one person is experiencing some sort of jumpy-ness. From personal experience, its better for everyone to realize there is a 250ms latency with commands, than having 90% of the people with 50ms latency and one guy with 400 ms latency who sees things happen rapidly every time he chatches up.

There are some maps though, where timing isn't nearly as needed, and I think this would make the game smoother for other players, if one player is lagging.
01-22-2010, 09:31 PM#3
Strilanc
I think you're talking about modifying the tick period, which is not what this system addresses. I'm talking about the maximum amount of time a player can be non-responsive before the lag screen pops up. Bots set it very high, which is great except that you don't realize your ally isn't answering you or moving because he's lagging.
01-22-2010, 09:36 PM#4
Ammorth
I was more talking about the !latency commands, as in if your ping is lower than the game latency, you don't feel any jumping or "lag spikes".

Ahh, so this system will ignore the lagger, but give the other players an indication a player is lagging... interesting.