• 🏆 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!

Desync Problems :O

Status
Not open for further replies.
Level 17
Joined
Feb 11, 2011
Messages
1,860
Hello guys,

People have reported to me and said that when they play my map multiplayer, the others get disconnected straight after the loading screen (when you press any key to continue). What are the most common causes of desyncs?

I do use GetLocalPlayer() and I am aware that you must use it for local traffic only. As far as I know, I have only used this function for displaying text messages to Player 1 only. This wouldn't cause it, would it?

Also, I have functions like this: DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "Get ready for the next round!"). (not in an "if" block). This wouldn't desync, would it?

Thanks for any help.
 
Level 20
Joined
Jul 14, 2011
Messages
3,213
Terrain deformation can to desync. Probably these users are using different WC3 versions. Of Course, GetLocalPlayer() can desync.

Does the desync happens ALWAYS and TO EVERYONE?
 
Level 17
Joined
Feb 11, 2011
Messages
1,860
Not quite sure how much you define as a lot :D
Here is my initialization code:

JASS:
library MapSetup initializer onInit requires Systems, NextLevelSetup

    globals
        constant integer DUMMY = 'h003'
        boolean Level_in_Progress = false
        boolean Want_Escape = true
        boolean Spell_Fanatic_Mode = false
        boolean Settings_Chosen = false
        boolean Level_Begun = false
        boolean Ability_Testing = false
        destructable Top_Gate = null
        destructable Bottom_Gate = null
        dialog Dialog
        button array Button
        integer Level = 0
        integer Player_Count = 0
        integer array Hero_Type
        integer array Normal_Creep_Type
        integer array Special_Creep_Type
        integer array Boss_Ability
        integer array Creep_Ability
        unit Boss = null
        unit Arena_Manager = null
        unit Difficulty_Dummy = null
        unit Tavern = null
        unit array Circle
        unit array Player_Hero
        unit array Hero_Selector
        unitpool Hero_Pool = CreateUnitPool()
        unitpool Critter_Pool = CreateUnitPool()
        rect array Cyclone_Spawn
        sound array Level_Sound
        string Game_Mode = ""
        string Game_Difficulty = ""
        string array Boss_Speech
    endglobals

    private function Player_Conditions takes nothing returns boolean
        if GetPlayerSlotState(GetFilterPlayer()) == PLAYER_SLOT_STATE_PLAYING and GetPlayerController(GetFilterPlayer()) == MAP_CONTROL_USER then
            set Player_Count = Player_Count + 1
        endif
        return false
    endfunction

    private function onInit takes nothing returns nothing
        local force Players = CreateForce()
        local integer i = 1
        local real x = GetStartLocationX(GetPlayerStartLocation(Player(11)))
        local real y = GetStartLocationY(GetPlayerStartLocation(Player(11)))
        call ForceEnumPlayers(Players, Condition(function Player_Conditions))
        call DestroyForce(Players)
        set Players = null        
        set Top_Gate = CreateDestructable('LTg1', GetRectCenterX(gg_rct_TopGate), GetRectCenterY(gg_rct_TopGate), 0, 1, 1)
        set Bottom_Gate = CreateDestructable('LTg1', GetRectCenterX(gg_rct_BottomGate), GetRectCenterY(gg_rct_BottomGate), 0, 1, 1)
        loop
            if GetPlayerSlotState(Player(i - 1)) == PLAYER_SLOT_STATE_PLAYING and GetPlayerController(Player(i - 1)) == MAP_CONTROL_USER then
                set Hero_Selector[i] = CreateUnit(Player(i - 1), 'h00K', x, y, 0)
            endif
            exitwhen i == 4
            set i = i + 1
        endloop
        set Circle[1] = CreateUnit(Player(0), 'n009', GetRectCenterX(gg_rct_Circle1), GetRectCenterY(gg_rct_Circle1), 0)
        set Circle[2] = CreateUnit(Player(1), 'n009', GetRectCenterX(gg_rct_Circle2), GetRectCenterY(gg_rct_Circle2), 0)
        set Circle[3] = CreateUnit(Player(2), 'n009', GetRectCenterX(gg_rct_Circle3), GetRectCenterY(gg_rct_Circle3), 0)
        set Circle[4] = CreateUnit(Player(3), 'n009', GetRectCenterX(gg_rct_Circle4), GetRectCenterY(gg_rct_Circle4), 0)
        set Cyclone_Spawn[1] = gg_rct_Cyclone1
        set Cyclone_Spawn[2] = gg_rct_Cyclone2
        set Cyclone_Spawn[3] = gg_rct_Cyclone3
        set Cyclone_Spawn[4] = gg_rct_Cyclone4
        set Cyclone_Spawn[5] = gg_rct_Cyclone5
        set Normal_Creep_Type[1] = 'h009'
        set Normal_Creep_Type[2] = 'h00A'
        set Normal_Creep_Type[3] = 'h007'
        set Normal_Creep_Type[4] = 'h00D'
        set Normal_Creep_Type[5] = 'U007'
        set Normal_Creep_Type[6] = 'h00E'
        set Normal_Creep_Type[7] = 'h00F'
        set Normal_Creep_Type[8] = 'u004'
        set Normal_Creep_Type[9] = 'h00I'
        set Normal_Creep_Type[10] = 'U00A'
        set Normal_Creep_Type[11] = 'n007'
        set Normal_Creep_Type[12] = 'o000'
        set Normal_Creep_Type[13] = 'o001'
        set Normal_Creep_Type[14] = 'u005'
        set Normal_Creep_Type[15] = 'N00W'
        set Normal_Creep_Type[16] = 'n008'
        set Normal_Creep_Type[17] = 'n00A'
        set Normal_Creep_Type[18] = 'n00B'
        set Normal_Creep_Type[19] = 'n00C'
        set Normal_Creep_Type[20] = 'H00L'
        set Normal_Creep_Type[21] = 'n00D'
        set Normal_Creep_Type[22] = 'n00E'
        set Normal_Creep_Type[23] = 'n00F'
        set Normal_Creep_Type[24] = 'n00G'
        set Normal_Creep_Type[25] = 'U00B'
        set Special_Creep_Type[1] = 'h002'
        set Special_Creep_Type[2] = 'o002'
        set Special_Creep_Type[3] = 'h005'
        set Special_Creep_Type[4] = 'o005'
        set Special_Creep_Type[5] = 0
        set Special_Creep_Type[6] = 'h00B'
        set Special_Creep_Type[7] = 'n00H'
        set Special_Creep_Type[8] = 'u008'
        set Special_Creep_Type[9] = 'h00C'
        set Special_Creep_Type[10] = 0
        set Special_Creep_Type[11] = 'n00K'
        set Special_Creep_Type[12] = 'o006'
        set Special_Creep_Type[13] = 'n00L'
        set Special_Creep_Type[14] = 'u009'
        set Special_Creep_Type[15] = 0
        set Special_Creep_Type[16] = 'n00N'
        set Special_Creep_Type[17] = 'e001'
        set Special_Creep_Type[18] = 'n00M'
        set Special_Creep_Type[19] = 'n00O'
        set Special_Creep_Type[20] = 0
        set Special_Creep_Type[21] = 'n00P'
        set Special_Creep_Type[22] = 'n00Q'
        set Special_Creep_Type[23] = 'n00R'
        set Special_Creep_Type[24] = 'n00S'
        set Special_Creep_Type[25] = 0
        set Creep_Ability[1] = 'A00U'
        set Creep_Ability[2] = 'A013'
        set Creep_Ability[3] = 'A01C'
        set Creep_Ability[4] = 'A01K'
        set Creep_Ability[5] = 0
        set Creep_Ability[6] = 'A03J'
        set Creep_Ability[7] = 'A03K'
        set Creep_Ability[8] = 'A03O'
        set Creep_Ability[9] = 'A03P'
        set Creep_Ability[10] = 0
        set Creep_Ability[11] = 'A03Q'
        set Creep_Ability[12] = 'A03R'
        set Creep_Ability[13] = 'A03S'
        set Creep_Ability[14] = 'A03U'
        set Creep_Ability[15] = 0
        set Creep_Ability[16] = 'A03Z'
        set Creep_Ability[17] = 'A040'
        set Creep_Ability[18] = 'S002'
        set Creep_Ability[19] = 'A041'
        set Creep_Ability[20] = 0
        set Creep_Ability[21] = 'A042'
        set Creep_Ability[22] = 'A043'
        set Creep_Ability[23] = 'A044'
        set Creep_Ability[24] = 'A045'
        set Creep_Ability[25] = 0
        set Boss_Speech[1] = "|cffffcc00Lich:|r You should see the skeletons in |cffff0000my|r closet!"
        set Boss_Speech[2] = "|cffffcc00Death Knight:|r Don't touch me - I'm evil!"
        set Boss_Speech[3] = "|cffffcc00Warlock:|r You know what burns my ass? A flame about this high!"
        set Boss_Speech[4] = "|cffffcc00Cyclone Invoker:|r If you don't master your anger, your anger will master you...I should know."
        set Boss_Speech[5] = "|cffffcc00Archimonde:|r The Scourge will devour all!"
        set Boss_Ability[1] = 'A02L'
        set Boss_Ability[2] = 'A02M'
        set Boss_Ability[3] = 'A02R'
        set Boss_Ability[4] = 'S001'
        set Boss_Ability[5] = 'A03V'
        set Boss_Ability[6] = 'A03W'
        set Boss_Ability[7] = 'A03X'
        set Boss_Ability[8] = 'A03Y'
        set Boss_Ability[9] = 'A011'
        set Boss_Ability[10] = 'A04P'
        set Boss_Ability[11] = 'A04R'
        set Boss_Ability[12] = 'A04B'
        set Boss_Ability[13] = 'A04U'
        set Boss_Ability[14] = 'A04W'
        set Boss_Ability[15] = 'A04D'
        set Boss_Ability[16] = 'A050'
        set Boss_Ability[17] = 'A047'
        set Boss_Ability[18] = 'A048'
        set Boss_Ability[19] = 'A04N'
        set Boss_Ability[20] = 'A04O'
        set Level_Sound[1] = gg_snd_Level1
        set Level_Sound[2] = gg_snd_Level2
        set Level_Sound[3] = gg_snd_Level3
        set Level_Sound[4] = gg_snd_Level4
        set Level_Sound[5] = gg_snd_Level5BOSS
        set Level_Sound[6] = gg_snd_Level6
        set Level_Sound[7] = gg_snd_Level7
        set Level_Sound[8] = gg_snd_Level8
        set Level_Sound[9] = gg_snd_Level9
        set Level_Sound[10] = gg_snd_Level10BOSS
        set Level_Sound[11] = gg_snd_Level11
        set Level_Sound[12] = gg_snd_Level12
        set Level_Sound[13] = gg_snd_Level13
        set Level_Sound[14] = gg_snd_Level14
        set Level_Sound[15] = gg_snd_Level15BOSS
        set Level_Sound[16] = gg_snd_Level16
        set Level_Sound[17] = gg_snd_Level17
        set Level_Sound[18] = gg_snd_Level18
        set Level_Sound[19] = gg_snd_Level19
        set Level_Sound[20] = gg_snd_Level20BOSS
        set Level_Sound[21] = gg_snd_Level21
        set Level_Sound[22] = gg_snd_Level22
        set Level_Sound[23] = gg_snd_Level23
        set Level_Sound[24] = gg_snd_Level24
        set Level_Sound[25] = gg_snd_Level25BOSS
        call SetPlayerName(Player(0), "|cffFF0202" + GetPlayerName(Player(0)) + "|r")
        call SetPlayerName(Player(1), "|cff0041FF" + GetPlayerName(Player(1)) + "|r")
        call SetPlayerName(Player(2), "|cff1BE5B8" + GetPlayerName(Player(2)) + "|r")
        call SetPlayerName(Player(3), "|cff530080" + GetPlayerName(Player(3)) + "|r")
        call SetPlayerName(Player(9), "|cff7DBEF1" + GetPlayerName(Player(9)) + "|r")
        call SetPlayerName(Player(11), "|cff4D2903" + GetPlayerName(Player(11)) + "|r")
        call SuspendTimeOfDay(true)
        call SetFloatGameState(GAME_STATE_TIME_OF_DAY, 12.00)
        call FogMaskEnable(false)
        call CinematicFadeBJ(bj_CINEFADETYPE_FADEOUT, 0.00, "ReplaceableTextures\\CameraMasks\\Black_mask.blp", 0, 0, 0, 0)
        call SetPlayerTechMaxAllowed(GetLocalPlayer(), 'HERO', 1)
        call SetPlayerState(GetLocalPlayer(), PLAYER_STATE_RESOURCE_GOLD, (750 + ((4 - Player_Count) * 150)))
        call SetPlayerAlliance(Player(9), GetLocalPlayer(), ALLIANCE_SHARED_CONTROL, true)
        call ClearTextMessages()
        call TriggerExecute(gg_trg_Level_Setup)
        set x = GetRectCenterX(gg_rct_WholeArena)
        set y = GetRectCenterY(gg_rct_WholeArena)
        set Difficulty_Dummy = CreateUnit(Player(11), DUMMY, x, y, 0)
        call RemoveGuardPosition(Difficulty_Dummy)
        call UnitAddAbility(Difficulty_Dummy, 'A04M')
        call SetUnitAbilityLevel(Difficulty_Dummy, 'A04M', Player_Count)
        call UnitAddAbility(Difficulty_Dummy, 'A059')
        call SetUnitAbilityLevel(Difficulty_Dummy, 'A059', Player_Count)
        call Systems_OpenGate(Top_Gate)
        call SetDestructableInvulnerable(Top_Gate, true)
        call SetDestructableInvulnerable(Bottom_Gate, true)
        
        call UnitPoolAddUnitType(Hero_Pool, 'O003', 1.00)
        call UnitPoolAddUnitType(Hero_Pool, 'O004', 1.00)
        call UnitPoolAddUnitType(Hero_Pool, 'U006', 1.00)
        call UnitPoolAddUnitType(Hero_Pool, 'E000', 1.00)
        call UnitPoolAddUnitType(Hero_Pool, 'H00G', 1.00)
        call UnitPoolAddUnitType(Hero_Pool, 'H008', 1.00)
        call UnitPoolAddUnitType(Hero_Pool, 'H006', 1.00)
        call UnitPoolAddUnitType(Hero_Pool, 'H004', 1.00)
        call UnitPoolAddUnitType(Hero_Pool, 'H001', 1.00)
        call UnitPoolAddUnitType(Hero_Pool, 'H00P', 1.00)
        call UnitPoolAddUnitType(Hero_Pool, 'H00O', 1.00)
        call UnitPoolAddUnitType(Hero_Pool, 'E002', 1.00)
        
        call UnitPoolAddUnitType(Critter_Pool, 'n00I', 1.00)
        call UnitPoolAddUnitType(Critter_Pool, 'n00V', 1.00)
        
        call NextLevelSetup_Actions()
    endfunction

endlibrary
JASS:
library BeginningCinematics initializer onInit requires TimerUtils

    globals
        private effect TP = null
    endglobals

    private function Timer_Actions3 takes nothing returns nothing
        local real x = GetRectCenterX(gg_rct_Tavern)
        local real y = GetRectCenterY(gg_rct_Tavern)
        call DestroyEffect(TP)
        call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Human\\MassTeleport\\MassTeleportCaster.mdl", x, y))
        call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdl", x, y))
        set Tavern = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), 'n000', x, y, bj_UNIT_FACING)
        call SetCameraTargetController(Tavern, 0, 0, false)
        call TriggerExecute(gg_trg_Create_Scoreboard)
        call PlaySoundBJ(gg_snd_Message)
        call ReleaseTimer(GetExpiredTimer())
    endfunction

    private function Timer_Actions2 takes nothing returns nothing
        local timer t = CreateTimer()
        call ReleaseTimer(GetExpiredTimer())
        call CinematicFadeBJ(bj_CINEFADETYPE_FADEIN, 2.00, "ReplaceableTextures\\CameraMasks\\Black_mask.blp", 0, 0, 0, 0)
        set TP = AddSpecialEffect("Abilities\\Spells\\Human\\MassTeleport\\MassTeleportTo.mdl", GetRectCenterX(gg_rct_Tavern), GetRectCenterY(gg_rct_Tavern))
        call TimerStart(t, 2, false, function Timer_Actions3)
        set t = null
    endfunction
    
    private function Timer_Actions takes nothing returns nothing
        local timer t
        if GetPlayerController(Player(0)) == MAP_CONTROL_USER and GetPlayerSlotState(Player(0)) == PLAYER_SLOT_STATE_PLAYING then
            if IsPlayerInForce(GetLocalPlayer(), bj_FORCE_ALL_PLAYERS) and GetLocalPlayer() != Player(0) then
                call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "|cffffcc00Please wait while|r " + (GetPlayerName(Player(0))) + " |cffffcc00selects the settings.|r")
            endif
        else
            if IsPlayerInForce(GetLocalPlayer(), bj_FORCE_ALL_PLAYERS) then
                call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "Since |cffff0000Player 1|r isn't playing, game settings have defaulted to:
     |cffffcc00Normal Difficulty|r - All players start with the normal gold amount.
     |cffffcc00Normal Mode|r - Special creeps and bosses will spawn. 
     
|cff00FFFFType|r -settings |cff00FFFFto review these settings.|r")
            endif
            set t = NewTimer()
            call TimerStart(t, 5, false, function Timer_Actions2)
        endif
        set t = null
    endfunction
    
    public function onInit takes nothing returns nothing
        local real x = GetRectCenterX(gg_rct_WholeArena)
        local real y = GetRectCenterY(gg_rct_WholeArena)
        local integer i = 1
        local timer t = NewTimer()
        local unit u
        call GroupEnumUnitsInRect(bj_lastCreatedGroup, gg_rct_WholeBase, null)
        loop
            set u = FirstOfGroup(bj_lastCreatedGroup)
            exitwhen u == null
            if IsUnitType(u, UNIT_TYPE_HERO) then
                call RemoveUnit(u)
            endif
            call GroupRemoveUnit(bj_lastCreatedGroup, u)
        endloop
        call PanCameraToTimed(GetRectCenterX(gg_rct_Tavern), GetRectCenterY(gg_rct_Tavern), 0)
        loop
            set bj_lastCreatedUnit = CreateUnit(Player(11), Normal_Creep_Type[i], x, y, 0)
            call RemoveUnit(bj_lastCreatedUnit)
            exitwhen i == 25
            set i = i + 1
        endloop
        set i = 1
        loop
            set bj_lastCreatedUnit = CreateUnit(Player(11), Special_Creep_Type[i], x, y, 0)
            call RemoveUnit(bj_lastCreatedUnit)
            exitwhen i == 25
            set i = i + 1
        endloop
        call TimerStart(t, 1, false, function Timer_Actions)
        set t = null
    endfunction

