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

GetLocalPlayer() vs loop

Status
Not open for further replies.
Level 17
Joined
Nov 13, 2006
Messages
1,814
in most of time i used this

JASS:
function Trig_Camera_Periodic_Actions takes nothing returns nothing
local integer i = 0
local integer maxp = 11
local player p
local location loc
local unit u
    loop
        exitwhen i > maxp
        set p = Player(i)
        set u = udg_SelectedUnit[i]
        set loc = GetUnitLoc(u)
        if ( udg_CameraType[i] == 1 and GetPlayerController(p) == MAP_CONTROL_USER ) then
            if (GetLocalPlayer() == p) then
                call SetCameraField(CAMERA_FIELD_ROTATION, GetUnitFacing(u), 1)
                call SetCameraField(CAMERA_FIELD_FARZ, 50000, 1)
                call SetCameraField(CAMERA_FIELD_ANGLE_OF_ATTACK, udg_AngleOfAttack[i], 1)
                call PanCameraToTimedWithZ (GetLocationX(loc),GetLocationY(loc),150+GetUnitFlyHeight(u)+GetLocationZ(loc),0.15)
            endif
        endif
        set i = i + 1
    endloop
call RemoveLocation(loc)
set p = null
set loc = null
set u = null
endfunction

but seems this work aswell in splayer

JASS:
function Trig_Camera_Periodic1_Actions takes nothing returns nothing
local player p = GetLocalPlayer()
local integer i = GetPlayerId(p)
local location loc 
local real z
local unit u 
if udg_CameraType[i] == 1 then
        set u = udg_SelectedUnit[GetPlayerId(p)]
        set loc = GetUnitLoc(u)
                call SetCameraField(CAMERA_FIELD_ROTATION, GetUnitFacing(u), 1)
                call SetCameraField(CAMERA_FIELD_FARZ, 50000, 1)
                call SetCameraField(CAMERA_FIELD_ANGLE_OF_ATTACK, udg_AngleOfAttack[i], 1)
                call PanCameraToTimedWithZ (GetLocationX(loc),GetLocationY(loc),150+GetUnitFlyHeight(u)+GetLocationZ(loc),0.15)
call RemoveLocation(loc)
endif
set p = null
set loc = null
set u = null
endfunction

here i thing still not desync but maybe somewhere else can where i add value to a variable array like for player 1, udg_CameraType[1=player number]=1, can disconect to player 2 coz there udg_CameraType[1=player number] still =0?
or no till i use array what another player dont touch?
if no then the another question, what happen if i use normal variable instead variable arrray like if GetLocalPlayer do action then udg_CameraType=1 endif

so basically if each player can have different value in same global variable

so i can use this in most of place where i must check 12 player and modify variable or its desync if example player 2 dont get when player 1 variable is modified?
 
It works, but whole idea behind GetLocalPlayer is to do something for 1 or group of players only.

JASS:
if GetLocalPlayer() == Player(0) then
     call SetCameraField(CAMERA_FIELD_ANGLE_OF_ATTACK, 300, 1)
endif
This will set camera angle for RED PLAYER ONLY to 300.
All other players will continue using some old value.
This way you can show/hide effects, units, text, anything from some players and do all kind of crazy shits.

But care GetLocalPlayer can desync if you store it into variable for example or do some other shits with it.

Simple example like that one I posted above should work, like always.

NOTE: YOU DON'T NEED IT IN SP MAPS
 
While the second example works in single player, it can cause a desync in multiplayer.
JASS:
local player p = GetLocalPlayer()
local integer i = GetPlayerId(p)
if udg_CameraType[i] == 1 then
        set u = udg_SelectedUnit[GetPlayerId(p)]
        set loc = GetUnitLoc(u)
                call SetCameraField(CAMERA_FIELD_ROTATION, GetUnitFacing(u), 1)
                call SetCameraField(CAMERA_FIELD_FARZ, 50000, 1)
                call SetCameraField(CAMERA_FIELD_ANGLE_OF_ATTACK, udg_AngleOfAttack[i], 1)
                call PanCameraToTimedWithZ (GetLocationX(loc),GetLocationY(loc),150+GetUnitFlyHeight(u)+GetLocationZ(loc),0.15)
