• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

locally set globals desync?

Status
Not open for further replies.
guys, will this desync?
JASS:
globals
    integer i
endglobals

function a takes nothing returns nothing
    if GetLocalPlayer() == Player(0) then
        set i = 1
    else
        set i = 2
    endif
    call BJDebugMsg(I2S(i))
endfunction
??
things about desync truly makes me crazy.. :ogre_rage:

That doesn't desync. However, if you use "i" anywhere, the value will be asynchronous. e.g. That message will display "1" for player 1, and "2" for everyone else.

But this has other implications too. While your code won't cause a disconnection, this will:
JASS:
globals
    integer i
endglobals

function a takes nothing returns nothing
    if GetLocalPlayer() == Player(0) then
        set i = 1
    else
        set i = 2
    endif
    call BJDebugMsg(I2S(i))

    if i == 1 then
        call CreateUnit(Player(0), 'hfoo', 0, 0, 0)
    endif
endfunction

In this sense, it is creating a player only for player 1, because he is the only person who has
i == 1. So even if the assignment won't cause a desync, you still have to be careful with it since it is asynchronous data.
 

Wrda

Spell Reviewer
Level 28
Joined
Nov 18, 2012
Messages
1,993
That doesn't desync. However, if you use "i" anywhere, the value will be asynchronous. e.g. That message will display "1" for player 1, and "2" for everyone else.

But this has other implications too. While your code won't cause a disconnection, this will:
JASS:
globals
    integer i
endglobals

function a takes nothing returns nothing
    if GetLocalPlayer() == Player(0) then
        set i = 1
    else
        set i = 2
    endif
    call BJDebugMsg(I2S(i))

    if i == 1 then
        call CreateUnit(Player(0), 'hfoo', 0, 0, 0)
    endif
endfunction

In this sense, it is creating a player only for player 1, because he is the only person who has
i == 1. So even if the assignment won't cause a desync, you still have to be careful with it since it is asynchronous data.
Right... makes sense :)
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,258
That is causing the desync. Basically you are creating a unique string between clients. All clients have to have the same strings declared in the same order or they will desync.

You will need to initialize somewhere before calling the function that a "1" and "2" string is created. This can be at map initialization even. After then all clients will have both "1" and "2" strings (because strings leak as they never get de-allocated once allocated) so calling I2S(i) on that asynchronous value will not cause a desync as it will not create a new string and only point at an already existing string.
 
Locally checking if a multiboard is displayed shouldn't desync. The actions within it may desync, depending on the content, but your code seems fine to me.

Try commenting out specific lines to see which one is causing the problem. First comment out everything within the if/elseif, and test it. Then comment out the SetTitleText functions only. From there, you can try commenting out other lines and determine which one is causing the desync. Just be sure that is the function causing the desync, or else you'll likely end up going through a lot of trouble for nothing.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,258
call MultiboardSetTitleText(Multiboard[Multistate], "|CFFFFBC00ARCANE STATISTIC|R")

The string used is not initialized globally prior to this function call. As this function call is first executed locally this will cause the client to lose synchronization as his string table does not match other clients. Solution is to either set a globally synchronous local to the value at the start of the function (easy, least efficient) or to set a local in an initialization function to the value (slightly less easy/convenient but faster in the long term).
 

Kazeon

Hosted Project: EC
Level 34
Joined
Oct 12, 2011
Messages
3,449
Does it desync if you only have that line? I would assume that it is causing some other trigger to desync. Where else do you use "Multistate"?

JASS:
        // Sure to skip
        if b == btn[id].button[12] then
            set MainCharacter[id] = CreateUnit(p, 'h000', -20546.04, -22201.10, 270.)
            set TabCharacter[id] = CreateUnit(p, 'h001', -20546.04, -22201.10, 270.)
            set InventoryUnit[id] = CreateUnit(p, 'H004', 0., 0., 270.)
            call RegisterInventoryUnit(MainCharacter[id], true, true)
            call SetUnitScale(TabCharacter[id], 0., 0., 0.)
            call initStatus(id)
            set Multistate[id] = 0
            if GetLocalPlayer() == p then
                call MultiboardDisplay(Multiboard[0], true)
                call MultiboardMinimize(Multiboard[0], false)
                call ClearSelection()
                call SelectUnit(MainCharacter[id], true)
                call SelectUnit(TabCharacter[id], true)
                call SetCameraTargetController(MainCharacter[id], 0., 0., false)
                call FogEnable(false)
                call FogMaskEnable(false)
            endif
        endif

JASS:
            if IsMultiboardMinimized(Multiboard[Multistate[i]]) and Multistate[i] != 2 then
                set Multistate[i] = Multistate[i] + 1
                if GetLocalPlayer() == Player(i) then
                    call MultiboardDisplay(Multiboard[Multistate[i] - 1], false)
                    call MultiboardDisplay(Multiboard[Multistate[i]], true)
                    if Multistate[i] != 2 then
                        call MultiboardSetTitleText(Multiboard[Multistate[i]], "|CFFFFBC00ARCANE STATISTIC|R")
                        call MultiboardMinimize(Multiboard[Multistate[i]], false)
                    else
                        call MultiboardSetTitleText(Multiboard[Multistate[i]], "")
                    endif
                endif
            elseif not IsMultiboardMinimized(Multiboard[Multistate[i]]) and Multistate[i] == 2 then
                set Multistate[i] = 0
                if GetLocalPlayer() == Player(i) then
                    call MultiboardDisplay(Multiboard[Multistate[i] - 1], false)
                    call MultiboardDisplay(Multiboard[Multistate[i]], true)
                endif
            endif

I just use it on two places, the first one is initialize the value (I'm not doing it locally, and I never set a global variables value locally, I'm affraid it will causes confusion somewhere).

