- Joined
- Feb 27, 2019
- Messages
- 401
Introduction
Players should be able to differentiate a crash, a player leaving and a player being desynchronized.
Desync is the fact that one or more player gets disconnected from a online multiplayer game. It's caused by differences in the game state between the game clients.
Below I tried gathering the all the desync causes identifed in previous post, plus my own testing results.
Players should be able to differentiate a crash, a player leaving and a player being desynchronized.
Desync is the fact that one or more player gets disconnected from a online multiplayer game. It's caused by differences in the game state between the game clients.
Below I tried gathering the all the desync causes identifed in previous post, plus my own testing results.
1. Causes that will desync at 100%
a. GetLocalPlayer() used for anything else than UI-display or sound-play, or used by Blizzard internal functions (search GetLocalPlayer here to get them). Here is a FAQ on how to use it properly.
b. GUI Function "Select unit group <group> for player <player>", alias JASS function SelectGroupForPlayerBJ. You should replace it by a for loop that adds unit 1 by 1 to selection (source: here).
c. [Fixed in 1.31] GUI Function "Pan Camera As Necessary", alias JASS function SmartCameraPanBJ (fix here).
d. [Since 1.32] Old widgetizer tools to protect the map (if players don't clean their cache by restarting Warcraft III between 2 different games)
e. GetCameraTargetPosition natives (X, Y, Z) returns an asynchronous value (each player has its own camera), so like for GetLocalPlayer() it must only be used for UI-display or sound-play.
f. Calling subfunctions in the arguments of BlzFrameSetText() in a "GetLocalPlayer() ==" condition. String concatenation is fine (source here).
g. JASS function GameCacheSync if called more than 344 times in a single frame (source here).
h. JASS function SetSkyModel called with an invalid model path as parameter (source here).
i. Iterating over Lua tables with pairs (not ipairs), because they are not sorted so there is a risk of iterating out of order (source and fix here).
j. Editing some Game Constants related to creeps with high values (sources: here and here) will desync on game start:
--- "Creed Guard Distance"
--- "Creeps - Guard Return Distance"
--- "Creeps - Maximum Creep Camp Radius"
2. Causes of desync with low propability (so desync may happen at random times)
a. Numerous "Player slot comparison"s, for example to check if a player is connected (source: my map. I recommand storing a player group for connected players updated with a trigger on event "player leaves the game").
b. Numerous "Player controller comparison"s (source: my map).
c. Weapon upgrades with effect "Attack Dice Bonus" desync when "Base + (Upgrade level -1) * Increment" is superior to 14 (source here, here, and my own tests). I've no idea why 14 is the limit, I tested many values below and above.
d. GetLocationZ calls if
--- A terrain deformations is ongoing below the unit (because deformations are not synchronized between the clients, and not displayed for players with low quality graphics settings)
--- Unit is on an animated walkable destructable.
e. Models and and textures when badly made (source here).
f. A very very huge amount of memory leaks.
g. Creating a periodic trigger with a null period (even with Blizzard has set a safety min of 0.0001). It will likely hit the op limit at different numbers of executions/different times for each computer the game was being run on.
h. Creating Timers with a very short delay (<= 0.01s) on map initialization has approx 25% chances of desync (source here).
i. Destroying user-created frames (source here).
3. Uncertain functions
LeP made a research in common.j for all annotations with "async" and found the functions below. So if you suspect one of your triggers of causing desync, you can check for the presence of any of those primitives.
GetDestructableName
GetSoundDuration
GetSoundFileDuration
GetCameraBoundMinX
GetCameraBoundMinY
GetCameraBoundMaxX
GetCameraBoundMaxY
GetCameraField
GetCameraTargetPositionX
GetCameraTargetPositionY
GetCameraTargetPositionZ
GetCameraTargetPositionLoc
GetCameraEyePositionX
GetCameraEyePositionY
GetCameraEyePositionZ
GetCameraEyePositionLoc
GetObjectName
GetLocalizedString
GetLocalizedHotkey
GetLocalPlayer
GetLocationZ
GetItemName
GetUnitName
GetPlayerSlotState
IsMultiboardMinimized
BlzGetLocalUnitZ
BlzGetUnitZ
BlzGetItemDescription
BlzGetItemTooltip
BlzGetItemExtendedTooltip
BlzGetLocalSpecialEffectX
BlzGetLocalSpecialEffectY
BlzGetLocalSpecialEffectZ
4. Unverified rumors, unlikely
a. Checking player slot in a trigger on Map Initialization Event. Fix would be to call it after 0.00s elasped.
b. GetEffectZ: I don't know this primitive, but read about it somewhere, and it would be based on host's value and synced.
c. SetSoundVolumeBJ & playing the same map many times in a row (source here).
d. GetLocationZ: randomly causes desync for player using a different setup (linux, mac, reforged vs classic). Also walkable destructables and stiff terrains will cause desync if some players are Classic and others are Reforged (source here).
e. Selection primitives (source here), but not sure. Indeed internally some selections use GetLocalPlayer, but normally it is synchronized by packets and primitives return the selection result properly for all clients only then.
f. Low "Backgrounf FPS Cap" in options + players tabbing out of the game (source here).
g. Creating frames while the game is tabbed-out by the player (because screen size getters may return 0).
5. Fake rumors, does not cause desync
a. Wait and PolledWait do not cause desync, they just may cause more network traffic to keep all clients synchronized, and may cause lags due to lack of time accuracy.
Last edited: