HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Handles!

09-17-2008, 05:01 AM#1
WNxCryptic
I've been away from the Jass world for a long time (about a year) and I'm working on a project from way back when. This project makes use of numerous handle functions (H2I, SetHandleHandle, SetHandleInt, SetHandleBoolean, SetHandleReal, etc. etc.) to control handles and all that jazz.

Are handles still used regularly? Have their functions changed in the last year (or are my old ones the same as what is 'current')?
09-17-2008, 05:27 AM#2
darkwulfv
Most people use Structs to do all that now, and just attach the structs (as integers) to timers, and retrieve them as such. No more I2H bugs, or whatever. It's also far cleaner, since you don't need to call a bunch of SetHandleBlah/GetHandleBlah stuff.
09-17-2008, 10:59 AM#3
TheDamien
Quote:
Originally Posted by darkwulfv
It's also far cleaner, since you don't need to call a bunch of SetHandleBlah/GetHandleBlah stuff.

Mostly replaced by SetBlahStructBlah..
09-17-2008, 11:50 AM#4
darkwulfv
Or a simple create method.
09-17-2008, 12:27 PM#5
Captain Griffen
Handles are still used...you can't avoid using handles in WC3...units, groups, locations, etc, are all handles. Then there are pseudo handles like lightning.

Anyway, handle variables like KaTaNNa's system are no longer used due to bugs with I2H, etc., and advances, primarily with vJASS through a preprocessor. Legacy support for avoiding the I2H issues is available through a KaTaNNa replacement library I made (search my threads in here), but it's slow, so really not recommended for new code.

Also, we no longer destroy triggers (dynamic triggers are out), and nor do we destroy groups (static groups) or timers (which we recycle). DestroyTrigger bugs (can cause multiple units to be on the same variable), groups leak if they are destroyed after being enumed (oh, and always enum with a boolexpr that isn't null, or that leaks every single enum), and timers are also dodgy when destroying them.
09-17-2008, 12:52 PM#6
grim001
I still have not seen why destroying triggers is always bad.
09-17-2008, 01:31 PM#7
WNxCryptic
Quote:
Handles are still used...you can't avoid using handles in WC3...units, groups, locations, etc, are all handles. Then there are pseudo handles like lightning.

But can you completely and effectively replace them with the new struct systems?
09-17-2008, 03:10 PM#8
grim001
Lol, how are you going to replace units with structs?

Some data structures such as groups and locations could be sometimes replaced with structs, but it's much slower, and you still have to deal with them when you are using natives that expect handles.
09-17-2008, 03:41 PM#9
WNxCryptic
So if Katanna's handle system isn't being used, what is? Even a link to the post where I can read up on it myself would be wonderful.
09-17-2008, 03:56 PM#10
Vexorian
Quote:
(H2I, SetHandleHandle, SetHandleInt, SetHandleBoolean, SetHandleReal, etc. etc.)
09-17-2008, 04:15 PM#11
WNxCryptic
Sorry for the long bit of code. Tried searching a bit for a post on current handle functions, just copy/pasted this from my old project. These are the 'current' ones in use, yes?

Thanks in advance Vex (and everyone!)

Collapse JASS:
// ===========================
function H2I takes handle h returns integer
    return h
    return 0
endfunction

// ===========================
function LocalVars takes nothing returns gamecache
    // Replace InitGameCache("jasslocalvars.w3v") with a global variable!!
    return InitGameCache("jasslocalvars.w3v")
endfunction

function SetHandleHandle takes handle subject, string name, handle value returns nothing
    if value==null then
        call FlushStoredInteger(LocalVars(),I2S(H2I(subject)),name)
    else
        call StoreInteger(LocalVars(), I2S(H2I(subject)), name, H2I(value))
    endif
endfunction

function SetHandleInt takes handle subject, string name, integer value returns nothing
    if value==0 then
        call FlushStoredInteger(LocalVars(),I2S(H2I(subject)),name)
    else
        call StoreInteger(LocalVars(), I2S(H2I(subject)), name, value)
    endif
endfunction

function SetHandleBoolean takes handle subject, string name, boolean value returns nothing
    if value==false then
        call FlushStoredBoolean(LocalVars(),I2S(H2I(subject)),name)
    else
        call StoreBoolean(LocalVars(), I2S(H2I(subject)), name, value)
    endif
endfunction

function SetHandleReal takes handle subject, string name, real value returns nothing
    if value==0 then
        call FlushStoredReal(LocalVars(), I2S(H2I(subject)), name)
    else
        call StoreReal(LocalVars(), I2S(H2I(subject)), name, value)
    endif
endfunction

function SetHandleString takes handle subject, string name, string value returns nothing
    if value==null then
        call FlushStoredString(LocalVars(), I2S(H2I(subject)), name)
    else
        call StoreString(LocalVars(), I2S(H2I(subject)), name, value)
    endif
endfunction

function GetHandleHandle takes handle subject, string name returns handle
    return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
    return null
endfunction
function GetHandleInt takes handle subject, string name returns integer
    return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
endfunction
function GetHandleBoolean takes handle subject, string name returns boolean
    return GetStoredBoolean(LocalVars(), I2S(H2I(subject)), name)
endfunction
function GetHandleReal takes handle subject, string name returns real
    return GetStoredReal(LocalVars(), I2S(H2I(subject)), name)
endfunction
function GetHandleString takes handle subject, string name returns string
    return GetStoredString(LocalVars(), I2S(H2I(subject)), name)
endfunction

function GetHandleUnit takes handle subject, string name returns unit
    return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
    return null
endfunction
function GetHandleTimer takes handle subject, string name returns timer
    return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
    return null
endfunction
function GetHandleTrigger takes handle subject, string name returns trigger
    return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
    return null
endfunction
function GetHandleEffect takes handle subject, string name returns effect
    return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
    return null
endfunction
function GetHandleGroup takes handle subject, string name returns group
    return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
    return null
endfunction
function GetHandleLightning takes handle subject, string name returns lightning
    return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
    return null
endfunction
function GetHandleWidget takes handle subject, string name returns widget
    return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
    return null
endfunction

function FlushHandleLocals takes handle subject returns nothing
    call FlushStoredMission(LocalVars(), I2S(H2I(subject)) )
endfunction
09-17-2008, 08:53 PM#12
Captain Griffen
Not really. SetHandleInt/GetHandleInt could still be used if you don't need 100% top notch speed, but attaching handles (units, timers, triggers, effects, etc.) is a no-no by that method, since it uses (inlined) I2H, which can cause issues.

There are different methods of attaching (oh so many). For legacy code, I made a system to replace that code (KaTaNNa's system) with the same API; since you've got a variation from the version at wc3jass, you'll need to tweak it a big, but nothing too hard.

New code should use one of the attachment systems in our database. Attachment to timers can be done via TimerUtils (which also has timer recycling - highly recommended), units you could use an indexing system like PUI or just attach, possibly with H2I and a hash / big arrays. Or just SetHandleInt. Really you want to be attaching structs for most cases (ie: one int).
09-17-2008, 09:03 PM#13
WNxCryptic
Well at the moment my implementation doesn't hardly make use of the handles at all (mainly because I don't have much of the JASS done yet) so now is the time to completely replace it with one of the new systems we're using.

How does attachment to timers work, specifically? And if I use something like TimerUtils would I also need an indexing system like PUI for units? Or can I attach units to timers using TimerUtils?
09-17-2008, 11:02 PM#14
the-thingy
Quote:
Or can I attach units to timers using TimerUtils?

You can store the unit in a struct, then attach that to the timer (and retrieve it later) e.g.
Collapse JASS:
struct MyData
  unit someUnit
//You can put the rest of your stuff that needs to be passed to the timer function in here as well
endstruct

function Callback takes nothing returns nothing
  local timer t = GetExpiredTimer ()
  local MyData d = GetTimerData (t) //I forget the precise function name
  call DoSomeStuffWithUnit (d.someUnit) //Poof, we've got the Triggering Unit from the Start function =D
  call ReleaseTimer (t)
  set t = null
endfunction

function Start takes nothing returns nothing
  local MyData d = MyData.create ()
  local timer t = NewTimer ()
  set d.someUnit = GetTriggerUnit ()
  call SetTimerData (t, d) //I forget the order of arguments ^_^
  call TimerStart (t, INTERVAL, false, function Callback)
  set t = null
endfunction
And that should bring that specific instance of someUnit to the Callback function safely (it's freehand though, so I might've gone wrong somewhere)
12-29-2008, 10:49 AM#15
Troll-Brain
Quote:
Originally Posted by Captain Griffen
Then there are pseudo handles like lightning.
What and witch handles are pseudo handles ?
We don't need to destroy them or what ?