The string used is not initialized globally prior to this function call. As this function call is first executed locally this will cause the client to lose synchronization as his string table does not match other clients. Solution is to either set a globally synchronous local to the value at the start of the function (easy, least efficient) or to set a local in an initialization function to the value (slightly less easy/convenient but faster in the long term).
but, why this doesn't desync :/
JASS:
        loop
            exitwhen i > 9
            if GetLocalPlayer() == Player(i) then
                call MultiboardSetTitleText(Multiboard[0], "|CFFFFBC00" + GetPlayerName(Player(i)) + "|R")
            endif
            set i = i + 1
        endloop

I have tried so many other methods for hours but still desynced, I really have no idea how to fix this.. D:


EDIT:

WAIIIITTT A SECOND, this doesnt desync!!!!!!
JASS:
        loop
            exitwhen i > 9
            if IsMultiboardMinimized(Multiboard[Multistate[i]]) and Multistate[i] != 2 then
                //set Multistate[i] = Multistate[i] + 1
                if GetLocalPlayer() == Player(i) then
                    call MultiboardDisplay(Multiboard[Multistate[i] - 1], false)
                    call MultiboardDisplay(Multiboard[Multistate[i]], true)
                    if Multistate[i] != 2 then
                        call MultiboardSetTitleText(Multiboard[Multistate[i]], "|CFFFFBC00ARCANE STATISTIC|R")
                        call MultiboardMinimize(Multiboard[Multistate[i]], false)
                    else
                        call MultiboardSetTitleText(Multiboard[Multistate[i]], "")
                    endif
                endif
            elseif not IsMultiboardMinimized(Multiboard[Multistate[i]]) and Multistate[i] == 2 then
                //set Multistate[i] = 0
                if GetLocalPlayer() == Player(i) then
                    call MultiboardDisplay(Multiboard[Multistate[i] - 1], false)
                    call MultiboardDisplay(Multiboard[Multistate[i]], true)
                endif
            endif
            set i = i + 1
        endloop
so the problem is on multistate :D
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
I'm quite sure that having a different string table for each players won't desync.
You forget that wc3 is not only in english, it's most likely that players will already have different strings.

And again you don't need GetLocalPlayer() to have local stuff, a perfect example is with camera.

I'm not sure you can use MultiBoardSet... in a local block without any desync, minimize it or not should be fine though, since players can already do that themselves.
So instead of use MultiboardSet in a local block, do it for each players but with a different value.
 
Last edited by a moderator:
Level 12
Joined
Feb 22, 2010
Messages
1,115
I'm quite sure that having a different string table for each players won't desync.

Yeah I agree, I don't know about the old times but I see so much people who tells use this first way:

JASS:
local string s = effectPath
if GetLocalPlayer() != myPlayer then
    s == ""
endif
call AddSpecialEffect()

instead of this second way
JASS:
local string s = ""
if GetLocalPlayer() != myPlayer then
    s == effectPath
endif
call AddSpecialEffect()

Because they tell second way will desync, but if I remember right I sometimes used second way and it was working.
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
I don't have a test ready to prove it but I guarantee you string tables cause desyncs

Then maybe it was fixed, i've never experienced it and didn't care about the string table.
As i have said wc3 is not only in english, so the internal string table for each player is likely to be already different.

Now, i suppose safety over "efficiency" and "less memory used" is always better.
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
Maps are provided with one set of strings, any language specific strings are defined in the application, so aren't part of the string table as far as we can tell

Sent from my mobile

Just as an example if you use GetUnitName on a footman il will be footman in english and fantassin in french.

I will take a look at your script later Dalvengyr.

Doing stuff in a local block is faster in the sense that it's done only for needed players.
 
Level 12
Joined
Feb 22, 2010
Messages
1,115
I tested again and this doesn't desync.

JASS:
scope DesyncTest initializer Init

globals
    string S1 = ""
    string S2 = ""
    string array SA
endglobals

function RunTest takes nothing returns nothing
    if GetLocalPlayer() == GetTriggerPlayer() then
        call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, S1 + S2)
        call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, SA[0] + SA[1])
    endif
endfunction


private function Init takes nothing returns nothing
    local trigger t = CreateTrigger()
    
    if GetLocalPlayer() == Player(0) then
        set S1 = "Welcome "
        set S2 = GetPlayerName(Player(0))
        set SA[0] = "Hope "
        set SA[1] = "you will have a good time"
    elseif GetLocalPlayer() == Player(1) then
        set S1 = "Get out "
        set S2 = GetPlayerName(Player(1))
        set SA[0] = "Hope "
        set SA[1] = "you will die"
    endif
    
    
    call TimerStart(CreateTimer(), 1.00, false, function RunTest)
    call TriggerRegisterPlayerEvent(t, Player(0), EVENT_PLAYER_END_CINEMATIC)
    call TriggerRegisterPlayerEvent(t, Player(1), EVENT_PLAYER_END_CINEMATIC)
    call TriggerAddAction(t, function RunTest)
    
    set t = null
endfunction

endscope
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
JASS:
if IsMultiboardMinimized ...
This is a local block, since the player X can have it minimized but not the player Y.

Again i'm not sure that using MultiBoardSet... is safe in a local block.
You should test that alone.
Tell me if you can do that, and if it's the case i will check more the code (i'm currently on the line 2122)
 
Just as an example if you use GetUnitName on a footman il will be footman in english and fantassin in french.

I believe that GetUnitName() alone won't cause problems, but you do local string s = "Your " + GetUnitName(u) + " has fallen." it will cause erroneous state and potentially cause a synchronization failure.
 
Level 12
Joined
Feb 22, 2010
Messages
1,115
You can even play same map with different language(I am not talking about game language, map language).
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
I believe that GetUnitName() alone won't cause problems, but you do local string s = "Your " + GetUnitName(u) + " has fallen." it will cause erroneous state and potentially cause a synchronization failure.

Why, because only the size of the internal string table but not the value of the strings does matter ?
Again, i've never experienced it.
Now, as said, just for safety, i suppose you can assume it desyncs.
I've simply never seen a proof of a such desync.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,258
will showing diifferent multiboards for each player causing desync?
No, and this is already in use by so many maps (Heroes and Empires is an example).

Locally modifying a multiboard can cause a desync as the process of creating and releasing multiboard items involves object generation. However I am pretty sure you can set multiboard items to a local value as long as the modification process is global (just the item change is run locally).
 

Kazeon

Hosted Project: EC
Level 34
Joined
Oct 12, 2011
Messages
3,449
The only place you should have local code is where you display the multiboard. The reason why is because you should have 12 multiboards.

Then in your update function just update the slots for all multiboards, using non-local code.
well, that doesnt mean I have to re-write them all, just re-construct :p wait I minute, I will try it..

EDIT:
well, I haven't shared the last code, actually, I have made 2 multiboards for each player (there are 10 players in game, that means there are 20 multiboards :p) and nothing is done locally bbut still desync :/

EDIT2:
okay, here is the last version
JASS:
library Multiboard initializer ini
    
    globals
        multiboard array Multiboard
        integer array Multistate
    endglobals
    
    private function update takes nothing returns nothing
        
        local integer i = 0
        local integer j
        local integer idex
        local integer idex2
        local multiboarditem mi
        local integer k
        local string b
        
        loop
            exitwhen i > 9
            if Multistate[i] == 0 then
                set k = 0
                loop
                    exitwhen k > 3
                    if k == 0 then
                        set b = "HP"
                        set idex = R2I(I2R(HP_Min[i])/I2R(HP_Max[i]) * 100.)
                    elseif k == 1 then
                        set b = "MP"
                        set idex = R2I(I2R(MP_Min[i])/I2R(MP_Max[i]) * 100.)
                    elseif k == 2 then
                        set b = "DG"
                        set idex = R2I(I2R(Defense_Gauge[i])/100. * 100.)
                    elseif k == 3 then
                        set b = "XP"
                        set idex = R2I(I2R(XP_Min[i])/I2R(XP_Max[i]) * 100.)
                    endif
                    set j = 0
                    loop
                        exitwhen j > 3
                        if idex >= 25 then
                            set idex = idex - 25
                            set idex2 = 25
                        else
                            if idex < 0 then
                                set idex = 0
                            endif
                            set idex2 = idex
                            set idex = 0
                        endif
                        if j == 0 or j == 3 then
                            set idex2 = R2I(I2R(idex2)/25. * 15.) + 1
                        else
                            set idex2 = R2I(I2R(idex2)/25. * 16.) + 1
                        endif
                        set mi = MultiboardGetItem(Multiboard[10*Multistate[i]+i], k, 2 + j)
                        if j == 0 then
                            call MultiboardSetItemIcon(mi, b + "Bar\\left" + I2S(idex2) + ".blp")
                        elseif j == 3 then
                            call MultiboardSetItemIcon(mi, b + "Bar\\right" + I2S(idex2) + ".blp")
                        else
                            call MultiboardSetItemIcon(mi, b + "Bar\\mid" + I2S(idex2) + ".blp")
                        endif
                        set j = j + 1
                    endloop
                    set k = k + 1
                endloop
            elseif Multistate[i] == 1 then
                set j = 0
                loop
                    exitwhen j > 17
                    set k = 0
                    loop
                        exitwhen k > 20
                        set mi = MultiboardGetItem(Multiboard[10*Multistate[i]+i], k, j)
                        if k >= 1 and k <= 9 then
                            if j == 2 then
                                if k == 1 then
                                    call MultiboardSetItemValue(mi, ": " + Name[i])
                                elseif k == 2 then
                                    call MultiboardSetItemValue(mi, ": " + Job[i])
                                elseif k == 3 then
                                    call MultiboardSetItemValue(mi, ": " + Class[i])
                                elseif k == 4 then
                                    call MultiboardSetItemValue(mi, ": " + I2S(Fame[i]))
                                elseif k == 5 then
                                    call MultiboardSetItemValue(mi, ": " + Title[i])
                                elseif k == 6 then
                                    call MultiboardSetItemValue(mi, ": " + I2S(Level[i]))
                                endif
                            elseif j == 4 then
                                if k == 1 then
                                    call MultiboardSetItemValue(mi, ": " + I2S(HP_Min[i]) + "/" + I2S(HP_Max[i]))
                                elseif k == 2 then
                                    call MultiboardSetItemValue(mi, ": " + I2S(MP_Min[i]) + "/" + I2S(MP_Max[i]))
                                elseif k == 3 then
                                    call MultiboardSetItemValue(mi, ": " + I2S(Defense_Gauge[i]) + "/100")
                                elseif k == 4 then
                                    call MultiboardSetItemValue(mi, ": " + I2S(XP_Min[i]) + "/" + I2S(XP_Max[i]))
                                elseif k == 5 then
                                    call MultiboardSetItemValue(mi, ": " + I2S(Damage_Physic_Min[i]) + "-" + I2S(Damage_Physic_Max[i]))
                                elseif k == 6 then
                                    call MultiboardSetItemValue(mi, ": " + I2S(Damage_Magic_Min[i]) + "-" + I2S(Damage_Magic_Max[i]))
                                elseif k == 7 then
                                    call MultiboardSetItemValue(mi, ": " + I2S(R2I(Critical_Damage[i] * 100.)) + "%" )
                                elseif k == 8 then
                                    call MultiboardSetItemValue(mi, ": " + I2S(Defense_Physic[i]))
                                elseif k == 9 then
                                    call MultiboardSetItemValue(mi, ": " + I2S(Defense_Magic[i]))
                                endif
                            elseif j == 5 then
                                if k == 6 then
                                    //Fire
                                    call MultiboardSetItemValue(mi, I2S(Element_Fire[i]))
                                endif
                            elseif j == 6 then
                                if k == 1 then
                                    call MultiboardSetItemValue(mi, ": " + R2SW(Accuracy[i], 3, 1))
                                elseif k == 2 then
                                    call MultiboardSetItemValue(mi, ": " + R2SW(Critical[i], 3, 1))
                                elseif k == 3 then
                                    call MultiboardSetItemValue(mi, ": " + R2SW(Disturb[i], 3, 1))
                                elseif k == 4 then
                                    call MultiboardSetItemValue(mi, ": " + R2SW(Knockback[i], 3, 1))
                                elseif k == 6 then
                                    // Water
                                    call MultiboardSetItemValue(mi, I2S(Element_Water[i]))
                                endif
                            elseif j == 7 then
                                if k == 6 then
                                    //Earth
                                    call MultiboardSetItemValue(mi, I2S(Element_Earth[i]))
                                endif
                            elseif j == 8 then
                                if k == 1 then
                                    call MultiboardSetItemValue(mi, ": " + R2SW(Block[i], 3, 1))
                                elseif k == 2 then
                                    call MultiboardSetItemValue(mi, ": " + R2SW(Deflect[i], 3, 1))
                                elseif k == 3 then
                                    call MultiboardSetItemValue(mi, ": " + R2SW(Evasion[i], 3, 1))
                                elseif k == 6 then
                                    //Wind
                                    call MultiboardSetItemValue(mi, I2S(Element_Wind[i]))
                                endif
                            elseif j == 10 then
                                if k == 1 then
                                    call MultiboardSetItemValue(mi, ": " + I2S(Attribute_Agility[i]))
                                elseif k == 2 then
                                    call MultiboardSetItemValue(mi, ": " + I2S(Attribute_Dexterity[i]))
                                elseif k == 3 then
                                    call MultiboardSetItemValue(mi, ": " + I2S(Attribute_Endurance[i]))
                                elseif k == 4 then
                                    call MultiboardSetItemValue(mi, ": " + I2S(Attribute_Intelligence[i]))
                                elseif k == 5 then
                                    call MultiboardSetItemValue(mi, ": " + I2S(Attribute_Luck[i]))
                                elseif k == 6 then
                                    call MultiboardSetItemValue(mi, ": " + I2S(Attribute_Magic[i]))
                                elseif k == 7 then
                                    call MultiboardSetItemValue(mi, ": " + I2S(Attribute_Strength[i]))
                                elseif k == 8 then
                                    call MultiboardSetItemValue(mi, ": " + I2S(Attribute_Vitality[i]))
                                endif
                            endif
                        elseif k >= 12 and k <= 19 then
                            if j >= 2 and j <= 6 then
                                // PT bar
                                /*if j == 6 then
                                    call MultiboardSetItemWidth(mi, 0.02)
                                else
                                    call MultiboardSetItemWidth(mi, 0.01)
                                endif
                                if j <= 17 then
                                    call MultiboardSetItemStyle(mi, false, true)
                                endif*/
                            elseif j == 7 then
                                if k == 12 then
                                    call MultiboardSetItemValue(mi, I2S(Mastery_Pt_Current_Melee[i]) + "/" + I2S(Mastery_Pt_Target_Melee[i]))
                                elseif k == 13 then
                                    call MultiboardSetItemValue(mi, I2S(Mastery_Pt_Current_Range[i]) + "/" + I2S(Mastery_Pt_Target_Range[i]))
                                elseif k == 14 then
                                    call MultiboardSetItemValue(mi, I2S(Mastery_Pt_Current_Magic[i]) + "/" + I2S(Mastery_Pt_Target_Magic[i]))
                                elseif k == 15 then
                                    call MultiboardSetItemValue(mi, I2S(Mastery_Pt_Current_Shield[i]) + "/" + I2S(Mastery_Pt_Target_Shield[i]))
                                elseif k == 16 then
                                    call MultiboardSetItemValue(mi, I2S(Mastery_Pt_Current_Crafting[i]) + "/" + I2S(Mastery_Pt_Target_Crafting[i]))
                                elseif k == 17 then
                                    call MultiboardSetItemValue(mi, I2S(Mastery_Pt_Current_Minion[i]) + "/" + I2S(Mastery_Pt_Target_Minion[i]))
                                endif
                            elseif j == 8 then
                                if k == 12 then
                                    call MultiboardSetItemValue(mi, "|CFFFFED00Ability 1|R")
                                elseif k == 13 then
                                    call MultiboardSetItemValue(mi, "|CFFFFED00Ability 2|R")
                                endif
                            elseif j >= 9 and j <= 13 then
                                // Ability PT bar
                                /*call MultiboardSetItemWidth(mi, 0.01)
                                call MultiboardSetItemStyle(mi, false, true)*/
                            endif
                        endif
                        set k = k + 1
                    endloop
                    set j = j + 1
                endloop
            endif
            set i = i + 1
        endloop
        set mi = null
        
    endfunction
    
    private function checkMin takes nothing returns nothing
        
        local integer i = 0
        local integer j
        local integer k
        local boolean b
        local multiboarditem mi
        
        // 0 normal
        // 1 arcane statistic
        // 2 minimized
        loop
            exitwhen i > 9
            if IsMultiboardDisplayed(Multiboard[10*Multistate[i]+i]) then
                if IsMultiboardMinimized(Multiboard[10*Multistate[i]+i]) and Multistate[i] != 2 then
                    call BJDebugMsg(I2S(Multistate[i]))
                    set Multistate[i] = Multistate[i] + 1
                    call BJDebugMsg(I2S(Multistate[i]))
                    if GetLocalPlayer() == Player(i) then
                        call MultiboardDisplay(Multiboard[10*(Multistate[i]-1)+i], false)
                        call MultiboardDisplay(Multiboard[10*Multistate[i]+i], true)
                    endif
                    if Multistate[i] != 2 then
                        call MultiboardSetTitleText(Multiboard[10*Multistate[i]+i], "|CFFFFBC00ARCANE STATISTIC|R")
                        if GetLocalPlayer() == Player(i) then
                            call MultiboardMinimize(Multiboard[10*Multistate[i]+i], false)
                        endif
                    else
                        call MultiboardSetTitleText(Multiboard[10*Multistate[i]+i], "")
                    endif
                elseif not IsMultiboardMinimized(Multiboard[10*Multistate[i]+i]) and Multistate[i] == 2 then
                    set Multistate[i] = 0
                    if GetLocalPlayer() == Player(i) then
                        call MultiboardDisplay(Multiboard[10*(Multistate[i]-1)+i], false)
                        call MultiboardDisplay(Multiboard[10*Multistate[i]+i], true)
                    endif
                endif
            endif
        set i = i + 1
        endloop
        
    endfunction
    
    private function create takes nothing returns nothing
        
        local integer i = 0
        local integer j
        local integer k
        local multiboarditem mi
        
        loop
            exitwhen i > 9
            set Multiboard[i] = CreateMultiboard()
            set Multiboard[10 + i] = CreateMultiboard()
            set Multiboard[20 + i] = Multiboard[10 + i]
            call MultiboardMinimize(Multiboard[i], true)
            call MultiboardMinimize(Multiboard[10+i], true)
            call MultiboardSetColumnCount(Multiboard[i], 6)
            call MultiboardSetRowCount(Multiboard[i], 4)
            call MultiboardSetColumnCount(Multiboard[10 + i], 18)
            call MultiboardSetRowCount(Multiboard[10 + i], 21)
            call MultiboardSetTitleText(Multiboard[i], "|CFFFFBC00" + GetPlayerName(Player(i)) + "|R")
            call MultiboardSetTitleText(Multiboard[10+i], "|CFFFFBC00ARCANE STATISTIC|R")
            call MultiboardDisplay(Multiboard[i], false)
            call MultiboardDisplay(Multiboard[10+i], false)
            set j = 0
            loop
                exitwhen j > 5
                set k = 0
                loop
                    exitwhen k > 3
                    set mi = MultiboardGetItem(Multiboard[i], k, j)
                    if j == 0 then
                        call MultiboardSetItemStyle(mi, true, false)
                        call MultiboardSetItemWidth(mi, 0.015)
                        if k == 0 then
                            call MultiboardSetItemValue(mi, "|CFFFFBC00HP|R")
                        elseif k == 1 then
                            call MultiboardSetItemValue(mi, "|CFFFFBC00MP|R")
                        elseif k == 2 then
                            call MultiboardSetItemValue(mi, "|CFFFFBC00DG|R")
                        elseif k == 3 then
                            call MultiboardSetItemValue(mi, "|CFFFFBC00XP|R")
                        endif
                    elseif j == 1 then
                        call MultiboardSetItemStyle(mi, false, false)
                        call MultiboardSetItemWidth(mi, 0.01)
                    elseif j > 1 then
                        call MultiboardSetItemStyle(mi, false, true)
                        call MultiboardSetItemWidth(mi, 0.01)
                    endif
                    call MultiboardReleaseItem(mi)
                    set k = k + 1
                endloop
                set j = j + 1
            endloop
            set j = 0
            loop
                exitwhen j > 17
                set k = 0
                loop
                    exitwhen k > 20
                    set mi = MultiboardGetItem(Multiboard[10+i], k, j)
                    if k == 0 then
                        call MultiboardSetItemStyle(mi, true, false)
                        if j == 0 then
                            call MultiboardSetItemWidth(mi, 0.035)
                        elseif j == 1 then
                            call MultiboardSetItemWidth(mi, 0.21)
                            call MultiboardSetItemValue(mi, "|CFFFFBC00IDENTITIES|R")
                        elseif j == 2 then
                            call MultiboardSetItemWidth(mi, 0.19)
                            call MultiboardSetItemValue(mi, "|CFFFFBC00COMBATIVES|R")
                        elseif j == 3 then
                            call MultiboardSetItemWidth(mi, 0.04)
                            call MultiboardSetItemValue(mi, "|CFFFFBC00ATTRIBUTES|R")
                        else
                            call MultiboardSetItemWidth(mi, 0.)
                        endif
                    elseif k >= 1 and k <= 9 then
                        call MultiboardSetItemStyle(mi, true, false)
                        if j == 0 then
                            call MultiboardSetItemWidth(mi, 0.005)
                        elseif j == 1 then
                            call MultiboardSetItemWidth(mi, 0.04)
                            if k == 1 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Name|R")
                            elseif k == 2 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Job|R")
                            elseif k == 3 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Class|R")
                            elseif k == 4 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Fame|R")
                            elseif k == 5 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Title|R")
                            elseif k == 6 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Level|R")
                            endif
                        elseif j == 2 then
                            call MultiboardSetItemWidth(mi, 0.07)
                            if k == 1 then
                                call MultiboardSetItemValue(mi, ": Dalvengyr")
                            elseif k == 2 then
                                call MultiboardSetItemValue(mi, ": Combatant")
                            elseif k == 3 then
                                call MultiboardSetItemValue(mi, ": Warlord")
                            elseif k == 4 then
                                call MultiboardSetItemValue(mi, ": 239035")
                            elseif k == 5 then
                                call MultiboardSetItemValue(mi, ": Sergeant")
                            elseif k == 6 then
                                call MultiboardSetItemValue(mi, ": 75")
                            endif
                        elseif j == 3 then
                            call MultiboardSetItemWidth(mi, 0.07)
                            if k == 1 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Health Point|R")
                            elseif k == 2 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Mana Point|R")
                            elseif k == 3 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Def. Gauge|R")
                            elseif k == 4 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Experience|R")
                            elseif k == 5 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Physic Damage|R")
                            elseif k == 6 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Magic Damage|R")
                            elseif k == 7 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Crit. Damage|R")
                            elseif k == 8 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Physic Def.|R")
                            elseif k == 9 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Magic Def.|R")
                            endif
                        elseif j == 4 then
                            call MultiboardSetItemWidth(mi, 0.07)
                            if k == 1 then
                                call MultiboardSetItemValue(mi, ": 13400/28525")
                            elseif k == 2 then
                                call MultiboardSetItemValue(mi, ": 1400/1400")
                            elseif k == 3 then
                                call MultiboardSetItemValue(mi, ": 100/100")
                            elseif k == 4 then
                                call MultiboardSetItemValue(mi, ": 128/136288")
                            elseif k == 5 then
                                call MultiboardSetItemValue(mi, ": 1777-1933")
                            elseif k == 6 then
                                call MultiboardSetItemWidth(mi, 0.08)
                                call MultiboardSetItemValue(mi, ": 0-0")
                            elseif k == 7 then
                                call MultiboardSetItemValue(mi, ": 435%")
                            elseif k == 8 then
                                call MultiboardSetItemValue(mi, ": 551")
                            elseif k == 9 then
                                call MultiboardSetItemValue(mi, ": 791")
                            endif
                        elseif j == 5 then
                            call MultiboardSetItemWidth(mi, 0.05)
                            if k == 1 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Accuracy|R")
                            elseif k == 2 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Critical|R")
                            elseif k == 3 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Disturb|R")
                            elseif k == 4 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Knockback|R")
                            elseif k == 6 then
                                //Fire
                                call MultiboardSetItemWidth(mi, 0.03)
                                call MultiboardSetItemValue(mi, "555")
                                call MultiboardSetItemStyle(mi, true, true)
                            endif
                        elseif j == 6 then
                            call MultiboardSetItemWidth(mi, 0.03)
                            if k == 1 then
                                call MultiboardSetItemValue(mi, ": 1.0")
                            elseif k == 2 then
                                call MultiboardSetItemValue(mi, ": 1.0")
                            elseif k == 3 then
                                call MultiboardSetItemValue(mi, ": 2.0")
                            elseif k == 4 then
                                call MultiboardSetItemValue(mi, ": 0.0")
                            elseif k == 6 then
                                // Water
                                call MultiboardSetItemWidth(mi, 0.03)
                                call MultiboardSetItemValue(mi, "555")
                                call MultiboardSetItemStyle(mi, true, true)
                            endif
                        elseif j == 7 then
                            call MultiboardSetItemWidth(mi, 0.05)
                            if k == 1 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Block|R")
                            elseif k == 2 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Deflect|R")
                            elseif k == 3 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Evasion|R")
                            elseif k == 6 then
                                //Earth
                                call MultiboardSetItemWidth(mi, 0.03)
                                call MultiboardSetItemValue(mi, "555")
                                call MultiboardSetItemStyle(mi, true, true)
                            endif
                        elseif j == 8 then
                            call MultiboardSetItemWidth(mi, 0.03)
                            if k == 1 then
                                call MultiboardSetItemValue(mi, ": 0.0")
                            elseif k == 2 then
                                call MultiboardSetItemValue(mi, ": 0.0")
                            elseif k == 3 then
                                call MultiboardSetItemValue(mi, ": 4.0")
                            elseif k == 6 then
                                //Wind
                                call MultiboardSetItemWidth(mi, 0.06)
                                call MultiboardSetItemValue(mi, "555")
                                call MultiboardSetItemStyle(mi, true, true)
                            endif
                        elseif j == 9 then
                            call MultiboardSetItemWidth(mi, 0.06)
                            if k == 1 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Agility|R")
                            elseif k == 2 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Dexterity|R")
                            elseif k == 3 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Endurance|R")
                            elseif k == 4 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Intelligence|R")
                            elseif k == 5 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Luck|R")
                            elseif k == 6 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Magic|R")
                            elseif k == 7 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Strength|R")
                            elseif k == 8 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Vitality|R")
                            endif
                        elseif j == 10 then
                            call MultiboardSetItemWidth(mi, 0.03)
                            if k == 1 then
                                call MultiboardSetItemValue(mi, ": 99")
                            elseif k == 2 then
                                call MultiboardSetItemValue(mi, ": 99")
                            elseif k == 3 then
                                call MultiboardSetItemValue(mi, ": 99")
                            elseif k == 4 then
                                call MultiboardSetItemValue(mi, ": 99")
                            elseif k == 5 then
                                call MultiboardSetItemValue(mi, ": 99")
                            elseif k == 6 then
                                call MultiboardSetItemValue(mi, ": 99")
                            elseif k == 7 then
                                call MultiboardSetItemValue(mi, ": 99")
                            elseif k == 8 then
                                call MultiboardSetItemValue(mi, ": 99")
                            endif
                        else
                            call MultiboardSetItemWidth(mi, 0.0)
                        endif
                    elseif k == 10 then
                        call MultiboardSetItemStyle(mi, false, false)
                        call MultiboardSetItemWidth(mi, 0.0)
                    elseif k == 11 then
                        call MultiboardSetItemStyle(mi, true, false)
                        if j == 0 then
                            call MultiboardSetItemWidth(mi, 0.05)
                        elseif j == 1 then
                            call MultiboardSetItemWidth(mi, 0.25)
                            call MultiboardSetItemValue(mi, "|CFFFFBC00SKILLS MASTERY|R")
                        elseif j == 2 then
                            call MultiboardSetItemWidth(mi, 0.20)
                            call MultiboardSetItemValue(mi, "|CFFFFBC00ABILITIES MASTERY|R")
                        else
                            call MultiboardSetItemWidth(mi, 0.0)
                        endif
                    elseif k >= 12 and k <= 19 then
                        call MultiboardSetItemStyle(mi, true, false)
                        if j == 0 then
                            call MultiboardSetItemWidth(mi, 0.02)
                        elseif j == 1 then
                            call MultiboardSetItemWidth(mi, 0.04)
                            if k == 12 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Melee|R")
                            elseif k == 13 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Range|R")
                            elseif k == 14 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Magic|R")
                            elseif k == 15 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Shield|R")
                            elseif k == 16 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Crafting|R")
                            elseif k == 17 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Taming|R")
                            endif
                        elseif j >= 2 and j <= 6 then
                            if j == 6 then
                                call MultiboardSetItemWidth(mi, 0.02)
                            else
                                call MultiboardSetItemWidth(mi, 0.01)
                            endif
                            if k <= 17 then
                                call MultiboardSetItemStyle(mi, false, true)
                            endif
                        elseif j == 7 then
                            call MultiboardSetItemWidth(mi, 0.04)
                            if k == 12 then
                                call MultiboardSetItemValue(mi, "35/99")
                            elseif k == 13 then
                                call MultiboardSetItemValue(mi, "36/99")
                            elseif k == 14 then
                                call MultiboardSetItemValue(mi, "37/99")
                            elseif k == 15 then
                                call MultiboardSetItemValue(mi, "38/99")
                            elseif k == 16 then
                                call MultiboardSetItemValue(mi, "39/99")
                            elseif k == 17 then
                                call MultiboardSetItemValue(mi, "40/99")
                            endif
                        elseif j == 8 then
                            call MultiboardSetItemWidth(mi, 0.04)
                            if k == 12 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Ability 1|R")
                            elseif k == 13 then
                                call MultiboardSetItemValue(mi, "|CFFFFED00Ability 2|R")
                            endif
                        elseif j >= 9 and j <= 13 then
                            call MultiboardSetItemWidth(mi, 0.01)
                            call MultiboardSetItemStyle(mi, false, true)
                        endif
                    else
                        call MultiboardSetItemWidth(mi, 0.0)
                        call MultiboardSetItemStyle(mi, false, false)
                    endif
                    call MultiboardReleaseItem(mi)
                    set k = k + 1
                endloop
                set j = j + 1
            endloop
            set i = i + 1
        endloop
        
    endfunction
    
    private function ini takes nothing returns nothing
        local integer i = 0
        
        loop
            exitwhen i > 9
            set Multistate[i] = 0
            set i = i + 1
        endloop
        call TimerStart(CreateTimer(), 0., false, function create)
        call TimerStart(CreateTimer(), 0.1, true, function update)
        call TimerStart(CreateTimer(), 0., true, function checkMin)
    endfunction
    
