• Check out the results of the Techtree Contest #19!
  • 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.
  • Create a void inspired texture for Warcraft 3 and enter Hive's 34th Texturing Contest: Void! Click here to enter!
  • The Hive's 22nd Icon Contest: Creep Abilities is now concluded, time to vote for your favourite set of icons! Click here to vote!

Get Handle Type

I'm using this as a dependency in my resources, but it might have some uses on its own, so I might as well upload it separately. Thanks to Wrda for telling me about the non-hashtable approach in Lua used by Eikonium in his DebugUtils library.

Returns the exact type of a handle, such as "unit", "player", or "abilitybooleanlevelarrayfield". You can add additional functions for specific types, such as "IsItem" from the IsUnit template.

I believe this is the most optimized implementation, although for IsHandle, you could just use type(var) == "userdata". IsHandle looks nicer though :prazz:. And you compute the handle type in one go.

Note: IsUnit overwrites the native with the same name. Since that is arguably the most useless native there is, I think that shouldn't be a problem.

Lua:
if Debug then Debug.beginFile("HandleType") end
do
    --[[
    ===============================================================================================================================================================
                                                                        Handle Type
                                                                        by Antares
    ===============================================================================================================================================================
    
    Determine the type of a Wacraft 3 object (handle). The result is stored in a table on the first execution to increase performance.

    HandleType[whichHandle]     -> string           Returns an empty string if variable is not a handle.
    IsHandle[whichHandle]       -> boolean
    IsWidget[whichHandle]       -> boolean
    IsUnit[whichHandle]         -> boolean

    These can also be called as a function, which has a nil-check, but is slower than the table-lookup

    ===============================================================================================================================================================
    ]]

    local widgetTypes = {
        unit = true,
        destructable = true,
        item = true
    }

    HandleType = setmetatable({}, {
        __mode = "k",
        __index = function(self, key)
            if type(key) == "userdata" then
                local str = tostring(key)
                self[key] = str:sub(1, (str:find(":", nil, true) or 0) - 1)
                return self[key]
            else
                self[key] = ""
                return ""
            end
        end,
        __call = function(self, key)
            if key then
                return self[key]
            else
                return ""
            end
        end
    })

    IsHandle = setmetatable({}, {
        __mode = "k",
        __index = function(self, key)
            self[key] = HandleType[key] ~= ""
            return self[key]
        end,
        __call = function(self, key)
            if key then
                return self[key]
            else
                return false
            end
        end
    })

    IsWidget = setmetatable({}, {
        __mode = "k",
        __index = function(self, key)
            self[key] = widgetTypes[HandleType[key]] == true
            return self[key]
        end,
        __call = function(self, key)
            if key then
                return self[key]
            else
                return false
            end
        end
    })

    IsUnit = setmetatable({}, {
        __mode = "k",
        __index = function(self, key)
            self[key] = HandleType[key] == "unit"
            return self[key]
        end,
        __call = function(self, key)
            if key then
                return self[key]
            else
                return false
            end
        end
    })
end
if Debug then Debug.endFile() end
Contents

Get Handle Type (Binary)

Reviews
Wrda
Works as expected, useful for debugging and for conditional code. OnInit.global("HandleType", function() end) What's up with this line at the bottom? It seems either something leftover or you wanted to make a library out of it. Nonetheless, Approved
I always like to see this kind of stuff. Eikonium's DebugUtils has a nice WarCraft3Type Lua function, which covers the functional utility of a resource like this. But it is a cool idea.
Yea, I got the string approach from the DebugUtils library. I just added the caching part and the IsWidget etc. specific functions.
 