call RemoveLocation(loc)
endif

The first thing to note is that if you create handles for a specific player (using GetLocalPlayer()) in a multiplayer map, then it will desync. Why? Because GetLocalPlayer() will retrieve the player who is currently executing that code, and therefore if you perform actions checking if the local player is player X, then it will only perform the actions for that player X. (since all other players will have GetLocalPlayer() return a different number)

You don't have to have a perfect understanding of it, but you should know it just to be safe. Now, this is the common way of causing a desync and it is easily noticeable:
JASS:
if GetLocalPlayer() == Player(0) then
    //... create/destroy a handle, among other things can cause desyncs
    call CreateUnit(...) // desync
endif

In the second example, it is a little less noticeable, but you are actually creating a local player block.
JASS:
local player p = GetLocalPlayer()
local integer i = GetPlayerId(p)
if udg_CameraType[i] == 1 then

The first line will assign the local player to the variable p. This value will be different for each player. For player 1 (red), it will be player 1, for player 2 (blue) it will be player 2, and so on.. The next variable, "i", will also be different for each player. For player 1, the value will be 0 (since player indexes start off at 0 in JASS), for player 2 it will be 1, player 3 will be 2, and so on...

So when you do this line:
if udg_CameraType[i] == 1 then
udg_CameraType will be different for each player. So for some players it will execute the code, and for others it won't. Then you have this line
set u = udg_SelectedUnit[GetPlayerId(p)]
Which will have a different value of "u" for each player. So for one player, it may point to some grunt while for another it may point to a footman. (just an example) This is fine so far since you haven't done anything, but the next line is where it causes problems:
set loc = GetUnitLoc(u)
This will create a handle (a location). So for any player who did not pass the condition, they will not have this location created. That is a desync. It also might cause a desync later with inappropriate manipulation since the location will return different coordinates for each player.

----

Long story short, GetLocalPlayer() doesn't make life easier in that sense. Remember that GetLocalPlayer() does not always substitute a loop. In most cases, it will cause a desync. It doesn't perform actions globally as one would expect, it instead will perform an action for only one player specifically. If you create a unit in a local player block, it may show up for one player but it won't for the others, and it will lead to a desync.

To properly optimize your code, you can simply make it like this:
JASS:
function Trig_Camera_Periodic_Actions takes nothing returns nothing
    local integer i = 0
    local location l = Location(0,0)
    local unit u
    local real z 
    loop
        exitwhen i > 11
        set u = udg_SelectedUnit[i]
        call MoveLocation(l, GetUnitX(u), GetUnitY(u))
        set z = GetLocationZ(l) // can't remember if this is necessary to do outside of a block
        // but it is better to be safe anyway
        if udg_CameraType[i] == 1 and GetPlayerController(Player(i)) == MAP_CONTROL_USER then
            if GetLocalPlayer() == Player(i) then
                call SetCameraField(CAMERA_FIELD_ROTATION, GetUnitFacing(u), 1)
		        call SetCameraField(CAMERA_FIELD_FARZ, 50000, 1)
                call SetCameraField(CAMERA_FIELD_ANGLE_OF_ATTACK, udg_AngleOfAttack[i], 1)
                call PanCameraToTimedWithZ(GetUnitX(u), GetUnitY(u), GetUnitFlyHeight(u) + 150 + z, 0.15)
		   endif
        endif
        set i = i + 1
    endloop
    call RemoveLocation(l)
    set l = null
    set u = null
endfunction

Sorry for my long-winded explanations, it is just a difficult concept. In general, I recommend that you be careful with using it. =) It works in mysterious ways, and it might not cause a desync immediately--which makes your map become a pain to debug.
 
