library Monitor initializer init
//==========================================================================================
// Monitor - v1.0 - 9/24/19
// by Pyrogasm
//
// Have you wondered what the last trigger run before an error was? Did you wish you could
// see a printout of what ran when and how many times? Have you always wanted to name your
// triggers? Well... sometimes I have, but mostly Ricola3D has so I made this for them. If
// this interests you or sounds like it might help, you should use this system to aid in
// your debugging quest.
//
// It requires one small change on your part:
// For any trigger you wish to register with Monitor, you must replace all calls to
// CreateTrigger()
// with
// Monitor_CreateTrigger("your trigger name here")
// which still returns the created trigger as the vanilla function does.
//
// The system automatically detects when you call TriggerAddCondition and TriggerAddAction
// and assigns its own TC/TA first before the first time you use them on a trigger so that
// its functions are called right before any of the trigger's real TCs and TAs. It requires
// no further input from you.
//
// Data is automatically cleaned when using DestroyTrigger, TriggerClearActions, and
// TriggerClearConditions, no input required.
//
// Monitor can output the following information immediately before that trigger's
// Conditions or Actions are evaluated/executed:
// - Name of the trigger
// - Execution count of the conditions/actions since the trigger was created
// - Timestamp (in seconds since map init) at which the conditions/actions were run
//
// Monitor features two further functions you may find useful in your debugging quest:
// - Monitor_GetTriggerName(triggerVariable)
// - Monitor_DumpLast(triggerVariable)
// This prints the most recently stored information about execution count & timestamp
//
// If you have further questions, contact me directly by PM at hiveworkshop.com
// Anyone is free to use all or part of this resource for any reason, all I ask
// is that you credit me with the original code.
//
//==========================================================================================
globals
//These globals enable/disable tracking & printing of various parts of the system (compiletime static ifs)
private constant boolean DO_CONDITIONS = true
private constant boolean DO_ACTIONS = true
private constant boolean DO_TIMESTAMP = true
private constant boolean DO_EXEC_COUNT = true
//This global enables/disables the system entirely while keeping the Monitor_CreateTrigger calls functional (compiletime static ifs)
private constant boolean ENABLED = true
private keyword ht
endglobals
globals
//Probably don't fuck with these
private hashtable ht
private timer clock
private boolexpr cPrint
private code aPrint
private boolean recursion = false
private constant integer KEY_NAME = 1
private constant integer KEY_COND = 2
private constant integer KEY_ACT = 3
private constant integer KEY_TIME_C = 4
private constant integer KEY_TIME_A = 5
private constant integer KEY_EXEC_C = 6
private constant integer KEY_EXEC_A = 7
endglobals
//====================
// PUBLIC FUNCTIONS
//====================
// This function has to have no public/private prefix because of how I've named it;
// calling it 'public function CreateTrigger' would produce a namespace conflict.
function Monitor_CreateTrigger takes string triggerName returns trigger
local trigger t = CreateTrigger()
static if ENABLED then
local integer ind = GetHandleId(t)
call FlushChildHashtable(ht, ind) //probably not necessary
call SaveStr(ht, ind, KEY_NAME, triggerName)
endif
return t
endfunction
public function GetTriggerName takes trigger t returns string
local string p = LoadStr(ht, GetHandleId(t), KEY_NAME)
static if ENABLED then
if p == "" then
debug call BJDebugMsg("Monitor Warning: name requested of trigger not registered with Monitor (or name left blank)")
endif
endif
return p
endfunction
public function DumpLast takes trigger t returns nothing
local integer ind = GetHandleId(t)
local string p
static if DO_CONDITIONS then
set p = LoadStr(ht, ind, KEY_NAME)+" - dump of last condition(s):"
static if DO_TIMESTAMP then
set p = p + "\nTimestamp: "+R2S(LoadReal(ht, ind, KEY_TIME_C))
endif
static if DO_EXEC_COUNT then
set p = p + "\nExec Count: "+I2S(LoadInteger(ht, ind, KEY_EXEC_C))
endif
endif
call BJDebugMsg(p)
static if DO_ACTIONS then
set p = LoadStr(ht, ind, KEY_NAME)+" - dump of last action(s):"
static if DO_TIMESTAMP then
set p = p + "\nTimestamp: "+R2S(LoadReal(ht, ind, KEY_TIME_A))
endif
static if DO_EXEC_COUNT then
set p = p + "\nExec Count: "+I2S(LoadInteger(ht, ind, KEY_EXEC_A))
endif
endif
call BJDebugMsg(p)
endfunction
//====================
//! textmacro MonitorInfoDump takes APPEND, DESCRIPTION
local integer ind = GetHandleId(GetTriggeringTrigger())
local real t
local integer c
local string p = LoadStr(ht, ind, KEY_NAME)+" - $DESCRIPTION$"
static if DO_TIMESTAMP then
set t = TimerGetElapsed(clock)
call SaveReal(ht, ind, KEY_TIME_$APPEND$, t)
set p = p + "\nTimestamp: "+R2S(t)
endif
static if DO_EXEC_COUNT then
set c = LoadInteger(ht, ind, KEY_EXEC_$APPEND$) + 1
call SaveInteger(ht, ind, KEY_EXEC_$APPEND$, c)
set p = p + "\nExec Count: "+I2S(c)
endif
call BJDebugMsg(p)
//! endtextmacro
private function ConditionPrint takes nothing returns boolean
//! runtextmacro MonitorInfoDump("C", "checking conditions:")
return true
endfunction
private function ActionPrint takes nothing returns nothing
//! runtextmacro MonitorInfoDump("A", "executing actions:")
endfunction
private function Monitor_TriggerAddCondition takes trigger t, boolexpr f returns nothing
static if ENABLED and DO_CONDITIONS then
local integer ind = GetHandleId(t)
if not recursion and LoadBoolean(ht, ind, KEY_COND) == false then
call SaveBoolean(ht, ind, KEY_COND, true)
set recursion = true
call TriggerAddCondition(t, cPrint)
set recursion = false
endif
endif
endfunction
private function Monitor_TriggerAddAction takes trigger t, code f returns nothing
static if ENABLED and DO_ACTIONS then
local integer ind = GetHandleId(t)
if not recursion and LoadBoolean(ht, ind, KEY_ACT) == false then
call SaveBoolean(ht, ind, KEY_ACT, true)
set recursion = true
call TriggerAddAction(t, aPrint)
set recursion = false
endif
endif
endfunction
private function Monitor_DestroyTrigger takes trigger t returns nothing
call FlushChildHashtable(ht, GetHandleId(t))
endfunction
private function Monitor_TriggerClearConditions takes trigger t returns nothing
static if ENABLED and DO_CONDITIONS then
call RemoveSavedBoolean(ht, GetHandleId(t), KEY_COND)
endif
endfunction
private function Monitor_TriggerClearActions takes trigger t returns nothing
static if ENABLED and DO_ACTIONS then
call RemoveSavedBoolean(ht, GetHandleId(t), KEY_ACT)
endif
endfunction
private function Monitor_CreateTriggerWarning takes nothing returns nothing
static if ENABLED then
debug call BJDebugMsg("Monitor Warning: trigger created by native CreateTrigger without registering in the system. If you meant to do this, ignore this message.")
endif
endfunction
hook CreateTrigger Monitor_CreateTriggerWarning
hook DestroyTrigger Monitor_DestroyTrigger
hook TriggerAddCondition Monitor_TriggerAddCondition
hook TriggerAddAction Monitor_TriggerAddAction
hook TriggerClearConditions Monitor_TriggerClearConditions
hook TriggerClearActions Monitor_TriggerClearActions
private function init takes nothing returns nothing
static if ENABLED then
set ht = InitHashtable()
set clock = CreateTimer()
call TimerStart(clock, 999999999., true, null)
set cPrint = Condition(function ConditionPrint)
set aPrint = function ActionPrint
endif
endfunction
endlibrary