• 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.
  • The Hive's 22nd Icon Contest: Creep Abilities is now concluded, time to vote for your favourite set of icons! Click here to vote!
  • ✅ The POLL for Hive's Texturing Contest #34 is OPEN! Vote for the TOP 3 SKINS! 🔗Click here to cast your vote!
  • ✅ The POLL for Hive's Techtree Contest #20 is OPEN! Vote for the TOP 3 FACTIONS! 🔗Click here to cast your vote!

[Lua] Synced override of GetUnitUserData and GetHandleId

I'm trying to make a Lua function override for GetUnitUserData and GetHandleId that addresses the issues found here lua and unit data and wanted to make sure I did it right.

Lua:
DetectRemoveAbility = FourCC("A01Z")

UnitUDataTable = {}

HandleIdKeyTable = {}
HandleIdValueTable = {}

SetUnitUserData = function(u,i)
    if u==nil then
        return
    end
    UnitUDataTable[u]=i
end

GetUnitUserData = function(u)
    if u==nil or UnitUDataTable[u]==nil then
        return 0
    end
    return UnitUDataTable[u]
end

function CleanUnitUserDataTable()
    local u = GetFilterUnit()
    if GetUnitAbilityLevel(u, DetectRemoveAbility) == 0 then
        UnitUDataTable[u]=nil
    end
    return false
end

GetHandleId = function(o)
    if o==nil then
        return 0
    end
    if HandleIdKeyTable[o]~=nil then
        return HandleIdKeyTable[o]
    end
    local length = #HandleIdValueTable + 1
  HandleIdKeyTable[o] = length
    HandleIdValueTable[length] = o
    return length
end

function InitUserDataCleanup()
    local t=CreateTrigger()
    for i=0,bj_MAX_PLAYERS do
        TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_ISSUED_ORDER, Filter(CleanUnitUserDataTable))
    end
end
 
Last edited:
yes, you are overriding the functions correctly.

however, I don't think SetUnitUserData and GetUnitUserData have any issues in Lua, even in multiplayer (as far as my testing goes). If you heard about any issues related to it, feel free to share. I'm guessing you might be mixing it up with userdata, which is a concept in Lua that is useful for defining custom types or for bridging types from C/C++.

Your function for GetHandleId should override the function correctly, but it might not be the best practice to hold strong references to the objects as that prevents garbage collection. You can make a table have use weak references by assigning a mode:
  1. setmetatable(<table name>, { __mode = "v" }) - use this for weak values (i.e. for HandleIdValueTable)
  2. setmetatable(<table name>, { __mode = "k" }) - use this for weak keys (i.e. for HandleIdKeyTable)
  3. setmetatable(<table name>, { __mode = "kv" }) - use this for weak keys and values
Also, your numbers just keep going up--you might want to consider some recycling of the IDs (unless you are fine with that for your map).

The other main thing is to just make sure that you don't use your GetHandleId(...) function in a GetLocalPlayer() context (or any similar async context) since you lazy-load the IDs. Otherwise, you could run into a scenario where Player 1 gets ID #7 assigned to Uther, but then Player 2 gets ID #7 assigned to Arthas--so you'd essentially end up with the same problem that you were trying to solve.

The last thing worth mentioning is that, to my knowledge, the handle IDs being out of sync in Lua isn't really an issue unless your code relies on those numbers to be synchronous across clients, which is rare.
 
Back
Top