Last edited:
Level 14
Joined
Apr 20, 2009
Messages
1,543
JASS:
function Trig_Camera_Periodic_Actions takes nothing returns nothing
    local integer i = 0
    local location l = Location(0,0)
    local unit u
    local real z 
    loop
        exitwhen i > 11
        set u = udg_SelectedUnit[i]
        call MoveLocation(l, GetUnitX(u), GetUnitY(u))
        set z = GetLocationZ(l) // can't remember if this is necessary to do outside of a block
        // but it is better to be safe anyway
        if udg_CameraType[i] == 1 and GetPlayerController℗ == MAP_CONTROL_USER then
            if GetLocalPlayer() == p then
                call SetCameraField(CAMERA_FIELD_ROTATION, GetUnitFacing(u), 1)
		       call SetCameraField(CAMERA_FIELD_FARZ, 50000, 1)
                call SetCameraField(CAMERA_FIELD_ANGLE_OF_ATTACK, udg_AngleOfAttack[i], 1)
                call PanCameraToTimedWithZ(GetUnitX(u), GetUnitY(u), GetUnitFlyHeight(u) + 150 + z, 0.15)
		   endif
        endif
        set i = i + 1
    endloop
    call RemoveLocation(l)
    set l = null
    set u = null
endfunction

Am I missing something here or is p undefined? Wouldn't this be Player(i)?
set z = GetLocationZ(l) returns a real, not a handle. So wouldn't that make it safe to be put inside the block?
 
You're right about the p part, I'll change that. I accidentally left the code as it was.

And GetLocationZ() was just a safety measure in case it returns different values. (i heard it may have weird values returned after terrain deformations or something along those lines)

EDIT: Sorry for the indenting and the &#8471, i was editing it in TextEdit and it just makes everything copy and paste weirdly.
 
Level 14
Joined
Apr 20, 2009
Messages
1,543
(i heard it may have weird values returned after terrain deformations or something along those lines)

Do you perhaps still know of a refference on where you've read that, I would really like to know :)

And GetLocationZ() was just a safety measure in case it returns different values.

Isn't Location(0,0) the same location on the map for every player? Then how can it return different values? Since your getting the z-height of the terrain on that specific location.
 
Level 26
Joined
Aug 18, 2009
Messages
4,097
No, the code should not cause a desync. Indeed an agent gets created in the local block but this location is also immediately and properly cleaned up with RemoveLocation and nullifying the references. So the id stack is the same as before. The different coordinates are fine too since they are only used for async functions.

Of course the GetLocationZ can be inside the block, it does not do anything besides retrieving data and this has nothing to do with whether the data alters.
 
Level 17
Joined
Nov 13, 2006
Messages
1,814
so overall then i can ignore a loop for 12 player,right?
JASS:
local integer i = 0
local integer maxp = 11
local player p
local location loc
local unit u
local real time = 0.15
local real z


    loop
        exitwhen i > maxp
        set p = Player(i)
        if ( udg_CameraType[i] == 1 and GetPlayerController(p) == MAP_CONTROL_USER ) then
        set u = udg_SelectedUnit[i]
        set loc = GetUnitLoc(u)
            if (GetLocalPlayer() == p) then
                call PanCameraToTimed(GetUnitX(u), GetUnitY(u), time)
                call SetCameraField(CAMERA_FIELD_ROTATION, GetUnitFacing(u), time)
                call SetCameraField(CAMERA_FIELD_FARZ, 50000, time)
                call SetCameraField(CAMERA_FIELD_ANGLE_OF_ATTACK, udg_Camera_AngleOfAttack[i], time)
                call SetCameraField(CAMERA_FIELD_TARGET_DISTANCE, udg_CameraDist[i], time)
                call SetCameraField(CAMERA_FIELD_ZOFFSET, 70 + GetLocationZ(loc) + GetUnitFlyHeight(u), time)

            endif
        endif
        set i = i + 1
    endloop
call RemoveLocation(loc)
set p = null
set loc = null
set u = null

if we talk about a multiboard then its work?