endlibrary
this is the only function that has relation with the multiboard
JASS:
        if b == btn[id].button[12] then
            set MainCharacter[id] = CreateUnit(p, 'h000', -20546.04, -22201.10, 270.)
            set TabCharacter[id] = CreateUnit(p, 'h001', -20546.04, -22201.10, 270.)
            set InventoryUnit[id] = CreateUnit(p, 'H004', 0., 0., 270.)
            call RegisterInventoryUnit(MainCharacter[id], true, true)
            call SetUnitScale(TabCharacter[id], 0., 0., 0.)
            call initStatus(id)
            set Multistate[id] = 0
            if GetLocalPlayer() == p then
                call MultiboardDisplay(Multiboard[id], true)
                call MultiboardMinimize(Multiboard[id], false)
                call ClearSelection()
                call SelectUnit(MainCharacter[id], true)
                call SelectUnit(TabCharacter[id], true)
                call SetCameraTargetController(MainCharacter[id], 0., 0., false)
                call FogEnable(false)
                call FogMaskEnable(false)
            endif
        endif
as you see there is no local action except display/undisplaying.

EDIT:
I suspect now the problem is on update function

believe it or not but I think this is (perhaps) unfixable because of this condition if IsMultiboardMinimized(Multiboard[Multistate[i]]). That condition automatically makes actions run locally, that's a shitty bug of wc3. But i'm still haven't surrender yet, still trying some possible tricks.. :p
 
