- Joined
- May 3, 2007
- Messages
- 210
I put up working with JASS a while ago out of frustration and laziness, but I took it up again just a bit ago. However, seeing as i'm sleep deprived and a little confused as to how it all works anymore, i'm kind of at a lose to what I was thinking back in the ol' days, i.e. i've lost my vision and I can't make sense of my old code anymore.
Here is the old mess:
And, the new mess:
Now That might be a little too much for the wondering eye, I imagine. So I suppose a little background is in order. The task was simple in my mind as I remember it, I wanted a way of handling events with greater respect, and rather with a dependency on units, individually. So I broke an old taboo about destroying Triggers, etc, got over that, decided I only wanted to register events that couldn't be done with PlayerUnitEvents to the local trigger inside the struct, and all the other events to the global one, discovered that hey, I can just "ignore" event procs, etc etc. Ultimately I feel like I'm missing something from old design which I gave up on long ago.
Now I realize my old design has some serious flaws, like a hashtable inside a struct (lol). And i'm sure the new one is riddled in is own, but thoughts, are kinda what i'm shooting for here.
Here is the old mess:
JASS:
library Unit requires Table
globals
playerunitevent array PLAYER_UNIT_EVENTS[46]
unitevent array UNIT_EVENTS[46]
Table wraps
hashtable units
trigger GLOBAL_EVENTS
trigger GLOBAL_COND_EVENTS
boolean array isRegistered[46][12]
boolean array isFilterReg[46][12]
timer queueTimer
integer queueCounter
trigger array queueStack[500]
integer GLOBAL_NORMAL = S2I("GLOBAL_NORMAL")
integer GLOBAL_FILTER = S2I("GLOBAL_FILTER")
integer LOCAL_NORMAL = S2I("LOCAL_NORMAL")
endglobals
function interface Actionfunc takes nothing returns nothing
function interface Conditionfunc takes nothing returns boolean
function HandleQueueTriggerDestroy takes nothing returns nothing
local integer i = queueCounter
local integer j = 0
if TimerGetElapsed(queueTimer) > 120 then
call DestroyTrigger(queueStack[j])
set queueStack[j] = null
call ResumeTimer(queueTimer)
loop
exitwhen j > i
set queueStack[j] = queueStack[j+1]
set j = j + 1
endloop
set queueCounter = queueCounter - 1
endif
endfunction
function UnitWrapperGlobalConditional takes nothing returns boolean
local UnitWrapper u = UnitWrapper.GetWrapper(GetTriggerUnit())
local integer e = UnitWrapper.getIndex(GetTriggerEventId())
local trigger t = GetTriggeringTrigger()
if t == GLOBAL_EVENTS then
return LoadBoolean(u.hasEvent,GLOBAL_NORMAL,e)
elseif t == GLOBAL_COND_EVENTS then
return LoadBoolean(u.hasEvent,GLOBAL_FILTER,e)
elseif t == u.trig then
return LoadBoolean(u.hasEvent,LOCAL_NORMAL,e)
endif
debug call BJDebugMsg("Error in UnitWrapperGlobalConditional : unknown triggering trigger")
return true
endfunction
function UnitWrapperGatewayActionLocal takes nothing returns nothing
local UnitWrapper u = UnitWrapper.GetWrapper(GetTriggerUnit())
local integer e = GetHandleId(GetTriggerEventId())
local integer i = 0
local integer count = LoadInteger(u.Actions,e,-1)
local Conditionfunc cond
local Actionfunc action
loop
exitwhen i > count
set cond = LoadInteger(u.Conditions,e,i)
set action = LoadInteger(u.Actions,e,i)
if cond.evaluate() then
call action.evaluate()
endif
set i = i + 1
endloop
endfunction
function UnitWrapperGatewayActionGlobal takes nothing returns nothing
local UnitWrapper u = UnitWrapper.GetWrapper(GetTriggerUnit())
local integer e = GetHandleId(GetTriggerEventId())
local integer i = 0
local integer count = LoadInteger(UnitWrapper.GlobalActions,e,-1)
local Conditionfunc cond
local Actionfunc action
loop
exitwhen i > count
set cond = LoadInteger(UnitWrapper.GlobalConditions,e,i)
set action = LoadInteger(UnitWrapper.GlobalActions,e,i)
if cond.evaluate() then
call action.evaluate()
endif
set i = i + 1
endloop
endfunction
struct UnitWrapper
integer userData
player owner
private integer id
private unit u
trigger trig
hashtable hasEvent
hashtable Actions
hashtable Conditions
private boolean array localIsReg[46]
static hashtable GlobalActions
static hashtable GlobalConditions
static method create takes player p, integer unitid, real x, real y, boolean flag returns UnitWrapper
local UnitWrapper uw
//local integer int = LoadInteger(units,unitid,-1)
local unit u
local integer i = 0
//if HaveSavedHandle(units,unitid,int) != null then
// set u = LoadUnitHandle(units,unitid,int)
// call SetUnitPathing(u,true)
// call ShowUnit(u,true)
// call SetUnitOwner(u,p,true)
// call SetUnitX(u, x)
// call SetUnitY(u, y)
// call SaveUnitHandle(units,unitid,int,null)
// call SaveInteger(units,unitid,-1,(int-1))
// if LoadInteger(units,unitid,-1) < 0 then
// call FlushChildHashtable(units,unitid)
// endif
// return UnitWrapper.GetWrapper(u)
//else
set uw = UnitWrapper.allocate()
set u = CreateUnit(p,unitid,x,y,0)
set uw.u = u
set uw.owner = p
set uw.trig = CreateTrigger()
call TriggerAddCondition(uw.trig,Condition(function UnitWrapperGlobalConditional))
call TriggerAddAction(uw.trig,function UnitWrapperGatewayActionLocal)
set uw.id = GetHandleId(u)
set wraps[uw.id] = uw
if flag then
loop
exitwhen i > 46
call SaveBoolean(uw.hasEvent,GLOBAL_NORMAL,i,true)
set i = i + 1
endloop
endif
return uw
//endif
debug call BJDebugMsg("Error in UnitWrapper.create()!")
return 0
endmethod
static method wrap takes unit u, boolean flag returns UnitWrapper
local UnitWrapper uw = UnitWrapper.allocate()
local integer i = 0
if not wraps.exists(GetHandleId(u)) then
set uw.u = u
set uw.owner = GetOwningPlayer(u)
set uw.trig = CreateTrigger()
call TriggerAddCondition(uw.trig,Condition(function UnitWrapperGlobalConditional))
call TriggerAddAction(uw.trig,function UnitWrapperGatewayActionLocal)
set uw.id = GetHandleId(u)
set wraps[uw.id] = uw
if flag then
loop
exitwhen i > 46
call SaveBoolean(uw.hasEvent,GLOBAL_NORMAL,i,true)
set i = i + 1
endloop
endif
return uw
else
if flag then
loop
exitwhen i > 46
call SaveBoolean(uw.hasEvent,GLOBAL_NORMAL,i,true)
set i = i + 1
endloop
endif
return wraps[GetHandleId(u)]
endif
endmethod
method destroy takes nothing returns nothing
call TriggerClearActions(this.trig)
call TriggerClearConditions(this.trig)
//call ResetTrigger(this.trig)
call UnitWrapper.QueueDestroy(this.trig)
set this.trig = null
call wraps.flush(this.id)
call this.destroy()
endmethod
// Currently ignoring this option, not even sure I want internal unit recycling.
// method recycle takes nothing returns nothing
// local integer q = LoadInteger(units,GetUnitTypeId(this.u),-1)
// if this.u != null then
// call ShowUnit(this.u,false)
// call SetUnitPathing(this.u,false)
// call SetUnitOwner(this.u,Player(14),false)
// if GetUnitState(this.u,UNIT_STATE_LIFE) < 0 then
// call SetUnitState(this.u,UNIT_STATE_LIFE,GetUnitState(this.u,UNIT_STATE_MAX_LIFE))
// call SetUnitState(this.u,UNIT_STATE_MANA,GetUnitState(this.u,UNIT_STATE_MAX_MANA))
// endif
// call SetUnitX(this.u, GetRectMaxX(bj_mapInitialPlayableArea)+100)
// call SetUnitY(this.u, GetRectMaxY(bj_mapInitialPlayableArea)+100)
// call SaveUnitHandle(units,GetUnitTypeId(this.u),q,this.u)
// call SaveInteger(units,GetUnitTypeId(this.u),-1,(q+1))
// else
// debug call BJDebugMsg("Unit in wrapper does not exist")
// endif
// endmethod
static method GetWrapper takes unit u returns UnitWrapper
return wraps[GetHandleId(u)]
endmethod
method RegisterSimple takes unitevent ue returns nothing
local integer e = UnitWrapper.getIndex(ue)
local integer p = GetPlayerId(this.owner)
if e < 42 then
if isRegistered[e] then
call SaveBoolean(this.hasEvent,GLOBAL_NORMAL,e,true)
else
call TriggerRegisterPlayerUnitEvent(GLOBAL_EVENTS,this.owner,PLAYER_UNIT_EVENTS[e],null)
set isRegistered[e] = true
call SaveBoolean(this.hasEvent,GLOBAL_NORMAL,e,true)
endif
else
if this.localIsReg[e] then
call SaveBoolean(this.hasEvent,LOCAL_NORMAL,e,true)
else
call TriggerRegisterUnitEvent(this.trig,this.u,UNIT_EVENTS[e])
set this.localIsReg[e] = true
call SaveBoolean(this.hasEvent,LOCAL_NORMAL,e,true)
endif
endif
endmethod
method RegisterInRange takes real range, boolexpr condition returns nothing
local integer e = UnitWrapper.getIndex(EVENT_UNIT_TARGET_IN_RANGE)
call TriggerRegisterUnitInRange(this.trig,this.u,range,condition)
call SaveBoolean(this.hasEvent,LOCAL_NORMAL,e,true)
endmethod
method RegisterUnitState takes unitstate state, limitop limit, real limitval returns nothing
local integer e = UnitWrapper.getIndex(EVENT_UNIT_STATE_LIMIT)
call TriggerRegisterUnitStateEvent(this.trig,this.u,state,limit,limitval)
call SaveBoolean(this.hasEvent,LOCAL_NORMAL,e,true)
endmethod
method RegisterFilter takes unitevent ue, boolexpr condition returns nothing
local integer e = UnitWrapper.getIndex(ue)
call TriggerRegisterFilterUnitEvent(this.trig,this.u,ue,condition)
call SaveBoolean(this.hasEvent,LOCAL_NORMAL,e,true)
endmethod
static method RegisterGlobal takes playerunitevent pe, integer playerId, boolean forAllPlayers returns nothing
local integer e = UnitWrapper.getIndex(pe)
local integer i = 0
local integer j = 0
if forAllPlayers then
loop
exitwhen i > GetPlayers()
if not isRegistered[e][i] then
call TriggerRegisterPlayerUnitEvent(GLOBAL_EVENTS,Player(i),PLAYER_UNIT_EVENTS[e],null)
set isRegistered[e][i] = true
endif
set i = i + 1
endloop
else
if not isRegistered[e][playerId] then
call TriggerRegisterPlayerUnitEvent(GLOBAL_EVENTS,Player(playerId),PLAYER_UNIT_EVENTS[e],null)
set isRegistered[e][playerId] = true
endif
endif
endmethod
static method RegisterGlobalFilter takes playerunitevent pe, player p, boolexpr condition returns nothing
local integer e = UnitWrapper.getIndex(pe)
call TriggerRegisterPlayerUnitEvent(GLOBAL_COND_EVENTS,p,pe,condition)
set isFilterReg[e][GetPlayerId(p)] = true
endmethod
method IgnoreLocal takes unitevent ue returns nothing
local integer e = UnitWrapper.getIndex(ue)
if HaveSavedBoolean(this.hasEvent,LOCAL_NORMAL,e) then
call SaveBoolean(this.hasEvent,LOCAL_NORMAL,e,false)
endif
endmethod
method IgnoreGlobal takes unitevent ue returns nothing
local integer e = UnitWrapper.getIndex(ue)
if HaveSavedBoolean(this.hasEvent,GLOBAL_NORMAL,e) then
call SaveBoolean(this.hasEvent,GLOBAL_NORMAL,e,false)
endif
endmethod
method IgnoreGlobalFilter takes playerunitevent pe returns nothing
local integer e = UnitWrapper.getIndex(pe)
call SaveBoolean(this.hasEvent,GLOBAL_FILTER,e,false)
endmethod
method Clear takes nothing returns nothing
local trigger t = this.trig
call UnitWrapper.QueueDestroy(this.trig)
set this.trig = null
set this.trig = CreateTrigger()
set t = null
endmethod
static method ClearGlobal takes nothing returns nothing
local trigger t = GLOBAL_COND_EVENTS
call UnitWrapper.QueueDestroy(GLOBAL_COND_EVENTS)
set GLOBAL_COND_EVENTS = null
set GLOBAL_COND_EVENTS = CreateTrigger()
set t = null
endmethod
method AddAction takes eventid e, Actionfunc action, Conditionfunc condition returns integer
local integer fkey = GetHandleId(e)
local integer skey = LoadInteger(this.Actions,fkey,-1)
call SaveInteger(this.Actions,fkey,skey,action)
call SaveInteger(this.Conditions,fkey,skey,condition)
call SaveInteger(this.Actions,fkey,skey,skey+1)
return (skey+1)
endmethod
method RemoveActions takes eventid e returns nothing
local integer fkey = GetHandleId(e)
call FlushChildHashtable(this.Actions,fkey)
call FlushChildHashtable(this.Conditions,fkey)
endmethod
method RemoveAction takes eventid e, integer index returns nothing
local integer fkey = GetHandleId(e)
local integer skey = LoadInteger(this.Actions,fkey,-1)
local integer i = 0
call RemoveSavedInteger(this.Actions,fkey,index)
call RemoveSavedInteger(this.Conditions,fkey,index)
loop
exitwhen i > skey
call SaveInteger(this.Actions,fkey,i,(LoadInteger(this.Actions,fkey,i+1)))
call SaveInteger(this.Conditions,fkey,i,(LoadInteger(this.Conditions,fkey,i+1)))
set i = i + 1
endloop
endmethod
static method AddGlobalAction takes playerunitevent pe, Actionfunc action, Conditionfunc condition returns integer
local integer fkey = GetHandleId(pe)
local integer skey = LoadInteger(GlobalActions,fkey,-1)
call SaveInteger(GlobalActions,fkey,skey,action)
call SaveInteger(GlobalConditions,fkey,skey,condition)
call SaveInteger(GlobalActions,fkey,skey,skey+1)
return (skey+1)
endmethod
static method RemoveGlobalActions takes playerunitevent pe returns nothing
local integer fkey = GetHandleId(pe)
call FlushChildHashtable(GlobalActions,fkey)
call FlushChildHashtable(GlobalConditions,fkey)
endmethod
static method RemoveGlobalAction takes playerunitevent pe, integer index returns nothing
local integer fkey = GetHandleId(pe)
local integer skey = LoadInteger(GlobalActions,fkey,-1)
local integer i = 0
call RemoveSavedInteger(GlobalActions,fkey,index)
call RemoveSavedInteger(GlobalConditions,fkey,index)
loop
exitwhen i > skey
call SaveInteger(GlobalActions,fkey,i,(LoadInteger(GlobalActions,fkey,i+1)))
call SaveInteger(GlobalConditions,fkey,i,(LoadInteger(GlobalConditions,fkey,i+1)))
set i = i + 1
endloop
endmethod
static method getIndex takes eventid id returns integer
local integer i = 0
loop
exitwhen i > 46
if UNIT_EVENTS[i] == id then
return i
elseif PLAYER_UNIT_EVENTS[i] == id then
return i
endif
set i = i + 1
endloop
return -1
endmethod
private static method QueueDestroy takes trigger t returns nothing
set queueStack[queueCounter] = t
set queueCounter = queueCounter + 1
set t = null
call ResumeTimer(queueTimer)
endmethod
private static method onInit takes nothing returns nothing
local integer i = 18
local integer j = 0
set wraps = Table.create()
set units = InitHashtable()
set queueTimer = CreateTimer()
call TriggerAddCondition(GLOBAL_EVENTS,Condition(function UnitWrapperGlobalConditional))
call TriggerAddAction(GLOBAL_EVENTS,function UnitWrapperGatewayActionGlobal)
call TriggerAddAction(GLOBAL_EVENTS,function UnitWrapperGatewayActionLocal)
call TriggerAddCondition(GLOBAL_COND_EVENTS,Condition(function UnitWrapperGlobalConditional))
call TriggerAddAction(GLOBAL_COND_EVENTS,function UnitWrapperGatewayActionGlobal)
call TimerStart(queueTimer,240,true,function HandleQueueTriggerDestroy)
call PauseTimer(queueTimer)
loop
exitwhen i > 51
set PLAYER_UNIT_EVENTS[j] = ConvertPlayerUnitEvent(i)
set i = i + 1
set j = j + 1
endloop
set i = 269
loop
exitwhen i > 277
set PLAYER_UNIT_EVENTS[j] = ConvertPlayerUnitEvent(i)
set i = i + 1
set j = j + 1
endloop
set UNIT_EVENTS[0] = EVENT_UNIT_ATTACKED
set UNIT_EVENTS[1] = EVENT_UNIT_RESCUED
set UNIT_EVENTS[2] = EVENT_UNIT_DEATH
set UNIT_EVENTS[3] = EVENT_UNIT_DECAY
set UNIT_EVENTS[4] = EVENT_UNIT_DETECTED
set UNIT_EVENTS[5] = EVENT_UNIT_HIDDEN
set UNIT_EVENTS[6] = EVENT_UNIT_SELECTED
set UNIT_EVENTS[7] = EVENT_UNIT_DESELECTED
set i = 64
set j = 9
loop
exitwhen i > 88
set UNIT_EVENTS[j] = ConvertUnitEvent(i)
set i = i + 1
set j = j + 1
endloop
set i = 286
loop
exitwhen i > 294
set UNIT_EVENTS[j] = ConvertUnitEvent(i)
set i = i + 1
set j = j + 1
endloop
set UNIT_EVENTS[43] = EVENT_UNIT_ACQUIRED_TARGET
set UNIT_EVENTS[44] = EVENT_UNIT_DAMAGED
set UNIT_EVENTS[45] = EVENT_UNIT_TARGET_IN_RANGE
set UNIT_EVENTS[46] = EVENT_UNIT_STATE_LIMIT
endmethod
endstruct
endlibrary
And, the new mess:
JASS:
library UnWrap requires Table
globals
Table wraps
playerunitevent array PLAYER_UNIT_EVENTS[46]
unitevent array UNIT_EVENTS[46]
boolean array GlobalRegistry[46][12]
trigger GLOBAL_TRIG = CreateTrigger()
endglobals
function interface Actionfunc takes nothing returns nothing
function interface Conditionfunc takes nothing returns boolean
function Gateway takes nothing returns nothing
local UnitWrapper u = UnitWrapper.GetWrap(GetTriggerUnit())
local integer e = UnitWrapper.getIndex(GetTriggerEventId())
local Actionfunc a = u.actions[e]
local Conditionfunc c = u.conditions[e]
if c.evaluate() and u.hasEvent(e) then
call a.evaluate()
endif
endfunction
struct UnitWrapper
player owner
integer id
unit u
trigger t
boolean array hasEvent[46]
boolean array LocalRegistry[4]
integer array actions[46]
integer array conditions[46]
static method create takes player p, integer id, real x, real y, real face returns UnitWrapper
local UnitWrapper uw
local unit u
set uw = UnitWrapper.allocate()
set uw.u = CreateUnit(p,id,x,y,face)
set uw.id = GetHandleId(uw.u)
set uw.owner = p
set uw.t = CreateTrigger()
call TriggerAddAction(uw.t, function Gateway)
set wraps[uw.id] = uw
return uw
endmethod
static method wrap takes unit u returns UnitWrapper
local UnitWrapper uw
if not wraps.exists(GetHandleId(u)) then
set uw = UnitWrapper.allocate()
set uw.u = u
set uw.id = GetHandleId(u)
set uw.owner = GetOwningPlayer(u)
set uw.t = CreateTrigger()
call TriggerAddAction(uw.t, function Gateway)
set wraps[uw.id] = uw
return uw
endif
return wraps[GetHandleId(u)]
endmethod
method destroy takes nothing returns nothing
call TriggerClearActions(this.trig)
call TriggerClearConditions(this.trig)
//call UnitWrapper.QueueDestroy(this.trig)
set this.trig = null
call wraps.flush(this.id)
call this.destroy()
endmethod
static method GetWrap takes unit u returns UnitWrapper
return wraps[GetHandleId(u)]
endmethod
method RegisterSimple takes unitevent ue returns nothing
local integer e = UnitWrapper.getIndex(ue)
local integer p = GetPlayerId(this.owner)
if e < 42 then
if GlobalRegistry[e] then
set this.hasEvent[e] = true
else
call TriggerRegisterPlayerUnitEvent(GLOBAL_TRIG,this.owner,PLAYER_UNIT_EVENTS[e],null)
set GlobalRegistry[e] = true
set hasEvent[e] = true
endif
else
if this.LocalRegistry[e-42] then
call this.hasEvent[e] = true
else
call TriggerRegisterUnitEvent(this.trig,this.u,UNIT_EVENTS[e])
set this.LocalRegistry[e-42] = true
set this.hasEvent[e] = true
endif
endif
endmethod
method Ignore takes unitevent ue returns nothing
local integer e = UnitWrapper.getIndex(ue)
set this.hasEvent[e] = false
endmethod
method AddAction takes Actionfunc a, Conditionfunc c, unitevent ue returns nothing
local integer e = UnitWrapper.getIndex(ue)
set this.actions[e] = a
set this.conditions[e] = c
endmethod
method RemoveAction takes unitevent ue returns nothing
local integer e = UnitWrapper.getIndex(ue)
set this.actions[e] = null
set this.conditions[e] = null
endmethod
static method getIndex takes eventid id returns integer
local integer i = 0
loop
exitwhen i > 46
if UNIT_EVENTS[i] == id then
return i
elseif PLAYER_UNIT_EVENTS[i] == id then
return i
endif
set i = i + 1
endloop
return -1
endmethod
private static method onInit takes nothing returns nothing
local integer i = 18
local integer j = 0
set wraps = Table.create()
call TriggerAddAction(GLOBAL_TRIG, function Gateway)
loop
exitwhen i > 51
set PLAYER_UNIT_EVENTS[j] = ConvertPlayerUnitEvent(i)
set i = i + 1
set j = j + 1
endloop
set i = 269
loop
exitwhen i > 277
set PLAYER_UNIT_EVENTS[j] = ConvertPlayerUnitEvent(i)
set i = i + 1
set j = j + 1
endloop
set UNIT_EVENTS[0] = EVENT_UNIT_ATTACKED
set UNIT_EVENTS[1] = EVENT_UNIT_RESCUED
set UNIT_EVENTS[2] = EVENT_UNIT_DEATH
set UNIT_EVENTS[3] = EVENT_UNIT_DECAY
set UNIT_EVENTS[4] = EVENT_UNIT_DETECTED
set UNIT_EVENTS[5] = EVENT_UNIT_HIDDEN
set UNIT_EVENTS[6] = EVENT_UNIT_SELECTED
set UNIT_EVENTS[7] = EVENT_UNIT_DESELECTED
set i = 64
set j = 9
loop
exitwhen i > 88
set UNIT_EVENTS[j] = ConvertUnitEvent(i)
set i = i + 1
set j = j + 1
endloop
set i = 286
loop
exitwhen i > 294
set UNIT_EVENTS[j] = ConvertUnitEvent(i)
set i = i + 1
set j = j + 1
endloop
set UNIT_EVENTS[43] = EVENT_UNIT_ACQUIRED_TARGET
set UNIT_EVENTS[44] = EVENT_UNIT_DAMAGED
set UNIT_EVENTS[45] = EVENT_UNIT_TARGET_IN_RANGE
set UNIT_EVENTS[46] = EVENT_UNIT_STATE_LIMIT
endmethod
endstruct
endlibrary
Now That might be a little too much for the wondering eye, I imagine. So I suppose a little background is in order. The task was simple in my mind as I remember it, I wanted a way of handling events with greater respect, and rather with a dependency on units, individually. So I broke an old taboo about destroying Triggers, etc, got over that, decided I only wanted to register events that couldn't be done with PlayerUnitEvents to the local trigger inside the struct, and all the other events to the global one, discovered that hey, I can just "ignore" event procs, etc etc. Ultimately I feel like I'm missing something from old design which I gave up on long ago.
Now I realize my old design has some serious flaws, like a hashtable inside a struct (lol). And i'm sure the new one is riddled in is own, but thoughts, are kinda what i'm shooting for here.