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

Typecasting - Handle to integer

Level 10
Joined
Nov 10, 2004
Messages
351
JASS:
function H2I takes handle h returns integer
    return h
    return 0
endfunction
The well known H2I function which is very usefull.
stores a handle's address in an integer, allowing various storing systems.
[broke=A handle is every variable type except for: real, boolean, integer, string, code ]What is a Handle?[/broke]

Return bug information by weaaddar:
weaaddar:
All variable types in warcraft 3 are four bytes in length. The atomic types (ints, reals, and booleans) use thier four bytes as direct value. Handles use thier four bytes of space as a "pointer" to thier object they references "memory address". I use the terms "pointer" loosely. As they are not first class pointers. As well as "memory address", it is believed all objects are stored in a specific heap and these are thier keys to them. But that is irrelavant.
Anyway, the Jass parser only checks the last return value satiates the return type. Thus we "trick" it into taking a handle when it really was meant to take an integer.

Converting the integer address of the handle back to a handle is done using functions like this:
JASS:
function I2U takes integer i returns unit
    return i
    return null
endfunction
function I2Trigger takes integer i returns trigger
    return i
    return null
endfunction
function I2Timer takes integer i returns timer
    return i
    return null
endfunction
Ex: if you converted a unit to an integer you will have to use I2U(ConvertedUnit) to retain the unit. For a trigger you would have to use I2Trigger(ConvertedTrigger)

NOTE: Do not use this on handles like

lightning, ubersplat, texttag, damagetype, attacktype, weapontype and playerstate
as some of them have similar ids.

Thanks to SuperIKI and Peppar for discovering this function.
 
Last edited:
Level 40
Joined
Dec 14, 2005
Messages
10,532
Ralle;

It's used for storing data to stuff through a gamecache, since each handle has a different ID, each gamecache slot will be different, allowing for you to store data under the same name to several different objects (usually timers) without overlap.

It can also be use for debugging, storing to custom values, etc, etc.
 
Level 14
Joined
Nov 20, 2005
Messages
1,156
It is H2I or h2i. Both are used. There was an attempt I believe to move to a standard of lower case for type casting functions, to differentiate more with functions like I2S, etc.

I'd say any 'author-less' resources are only placed by a staff member, with clear indication in the title it is not their work. I'd also recommend that if you put this one in, it gets stickied due to overall importance.
 
Level 32
Joined
Oct 23, 2006
Messages
5,291
[off-topic]

Why the heck even > I < can't rename the thread from "H2i" to "H2I" only the webmaster can say.

I (unsucessfully) tried to edit both the thread itself and the original post. :confused:

Idea.gif
I have another card hidden up my sleeve: I'll play that one.

[EDIT] <expletive deleted>
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
So, are we planning on reaching any sort of conclusion on this?

Admins: will we make an exception for H2I, and mention SuperIKI in the credits (who PitzerMike said was the first person to use H2I, and thus I assume he was the one that made it), or shall we stick 100% to the rule that Griffen pointed out?
 
Level 3
Joined
Sep 4, 2007
Messages
49
damagetype, attacktype, weapontype and playerstate

The above handles are actually constant integers, when you use H2I on a certain damage type for example it will always return the same value for that damage type i.e. DAMAGE_TYPE_MAGIC is 14 etc. You should probably mention that is the reason why you can get problems with it, although the indexes for the pointer type handles start at 1048665
 
Level 12
Joined
Aug 20, 2007
Messages
866
Hold on a sec

So, this storage system kinda gives any handle a custom value???

I suppose this would be the very efficient JASS way of using an array (similar function could be done using GUI arrays)

How does it work??
couldn't understand a few things...
parser = compiler?
satiates = I have no idea!?!?!?
 
Level 13
Joined
Nov 22, 2006
Messages
1,260
Well, not exactly, this allows you to store stuff in a game cache, which is used for transferring data between maps (campaigns for example). This way you can transfer data from one function to another through a certain handle that is common to both functions.

Due to the laginess of game cache, it is really bad to use plain Handle Vars system (made by KaTTaNa - wc3jass.com), so people made few improvement systems. Vexorian's JNGP allows the best and the fastest way to do that.

