• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

desync problems (lua)

Status
Not open for further replies.
Level 3
Joined
Mar 7, 2020
Messages
16
hi,

i have desync problems with one of my custom resurrection abilitys. If any player uses this ability, everyone gets kicket out (no error messege) to the score board. This ability works fine in single player. The desync happen on cast.
My lua code with some comments, is below.

Thanks in advance

JASS:
    function ReviveClass:Execute(info)
        //get death units
        local deathUnits = UnitClass.GetDeathInRange(self.radius, info.targetLoc)
        local count = 0
        for _, v in pairs(deathUnits) do
            local loc = GetUnitLoc(v)
            local id = GetUnitTypeId(v)
            local typeObj = UnitTypeClass.UNITS[GetUnitTypeId(v)] //table with information if its a hero, building and much more
            local orderble = typeObj:CanGetOrder() //simple boolean check if its a hero, building ...
            //if its not a building ... create a new one (same type) and delete the corpse
            if orderble then
                //UnitClass.NewUnit ... Create a unit and store in a table with some information
                //Im using this a lot, so it shouldn be the problem
                local unitObj = UnitClass.NewUnit(units[info.unit],loc,id)
                RemoveUnit(v)
                RemoveLocation(loc)
                count = count + 1
                //resurrect max 2 units
                if count >= self.max then break end //max=2
            end
        end
        //create an effect at location for 4.5 sec
        CreateEffectLoc(4.5,info.targetLoc,"Abilities\\Spells\\Human\\Resurrect\\ResurrectCaster.mdl")
    end

    UnitClass.GetDeathInRange = function(radius, loc)
        local death = {}
        local g = GetUnitsInRangeOfLocAll(radius, loc)
        local u = FirstOfGroup(g)
        while u ~= nil do
            if IsUnitAliveBJ(u) == false then
                death[u]=u
            end
            GroupRemoveUnit(g, u)
            u = FirstOfGroup(g)
        end
        DestroyGroup(g)
        return death
    end

    function CreateEffectLoc(duration,loc,model)
        local ExpiredFunc = function()
            local t = timers[GetExpiredTimer()]
            local e = t.arg[1]
            BlzSetSpecialEffectPosition(e,0, 0, 1000)
            DestroyEffectBJ(e)
            t:Remove()
        end
        local effect = AddSpecialEffectLoc(model, loc)
        TimerClass:Create(duration,false,ExpiredFunc,effect)
    end

    //Im using this timer a ton, so it shouldn be the problem
    timers = {}
    TimerClass = {}
    function TimerClass:Create(duration,isPeriodic,ExpiredFunc,...)
        local this = {}
        this.this = CreateTimer()
        this.duration = duration
        this.isPeriodic = isPeriodic
        this.ExpiredFunc = ExpiredFunc
        this.arg = {...}
        self.__index = self
        setmetatable(this, self)
        timers[this.this] = this
        TimerStart(this.this, duration, isPeriodic, this.ExpiredFunc)
        return this
    end

    function TimerClass:Remove()
        if self.isPeriodic == false then
            DestroyTimer(self.this)
            timers[self] = nil
        end
    end
 
Last edited:

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,538
Apparently the garbage collector can cause problems.

Quoting someone from this thread Narrowing Down Desync Cause

"UPDATE 2: Seems by default wc3 will use something called `__jarray(0.0)` when you create a global array of reals. If I change that to use `{}` the desync comes back. So I guess something is wrong with `{}` for whatever reason in lua. I don't really understand why that would matter, since `__jarray(0.0)` just makes a table anyway...

Maybe it's related to the sizing of the lua tables. From what I understand whenever you hit the size limit it doubles it internally. So maybe `__jarray()` starts it with a large size already or something...

UPDATE 3: If anyone comes here from google or search or whatever, I found out it was caused by lua garbage collection. You can turn it off to verify, and then manually call it on a timer to sync it for each player and that fixes the issue!"
 
There are definitely some things to watch out for with garbage collection. For example if you create a global trigger outside of any scope it will get garbage collected (maybe at different times for each player), at least last time I tested.

Also, you say the code desyncs when the ability is cast but I don't see any code related to casting in the script you posted?

UPDATE 3: If anyone comes here from google or search or whatever, I found out it was caused by lua garbage collection. You can turn it off to verify, and then manually call it on a timer to sync it for each player and that fixes the issue!"

You can no longer disable garbage collection. It only worked during the beta.
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,538
There are definitely some things to watch out for with garbage collection. For example if you create a global trigger outside of any scope it will get garbage collected (maybe at different times for each player), at least last time I tested.

Also, you say the code desyncs when the ability is cast but I don't see any code related to casting in the script you posted?



You can no longer disable garbage collection. It only worked during the beta.
Do you know if Pairs causes issues as well? Because i'm using it A LOT, lol.
 
Do you know if Pairs causes issues as well? Because i'm using it A LOT, lol.

The order of pairs is undefined so yes it can desync depending on how you are using it. If you need to rely on order then you can use ipairs or something like ordered pairs. There is even a compressed version that can replace pairs.
 
Level 3
Joined
Mar 7, 2020
Messages
16
Thanks!
Based on your information i changed deathUnits table from key value to index value and used ipair. Played a few online games and no desyncs so far. Looks now promasing!

I think it's ok to use pair as long as the whole table is used.
 
Last edited:
Status
Not open for further replies.
Top