| 03-25-2008, 10:03 PM | #1 |
Here's something I figured I'd try to do today. The challenge is: given a handle, figure out what derivative type it is. It's not possible to do all of them, for example "button" and "dialog" are probably lost causes. Unit group was a bit tough... I was surprised to find that the types of these handles seems to be checked before using natives on them (except for the lightning ones...). The interesting part is: destroyed handles, except for unit, all seem to come up as "unknown". So it's possible to write an "Is handle destroyed" function that will be accurate for many of the handle type derivatives. Code and output follow. I am aware I have not done all handle types. JASS:library HandleNamer initializer initHandleNamer //! textmacro H2HandleType takes handletype private function H2$handletype$ takes handle h returns $handletype$ return h return null endfunction //! endtextmacro //! runtextmacro H2HandleType("unit") //! runtextmacro H2HandleType("player") //! runtextmacro H2HandleType("location") //! runtextmacro H2HandleType("group") //! runtextmacro H2HandleType("force") //! runtextmacro H2HandleType("timer") //! runtextmacro H2HandleType("trigger") //! runtextmacro H2HandleType("timerdialog") //! runtextmacro H2HandleType("effect") //! runtextmacro H2HandleType("lightning") //! runtextmacro H2HandleType("item") //! runtextmacro H2HandleType("destructable") private function isLightning takes handle h returns boolean //causes crashes (memory access violation) return false //local lightning ltng = H2lightning(h) //local real r = GetLightningColorR(ltng) //local real g = GetLightningColorG(ltng) //local real b = GetLightningColorB(ltng) //local real a = GetLightningColorA(ltng) //if r == 0 then //call SetLightningColor(ltng, 1, g, b, a) //else //call SetLightningColor(ltng, 0, g, b, a) //endif //if r != GetLightningColorR(ltng) then //call SetLightningColor(ltng, r, g, b, a) //set ltng = null //return true //else //set ltng = null //return false //endif endfunction private function isDestructable takes handle h returns boolean return GetDestructableTypeId(H2destructable(h)) != 0 endfunction private function isItem takes handle h returns boolean return GetItemTypeId(H2item(h)) != 0 endfunction private function isEffect takes handle h returns boolean return false //??? endfunction private function isDialog takes handle h returns boolean return false //??? endfunction private function isButton takes handle h returns boolean return false //??? endfunction private function isTimerDialog takes handle h returns boolean local timerdialog d = H2timerdialog(h) local boolean b = IsTimerDialogDisplayed(d) call TimerDialogDisplay(d, not b) if IsTimerDialogDisplayed(d) != b then call TimerDialogDisplay(d, b) set d = null return true else set d = null return false endif endfunction private function isTrigger takes handle h returns boolean local trigger t = H2trigger(h) local triggeraction a = TriggerAddAction(t, function DoNothing) if a != null then call TriggerRemoveAction(t, a) //leak? set a = null set t = null return true else set t = null return false endif endfunction private function isPlayer takes handle h returns boolean return GetPlayerName(H2player(h)) != null endfunction private function isTimer takes handle h returns boolean local timer t = H2timer(h) local boolean b //this works even for timers that have not been started set b = TimerGetRemaining(t) != 0 or TimerGetElapsed(t) != 0 or TimerGetTimeout(t) != 0 set t = null return b endfunction private function isForce takes handle h returns boolean local force f = H2force(h) local boolean b if IsPlayerInForce(Player(0), f) then return true endif call ForceAddPlayer(f, Player(0)) if IsPlayerInForce(Player(0), f) then call ForceRemovePlayer(f, Player(0)) set f = null return true endif set f = null return false endfunction private function isGroup takes handle h returns boolean local group g = H2group(h) local group g2 local unit u local boolean b local rect r if FirstOfGroup(g) != null then set g = null return true endif //... seems like a lot to do something so simple ... set g2 = CreateGroup() if g2 == g then //clearly something is screwed up (fake handle passed) set b = false else //we don't want to constantly create units, so try to get an existing one set r = GetWorldBounds() call GroupEnumUnitsInRectCounted(g2, r, null, 1) call RemoveRect(r) set r = null set u = FirstOfGroup(g2) if u != null then call GroupAddUnit(g, u) set b = FirstOfGroup(g) == u call GroupRemoveUnit(g, u) else //no existing units, use a temp flying unit (likely not modified) //the gibllets will count as a previous unit for a second or two set u = CreateUnit(Player(0), 'nnht', 0, 0, 0) //nether dragon hatchling call GroupAddUnit(g, u) set b = FirstOfGroup(g) == u call GroupRemoveUnit(g, u) call ShowUnit(u, false) call SetUnitExploded(u, true) call KillUnit(u) endif set u = null endif call DestroyGroup(g2) set g2 = null set g = null return b endfunction private function isUnit takes handle h returns boolean return GetUnitTypeId(H2unit(h)) != 0 endfunction private function isLocation takes handle h returns boolean local location p = H2location(h) local real x = GetLocationX(p) local real y = GetLocationY(p) call MoveLocation(p, x+1, y) if GetLocationX(p) != x then call MoveLocation(p, x, y) set p = null return true else set p = null return false endif endfunction function HandleType takes handle h returns string if h == null then return "null" elseif isTimer(h) then return "timer" elseif isLocation(h) then return "location" elseif isUnit(h) then return "unit" elseif isGroup(h) then return "group" elseif isPlayer(h) then return "player" elseif isForce(h) then return "force" elseif isTrigger(h) then return "trigger" elseif isDialog(h) then return "dialog" elseif isTimerDialog(h) then return "timerdialog" elseif isButton(h) then return "button" elseif isEffect(h) then return "effect" elseif isLightning(h) then return "lightning" elseif isItem(h) then return "item" elseif isDestructable(h) then return "destructable" endif return "unknown" //"unknown" returned on removed handles //except not always for units for some reason endfunction private function test takes nothing returns nothing local timer t = CreateTimer() local location p = Location(0, 0) local unit u = CreateUnit(Player(0), 'hfoo', 0, 0, 0) local item i = CreateItem('texp', 0, 0) local effect e = AddSpecialEffect("Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.mdl", 0, 0) local group g = CreateGroup() local force f = CreateForce() call BJDebugMsg("timer(new) = " + HandleType(t)) call TimerStart(t, 10, false, null) call BJDebugMsg("timer(run) = " + HandleType(t)) call BJDebugMsg("location = " + HandleType(p)) call BJDebugMsg("unit = " + HandleType(u)) call BJDebugMsg("item = " + HandleType(i)) call BJDebugMsg("effect = " + HandleType(e)) call BJDebugMsg("group(empty) = " + HandleType(g)) call GroupAddUnit(g, u) call BJDebugMsg("group(1) = " + HandleType(g)) call BJDebugMsg("force(empty) = " + HandleType(f)) call ForceAddPlayer(f, Player(0)) call BJDebugMsg("force(1) = " + HandleType(f)) call BJDebugMsg("*** DESTROY ***") call DestroyTimer(t) call RemoveLocation(p) call RemoveUnit(u) call RemoveItem(i) call DestroyEffect(e) call DestroyGroup(g) call DestroyForce(f) call BJDebugMsg("timer = " + HandleType(t)) call BJDebugMsg("location = " + HandleType(p)) call BJDebugMsg("unit = " + HandleType(u)) call BJDebugMsg("item = " + HandleType(i)) call BJDebugMsg("effect = " + HandleType(e)) call BJDebugMsg("group = " + HandleType(g)) call BJDebugMsg("force = " + HandleType(f)) endfunction private function initHandleNamer takes nothing returns nothing local trigger t = CreateTrigger() call TriggerAddAction(t, function test) call TriggerRegisterTimerEvent(t, 0, false) endfunction endlibrary OUTPUT Code:
timer(new) = timer timer(run) = timer location = location unit = unit item = item effect = unknown group(empty) = group group(1) = group force(empty) = force force(1) = force *** DESTROY *** timer = unknown location = unknown unit = unit item = unknown effect = unknown group = unknown force = unknown |