Note that not all handles can transfer data like that, there are handles that are not-exactly-handles, such as the ones that Diablo pointed out.

But you can always use global arrays...... :)
 
Level 12
Joined
Aug 20, 2007
Messages
866
Heh

Yeah I was making another quadratic spell using JASS, and I noticed it would be 10000x more efficient using the LocalVars() stuffs, if I wanted to use global arrays I woulda just done it in GUI x)

I'm gonna make another thread with that code in it, and questions on how to make it MUI, and how to use the LocalVars() appropriately (and a few others about damage_area)
 
Level 12
Joined
Aug 20, 2007
Messages
866
:O

:O
:O
:O

Then how does vJass get it's legendary speed that I keep hearing about over and over again?

//====================================

Question about globals vs. local handle vars
I made a quadratic arc type of function, and I was wondering if I used global arrays, and just one integer attached to the timer to reference all of the information from the globals, would that be faster than to use all of the information attached to the timer?

//====================================
I apologize for the original question, thought satiates was a typo

Code:
Anyway, the Jass parser only checks that the last return value satisfies the return type

makes much more sense to me

Ah yes!, I finally get it!!

The function returns an integer, when it already returned a handle, giving the handle a reference (I think?)

Also, do you need to nullify integers, reals, booleans, etc. if they are attached to handles using the vars system?
 
Last edited:
Level 12
Joined
Aug 20, 2007
Messages
866
Sorry for double-post

Figured you guys couldn't see that I added more questions to the original

I'm starting to understand how the bug exploit works, but how could I connect an integer to a handle, rather than a handle stored as an integer?
 
Level 6
Joined
Sep 5, 2007
Messages
264
???

I'm not sure of this, but I think that the author of H2I was KaTaNa. That was the first person, that I know of, to use it. Especially to attach vars to handles.

I'm in the process of making a DotA'ish map of my own (from scratch). It uses a fair amount of triggered abilities and for speed's sake I use these functions:
JASS:
//**************************************
//        Local Handle Variables
//**************************************
function H2I takes handle h returns integer
    return h
    return 0
endfunction
function H2S takes handle h returns string
    return I2S(H2I(h))
endfunction

function InitLocalVars takes nothing returns nothing
    if (udg_Cache_LocalVars == null) then
        set udg_Cache_LocalVars = InitGameCache("local_vars.w3v")
    endif
endfunction

// **  Integer  **
function SetHandleVarInt takes string subject, string name, integer value returns nothing
    call StoreInteger(udg_Cache_LocalVars, subject, name, value)
endfunction
function GetHandleVarInt takes string subject, string name returns integer
    return GetStoredInteger(udg_Cache_LocalVars, subject, name)
endfunction
// **   Float   **
function SetHandleVarReal takes string subject, string name, real value returns nothing
    call StoreReal(udg_Cache_LocalVars, subject, name, value)
endfunction
function GetHandleVarReal takes string subject, string name returns real
    return GetStoredReal(udg_Cache_LocalVars, subject, name)
endfunction
// **  String   **
function SetHandleVarString takes string subject, string name, string value returns nothing
    call StoreString(udg_Cache_LocalVars, subject, name, value)
endfunction
function GetHandleVarString takes string subject, string name returns string
    return GetStoredString(udg_Cache_LocalVars, subject, name)
endfunction
// **  Boolean  **
function SetHandleVarBoolean takes string subject, string name, boolean value returns nothing
    call StoreBoolean(udg_Cache_LocalVars, subject, name, value)
endfunction
function GetHandleVarBoolean takes string subject, string name returns boolean
    return GetStoredBoolean(udg_Cache_LocalVars, subject, name)
endfunction

//-------------------
//    CONVERSIONS
//-------------------
function GetHandleVarUnit takes string subject, string name returns unit
    return GetStoredInteger(udg_Cache_LocalVars, subject, name)
    return null
endfunction
function GetHandleVarEffect takes string subject, string name returns effect
    return GetStoredInteger(udg_Cache_LocalVars, subject, name)
    return null
endfunction
function GetHandleVarTrigger takes string subject, string name returns trigger
    return GetStoredInteger(udg_Cache_LocalVars, subject, name)
    return null
endfunction
function GetHandleVarRect takes string subject, string name returns rect
    return GetStoredInteger(udg_Cache_LocalVars, subject, name)
    return null
endfunction
function GetHandleVarRegion takes string subject, string name returns region
    return GetStoredInteger(udg_Cache_LocalVars, subject, name)
    return null
endfunction
function GetHandleVarWeatherFX takes string subject, string name returns weathereffect
    return GetStoredInteger(udg_Cache_LocalVars, subject, name)
    return null
endfunction
function GetHandleVarTimer takes string subject, string name returns timer
    return GetStoredInteger(udg_Cache_LocalVars, subject, name)
    return null
endfunction
function GetHandleVarTimerDialog takes string subject, string name returns timerdialog
    return GetStoredInteger(udg_Cache_LocalVars, subject, name)
    return null
endfunction
function GetHandleVarGroup takes string subject, string name returns group
    return GetStoredInteger(udg_Cache_LocalVars, subject, name)
    return null
endfunction

function I2UNIT takes integer i returns unit
    return i
    return null
endfunction
function I2TIMER takes integer i returns timer
    return i
    return null
endfunction
function I2TIMER_DIALOG takes integer i returns timerdialog
    return i
    return null
endfunction
function I2EFFECT takes integer i returns effect
    return i
    return null
endfunction
function I2TRIGGER takes integer i returns trigger
    return i
    return null
endfunction
function I2RECT takes integer i returns rect
    return i
    return null
endfunction
function I2REGION takes integer i returns region
    return i
    return null
endfunction
function I2WEATHER_FX takes integer i returns weathereffect
    return i
    return null
endfunction
function I2GROUP takes integer i returns group
    return i
    return null
endfunction

function FlushHandleVars takes string subject returns nothing
    call FlushStoredMission(udg_Cache_LocalVars, subject)
endfunction

function FlushHandleVarReal takes string subject, string name returns nothing
    call FlushStoredReal(udg_Cache_LocalVars, subject, name)
endfunction
function FlushHandleVarInt takes string subject, string name returns nothing
    call FlushStoredInteger(udg_Cache_LocalVars, subject, name)
endfunction
function FlushHandleVarString takes string subject, string name returns nothing
    call FlushStoredString(udg_Cache_LocalVars, subject, name)
endfunction
function FlushHandleVarBoolean takes string subject, string name returns nothing
    call FlushStoredBoolean(udg_Cache_LocalVars, subject, name)
endfunction

To attach or read an attached var I use:
JASS:
    local string hand = H2I([I]unit[/I])
    local integer var = GetHandleVarInt(hand, "name")

    <Insert other code here>

    set hand = null

Doing the H2I only once per handle is alot faster than doing it per variable.
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
That's the idea behind vex's tables. Either way, attaching handles by gamecache is so horribly out of date that I suggest you avoid it at all costs. It's buggy and slow.

Also, KaTTaNa was not the author of H2I. If I recall correctly, the original author was called Super(something), perhaps SuperLKL or such.
 
Level 6
Joined
Sep 5, 2007
Messages
264
What would you suggest instead of H2I?

@PurplePoot:

I'm after the fastest MOST efficient way of doing things. I've found that my way IS faster than the way that KaTTaNa originally wrote. But, if you can suggest a much better way of doing it, I'd be extremely greatful.

Just a question here: how is the gamecache way "buggy"?

Thanx.
 
Level 14
Joined
Nov 20, 2005
Messages
1,156
Ha. Most efficient way is not to touch GC (normally, some uses it is nice...not here).

GC isn't buggy, but LHV are, when attaching handles, as they use a I2H typecast, which is unsafe.

H2I's origins are unknown...weaaader or one of a few others around the same time were the first to use it.
 
Level 8
Joined
Aug 6, 2008
Messages
451
Actually, I think it was magnus99 who discovered the return bug and COOLer who invented the gamecache method.

The first JASSer to exploit H2I was SuperIKI followed by Peppar.

Oh yea, SuperIKI was the first one.
 
Level 8
Joined
Aug 6, 2008
Messages
451
Why is it strange? Tell us more please.

H2I is afterall one of the coolest functions ever invented.
 
Top