There's several ways, usually from what I understand can be like this:
You have a scope of do .... end engulf everything you want to initialize into a local function, and then use OnInit at the end, with that function as 2nd parameter.
Lua:
if Debug then Debug.beginFile("HandleType") end
    --[[
    ===============================================================================================================================================================
                                                                        Handle Type
                                                                        by Antares
    ===============================================================================================================================================================
    
    Determine the type of a Wacraft 3 object (handle). The result is stored in a table on the first execution to increase performance.
    HandleType[whichHandle]     -> string           Returns an empty string if variable is not a handle.
    IsHandle[whichHandle]       -> boolean
    IsWidget[whichHandle]       -> boolean
    IsUnit[whichHandle]         -> boolean
    These can also be called as a function, which has a nil-check, but is slower than the table-lookup
    ===============================================================================================================================================================
    ]]
do
    local function init()
        local widgetTypes = {
            unit = true,
            destructable = true,
            item = true
        }
        HandleType = setmetatable({}, {
            __mode = "k",
            __index = function(self, key)
                if type(key) == "userdata" then
                    local str = tostring(key)
                    self[key] = str:sub(1, (str:find(":", nil, true) or 0) - 1)
                    return self[key]
                else
                    self[key] = ""
                    return ""
                end
            end,
            __call = function(self, key)
                if key then
                    return self[key]
                else
                    return ""
                end
            end
        })
        IsHandle = setmetatable({}, {
            __mode = "k",
            __index = function(self, key)
                self[key] = HandleType[key] ~= ""
                return self[key]
            end,
            __call = function(self, key)
                if key then
                    return self[key]
                else
                    return false
                end
            end
        })
        IsWidget = setmetatable({}, {
            __mode = "k",
            __index = function(self, key)
                self[key] = widgetTypes[HandleType[key]] == true
                return self[key]
            end,
            __call = function(self, key)
                if key then
                    return self[key]
                else
                    return false
                end
            end
        })
        IsUnit = setmetatable({}, {
            __mode = "k",
            __index = function(self, key)
                self[key] = HandleType[key] == "unit"
                return self[key]
            end,
            __call = function(self, key)
                if key then
                    return self[key]
                else
                    return false
                end
            end
        })
    end
    OnInit.global("HandleType", init)
end
if Debug then Debug.endFile() end

This one has no do ... end scope, but the rest is similar
Lua:
if Debug then Debug.beginFile("HandleType") end
    --[[
    ===============================================================================================================================================================
                                                                        Handle Type
                                                                        by Antares
    ===============================================================================================================================================================
    
    Determine the type of a Wacraft 3 object (handle). The result is stored in a table on the first execution to increase performance.

    HandleType[whichHandle]     -> string           Returns an empty string if variable is not a handle.
    IsHandle[whichHandle]       -> boolean
    IsWidget[whichHandle]       -> boolean
    IsUnit[whichHandle]         -> boolean

    These can also be called as a function, which has a nil-check, but is slower than the table-lookup

    ===============================================================================================================================================================
    ]]
    function HandleTypesInit()
        local widgetTypes = {
            unit = true,
            destructable = true,
            item = true
        }

        HandleType = setmetatable({}, {
            __mode = "k",
            __index = function(self, key)
                if type(key) == "userdata" then
                    local str = tostring(key)
                    self[key] = str:sub(1, (str:find(":", nil, true) or 0) - 1)
                    return self[key]
                else
                    self[key] = ""
                    return ""
                end
            end,
            __call = function(self, key)
                if key then
                    return self[key]
                else
                    return ""
                end
            end
        })

        IsHandle = setmetatable({}, {
            __mode = "k",
            __index = function(self, key)
                self[key] = HandleType[key] ~= ""
                return self[key]
            end,
            __call = function(self, key)
                if key then
                    return self[key]
                else
                    return false
                end
            end
        })

        IsWidget = setmetatable({}, {
            __mode = "k",
            __index = function(self, key)
                self[key] = widgetTypes[HandleType[key]] == true
                return self[key]
            end,
            __call = function(self, key)
                if key then
                    return self[key]
                else
                    return false
                end
            end
        })

        IsUnit = setmetatable({}, {
            __mode = "k",
            __index = function(self, key)
                self[key] = HandleType[key] == "unit"
                return self[key]
            end,
            __call = function(self, key)
                if key then
                    return self[key]
                else
                    return false
                end
            end
        })
    end
    OnInit.global("HandleType", HandleTypesInit)
if Debug then Debug.endFile() end

3rd method involves you engulfing everything inside your OnInit function call, with an anonymous function
Lua:
if Debug then Debug.beginFile("HandleType") end
    --[[
    ===============================================================================================================================================================
                                                                        Handle Type
                                                                        by Antares
    ===============================================================================================================================================================
    
    Determine the type of a Wacraft 3 object (handle). The result is stored in a table on the first execution to increase performance.

    HandleType[whichHandle]     -> string           Returns an empty string if variable is not a handle.
    IsHandle[whichHandle]       -> boolean
    IsWidget[whichHandle]       -> boolean
    IsUnit[whichHandle]         -> boolean

    These can also be called as a function, which has a nil-check, but is slower than the table-lookup

    ===============================================================================================================================================================
    ]]
OnInit.global("HandleType", function()
    local widgetTypes = {
        unit = true,
        destructable = true,
        item = true
    }

    HandleType = setmetatable({}, {
         __mode = "k",
        __index = function(self, key)
            if type(key) == "userdata" then
                local str = tostring(key)
                self[key] = str:sub(1, (str:find(":", nil, true) or 0) - 1)
                return self[key]
            else
                self[key] = ""
                return ""
            end
        end,
         __call = function(self, key)
            if key then
                return self[key]
            else
                return ""
            end
        end
    })

    IsHandle = setmetatable({}, {
        __mode = "k",
        __index = function(self, key)
            self[key] = HandleType[key] ~= ""
            return self[key]
        end,
        __call = function(self, key)
            if key then
                return self[key]
            else
                return false
            end
        end
    })

    IsWidget = setmetatable({}, {
        __mode = "k",
        __index = function(self, key)
            self[key] = widgetTypes[HandleType[key]] == true
            return self[key]
        end,
        __call = function(self, key)
            if key then
                return self[key]
            else
                return false
            end
        end
    })

    IsUnit = setmetatable({}, {
        __mode = "k",
        __index = function(self, key)
            self[key] = HandleType[key] == "unit"
            return self[key]
        end,
        __call = function(self, key)
            if key then
                return self[key]
            else
                return false
            end
        end
    })
end)
if Debug then Debug.endFile() end

Also, I realised you forgot to put if Debug then Debug.endFile() end at the end of the script :D so Debug Utils wouldn't behave very well.
 
Works well. I added this simple function to automatically get a handle type id without needing to know the handle type
Lua:
    local typeIdFuncs = {unit=GetUnitTypeId, item=GetItemTypeId, destructable=GetDestructableTypeId, ability=BlzGetAbilityId}
    ---@param handle userdata
    ---@return integer
    function GetObjectTypeId(handle)
        local handleType = HandleType[handle]
        local func = typeIdFuncs[handleType]
        if func then
            return func(handle)
        else
            return 0
        end
    end

Using it for pretty prints:
Lua:
---@param tbl table
---@return string
function TableToStr(tbl)
    local out = {}
    table.insert(out, "{")
    for k, v in pairs(tbl) do
        table.insert(out, PrettyString(k))
        table.insert(out, ": ")
        table.insert(out, PrettyString(v))
        table.insert(out, ", ")
    end
    table.insert(out, "}")
    return table.concat(out)
end

---@param arg any
---@return string -- returns a pretty string representation of the argument
function PrettyString(arg)
    if type(arg) == "table" then
        return TableToStr(arg)
    elseif type(arg) == "userdata" then
        local id = GetObjectTypeId(arg)
        local type = HandleType[arg]
        if type == "" then
            return tostring(arg)
        end
        return type .. ": " .. GetObjectName(id) .. "('" .. FourCC2Str(id) .. "')"
    else
        return tostring(arg)
    end
end
 
Back
Top