| 01-22-2010, 05:42 AM | #1 |
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.* 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 |
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 |
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 |
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. |