Last edited by a moderator:
Level 26
Joined
Aug 18, 2009
Messages
4,097
It's perfectly normal, not a bug, since the individual client can have its board displayed or not. You were hinted above that MultiboardGetItem spouts a new multiboarditem object, an agent, which should be avoided to be done inside a local block, which you have due to your Multistate asynchronity.

I cannot confirm the rumored string table desync either. The only scenario where this would make sense is if it broadcasts indexes of this table and other players find it empty or start different chat events based on that.

@Troll-Brain: While there can be language-local strings, that's not the same as if you were not to expand the table evenly at all.

@Ceday: Setting s to the value of effectPath does not change a thing. The string behind effectPath is already allocated when entering the function.
 

Ralle

Owner
Level 79
Joined
Oct 6, 2004
Messages
10,184
Guys, in cases where you have more to add to the conversation but nobody replied yet, please use the
edit.gif
button.
that's a true story bro :p each time I tried to show the value of dat variable, player 2 is disconnected 3 seconds later, it was because I didn't initialize the value correctly (perhaps) but I have fixed it, but still dunno why player 2 keeps disconnected :/

uhm, I'm not sure where is the last version of it :p I have more than 5 versions here, all is not working :p off_topic: I have tested and tried to fix this for more than 30 times and wasting my holiday with disappointing result :(

