- Joined
- May 9, 2014
- Messages
- 1,819
Greetings, HIVERS.
This is a library that goes beyond the conventional functionality of
If you need to use the Hashtable version, just set USE_HASH to true. If you want safety in recursion depth, you can set Event.SAFETY_ENABLED to true.
By default, the fire and run method in the struct Event indirectly cheat the op limit.
A clear method operator that will clear the designated trigger group related to the real instance of the event instance. (Re-implemented in Wurst)
This is a library that goes beyond the conventional functionality of
TriggerRegisterVariableEvent
by mimicking its' interface and providing a safe unregistration of instances. It can also fire all triggers related to the event if possible. This is directed to vJASSers, casual and extreme alike.If you need to use the Hashtable version, just set USE_HASH to true. If you want safety in recursion depth, you can set Event.SAFETY_ENABLED to true.
By default, the fire and run method in the struct Event indirectly cheat the op limit.
A clear method operator that will clear the designated trigger group related to the real instance of the event instance. (Re-implemented in Wurst)
vJASS
Wurst
JASS:
library PseudoVarEvent requires /*
*/ AllocationAndLinks, /*
* - For the allocation and creation of the necessary linked lists
*
*/ optional Table /*
* - Bribe, https://www.hiveworkshop.com/threads/snippet-new-table.188084/
* - Allows USE_HASH to take effect.
*
*/ optional UtilityFunctions /*
* - Allows a break line in the console, but otherwise useless.
* Ignore if possible.
*
*/
/*
* /================/
* /Pseudo Var Event/
* /v.1.2.0.0 /
* /================/
*
* - A library for easily creating new Events and allowing the execution of triggers through those Events.
* Much like jesus4lyf's event, but with the ability to act as a priority queue if configured well enough.
*
* ====================================================//
* What is Pseudo Var Event? //
* ====================================================//
*
* - It is a library which allows one to easily create a trigger group that will fire when an Event instance
* is fired or ran. Registering the individual triggers won't be that much of a hassle, since it is regulated
* via the struct EventTrigs' register method. Unregistering is a breeze as well, which allows triggers in the
* trigger group to no longer fire.
*
* ====================================================//
* Application Programming Interface //
* ====================================================//
*
* struct Event
*
* important variables:
* readonly static Event array current
* - The array that holds the necessary Event.
* readonly static real array real
* - The array that holds the necessary real instance.
* readonly static integer instruction
* - The integer that tells the handler trigger (Event.EXEC) which function to call.
* readonly static integer count_parallel
* - The integer that tells how many times the Event thread has been called.
* (Either through run() or op_fire(real r)
* readonly static integer count
* - The integer that holds the depth of recursion.
*
* readonly static constant trigger EXEC
* - The handler trigger that calls the appropriate methods in the struct EventTrigs
* depending on the instruction sent.
*
* methods:
* private static method remap()
* - remaps the currently firing Event and its' equivalent real.
* method create() returns Event
* - constructor method.
* method run()
* - Fires all triggers related to that Event. Checks if a trigger has been already been fired once.
* method op_fire(real r)
* - Fires all triggers related to the real instance of the Event.
*
* struct EventTrigs
*
* important variables:
*
* methods:
* private static method event_get(Event e) returns EventTrigs
* - Returns the head of the Event instance. (Acts as a wrapper for EventTrigs(e).head)
* O(1) complexity
* private static method real_get(Event e, real r) returns EventTrigs
* - Returns the head of the real instance of the Event instance. (Internally calls event_get(e))
* Potential O(n) complexity
* private static method trigger_get(Event e, real r, trigger t) returns EventTrigs
* - Returns the unique trigger of the real instance of the Event instance. (calls real_get(e, r))
* Potential O(2n) complexity
* static method getInstance(Event e, real r, trigger t) returns EventTrigs
* - Wrapper for trigger_get(e, r, t). Also adds backwards compatibility.
* private method unlink()
* - Removes the links of a certain EventTrigs instance.
* method unregister()
* - Destructor of an EventTrigs instance. (Internally calls unlink)
* private method link(Event e, real r, trigger t)
* - Adds the links for a certain trigger instance.
* static method register(Event e, real r, trigger t)
* - Constructor of an EventTrigs instance. (If instance exists, acts as a wrapper for
* trigger_get(e, r, t))
* method op_eventid(Event e)
* - Remaps the instance to another Event.
* method op_event(real r)
* - Remaps the instance to another real instance of the Event.
*
* module generated methods:
* static method fire(Event e, real r)
* - Is called when op_(Event(instance).fire = r) is called. (See Event.op_fire for more
* details)
* static method all_fire(Event e)
* - Is called when Event.run() is called. (See Event.run for more details)
* static method remove(Event e)
* - Is called when Event.destroy() is called. It destroys all EventTrigs instances related to
* the Event instace.
*
* imported modules:
* module EventTrigs_all_fire
* module EventTrigs_fire
* module EventTrigs_remove
* - These modules are implemented to maximize readability in the main struct.
* Very difficult to read and understand, but more important to not touch!
*
* module Alloc_MyPad or AllocH
* module DoubleLink(H)_event
* module DoubleLink(H)_real
* module DoubleLink(H)_trigger
* - These modules are responsible for making everything in the struct work more
* properly such as the addition of an allocator and deallocator method, of which
* the custom implementation is favored over the former.
*
* The DoubleLink modules are what essentially enables easy link creation.
*
* globals:
* private constant boolean USE_HASH
* - Affects the struct EventTrigs.
* private constant boolean ALLOW_DEBUG
* - Will only print messages if already in debug mode.
*
* functions:
* LineBreak()
* - Prints an empty line.
* constant GetEvent() returns Event
* - Returns the current Event (Event.current[count])
* constant GetRealEvent() returns real
* - Returns the current real instance of the Event (Event.real[count])
*/
globals
private constant boolean USE_HASH = true
private constant boolean ALLOW_DEBUG = false
endglobals
static if not LIBRARY_UtilityFunctions then
function LineBreak takes nothing returns nothing
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, " ")
endfunction
endif
struct Event extends array
implement Alloc_MyPad
// For static depth
private static constant boolean SAFETY_ENABLED = false
private static constant integer FIRE_WARNING = 16
private static constant integer FIRE_LIMIT = 32
// For the execution
readonly static thistype array current
readonly static real array real
readonly static integer instruction = 0
readonly static integer count_parallel = 0
readonly static integer count = 0
// For the handler-triggercondition
readonly static constant trigger EXEC = CreateTrigger()
private static method remap takes nothing returns nothing
set current[count] = current[0]
set real[count] = real[0]
set count = count - 1
if count <= 0 then
set count = 0
set count_parallel = 0
endif
endmethod
method destroy takes nothing returns nothing
set count = count + 1
set instruction = 3
set current[count] = this
call TriggerEvaluate(EXEC)
call deallocate()
call remap()
endmethod
method run takes nothing returns nothing
set count = count + 1
set count_parallel = count_parallel + 1
set instruction = 2
set current[count] = this
static if not thistype.SAFETY_ENABLED then
call TriggerEvaluate(EXEC)
else
if count > thistype.FIRE_LIMIT then
debug call BJDebugMsg("Error: Depth exceeded fire limit!")
else
if count > thistype.FIRE_WARNING then
debug call BJDebugMsg("Warning: Recursive call of fire limit detected!")
debug call BJDebugMsg("Please refrain from calling a run method within the firing of an Event")
debug call BJDebugMsg("Depth of recursion: " + I2S(count))
debug call BJDebugMsg("========================")
debug call BJDebugMsg(" ")
endif
call TriggerEvaluate(EXEC)
endif
endif
call remap()
endmethod
method operator fire= takes real r returns nothing
set count = count + 1
set count_parallel = count_parallel + 1
set instruction = 1
set current[count] = this
set real[count] = r
static if not thistype.SAFETY_ENABLED then
call TriggerEvaluate(EXEC)
else
if count > thistype.FIRE_LIMIT then
debug call BJDebugMsg("Error: Depth exceeded fire limit!")
else
if count > thistype.FIRE_WARNING then
debug call BJDebugMsg("Warning: Recursive call of fire limit detected!")
debug call BJDebugMsg("Please refrain from calling a fire method within the firing of an Event")
debug call BJDebugMsg("Depth of recursion: " + I2S(count))
debug call BJDebugMsg("========================")
debug call BJDebugMsg(" ")
endif
call TriggerEvaluate(EXEC)
endif
endif
call remap()
endmethod
static method create takes nothing returns thistype
return allocate()
endmethod
static method isWarning takes nothing returns boolean
static if thistype.SAFETY_ENABLED then
return count < FIRE_WARNING
else
return true
endif
endmethod
endstruct
constant function GetEvent takes nothing returns Event
return Event.current[Event.count]
endfunction
constant function GetRealEvent takes nothing returns real
return Event.real[Event.count]
endfunction
function RecursionFlag takes nothing returns boolean
return Event.isWarning()
endfunction
function Execute takes code func returns nothing
call ForForce(bj_FORCE_PLAYER[0], func)
endfunction
private module EventTrigs_fire
static if LIBRARY_Table and USE_HASH then
private static thistype EventTrigs_fire_head = 0
private static thistype EventTrigs_fire_this = 0
private static integer EventTrigs_fire_i = 0
private static method exec_fire takes nothing returns nothing
set EventTrigs_fire_i = 0
loop
exitwhen EventTrigs_fire_this == EventTrigs_fire_head or EventTrigs_fire_i >= 80
if IsTriggerEnabled(EventTrigs_fire_this.trigger) then
call ConditionalTriggerExecute(EventTrigs_fire_this.trigger)
endif
set EventTrigs_fire_this = EventTrigs_fire_this.trigger_next
set EventTrigs_fire_i = EventTrigs_fire_i + 1
endloop
if EventTrigs_fire_i >= 80 then
call Execute(function thistype.exec_fire)
return
endif
set EventTrigs_fire_head = 0
set EventTrigs_fire_this = 0
set EventTrigs_fire_i = 0
endmethod
endif
static method fire takes Event e, real r returns nothing
static if LIBRARY_Table and USE_HASH then
set EventTrigs_fire_head = real_get(e, r)
set EventTrigs_fire_this = EventTrigs_fire_head.trigger_next
if EventTrigs_fire_head == 0 then
set EventTrigs_fire_head = 0
set EventTrigs_fire_this = 0
return
endif
if IsTriggerEnabled(EventTrigs_fire_head.trigger) then
call ConditionalTriggerExecute(EventTrigs_fire_head.trigger)
endif
call exec_fire()
else
local thistype head = real_get(e, r)
local thistype this = head.trigger_next
if head == 0 then
return
endif
if IsTriggerEnabled(head.trigger) then
call ConditionalTriggerExecute(head.trigger)
endif
loop
exitwhen this == head
if IsTriggerEnabled(trigger) then
call ConditionalTriggerExecute(trigger)
endif
set this = trigger_next
endloop
endif
endmethod
endmodule
private module EventTrigs_all_fire
static if LIBRARY_Table and USE_HASH then
//! runtextmacro op_set("Num05", "EventTrigs_all_fire_trig", "trigger", "null", "")
private static method onInit takes nothing returns nothing
set Num05 = Table.create()
endmethod
else
private trigger EventTrigs_all_fire_trig
endif
private static integer EventTrigs_all_fire_count = 0
private static method EventTrigs_all_fire_check takes trigger t returns boolean
local thistype this = 1
loop
exitwhen integer(this) > EventTrigs_all_fire_count or EventTrigs_all_fire_trig == t
set this = this + 1
endloop
if integer(this) > EventTrigs_all_fire_count then
set this = 0
endif
return this == 0
endmethod
private static method EventTrigs_all_fire_clear takes nothing returns nothing
local thistype this = 1
loop
exitwhen integer(this) > EventTrigs_all_fire_count
set EventTrigs_all_fire_trig = thistype(0).EventTrigs_all_fire_trig
set this = this + 1
endloop
set EventTrigs_all_fire_count = 0
endmethod
static if LIBRARY_Table and USE_HASH then
private static thistype EventTrigs_all_fire_head = 0
private static thistype EventTrigs_all_fire_this = 0
private static integer EventTrigs_all_fire_i = 0
private static method exec_all_fire takes nothing returns nothing
set EventTrigs_all_fire_i = 0
loop
exitwhen EventTrigs_all_fire_this == EventTrigs_all_fire_head or EventTrigs_all_fire_i >= 75
if IsTriggerEnabled(EventTrigs_all_fire_this.trigger) then
if EventTrigs_all_fire_check(EventTrigs_all_fire_this.trigger) then
call ConditionalTriggerExecute(EventTrigs_all_fire_this.trigger)
set EventTrigs_all_fire_count = EventTrigs_all_fire_count + 1
set thistype(EventTrigs_all_fire_count).EventTrigs_all_fire_trig = EventTrigs_all_fire_this.trigger
endif
endif
set EventTrigs_all_fire_this = EventTrigs_all_fire_this.event_next
set EventTrigs_all_fire_i = EventTrigs_all_fire_i + 1
endloop
if EventTrigs_all_fire_i >= 75 then
call Execute(function thistype.exec_all_fire)
return
endif
set EventTrigs_all_fire_head = 0
set EventTrigs_all_fire_this = 0
set EventTrigs_all_fire_i = 0
call Execute(function thistype.EventTrigs_all_fire_clear)
endmethod
endif
static method all_fire takes Event e returns nothing
static if LIBRARY_Table and USE_HASH then
set EventTrigs_all_fire_head = event_get(e)
set EventTrigs_all_fire_this = EventTrigs_all_fire_head.event_next
if EventTrigs_all_fire_head == 0 then
set EventTrigs_all_fire_head = 0
set EventTrigs_all_fire_this = 0
return
endif
if IsTriggerEnabled(EventTrigs_all_fire_head.trigger) then
if EventTrigs_all_fire_check(EventTrigs_all_fire_head.trigger) then
call ConditionalTriggerExecute(EventTrigs_all_fire_head.trigger)
set EventTrigs_all_fire_count = EventTrigs_all_fire_count + 1
set thistype(EventTrigs_all_fire_count).EventTrigs_all_fire_trig = EventTrigs_all_fire_head.trigger
endif
endif
call exec_all_fire()
else
local thistype head = event_get(e)
local thistype this = head.event_next
if head == 0 then
return
endif
if IsTriggerEnabled(head.trigger) then
if EventTrigs_all_fire_check(head.trigger) then
call ConditionalTriggerExecute(head.trigger)
set EventTrigs_all_fire_count = EventTrigs_all_fire_count + 1
set thistype(EventTrigs_all_fire_count).EventTrigs_all_fire_trig = head.trigger
endif
endif
loop
exitwhen this == head
if IsTriggerEnabled(trigger) then
if EventTrigs_all_fire_check(trigger) then
call ConditionalTriggerExecute(trigger)
set EventTrigs_all_fire_count = EventTrigs_all_fire_count + 1
set thistype(EventTrigs_all_fire_count).EventTrigs_all_fire_trig = trigger
endif
endif
set this = event_next
endloop
call Execute(function thistype.EventTrigs_all_fire_clear)
endif
endmethod
endmodule
private module EventTrigs_remove
static if LIBRARY_Table and USE_HASH then
private static thistype EventTrigs_remove_head = 0
private static thistype EventTrigs_remove_this = 0
private static integer EventTrigs_remove_i = 0
private static method exec_remove takes nothing returns nothing
set EventTrigs_remove_i = 0
loop
exitwhen EventTrigs_remove_this == EventTrigs_remove_head or EventTrigs_remove_i >= 80
call EventTrigs_remove_this.unregister()
set EventTrigs_remove_this = EventTrigs_remove_this.event_prev
set EventTrigs_remove_i = EventTrigs_remove_i + 1
endloop
if EventTrigs_remove_i >= 80 then
call Execute(function thistype.exec_remove)
return
endif
call EventTrigs_remove_this.unregister()
set EventTrigs_remove_head = 0
set EventTrigs_remove_this = 0
set EventTrigs_remove_i = 0
endmethod
endif
static method remove takes Event e returns nothing
static if LIBRARY_Table and USE_HASH then
set EventTrigs_remove_head = event_get(e)
set EventTrigs_remove_this = EventTrigs_remove_head.event_prev
if EventTrigs_remove_head == 0 then
set EventTrigs_remove_head = 0
set EventTrigs_remove_this = 0
return
endif
call exec_remove()
else
local thistype head = event_get(e)
local thistype this = head.event_prev
if head == 0 then
return
endif
loop
exitwhen this == head
call unregister()
set this = event_prev
endloop
call unregister()
endif
endmethod
endmodule
static if LIBRARY_Table and USE_HASH then
//! runtextmacro link_moduleH("event", "private")
//! runtextmacro link_moduleH("trigger", "private")
//! runtextmacro link_moduleH("real", "private")
private module EventTrigs_m
private static method onInit takes nothing returns nothing
set Num01 = Table.create()
set Num02 = Table.create()
set Num03 = Table.create()
set Num04 = Table.create()
endmethod
endmodule
else
//! runtextmacro link_module("event", "private")
//! runtextmacro link_module("trigger", "private")
//! runtextmacro link_module("real", "private")
endif
struct EventTrigs extends array
static if LIBRARY_Table and USE_HASH then
implement AllocH
//! runtextmacro op_read("Num01", "event", "integer", "0")
//! runtextmacro op_read("Num02", "trigger", "trigger", "null")
//! runtextmacro op_read("Num03", "real", "real", "0.")
//! runtextmacro op_set("Num04", "head", "integer", "0", "private")
implement DoubleLinkH_event
implement DoubleLinkH_trigger
implement DoubleLinkH_real
implement EventTrigs_m
else
implement Alloc_MyPad
readonly integer event
readonly trigger trigger
readonly real real
private integer head
implement DoubleLink_event
implement DoubleLink_trigger
implement DoubleLink_real
endif
private static method event_get takes Event e returns thistype
static if ALLOW_DEBUG then
debug call BJDebugMsg("thistype.event_get: returning {" + I2S(thistype(e).head) + "}")
endif
return thistype(e).head
endmethod
private static method real_get takes Event e, real r returns thistype
local thistype head = event_get(e)
local thistype this = head.real_next
if head == 0 or head.real == r then
static if ALLOW_DEBUG then
debug call BJDebugMsg("thistype.real_get: {head} returning {" + I2S(head) + "}")
endif
return head
endif
loop
exitwhen this == head or this == 0 or real == r
set this = real_next
endloop
if this == head then
set this = 0
endif
static if ALLOW_DEBUG then
debug call BJDebugMsg("thistype.real_get: {this} returning {" + I2S(this) + "}")
endif
return this
endmethod
private static method trigger_get takes Event e, real r, trigger t returns thistype
local thistype head = real_get(e, r)
local thistype this = head.trigger_next
if head == 0 or head.trigger == t then
static if ALLOW_DEBUG then
debug call BJDebugMsg("thistype.trigger_get: {head} returning {" + I2S(head) + "}")
endif
return head
endif
loop
exitwhen this == head or this == 0 or trigger == t
set this = trigger_next
endloop
if this == head then
set this = 0
endif
static if ALLOW_DEBUG then
debug call BJDebugMsg("thistype.trigger_get: {this} returning {" + I2S(this) + "}")
endif
return this
endmethod
static method getInstance takes Event e, real r, trigger t returns thistype
return trigger_get(e, r, t)
endmethod
private method unlink takes nothing returns nothing
local thistype that = event_get(event)
// If the instance is the head of the list of the Event instance...
if this == that then
// Check if the next EventTrigs trigger instance exists.
if trigger_next != this then
// Trigger instance exists.
set that = trigger_next
call that.real_insert(real_next)
// Check if the next EventTrigs real instance exists...
elseif real_next != this then
// It exists
set that = real_next
else
set that = 0
endif
call real_pop()
set thistype(event).head = that
else
// If the instance is a head of its' real list.
if real_head != 0 then
// Check if the next EventTrigs trigger instance exists...
if trigger_next != this then
set that = trigger_next
call that.real_insert(real_next)
endif
call real_pop()
else
// No need to adjust, it's just a trigger instance.
endif
endif
call trigger_pop()
call event_pop()
set event_next = 0
set event_prev = 0
set event_head = 0
set trigger_next = 0
set trigger_prev = 0
set trigger_head = 0
set real_next = 0
set real_prev = 0
set real_head = 0
endmethod
method unregister takes nothing returns nothing
if this == 0 then
debug call BJDebugMsg("thistype.unregister: Trigger to be unregistered is not registered to begin with.")
return
endif
call unlink()
set trigger = null
set real = 0.
set event = 0
static if ALLOW_DEBUG then
debug call BJDebugMsg("================")
debug call LineBreak()
endif
call deallocate()
endmethod
implement EventTrigs_fire
implement EventTrigs_all_fire
implement EventTrigs_remove
private method link takes Event e, real r returns nothing
local thistype array that
static if ALLOW_DEBUG then
debug call LineBreak()
debug call BJDebugMsg("================")
debug call BJDebugMsg("Instance allocated: " + I2S(this))
endif
set that[1] = event_get(e)
if that[1] == 0 then
set that[1] = this
set thistype(e).head = this
static if ALLOW_DEBUG then
debug call BJDebugMsg("Head of Event is now mapped to " + I2S(that[1]))
endif
debug else
static if ALLOW_DEBUG then
debug call BJDebugMsg("Head of Event is " + I2S(that[1]))
endif
endif
static if ALLOW_DEBUG then
debug call LineBreak()
endif
set that[2] = real_get(e, r)
if that[2] == 0 then
set that[2] = this
call real_insert(that[1])
set real_head = 1
static if ALLOW_DEBUG then
debug call BJDebugMsg("Head of real list in Event is now mapped to " + I2S(that[2]))
endif
endif
call trigger_insert(that[2])
call event_insert(that[1])
static if ALLOW_DEBUG then
debug call LineBreak()
debug call BJDebugMsg("================")
endif
endmethod
static method register takes Event e, real r, trigger t returns thistype
local thistype this
local thistype that
set that = trigger_get(e, r, t)
if that == 0 then
set this = allocate()
static if ALLOW_DEBUG then
call BJDebugMsg("Registering")
endif
call link(e, r)
set event = e
set real = r
set trigger = t
return this
endif
return that
endmethod
method operator eventid= takes Event new returns nothing
if event == new then
return
endif
call unlink()
call link(new, real)
set event = new
endmethod
method operator prio= takes real new returns nothing
if not (real != new) then
return
endif
call unlink()
call link(event, new)
set real = new
endmethod
endstruct
private function OnHandlerFunc takes nothing returns nothing
if Event.instruction == 1 then
call EventTrigs.fire(GetEvent(), GetRealEvent())
elseif Event.instruction == 2 then
call EventTrigs.all_fire(GetEvent())
elseif Event.instruction == 3 then
call EventTrigs.remove(GetEvent())
endif
endfunction
private module EventInit_m
private static method onInit takes nothing returns nothing
call TriggerAddCondition(Event.EXEC, function OnHandlerFunc)
endmethod
endmodule
private struct EventInit_s extends array
implement EventInit_m
endstruct
endlibrary
library_once EventStruct uses PseudoVarEvent
endlibrary
Wurst:
package Event
import ErrorHandling
import HashMap
import LinkedList
constant HANDLER_TRIG = CreateTrigger()
constant HANDLER_FUNC = TriggerAddCondition(HANDLER_TRIG, Condition(function handler_func))
enum INS
fire
clear
destruct
nil
/** The handler function which calls the necessary functions. */
function handler_func()
switch getIns()
case fire
EvListener.fireEv(getEvent(), getRealOfEvent())
case clear
EvListener.clearEv(getEvent(), getRealOfEvent())
case destruct
EvListener.destroyEv(getEvent())
default
/** A more sensible trigger function that dereferences said trigger from all real instances.
of a certain Event. */
public function trigger.unbindFromEvent(Event e) returns bool
return EvListener.unbindTriggerEv(e, this)
/** A trigger wrapper function for unbinding from a specific real instance of an Event. */
public function trigger.unbindFromEvent(Event e, real r) returns bool
return EvListener.getInstance(e, r, this)..deregister() != null
/** A trigger wrapper function for binding */
public function trigger.bindToEvent(Event e, real r) returns EvListener
return EvListener.register(e, r, this)
/** Returns the currently triggered Event object */
public function getEvent() returns Event
return Event.curEv[Event.cur]
/** Returns the currently calibrated real. */
public function getRealOfEvent() returns real
return Event.curReal[Event.cur]
/** Reserved function, internally used in handler_func() */
function getIns() returns INS
return Event.curIns[Event.cur]
public class Event
protected static Event array curEv
protected static real array curReal
protected static INS array curIns
protected static int cur
private static function assign(Event that, real r, INS which)
cur++
curEv[cur] = that
curReal[cur] = r
curIns[cur] = which
HANDLER_TRIG.evaluate()
curIns[cur] = INS.nil
curReal[cur] = 0.
curEv[cur] = null
cur--
ondestroy
assign(this, 0., INS.destruct)
function clear(real r)
assign(this, r, INS.clear)
function fire(real r)
assign(this, r, INS.fire)
public class EvListener
private static HashMap<Event, EvListener> evHead = new HashMap<Event, EvListener>()
/** These variables are to be read-only. */
trigger trig
Event ev
real r
private LinkedList<EvListener> rList
private LinkedList<EvListener> tList
ondestroy
this.trig = null
this.ev = null
this.r = 0.
private construct()
private construct(Event e, real r, trigger t)
this.trig = t
this.r = r
this.ev = e
/** Returns the representative instance of the Event object. */
private static function getHead(Event e) returns EvListener
return evHead.get(e)
/** Internal method that gets the head node at a specified real. */
private static function getReal(EvListener that, real r) returns EvListener
if that == null or not (that.r != r)
return that
EvListener temp = null
for iter in that.rList
if not (iter.r != r)
temp = iter
break
return temp
/** Internal method that gets the instance with a matching trigger. */
private static function getTrig(EvListener that, trigger t) returns EvListener
if that == null or not (that.trig != t)
return that
EvListener temp = null
for iter in that.tList
if not (iter.trig != t)
temp = iter
break
return temp
/** This basically serves as a wrapper inner function for getInstance.
Returns a head instance in the main real list with the specified real value. */
private static function getRealHead(Event e, real r) returns EvListener
return getReal(getHead(e), r)
/** Gets */
static function getInstance(Event e, real r, trigger t) returns EvListener
return getTrig(getRealHead(e, r), t)
/** Deregisters a trigger and destroys its instance. */
function deregister()
EvListener array other
// Check if the instance is the head
other[1] = evHead.get(this.ev)
if other[1] == this
// Instance is the head
// We search first at the list of triggers with the same real value.
if this.tList.size() > 1
// Since the first instance is always first...
this.tList.remove(this)
this.rList.remove(this)
this.rList.addAt(other[1].tList.get(1), 1)
other[1] = this.tList.get(1)
other[1].tList = this.tList
other[1].rList = this.tList
evHead.put(this.ev, other[1])
else
// No more instances remaining in the list remaining.
destroy this.tList
// We search at any available real list and check if it has
// more than 1 entry.
if this.rList.size() > 1
// At least another instance exists.
this.rList.remove(this)
other[1] = this.rList.get(1)
other[1].rList = this.rList
evHead.put(this.ev, other[1])
else
// We destroy the instance.
destroy this.rList
this.rList = null
this.tList = null
else
if this.tList != null
// The instance is head.
if this.tList.size() > 1
// At least another instance exists.
this.tList.remove(this)
var counter = 0
for iter in this.rList
counter++
if iter == this
break
other[1].rList.remove(this)
other[1].rList.addAt(this.tList.get(1), counter)
other[2] = this.tList.get(1)
other[2].tList = this.tList
else
// We destroy the instance.
destroy this.tList
this.tList = null
destroy this
/** Registers a trigger to a specified Event object at the desired real. */
static function register(Event e, real r, trigger t) returns EvListener
if t == null or e == null
if t == null
error("EvListener.register: invalid trigger object")
else if e == null
error("EvListener.register: invalid Event object")
return null
EvListener array other
EvListener temp = null
other[1] = getHead(e)
if other[1] == null
other[1] = new EvListener(e, r, t)
other[1].rList = new LinkedList<EvListener>..add(other[1])
other[1].tList = new LinkedList<EvListener>..add(other[1])
evHead.put(e, other[1])
temp = other[1]
return temp
other[2] = getReal(other[1], r)
if other[2] == null
other[2] = new EvListener(e, r, t)
other[2].tList = new LinkedList<EvListener>..add(other[2])
other[1].rList.add(other[2])
temp = other[2]
return temp
other[3] = getTrig(other[2], t)
if other[3] == null
other[3] = new EvListener(e, r, t)
other[2].tList.add(other[3])
// Just to fool the console...
if temp == null
temp = other[3]
return temp
/** Unbinds a trigger from an Event object in all its' real lists. */
static function unbindTriggerEv(Event e, trigger t) returns bool
let header = getHead(e)
var counter = 0
if header != null
for iter in header.rList
var iter1 = getInstance(e, iter.r, t)
if iter1 != null
iter1.deregister()
counter++
return counter != 0
protected static function fireEv(Event e, real r)
let header = getRealHead(e, r)
if header != null
for iter in header.tList
if iter.trig.isEnabled()
if iter.trig.evaluate()
iter.trig.execute()
protected static function clearEv(Event e, real r)
let header = getRealHead(e, r)
if header != null
for iter in header.tList
if iter != header
iter.deregister()
header.deregister()
protected static function destroyEv(Event e)
let header = getHead(e)
if header != null
LinkedList<EvListener> iter = header.rList
LinkedList<EvListener> iter_shadow = iter.copy()
for iter1 in iter_shadow
if iter1 != header
clearEv(e, iter1.r)
clearEv(e, header.r)
destroy iter_shadow
Last edited: