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

[Solved] GetLocalPlayer() Question

Status
Not open for further replies.
Level 11
Joined
Jun 30, 2008
Messages
580
Hello Hivers,

So I have a question about GetLocalPlayer(), I noticed in a system like this:

JASS:
private function bPeriodic takes nothing returns nothing
        local integer p = GetPlayerId(GetLocalPlayer())
        
        // Applies BattleCam
        if bUnit != null then
            if TimerGetRemaining(StartPan) <= PAN_DURATION then
                call ApplyBattleCam(p, PAN_DURATION)
            else
                call ApplyBattleCam(p, TimerGetRemaining(StartPan))
            endif
        endif
        set p = p+1

The GetLocalPlayer() doesn't cause a desync, but when I use it here it causes a desync:

JASS:
private function DistanceCheck takes nothing returns nothing
        local CharData cData = LoadInteger(CharacterHash, GetPlayerId(GetLocalPlayer()), 1)
        local unit u
         
        if cData.uData.Target != null then
            
            // Sets Selection Dummy to Target
            call SetUnitPosition(DummyUnits[i], GetUnitX(cData.uData.Target), GetUnitY(cData.uData.Target))
                
            // Removes Target if out of Target Range
            if Distance(cData.uData.Unit, cData.uData.Target) >= MAX_TARGET_DISTANCE and cData.uData.Target != null then
                call RemoveUnit(DummyUnits[i])
                set u = cData.uData.Target
                set cData.uData.Target = null
                call cData.mHUD.removeBlock(u, 4)
            endif
            
            // If out of combat zone sets to false and enables ThirdPersonCam
            if Distance(cData.uData.Unit, cData.uData.Target) > MAX_COMBAT_DISTANCE and cData.uData.InCombat != false then
                call EnableBattleCam(Player(i), null, null, 0)
                call EnableThirdPersonCam(Player(i), cData.uData.Unit, 2)
                set cData.uData.InCombat = false
            endif
            
            // Enables BattleCam if in distance of selected target
            if Distance(cData.uData.Unit, cData.uData.Target) <= MAX_COMBAT_DISTANCE and cData.uData.InCombat == false then
                set cData.uData.InCombat = true
                call EnableThirdPersonCam(Player(i), null, 0.0)
                call EnableBattleCam(Player(i), cData.uData.Unit, cData.uData.Target, 2.0)
            endif
        endif
    endfunction
 
Well, for the first code, it is likely just doing camera changes. That stuff is all safe locally.

However, in your case, you have to be a bit more careful:
JASS:
        local CharData cData = LoadInteger(CharacterHash, GetPlayerId(GetLocalPlayer()), 1)
This will return different values for different players. Player 1 running it will load the integer at 0, 1. Player 2 running it will load the integer at 1, 1, etc.

As such, this:
if cData.uData.Target != null then

Will have different results for different players. For some players, it will be null. For other players, it will not be null. The key thing, cData is different for each player. It points to a different integer for each player, so when you do this:
call SetUnitPosition(DummyUnits[i], GetUnitX(cData.uData.Target), GetUnitY(cData.uData.Target))
All hell breaks loose. The game will try to move DummyUnits to the target's XY for player 1's cData, and DummyUnits to the target's XY for player 2's cData, etc.. All these movements are performed locally, and once wc3 realizes that the positions are out of sync, it'll desync.

You have to be a bit more careful when you are loading the data. You should actually be using a loop:
JASS:
local CharData cData
local unit u
local integer i = 0

loop
    exitwhen i == 12
    set cData = LoadInteger(CharacterHash, i, 1)
    // actions
    set i = i + 1
    // actions
endloop
 
Yeah, I forgot you can move units to different coords so long as they don't receive any interactions (although, beware of "Unit enters rect..." and other events!). Although, the key thing to note is that he is using SetUnitPosition, which performs pathing checks and issues a stop order to the unit. That may be enough to force a desync. Otherwise, RemoveUnit() will be the problem. All in all, just use the loop to make life easier. :p But thanks for the correction.
 
Status
Not open for further replies.
Top