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

I2H without Typecasting

Level 16
Joined
Oct 12, 2008
Messages
1,570
Ever since the 1.23b patch was even mentioned, i heard people whining about I2H (e.g. I2U, I2Trigger, I2Timer) disappearing. So i decided to make my own I2H function without Typecasting.
I named the functions Get$NAME$IdEx and GetId$NAME$Ex

Introducing new version: Hashtable-version. This version supports basic Warcraft3 types, and should be enough for most people.

Struct-version:

Pros
* Converting from Integer (ID) to Handle is possible again, without typecasting.
* When a handle gets GetHandleIdEx'd twice, no second struct is created.

Cons
* In order to use GetId$NAME$Ex, the handle integer MUST have been generated by my own Get$NAME$IdEx function.
* Not all types are usable at first. A textmacro line enables different handle-types.
* A limit of 8192 handles per type can be converted at max.

JASS:
//! textmacro HANDLEID takes NAME, TYPE
library $NAME$Id
    private struct $NAME$DATA
        $TYPE$ Type = null
        integer ID = -1
    endstruct
    globals
        private $NAME$DATA array $NAME$Da
        private integer $NAME$Total = 0
    endglobals
    function Get$NAME$IdEx takes $TYPE$ h returns integer
        local $NAME$DATA dat
        local integer i = 0
        local boolean b = false
        loop
            exitwhen b or i >= $NAME$Total
            set dat = $NAME$Da[i]
            if dat.Type == h then
                set b = true
            endif
            set i = i + 1
        endloop
        if not b then
            set dat = $NAME$DATA.create()
            set dat.Type = h
            set dat.ID = GetHandleId(h)
            set $NAME$Da[$NAME$Total] = dat
            set $NAME$Total = $NAME$Total + 1
        endif
        return dat.ID
    endfunction
    function GetId$NAME$Ex takes integer ID returns $TYPE$
        local $NAME$DATA dat
        local integer i = 0
        local boolean b = false
        loop
            exitwhen b or i >= $NAME$Total
            set dat = $NAME$Da[i]
            if dat.ID == ID then
                set b = true
            endif
            set i = i + 1
        endloop
        if b then
            return dat.Type
        else
            debug call BJDebugMsg("Warning:  ID is not generated by Get-Handle-IdEx, returning null")
            return null
        endif
    endfunction
endlibrary
//! endtextmacro

Example of different type-usage.
JASS:
//! runtextmacro HANDLEID("Unit","unit")
//! runtextmacro HANDLEID("Destructable","destructable")
// or even:
//! runtextmacro HANDLEID("Handle","handle")

Hashtable-version:

Pros
* converting from ID to handle is possible again, without typecasting
* Faster than struct-version.
* Unlimited converting-usage.

Cons
* Not usable for every type of variable.
* Types have to be activated before use.
* The ID has to be generated by Get$NAME$IdEx in order to return the handle again.

JASS:
//! textmacro HANDLEID takes NAME, TYPE
library $NAME$Id initializer Init 
    globals
        private hashtable $NAME$Hash
    endglobals
    function Get$NAME$IdEx takes $TYPE$ h returns integer
        call Save$NAME$Handle(Hash,0,GetHandleId(h),h)
        return GetHandleId(h)
    endfunction
    function GetId$NAME$Ex takes integer ID returns $TYPE$
        return Load$NAME$Handle(Hash,0,ID)
    endfunction
    private function Init takes nothing returns nothing
        set $NAME$Hash = InitHashtable()
    endfunction
endlibrary
//! endtextmacro

Example of different type-usage.
JASS:
//! runtextmacro HANDLEID("Unit","unit")
//! runtextmacro HANDLEID("Destructable","destructable")
// BUT NOT:
//! runtextmacro HANDLEID("Handle","handle")
// As there is no:
SaveHandleHandle() // or
LoadHandleHandle()




I hope this comes in hand to people who want to use I2H-alias functions.

Please report any improvements or bugs.

My testing scene:
(Ok, the code this thing is useless, but it shows that it works!)
JASS:
//! runtextmacro HANDLEID("Unit","unit")
//! runtextmacro HANDLEID("Destructable","destructable")
// ...
// And the testing code:
// ...
function Unit takes nothing returns nothing
    call BJDebugMsg(GetHeroProperName(GetIdUnitEx(GetUnitIdEx(GetEnumUnit()))) + " IdEx: " + I2S(GetUnitIdEx(GetEnumUnit())) + "  Id: " + I2S(GetHandleId(GetEnumUnit())))
endfunction
function Dest takes nothing returns nothing
    call BJDebugMsg(GetDestructableName(GetIdDestructableEx(GetDestructableIdEx(GetEnumDestructable()))) + " IdEx: " + I2S(GetDestructableIdEx(GetEnumDestructable())) + "  Id: " + I2S(GetHandleId(GetEnumDestructable())))
endfunction
function Actions takes nothing returns nothing
    local group g = CreateGroup()
    call GroupEnumUnitsInRect(g,bj_mapInitialPlayableArea,null)
    call ForGroup( g, function Unit )
    call DestroyGroup(g)
    set g = null
    call EnumDestructablesInRect( bj_mapInitialPlayableArea,null, function Dest )
    call GetIdUnitEx(0)
endfunction
//===========================================================================
function InitTrig_Test takes nothing returns nothing
    local trigger t = CreateTrigger(  )
    call TriggerRegisterTimerEvent( t, 0.00 ,false)
    call TriggerAddAction( t, function Actions )
endfunction

And the showed messages (Including the composition, so you can see what was converted)
jasspic.jpg
 
Last edited:
You should make the textmacro encompass the whole library (including library/endlibrary keywords), or mention that the textmacro has to be run inside the library, at the bottom. This will currently cause errors (private keyword outside library, stuff like that) if you run the textmacros outside a library or scope, or in the case of the hashtable version, in your own library or scope.

Other than that, it seems quite useful, but what I really will miss is stuff like
JASS:
local handle h = I2H(0x100000 + 200)
 
Level 16
Joined
Oct 12, 2008
Messages
1,570
Thanks EoW, i didnt think of such a problem! And thanks TriggerHappy187, for opposing a problem with the global Hashtable, it now has a private hashtable for every type.

And EoW, i dont think there will ever be (or at least that I will ever create) a way to do such a thing, unless you know some way?
 
Top