JASS:
function Trig_Stat_multiboard_update_Actions takes nothing returns nothing
    local integer a = 1
    local integer b = 1
    local integer eqmax = 5
    local integer maxpl = 10
    local integer cv
    local integer str
    local integer agi
    local integer int
    local integer array i
    local integer evab
    local integer alvb
    local integer dlvb
    local integer critb
    local integer critdmgb
    local integer pdefb
    local integer mdefb
    local integer refb 
    local real petbonus = 0 
    local integer spb
    local real ms
    local unit u
    local player p
    local multiboarditem mbitem
    set a = 1
    set maxpl = 10
	
    loop
        exitwhen a > maxpl
        set p = Player(a - 1)
        if ( GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING and GetPlayerController(p) == MAP_CONTROL_USER ) then
            set u = udg_Hero[a]
            set cv = GetUnitUserData(u)
            set str = GetHeroStr(u, true)
            set agi = GetHeroAgi(u, true)
            set int = GetHeroInt(u, true)
            set evab = LoadInteger(udg_Buff_Table, 10, cv)
            set alvb = LoadInteger(udg_Buff_Table, 3, cv)
            set dlvb = LoadInteger(udg_Buff_Table, 4, cv)
            set critb = LoadInteger(udg_Buff_Table, 1, cv)
            set critdmgb = LoadInteger(udg_Buff_Table, 2, cv)
            set pdefb = LoadInteger(udg_Buff_Table, 11, cv)
            set mdefb = LoadInteger(udg_Buff_Table, 12, cv)
            set spb = LoadInteger(udg_Buff_Table, 7, cv)
            set refb = LoadInteger(udg_Buff_Table, 19, cv)
            set ms = GetUnitMoveSpeed (udg_Hero[a])
            set udg_Global_Eva[cv] = udg_Stat_Evasion[a] + agi / 20
            set udg_Global_Crit[cv] = udg_Stat_Crit[a] + agi / 20 + 1
            set udg_Global_CritDmg[cv] = udg_Stat_RageDmg[a]
            set udg_Global_AttLv[cv] = udg_Stat_AttackLv[a]
            set udg_Global_DefLv[cv] = udg_Stat_DefLv[a]
            set udg_Global_Pdef[cv] = udg_Stat_Pdef[a] + R2I(udg_Stat_Pdef[a] * str / 400.00 )
            set udg_Global_Mdef[cv] = udg_Stat_Mdef[a] + R2I(udg_Stat_Mdef[a] * int / 400.00 )
            set udg_Global_Reflect[cv] = udg_Stat_Reflect[a] + refb
            set udg_Global_LifeSteal[cv] = udg_Stat_LifeSteal[a]
            set udg_Global_ManaSteal[cv] = udg_Stat_ManaSteal[a]
            set udg_TotalSpellPower[a] = udg_Stat_SpellPower[a] + udg_Stat_SpellPower[a] * (int + spb) / 100
            if udg_Class2[a]==6 then
                set petbonus = int / 100.00
            endif
            if ( agi > str ) then
                set udg_TotalDmg[a] = udg_Stat_Dmg[a] + udg_Stat_Dmg[a] / 100 * agi
            else
                set udg_TotalDmg[a] = udg_Stat_Dmg[a] + udg_Stat_Dmg[a] / 100 * str
            endif
            set i[1] = udg_Helm[a]
            set i[2] = udg_Armor[a]
            set i[3] = udg_Weapon[a]
            set i[4] = udg_Boot[a]
            set i[5] = udg_Wings[a]
            set b = 1
            set eqmax = 5
            loop
                exitwhen b > eqmax
                if ( b != 5 ) then
                    set mbitem = MultiboardGetItem(udg_Multiboard[a], b, 2)
                    call MultiboardSetItemValue(mbitem, I2S(udg_Item_Socket[i[b]]) + "/" + I2S(udg_Stat_Sockets[ a * 10 + b ]))
                    call MultiboardReleaseItem(mbitem)
                else
                    set mbitem = MultiboardGetItem(udg_Multiboard[a], 9, 2)
                    call MultiboardSetItemValue(mbitem, I2S(udg_Item_Socket[i[b]]) + "/" + I2S(udg_Stat_Sockets[ a * 10 + b ] ))
                    call MultiboardReleaseItem(mbitem)
                endif
                set b = b + 1
            endloop
            set udg_TotalExp[a] = ( ( ( udg_Difficulty * 50 ) + udg_Stat_Exp[a] ) + 50 )
            set b = 1
            set eqmax = 10
            loop
                exitwhen b > eqmax
                set mbitem = MultiboardGetItem(udg_Multiboard[a], b, 3)
                call MultiboardSetItemValue(mbitem, "     " + I2S(udg_Stat_Refine[ a * 20 + b ]))
                call MultiboardReleaseItem(mbitem)
                set b = b + 1
            endloop
            call SetPlayerHandicapXP(p, udg_TotalExp[a] * 0.01)
//----------------------------------------------------
  if (GetLocalPlayer() == p) then
//----------------------------------------------------
            set mbitem = MultiboardGetItem(udg_Multiboard2[a], 1, 1)
            call MultiboardSetItemValue(mbitem, I2S(udg_Global_Crit[cv] + critb) + "%")
            call MultiboardReleaseItem(mbitem)
            set mbitem = MultiboardGetItem(udg_Multiboard2[a], 2, 1)
            call MultiboardSetItemValue(mbitem, I2S(udg_Global_CritDmg[cv] + critdmgb) + "%")
            call MultiboardReleaseItem(mbitem)
            set mbitem = MultiboardGetItem(udg_Multiboard2[a], 3, 1)
            call MultiboardSetItemValue(mbitem, I2S(udg_Global_LifeSteal[cv]) + "%")
            call MultiboardReleaseItem(mbitem)
            set mbitem = MultiboardGetItem(udg_Multiboard2[a], 4, 1)
            call MultiboardSetItemValue(mbitem, I2S(udg_Global_ManaSteal[cv]) + "%")
            call MultiboardReleaseItem(mbitem)
            set mbitem = MultiboardGetItem(udg_Multiboard2[a], 5, 1)
            call MultiboardSetItemValue(mbitem, I2S(udg_Global_AttLv[cv] + alvb))
            call MultiboardReleaseItem(mbitem)
            set mbitem = MultiboardGetItem(udg_Multiboard2[a], 6, 1)
            call MultiboardSetItemValue(mbitem, I2S(udg_Global_DefLv[cv] + dlvb))
            call MultiboardReleaseItem(mbitem)
            set mbitem = MultiboardGetItem(udg_Multiboard2[a], 7, 1)
            call MultiboardSetItemValue(mbitem, I2S(udg_TotalSpellPower[a]))
            call MultiboardReleaseItem(mbitem)
            set mbitem = MultiboardGetItem(udg_Multiboard2[a], 8, 1)
            call MultiboardSetItemValue(mbitem, I2S(udg_Stat_Pet_Power[a]) + "(+"+R2SW(petbonus, 3, 2)+"%)")
            call MultiboardReleaseItem(mbitem)
            set mbitem = MultiboardGetItem(udg_Multiboard2[a], 9, 1)
            call MultiboardSetItemValue(mbitem, I2S(udg_Global_Reflect[cv]) + "%")
            call MultiboardReleaseItem(mbitem)
            set mbitem = MultiboardGetItem(udg_Multiboard2[a], 10, 1)
            call MultiboardSetItemValue(mbitem, I2S(udg_Stat_AttackSpeed[a] + 100 + agi ) + "%")
            call MultiboardReleaseItem(mbitem)
            set mbitem = MultiboardGetItem(udg_Multiboard2[a], 11, 1)
            call MultiboardSetItemValue(mbitem, I2S(R2I(ms)))
            call MultiboardReleaseItem(mbitem)
            set mbitem = MultiboardGetItem(udg_Multiboard2[a], 12, 1)
            call MultiboardSetItemValue(mbitem, I2S(udg_Global_Pdef[cv]))
            call MultiboardReleaseItem(mbitem)
            set mbitem = MultiboardGetItem(udg_Multiboard2[a], 13, 1)
            call MultiboardSetItemValue(mbitem, I2S(udg_Global_Mdef[cv]))
            call MultiboardReleaseItem(mbitem)
            set mbitem = MultiboardGetItem(udg_Multiboard2[a], 14, 1)
            call MultiboardSetItemValue(mbitem, R2SW(udg_Stat_HpRegen[a], 4, 2))
            call MultiboardReleaseItem(mbitem)
            set mbitem = MultiboardGetItem(udg_Multiboard2[a], 15, 1)
            call MultiboardSetItemValue(mbitem, R2SW(udg_Stat_MpRegen[a], 4, 2))
            call MultiboardReleaseItem(mbitem)
            set mbitem = MultiboardGetItem(udg_Multiboard2[a], 16, 1)
            call MultiboardSetItemValue(mbitem, I2S(udg_Global_Eva[cv] + evab) + "%")
            call MultiboardReleaseItem(mbitem)
            set mbitem = MultiboardGetItem(udg_Multiboard2[a], 17, 1)
            call MultiboardSetItemValue(mbitem, I2S(udg_Stat_BlockDmg[a] ) + "%")
            call MultiboardReleaseItem(mbitem)
            set mbitem = MultiboardGetItem(udg_Multiboard2[a], 18, 1)
            call MultiboardSetItemValue(mbitem, I2S(udg_TotalExp[a]) + "%")
            call MultiboardReleaseItem(mbitem)
            set mbitem = MultiboardGetItem(udg_Multiboard2[a], 19, 1)
            call MultiboardSetItemValue(mbitem, I2S(udg_Stat_Vigor[a]))
            call MultiboardReleaseItem(mbitem)
            set mbitem = MultiboardGetItem(udg_Multiboard2[a], 20, 1)
            call MultiboardSetItemValue(mbitem, "|cffffcc00" + I2S(udg_Stat_Point[a]) + "|r")
            call MultiboardReleaseItem(mbitem)