endlibrary
 
Level 26
Joined
Aug 18, 2009
Messages
4,097
JASS:
        call SetPlayerState(GetLocalPlayer(), PLAYER_STATE_RESOURCE_GOLD, (750 + ((4 - Player_Count) * 150)))
        call SetPlayerAlliance(Player(9), GetLocalPlayer(), ALLIANCE_SHARED_CONTROL, true)

Err?

Additionally, in Timer_Actions, you desync the string table by creating strings within local blocks. GetPlayerName might be async anyway but the counter differs the way you do it. (Do not claim that this would be critical though)
 
Level 17
Joined
Feb 11, 2011
Messages
1,860
JASS:
        call  SetPlayerState(GetLocalPlayer(), PLAYER_STATE_RESOURCE_GOLD, (750 + ((4 -  Player_Count) * 150)))
        call SetPlayerAlliance(Player(9), GetLocalPlayer(), ALLIANCE_SHARED_CONTROL, true)
Err?

I used GetLocalPlayer() because I want it to apply for all players. Should I rather have used if IsPlayerInForce... then?

Additionally, in Timer_Actions, you desync the string table by creating strings within local blocks. GetPlayerName might be async anyway but the counter differs the way you do it. (Do not claim that this would be critical though)

Sorry? Can you explain this in a simpler way :grin:

Thanks for the help.
 
Level 26
Joined
Aug 18, 2009
Messages
4,097
GetLocalPlayer() is not all players. Every client has the same jass script. Replacing the individual return values for GetLocalPlayer(), this would practically be:

JASS:
call  SetPlayerState(Player(0), PLAYER_STATE_RESOURCE_GOLD, (750 + ((4 -  Player_Count) * 150)))
call SetPlayerAlliance(Player(9), Player(0), ALLIANCE_SHARED_CONTROL, true)

for player Red,

JASS:
call  SetPlayerState(Player(1), PLAYER_STATE_RESOURCE_GOLD, (750 + ((4 -  Player_Count) * 150)))
call SetPlayerAlliance(Player(9), Player(1), ALLIANCE_SHARED_CONTROL, true)

for player Blue and so on. This means that every client sets the properties of exactly one player (different ones) and has no clues about the other changes. Player Blue does not know that Red received gold because it is not written in his code.

You may only use GetLocalPlayer() as "all players" in case it's an async function you call and other players do not need the information.

Sorry? Can you explain this in a simpler way

There is a table in wc3 that recycles strings, so they can be accessed faster and do not have to be stored multiple times. When you write "abc" or call any string function, this creates a new string/looks up the table. Now GetPlayerName() might return different values on different clients due to name spoofer or language versions (Computer players use their default name when unchanged). I do not know if the string table needs to be synced. It does not make sense actually because you do not need to provide information about your cache. Nonetheless, I read it a few times in the forums.
 
Status
Not open for further replies.
Top