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

[JASS] GetLocalPlayer() Desync

Status
Not open for further replies.
Level 11
Joined
Sep 14, 2009
Messages
284
Hi. So last night I tested my map with a friend, who was disconnected during gameplay, and I learned of the GetLocalPlayer() desync problem.

So I rewrote the scripts that uses GetLocalPlayer() and now my script looks like below.
My question is will this cuase desyncs? And how do I learn to identify what causes desyncs so I can solve this by myself?

JASS:
function DamageBasicAttack_Conditions takes nothing returns boolean
    return udg_DamageEventSource != udg_DamageEventTarget and udg_AbilityMagical == false and udg_AbilityPhysical == false and GetUnitState(udg_DamageEventTarget, UNIT_STATE_LIFE) > 0.405 and GetUnitAbilityLevel(udg_DamageEventTarget, 'A001') < 1
endfunction

function DamageBasicAttack_Actions takes nothing returns nothing
    local real dAmount = udg_DamageEventAmount
    local unit dSource = udg_DamageEventSource
    local unit dTarget = udg_DamageEventTarget
    local real angle = GetRandomReal(70, 110)
    local texttag t = null
    local string s = I2S(R2I(dAmount))
    if GetLocalPlayer() != GetOwningPlayer(dSource) then
        set s = ""
    endif
    if s != "" then
        set t = CreateTextTag()
        call SetTextTagText(t, "|cffDC4522"+s+"|r", 0.022 + ((dAmount / 500) * (0.023 / 10)))
        call SetTextTagPos(t, GetUnitX(dTarget), GetUnitY(dTarget), 0)
        call SetTextTagVelocity(t, 0.11*Cos(angle*bj_DEGTORAD), 0.11*Sin(angle*bj_DEGTORAD))
        call SetTextTagVisibility(t, true)
        call SetTextTagFadepoint(t, 1.25)
        call SetTextTagLifespan(t, 2)
        call SetTextTagPermanent(t, false)
        set t = null
    endif
    set dSource = null
    set dTarget = null
endfunction

//===========================================================================
function InitTrig_DamageBasicAttack takes nothing returns nothing
    set gg_trg_DamageBasicAttack = CreateTrigger()
    call TriggerRegisterVariableEvent(gg_trg_DamageBasicAttack, "udg_DamageEvent", EQUAL, 1.0)
    call TriggerAddCondition(gg_trg_DamageBasicAttack, Condition(function DamageBasicAttack_Conditions))
    call TriggerAddAction(gg_trg_DamageBasicAttack, function DamageBasicAttack_Actions)
endfunction
 
Level 11
Joined
Dec 19, 2012
Messages
411
I believe it will still cause desync :
JASS:
    local string s = I2S(R2I(dAmount))
    if GetLocalPlayer() != GetOwningPlayer(dSource) then
        set s = ""
    endif
    if s != "" then //since different player have different value of s, warcraft 3 found out
                       //it not sync, desync will occurs
      ...

All you need to do is remove the if s != "" then condition block, and will be working fine.
 
Level 3
Joined
Dec 14, 2014
Messages
16
JASS:
function DamageBasicAttack_Actions takes nothing returns nothing
    local real dAmount = udg_DamageEventAmount
    local unit dSource = udg_DamageEventSource
    local unit dTarget = udg_DamageEventTarget
    local real angle = GetRandomReal(70, 110)
    local texttag t = null
    local string s = I2S(R2I(dAmount))
    set t = CreateTextTag()
    call SetTextTagText(t, "|cffDC4522"+s+"|r", 0.022 + ((dAmount / 500) * (0.023 / 10)))
    call SetTextTagPos(t, GetUnitX(dTarget), GetUnitY(dTarget), 0)
    call SetTextTagVelocity(t, 0.11*Cos(angle*bj_DEGTORAD), 0.11*Sin(angle*bj_DEGTORAD))
    call SetTextTagFadepoint(t, 1.25)
    call SetTextTagLifespan(t, 2)
    call SetTextTagPermanent(t, false)
    call SetTextTagVisibility(t, GetLocalPlayer() == GetOwningPlayer(dSource))
    set t = null
    set dSource = null
    set dTarget = null
endfunction
 
How do I learn to identify what causes desyncs so I can solve this by myself?

Mainly testing, but the logic is something like this: Clientside information causes no decyncs, while serverside stuff causes desyncs. Clientside is mainly information no other players need to know for their game to function, like graphics rendering, text on the screen, multiboards, ect. So mainly visuals. While Serverside is what their games DO need to know, like the value of variables, object information, ect. Desyncs is when two different computers have different information on what is going on in game. Wc3 is programmed in such a way that it crashes when it detects a desync.
 

Zwiebelchen

Hosted Project GR
Level 35
Joined
Sep 17, 2009
Messages
7,236
I believe it will still cause desync :
JASS:
    local string s = I2S(R2I(dAmount))
    if GetLocalPlayer() != GetOwningPlayer(dSource) then
        set s = ""
    endif
    if s != "" then //since different player have different value of s, warcraft 3 found out
                       //it not sync, desync will occurs
      ...

All you need to do is remove the if s != "" then condition block, and will be working fine.
That would normally be a problem, yes, but texttags are kind of the exception here, as they aren't synced anyway.
 
Level 11
Joined
Dec 19, 2012
Messages
411
strings aren't objects, they are just being cached in order to improve perfomance, nothing else. different players may have different wc3 language and/or map language, do you think they constantly get desynced?