Oh wait a second! I think I know another possible cause here..

please, someone merge this.

I have an emergency question, will showing diifferent multiboards for each player causing desync?

I'm quite sure that having a different string table for each players won't desync.
You forget that wc3 is not only in english, it's most likely that players will already have different strings.

And again you don't need GetLocalPlayer() to have local stuff, a perfect example is with camera.

I'm not sure you can use MultiBoardSet... in a local block without any desync, minimize it or not should be fine though, since players can already do that themselves.
So instead of use MultiboardSet in a local block, do it for each players but with a different value.

Thank you.
 
Level 26
Joined
Aug 18, 2009
Messages
4,097
JASS:
    private function checkMin takes nothing returns nothing
       
        local integer i = 0
        local integer j
        local integer k
        local boolean b
        local multiboarditem mi
       
        // 0 normal
        // 1 arcane statistic
        // 2 minimized
        loop
            exitwhen i > 9
            if IsMultiboardDisplayed(Multiboard[10*Multistate[i]+i]) then
                if IsMultiboardMinimized(Multiboard[10*Multistate[i]+i]) and Multistate[i] != 2 then
                    call BJDebugMsg(I2S(Multistate[i]))
                    set Multistate[i] = Multistate[i] + 1
                    call BJDebugMsg(I2S(Multistate[i]))
                    if GetLocalPlayer() == Player(i) then
                        call MultiboardDisplay(Multiboard[10*(Multistate[i]-1)+i], false)
                        call MultiboardDisplay(Multiboard[10*Multistate[i]+i], true)
                    endif
                    if Multistate[i] != 2 then
                        call MultiboardSetTitleText(Multiboard[10*Multistate[i]+i], "|CFFFFBC00ARCANE STATISTIC|R")
                        if GetLocalPlayer() == Player(i) then
                            call MultiboardMinimize(Multiboard[10*Multistate[i]+i], false)
                        endif
                    else
                        call MultiboardSetTitleText(Multiboard[10*Multistate[i]+i], "")
                    endif
                elseif not IsMultiboardMinimized(Multiboard[10*Multistate[i]+i]) and Multistate[i] == 2 then
                    set Multistate[i] = 0
                    if GetLocalPlayer() == Player(i) then
                        call MultiboardDisplay(Multiboard[10*(Multistate[i]-1)+i], false)
                        call MultiboardDisplay(Multiboard[10*Multistate[i]+i], true)
                    endif
                endif
            endif
        set i = i + 1
        endloop
       
    endfunction