//----------------------------------------------------
endif
//----------------------------------------------------
            set udg_Global_Block[cv] = udg_Stat_BlockDmg[a]
        endif
        set a = a + 1
    endloop
    set u = null
    set p = null
    set mbitem = null
endfunction

//===========================================================================
function InitTrig_Stat_multiboard_update takes nothing returns nothing
    set gg_trg_Stat_multiboard_update = CreateTrigger( )
    call DisableTrigger( gg_trg_Stat_multiboard_update )
    call TriggerRegisterTimerEventPeriodic( gg_trg_Stat_multiboard_update, 1.00 )
    call TriggerAddAction( gg_trg_Stat_multiboard_update, function Trig_Stat_multiboard_update_Actions )
endfunction
 
Level 26
Joined
Aug 18, 2009
Messages
4,097
In the first snippet you just posted, you even leak locations by using the same var over and over again but only destroying the last one after the loop. I would not use GetUnitLoc anyway. Just use a globally stored location and move it with MoveLocation (Maker had already shown this above).
 
Level 17
Joined
Nov 13, 2006
Messages
1,814
In the first snippet you just posted, you even leak locations by using the same var over and over again but only destroying the last one after the loop. I would not use GetUnitLoc anyway. Just use a globally stored location and move it with MoveLocation (Maker had already shown this above).

ok i changed what about multiboard where i use this?
JASS:
            set mbitem = MultiboardGetItem(udg_Multiboard2[a], 3, 1)
            call MultiboardSetItemValue(mbitem, I2S(udg_Global_LifeSteal[cv]) + "%")
            call MultiboardReleaseItem(mbitem)

its work if lets say before getlocalplayer if i use mbitem=null and before end if i use again mbitem=null?

i mean if a variable changed inside the if getlocalplayer block but before andif i restore that variable value to original, then not desync?
 
Level 26
Joined
Aug 18, 2009
Messages
4,097
The object won't be fully destroyed until you reset all variables pointing to it. Your case looks okay but something like this

JASS:
if (GetLocalPlayer() == <player>) then
    set mbItem = MultiboardGetItem...

    call MultiboardReleaseItem(mbItem)
endif

call CreateUnit...

set mbItem = null

would not, because the multiboarditem's id is still not released, therefore the newly created unit ends up with different ids on different clients.

You do desync the string table but I do not know whether this is a problem.
 
Status
Not open for further replies.
Top