I think you've misunderstand my question. What i meant is creating string through trigger, what you said are the string which stored (not created through trigger) in player's computer which is not even access through internet. Anywhere, i did a quick test :
JASS:
    local string s = "A"
	if GetLocalPlayer() == Player(0) then
	  set s = "B"
	endif
	if s == "A" then
      call BJDebugMsg("s == A")
	endif
	call BJDebugMsg("s : " + s)

There is no desync occurs and each player received different value of string s. So string is not sync during comparing (i would think it would also apply to integer/real)
 

Dr Super Good

Spell Reviewer
Level 63
Joined
Jan 18, 2005
Messages
27,192
strings aren't objects, they are just being cached in order to improve perfomance, nothing else. different players may have different wc3 language and/or map language, do you think they constantly get desynced?
Except those are not trigger strings. Strings are JASS objects, probably completely different from the internal C++ strings used by the game engine.
Apparently locally creating a unique string causes an out of sync error.
 

Zwiebelchen

Hosted Project GR
Level 35
Joined
Sep 17, 2009
Messages
7,236
I see. So how sound i go about to solve this then?
Pretty simple: you define both strings globally (so that they both got written into the string table), then you just change the local string to the value you need:
JASS:
local string EMPTY = ""
local string dmg = "4775"
if GetLocalPlayer() == Player(0) then
    set dmg = EMPTY
endif
//dostuff
 

Dr Super Good

Spell Reviewer
Level 63
Joined
Jan 18, 2005
Messages
27,192
Be aware that string concatenation (adding two strings together) will create a new unique string. You do this for your colour code (why?).

Why not use the following native to colour text tags?
JASS:
native SetTextTagColor takes texttag t,integer red,integer green,integer blue,integer alpha returns nothing
This would reduce the number and length of unique strings created since they will no longer contain format codes.
 
Apparently locally creating a unique string causes an out of sync error.

I think I helped proliferate this rumor a bit, but it isn't necessarily true. It doesn't cause a disconnection (not as far as my testing went).

The mixup/source of the issue might be related to how we used to use S2I before StringHash existed. Before hashtables, it was pretty important to keep the string table in sync if you hashed strings by their table ID. It probably doesn't matter much anymore (I can't prove that it doesn't matter, but basic testing shows that it won't desync).
 

Zwiebelchen

Hosted Project GR
Level 35
Joined
Sep 17, 2009
Messages
7,236
I think I helped proliferate this rumor a bit, but it isn't necessarily true. It doesn't cause a disconnection (not as far as my testing went).

The mixup/source of the issue might be related to how we used to use S2I before StringHash existed. Before hashtables, it was pretty important to keep the string table in sync if you hashed strings by their table ID. It probably doesn't matter much anymore (I can't prove that it doesn't matter, but basic testing shows that it won't desync).
It does. I don't know why and it's one of those magic issues that just happen in WC3 for some odd reason or another (like the corrupted tile desync I had in the past*) I actually had desync issues in the past because of not globally initialized strings.
It certainly doesn't desync instantly (like actual asynchronous handle data does), but it leaves a certain vulnerability lingering in your game.


*this was some really weird shit. When players stepped on a certain tile they randomly desynced. After removing and readding the tile from the tileset, the desync was gone.
 

Zwiebelchen

Hosted Project GR
Level 35
Joined
Sep 17, 2009
Messages
7,236
Actually it seems Neco's solution seems to be working just fine. Just tested with a friend and I can confirm it. Problem solved. Thanks everyone.
If you do it that way, remember that the floating texts of ALL units, regardless of visibility state will go into the 100 tag limit (so if you have 10 players, each player can only have on average 10 tags visible at the same time).
If that is no problem, no reason not to use Neco's solution. If it is, better use proper string definition and create locally.
 
Level 19
Joined
Dec 12, 2010
Messages
2,069
It does. I don't know why and it's one of those magic issues that just happen in WC3 for some odd reason or another (like the corrupted tile desync I had in the past*) I actually had desync issues in the past because of not globally initialized strings.
It certainly doesn't desync instantly (like actual asynchronous handle data does), but it leaves a certain vulnerability lingering in your game.


*this was some really weird shit. When players stepped on a certain tile they randomly desynced. After removing and readding the tile from the tileset, the desync was gone.

I've been using async strings in LoD for years now. No desync ever was caused by this technic. It's archaic mechanic, as Purge&Fire said.

I repeat, the only reason caching is exists, it's how C handles strings.
http://stackoverflow.com/questions/16636363/string-caching-memory-optimization-and-re-use
more info can be found with "C strings cache" queries
 
Level 11
Joined
Sep 14, 2009
Messages
284
If you do it that way, remember that the floating texts of ALL units, regardless of visibility state will go into the 100 tag limit (so if you have 10 players, each player can only have on average 10 tags visible at the same time).
If that is no problem, no reason not to use Neco's solution. If it is, better use proper string definition and create locally.

Yea I know. My map only has 6 players and each player will only control 1 unit, in addition neutral hostile is filtered out in the conditions, so I don't think it will be a problem.

Anyways what happens when you reach the 100-tag limit? Will it cause desyncs or will it simply not display more text tags?
 
Level 11
Joined
Dec 19, 2012
Messages
411
CreateTextTag will return 0, basically equal to null, no tt will be created

You're half right. When the texttag limit reaches, the handle id of texttag will becomes 0. But 0 is consider as texttag handle id as well (it starts from 99 and decreases to 0), so if you continue to create more texttag, the last texttag (which is the 0 handle id texttag/100th texttag), will keep getting overwritten.
 
Status
Not open for further replies.
Top