IsMultiboardDisplayed and IsMultiboardMinimized span a local block -> set Multistate[i] = Multistate[i] + 1 -> Multistate becomes async.

JASS:
    private function update takes nothing returns nothing
       
        local integer i = 0
        local integer j
        local integer idex
        local integer idex2
        local multiboarditem mi
        local integer k
        local string b
       
        loop
            exitwhen i > 9
            if Multistate[i] == 0 then
                set k = 0
                loop
                    exitwhen k > 3
                    if k == 0 then
                        set b = "HP"
                        set idex = R2I(I2R(HP_Min[i])/I2R(HP_Max[i]) * 100.)
                    elseif k == 1 then
                        set b = "MP"
                        set idex = R2I(I2R(MP_Min[i])/I2R(MP_Max[i]) * 100.)
                    elseif k == 2 then
                        set b = "DG"
                        set idex = R2I(I2R(Defense_Gauge[i])/100. * 100.)
                    elseif k == 3 then
                        set b = "XP"
                        set idex = R2I(I2R(XP_Min[i])/I2R(XP_Max[i]) * 100.)
                    endif
                    set j = 0
                    loop
                        exitwhen j > 3
                        if idex >= 25 then
                            set idex = idex - 25
                            set idex2 = 25
                        else
                            if idex < 0 then
                                set idex = 0
                            endif
                            set idex2 = idex
                            set idex = 0
                        endif
                        if j == 0 or j == 3 then
                            set idex2 = R2I(I2R(idex2)/25. * 15.) + 1
                        else
                            set idex2 = R2I(I2R(idex2)/25. * 16.) + 1
                        endif
                        set mi = MultiboardGetItem(Multiboard[10*Multistate[i]+i], k, 2 + j)
                        if j == 0 then
                            call MultiboardSetItemIcon(mi, b + "Bar\\left" + I2S(idex2) + ".blp")
                        elseif j == 3 then
                            call MultiboardSetItemIcon(mi, b + "Bar\\right" + I2S(idex2) + ".blp")
                        else
                            call MultiboardSetItemIcon(mi, b + "Bar\\mid" + I2S(idex2) + ".blp")
                        endif
                        set j = j + 1
                    endloop
                    set k = k + 1
                endloop
...

JASS:
            if Multistate[i] == 0 then
-> async -> set mi = MultiboardGetItem(Multiboard[10*Multistate[i]+i], k, 2 + j) -> desync

Also what is up with the absurdly large loops and branching? Can you not summarize it more neatly?
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
It's not like we have not already warned you about local stuff without any use of GetLocalPlayer, at least i did.
But well, tell us what you want to do exactly and we can give you a pseudo code (or even a vjass code if someone is motivated enough)
 
You just need to get:
JASS:
set mi = MultiboardGetItem(Multiboard[10*Multistate[i]+i], k, 2 + j)
Outside of the "if Multistate == 0" block. And you have to make the array index not depend on the Multistate (or else it may grab different items for different players). I don't know if that'll cause a desync, but it would be bad programming.

But of course, that doesn't really work in your case, since it is supposed to be in a loop and stuff. So you may need to find a different way to evaluate your code.

Anyway, checking if a multiboard is displayed will always be asynchronous if you are using GetLocalPlayer() to show/hide the multiboard to different players. Just don't bother checking "Multistate", even if you're trying to save performance. There are always other safer and cleaner options. Technically, it is possible to assign "multistate" and sync it between players, but that will have delays depending on latency, so it is a worst-case scenario option.
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
Then you should just handle 2 multiboards (not 2*number of players) and display/hide/minimize them locally.

As long each player will always have the same number of multiboard items and in the same way at the very same time but with different values.
And instead of using arrays for multiboard items, use a simple global but with a different value for each player.
EDIT : i'm talking about what is used for filling the multiboard, such as HP_Min

As it has been said i suppose it is safe to that this way.
And yes just don't care if the multiboard is hidden or not, update it regardless that.

If it's not clear i can give a simple example.
 
Status
Not open for further replies.
Top