From da6651ff20491f4b55fe9ee8164ce5cd59398298 Mon Sep 17 00:00:00 2001 From: shaga <14+shaga@noreply.octowow.st> Date: Mon, 15 Jun 2026 11:03:18 -0700 Subject: [PATCH] Import Chronos timekeeping/scheduling library (vanilla 1.12) Verbatim import of the Chronos addon from refaim's Vanilla WoW 1.12 addon development libraries archive: https://github.com/refaim/Vanilla-WoW-1.12-Addon-Development-Libraries-Archive (Libraries/Chronos) Chronos is a hard dependency of CallOfElements (Chronos.scheduleByName/ startTimer/etc.). Hosting it as a standalone addon so the launcher can install it alongside CoE. Co-Authored-By: Claude Opus 4.8 --- Chronos.lua | 879 ++++++++++++++++++++++++++++++++++++++++++++ Chronos.toc | 6 + Chronos.xml | 12 + localization.de.lua | 12 + localization.en.lua | 8 + localization.fr.lua | 12 + 6 files changed, 929 insertions(+) create mode 100644 Chronos.lua create mode 100644 Chronos.toc create mode 100644 Chronos.xml create mode 100644 localization.de.lua create mode 100644 localization.en.lua create mode 100644 localization.fr.lua diff --git a/Chronos.lua b/Chronos.lua new file mode 100644 index 0000000..d1ef3dd --- /dev/null +++ b/Chronos.lua @@ -0,0 +1,879 @@ +--[[ +-- +-- Chronos +-- Keeper of Time +-- +-- By Alexander Brazie, Thott and AnduinLothar +-- +-- Chronos manages time. You can schedule a function to be called +-- in X seconds, with or without an id. You can request a timer, +-- which tracks the elapsed duration since the timer was started. +-- +-- To use as an embeddable addon: +-- - Put the Chronos folder inside your Interface/AddOns// folder. +-- - Add Chronos\ Chronos.xml to your toc or load it in your xml before your localization files. +-- - Add Chronos to the OptionalDeps in your toc +-- +-- To use as an addon library: +-- - Put the Chronos folder inside your Interface/AddOns/ folder. +-- - Add Chronos to the Dependencies in your toc +-- +-- Please see below or see http://www.wowwiki.com/Chronos for details. +-- +-- $LastChangedBy: karlkfi $ +-- $Date: 2006-05-04 16:47:47 -0700 (Thu, 04 May 2006) $ +-- $Rev: 3496 $ +-- +--]] + +local CHRONOS_REV = 2.01; + +local isBetterInstanceLoaded = ( Chronos and Chronos.version and Chronos.version >= CHRONOS_REV ); + +if (not isBetterInstanceLoaded) then + + if (not Chronos) then + Chronos = {}; + end + + Chronos.version = CHRONOS_REV; + + ------------------------------------------------------------------------------ + --[[ Variables ]]-- + ------------------------------------------------------------------------------ + + Chronos.online = true; + + CHRONOS_DEBUG = false; + CHRONOS_DEBUG_WARNINGS = false; + + -- Chronos Data + if (not ChronosData) then + ChronosData = {}; + end + + -- Initialize the Timers + if (not ChronosData.timers) then + ChronosData.timers = {}; + end + + -- Initialize the perform-over-time task list + if (not ChronosData.tasks) then + ChronosData.tasks = {}; + end + + -- Maximum items per frame + Chronos.MAX_TASKS_PER_FRAME = 100; + + -- Maximum steps per task + Chronos.MAX_STEPS_PER_TASK = 300; + + -- Maximum time delay per frame + Chronos.MAX_TIME_PER_STEP = .3; + + Chronos.emptyTable = {}; + + ------------------------------------------------------------------------------ + --[[ User Functions ]]-- + ------------------------------------------------------------------------------ + + --[[ + -- debug(boolean) + -- + -- Toggles debug mode + ]]-- + function Chronos.debug(enable) + if (enable) then + ChronosFrame:SetScript("OnUpdate", Chronos.OnUpdate_Debug); + CHRONOS_DEBUG = true; + CHRONOS_DEBUG_WARNINGS = true; + else + ChronosFrame:SetScript("OnUpdate", Chronos.OnUpdate_Quick); + CHRONOS_DEBUG = false; + CHRONOS_DEBUG_WARNINGS = false; + end + end + + --[[ + -- Scheduling functions + -- Parts rewritten by AnduinLothar for efficiency + -- Parts rewritten by Thott for speed + -- Written by Alexander + -- Original by Thott + -- + -- Usage: Chronos.schedule(when,handler,arg1,arg2,etc) + -- + -- After seconds pass (values less than one and fractional values are + -- fine), handler is called with the specified arguments, i.e.: + -- handler(arg1,arg2,etc) + -- + -- If you'd like to have something done every X seconds, reschedule + -- it each time in the handler or preferably use scheduleRepeating. + -- + -- Also, please note that there is a limit to the number of + -- scheduled tasks that can be performed per xml object at the + -- same time. + --]] + function Chronos.schedule(when,handler,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) + if ( not Chronos.online ) then + return; + end + if ( not handler) then + Chronos.printError("ERROR: nil handler passed to Chronos.schedule()"); + return; + end + + --local memstart = gcinfo(); + -- -- Assign an id + -- local id = ""; + -- if ( not this ) then + -- id = "Keybinding"; + -- else + -- id = this:GetName(); + -- end + -- if ( not id ) then + -- id = "_DEFAULT"; + -- end + -- if ( not when ) then + -- Chronos.printDebugError("CHRONOS_DEBUG_WARNINGS", "Chronos Error Detection: ", id , " has sent no interval for this function. ", when ); + -- return; + -- end + + -- -- Ensure we're not looping ChronosFrame + -- if ( id == "ChronosFrame" and ChronosData.lastID ) then + -- id = ChronosData.lastID; + -- end + + local task; + -- reuse task memory if possible to avoid excessive garbage collection --Thott + if(not ChronosData.sched[ChronosData.sched.n+1]) then + ChronosData.sched[ChronosData.sched.n+1] = {}; + end + ChronosData.sched.n = ChronosData.sched.n+1; + local i = ChronosData.sched.n; + -- ChronosData.sched[i].id = id; + ChronosData.sched[i].time = when + GetTime(); + ChronosData.sched[i].handler = handler; + ChronosData.sched[i].args = Chronos.getArgTable(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20); + + -- task list is a heap, add new --Thott + while(i > 1) do + parent = floor(i/2); + if(ChronosData.sched[parent].time > ChronosData.sched[i].time) then + Chronos.swap(i,parent); + else + break; + end + i = parent; + end + + -- Debug print + --Chronos.printDebugError("CHRONOS_DEBUG", "Scheduled ", handler," in ",when," seconds from ", id ); + --Chronos.printError("Memory change in schedule: ",memstart,"->",memend," = ",memend-memstart); + end + + + --[[ + -- Chronos.scheduleByName(name, delay, function, arg1, ... ); + -- + -- Same as Chronos.schedule, except it takes a schedule name argument. + -- Only one event can be scheduled with a given name at any one time. + -- Thus if one exists, and another one is scheduled, the first one + -- is deleted, then the second one added. + -- + --]] + function Chronos.scheduleByName(name,when,handler,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) + if ( not name ) then + Chronos.printDebugError("CHRONOS_DEBUG_WARNINGS","Chronos Error Detection: No name specified to Chronos.scheduleByName"); + return; + end + if(ChronosData.byName[name] and handler) then + Chronos.printDebugError("CHRONOS_DEBUG_WARNINGS","Chronos Error Detection: scheduleByName is reasigning '".. name.."'."); + ChronosData.byName[name] = { time = when+GetTime(), handler = handler, arg = Chronos.getArgTable(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20); }; + else + if ( not handler ) then + if ( not ChronosData.byName[name] ) then + Chronos.printDebugError("CHRONOS_DEBUG_WARNINGS","Chronos Error Detection: No handler specified to Chronos.scheduleByName, no previous entry found for scheduled entry '".. name.."'."); + return; + end + if ( not ChronosData.byName[name].handler ) then + Chronos.printDebugError("CHRONOS_DEBUG_WARNINGS","Chronos Error Detection: No handler specified to Chronos.scheduleByName, no handler could be found in previous entry of '".. name.."' either."); + return; + end + handler = ChronosData.byName[name].handler; + Chronos.printDebugError("CHRONOS_DEBUG_WARNINGS","Chronos: scheduleByName is updating '".. name.."' to time: ".. when); + else + Chronos.printDebugError("CHRONOS_DEBUG_WARNINGS","Chronos: scheduleByName is asigning '".. name.."'."); + end + ChronosData.byName[name] = { time = when+GetTime(), handler = handler, arg = Chronos.getArgTable(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20); }; + end + end + + --[[ + -- unscheduleByName(name); + -- + -- Removes an entry that was created with scheduleByName() + -- + -- Args: + -- name - the name used + -- + --]] + function Chronos.unscheduleByName(name) + if ( not Chronos.online ) then + return; + end + if ( not name ) then + Chronos.printError("No name specified to Chronos.unscheduleByName"); + return; + end + if(ChronosData.byName[name]) then + ChronosData.byName[name] = nil; + end + + -- Debug print + --Chronos.printDebugError("CHRONOS_DEBUG", "Cancelled scheduled timer of name ",name); + end + + --[[ + -- unscheduleRepeating(name); + -- Mirrors unscheduleByName for backwards compatibility + --]] + Chronos.unscheduleRepeating = Chronos.unscheduleByName; + + --[[ + -- isScheduledByName(name) + -- Returns the amount of time left if it is indeed scheduled by name! + -- + -- returns: + -- number - time remaining + -- nil - not scheduled + -- + --]] + function Chronos.isScheduledByName(name) + if ( not Chronos.online ) then + return; + end + if ( not name ) then + Chronos.printError("No name specified to Chronos.isScheduledByName ", this:GetName()); + return; + end + if(ChronosData.byName[name]) then + return ChronosData.byName[name].time - GetTime(); + end + + -- Debug print + --Chronos.printDebugError("CHRONOS_DEBUG", "Did not find timer of name ",name); + return nil; + end + + --[[ + -- isScheduledRepeating(name) + -- Mirrors isScheduledByName for backwards compatibility + --]] + Chronos.isScheduledRepeating = Chronos.isScheduledByName; + + --[[ + -- Chronos.scheduleRepeating(name, delay, function); + -- + -- Same as Chronos.scheduleByName, except it repeats without recalling and takes no arguments. + -- + --]] + function Chronos.scheduleRepeating(name,when,handler) + if ( not name ) then + Chronos.printDebugError("CHRONOS_DEBUG_WARNINGS","Chronos Error Detection: No name specified to Chronos.scheduleRepeating"); + return; + end + if(ChronosData.byName[name] and handler) then + Chronos.printDebugError("CHRONOS_DEBUG_WARNINGS","Chronos Error Detection: scheduleRepeating is reasigning ".. name); + ChronosData.byName[name] = { time = when+GetTime(), period = when, handler = handler, repeating = true }; + else + if ( not handler ) then + if ( not ChronosData.byName[name] ) then + Chronos.printDebugError("CHRONOS_DEBUG_WARNINGS","Chronos Error Detection: No handler specified to Chronos.scheduleRepeating, no previous entry found for scheduled entry '".. name.."'."); + return; + end + if ( not ChronosData.byName[name].handler ) then + Chronos.printDebugError("CHRONOS_DEBUG_WARNINGS","Chronos Error Detection: No handler specified to Chronos.scheduleRepeating, no handler could be found in previous entry '".. name.."' either."); + return; + end + handler = ChronosData.byName[name].handler; + Chronos.printDebugError("CHRONOS_DEBUG_WARNINGS","Chronos: scheduleRepeating is updating '".. name.."' to time: ".. when); + else + Chronos.printDebugError("CHRONOS_DEBUG_WARNINGS","Chronos: scheduleRepeating is asigning '".. name.."'."); + end + ChronosData.byName[name] = { time = when+GetTime(), period = when, handler = handler, repeating = true }; + end + end + + --[[ + -- Chronos.flushByName(name, when); + -- + -- Updates the ByName or Repeating event to flush at the time specified. If no time is specified flush will be immediate. If it is a Repeating event the timer will be reset. + -- + --]] + function Chronos.flushByName(name,when) + if ( not name ) then + Chronos.printDebugError("CHRONOS_DEBUG_WARNINGS","Chronos Error Detection: No name specified to Chronos.flushByName"); + return; + elseif ( not ChronosData.byName[name] ) then + Chronos.printDebugError("CHRONOS_DEBUG_WARNINGS","Chronos Error Detection: no previous entry found for Chronos.flushByName entry '".. name.."'."); + return; + end + if (not when) then + Chronos.printDebugError("CHRONOS_DEBUG_WARNINGS","Chronos: flushing '".. name.."'."); + when = GetTime(); + else + Chronos.printDebugError("CHRONOS_DEBUG_WARNINGS","Chronos: flushing '".. name.."' in "..when.." seconds."); + when = when+GetTime(); + end + ChronosData.byName[name].time = when; + end + + --[[ + -- Chronos.startTimer([ID]); + -- Starts a timer on a particular + -- + -- Args + -- ID - optional parameter to identify who is asking for a timer. + -- + -- If ID does not exist, this:GetName() is used. + -- + -- When you want to get the amount of time passed since startTimer(ID) is called, + -- call getTimer(ID) and it will return the number in seconds. + -- + --]] + function Chronos.startTimer( id ) + if ( not Chronos.online ) then + return; + end + + if ( not id ) then + id = this:GetName(); + end + + -- Create a table for this id's timers + if ( not ChronosData.timers[id] ) then + ChronosData.timers[id] = {}; + ChronosData.timers[id].n = 0; + end + + -- Clear out an entry if the table is too big. + if (ChronosData.timers[id].n > Chronos.MAX_TASKS_PER_FRAME) then + Chronos.printError("Too many Chronos timers created for id ",id); + return; + end + + -- Add a new timer entry + table.insert(ChronosData.timers[id],GetTime()); + end + + + --[[ + -- endTimer([id]); + -- + -- Ends the timer and returns the amount of time passed. + -- + -- args: + -- id - ID for the timer. If not specified, then ID will + -- be this:GetName() + -- + -- returns: + -- (Number delta, Number start, Number end) + -- + -- delta - the amount of time passed in seconds. + -- start - the starting time + -- now - the time the endTimer was called. + --]] + + function Chronos.endTimer( id ) + if ( not Chronos.online ) then + return; + end + + if ( not id ) then + id = this:GetName(); + end + + if ( not ChronosData.timers[id] or ChronosData.timers[id].n == 0) then + return nil; + end + + local now = GetTime(); + + -- Grab the last timer called + local startTime = Chronos.pop(ChronosData.timers[id]); + + return (now - startTime), startTime, now; + end + + + --[[ + -- getTimer([id]); + -- + -- Gets the timer and returns the amount of time passed. + -- Does not terminate the timer. + -- + -- args: + -- id - ID for the timer. If not specified, then ID will + -- be this:GetName() + -- + -- returns: + -- (Number delta, Number start, Number end) + -- + -- delta - the amount of time passed in seconds. + -- start - the starting time + -- now - the time the endTimer was called. + --]] + + function Chronos.getTimer( id ) + if ( not Chronos.online ) then + return; + end + + if ( not id ) then + id = this:GetName(); + end + + local now = GetTime(); + if ( not ChronosData.timers[id] or ChronosData.timers[id].n == 0) then + return 0,0,now; + end + + -- Grab the last timer called + local startTime = ChronosData.timers[id][ChronosData.timers[id].n]; + + return (now - startTime), startTime, now; + end + + --[[ + -- isTimerActive([id]) + -- returns true if the timer exists. + -- + -- args: + -- id - ID for the timer. If not specified, then ID will + -- be this:GetName() + -- + -- returns: + -- true - exists + -- false - does not + --]] + function Chronos.isTimerActive( id ) + if ( not Chronos.online ) then + return; + end + + if ( not id ) then + id = this:GetName(); + end + + -- Create a table for this id's timers + if ( not ChronosData.timers[id] ) then + return false; + end + + return true; + end + + --[[ + -- getTime() + -- + -- returns the Chronos internal elapsed time. + -- + -- returns: + -- (elapsedTime) + -- + -- elapsedTime - time in seconds since Chronos initialized + --]] + function Chronos.getTime() + return ChronosData.elapsedTime; + end + + --[[ + -- Chronos.afterInit(func, ...) + -- Performs func after the game has truely started. + -- By Thott + --]] + function Chronos.afterInit(func, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) + local id; + if(this) then + id = this:GetName(); + else + id = "unknown"; + end + --if(id == "SkyFrame") then + -- Chronos.printError("Ignoring Sky init"); + -- return; + --end + if(ChronosData.initialized) then + func(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20); + else + if(not ChronosData.afterInit) then + ChronosData.afterInit = {}; + ChronosData.afterInit.n = 0; + Chronos.schedule(0.2,Chronos.initCheck); + end + local n = ChronosData.afterInit.n+1; + ChronosData.afterInit[n] = {}; + ChronosData.afterInit[n].func = func; + ChronosData.afterInit[n].args = Chronos.getArgTable(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20); + ChronosData.afterInit[n].id = id; + ChronosData.afterInit.n = n; + end + end + + + ------------------------------------------------------------------------------ + --[[ Helpers Functions ]]-- + ------------------------------------------------------------------------------ + + function Chronos.getArgTable(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) + if (( a1 == nil ) and ( a2 == nil ) and ( a3 == nil ) and ( a4 == nil ) and ( a5 == nil ) and ( a6 == nil ) and ( a7 == nil ) and ( a8 == nil ) and ( a9 == nil ) and ( a10 == nil ) and ( a11 == nil ) and ( a12 == nil ) and ( a13 == nil ) and ( a14 == nil ) and ( a15 == nil ) and ( a16 == nil ) and ( a17 == nil ) and ( a18 == nil ) and ( a19 == nil ) and ( a20 == nil )) then + return Chronos.emptyTable; + else + local args = {}; + table.setn(args, 0); + table.insert(args, a1); + table.insert(args, a2); + table.insert(args, a3); + table.insert(args, a4); + table.insert(args, a5); + table.insert(args, a6); + table.insert(args, a7); + table.insert(args, a8); + table.insert(args, a9); + table.insert(args, a10); + table.insert(args, a11); + table.insert(args, a12); + table.insert(args, a13); + table.insert(args, a14); + table.insert(args, a15); + table.insert(args, a16); + table.insert(args, a17); + table.insert(args, a18); + table.insert(args, a19); + table.insert(args, a20); + return args; + end + end + + -- + -- pop ( table ) + -- + -- Removes a value and returns it from the table + -- Arg: + -- table - the table + -- + -- duplicated from Sea + function Chronos.pop(table1) + if(not table1) then + Chronos.printDebugError(nil, "Bad table passed to pop"); + return nil; + end + local n = table.getn(table1); + if(not n) then + Chronos.printDebugError(nil, "Bad table.getn() passed to pop"); + return nil; + end + if ( n == 0 ) then + return nil; + end + + local v = table1[n]; + table.setn(table1, n-1) + --Doesn't nil the entry like table.remove, so it's never garbage collected and can be replaced + --v = table.remove(table1); + return v; + end + + function Chronos.popTask() + if(ChronosData.sched.n == 1) then + ChronosData.sched.n = 0; + return 1; + end + Chronos.swap(1,ChronosData.sched.n); + ChronosData.sched.n = ChronosData.sched.n - 1; + local i = 1; + local new; + while(ChronosData.sched[i] and i <= ChronosData.sched.n) do + new = i*2; + if(new > ChronosData.sched.n) then + break; + elseif(new < ChronosData.sched.n) then + if(ChronosData.sched[new+1].time < ChronosData.sched[new].time) then + new = new + 1; + end + end + if(ChronosData.sched[new].time < ChronosData.sched[i].time) then + Chronos.swap(i,new); + i = new; + else + break; + end + end + return ChronosData.sched.n+1; + end + + function Chronos.run(func,arg) + if(func) then + if(arg) then + return func(unpack(arg)); + else + return func(); + end + end + end + + function Chronos.swap(i,j) + local t = ChronosData.sched[i]; + ChronosData.sched[i] = ChronosData.sched[j]; + ChronosData.sched[j] = t; + end + + function Chronos.printError(text) + ChatFrame1:AddMessage(text, RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b, 1.0, UIERRORS_HOLD_TIME); + end + + function Chronos.printDebugError(var, text) + if (var) and (getglobal(var)) then + Chronos.printError(text); + end + end + + ------------------------------------------------------------------------------ + --[[ Frame Script Helpers ]]-- + ------------------------------------------------------------------------------ + + function Chronos.chatColorsInit() + ChronosData.chatColorsInitialized = true; + ChronosFrame:UnregisterEvent("UPDATE_CHAT_COLOR"); + end + + function Chronos.initCheck() + if(not ChronosData.initialized) then + if(UnitName("player") and UnitName("player")~=UKNOWNBEING and UnitName("player")~=UNKNOWNBEING and UnitName("player")~=UNKNOWNOBJECT and ChronosData.variablesLoaded and ChronosData.enteredWorld and ChronosData.chatColorsInitialized) then + ChronosData.initialized = true; + Chronos.schedule(1,Chronos.initCheck); + return; + else + Chronos.schedule(0.2,Chronos.initCheck); + return; + end + end + if(ChronosData.afterInit) then + local i = ChronosData.afterInit_i; + if(not i) then + i = 1; + end + ChronosData.afterInit_i = i+1; + --Chronos.printError("afterInit: processing ",i," of ",ChronosData.afterInit.n," initialization functions, id: ",ChronosData.afterInit[i].id); + Chronos.run(ChronosData.afterInit[i].func,ChronosData.afterInit[i].args); + if(i == ChronosData.afterInit.n) then + ChronosData.afterInit = nil; + ChronosData.afterInit_i = nil; + else + Chronos.schedule(0.1,Chronos.initCheck); + return; + end + end + end + + --[[ + -- Sends a chat command through the standard editbox + --]] + function Chronos.SendChatCommand(command) + local text = ChatFrameEditBox:GetText(); + ChatFrameEditBox:SetText(command); + ChatEdit_SendText(ChatFrameEditBox); + ChatFrameEditBox:SetText(text); + end + + function Chronos.RegisterSlashCommands() + --Needs to be able Variables load if you want to use Sky + local chronosFunc = function(msg) + local _,_,seconds,command = string.find(msg,"([%d\.]+)%s+(.*)"); + if(seconds and command) then + Chronos.schedule(seconds,Chronos.SendChatCommand,command); + else + Chronos.printError(SCHEDULE_USAGE1); + Chronos.printError(SCHEDULE_USAGE2); + end + end + if(Sky) then + Sky.registerSlashCommand( + { + id = "Schedule"; + commands = SCHEDULE_COMM; + onExecute = chronosFunc; + helpText = SCHEDULE_DESC; + replace = true; + } + ); + else + SlashCmdList["CHRONOS_SCHEDULE"] = chronosFunc; + for i = 1, table.getn(SCHEDULE_COMM) do setglobal("SLASH_CHRONOS_SCHEDULE"..i, SCHEDULE_COMM[i]); end + end + end + + ------------------------------------------------------------------------------ + --[[ Frame Scripts ]]-- + ------------------------------------------------------------------------------ + + function Chronos.OnLoad() + Chronos.framecount = 0; + + if (not ChronosData.byName) then + ChronosData.byName = {}; + end + if (not ChronosData.repeating) then + ChronosData.repeating = {}; + end + if (not ChronosData.sched) then + ChronosData.sched = {}; + ChronosData.sched.n = 0; + end + ChronosData.elapsedTime = 0; + + Chronos.afterInit(Chronos.RegisterSlashCommands); + end + + function Chronos.OnEvent() + if(event == "VARIABLES_LOADED") then + ChronosData.variablesLoaded = true; + ChronosFrame:Show(); + elseif (event == "PLAYER_ENTERING_WORLD") then + ChronosData.enteredWorld = true; + Chronos.online = true; + elseif (event == "PLAYER_LEAVING_WORLD") then + Chronos.online = false; + elseif ( event == "UPDATE_CHAT_COLOR" ) then + Chronos.scheduleByName("ChronosAfterChatColorInit", 1, Chronos.chatColorsInit); + end + end + + function Chronos.OnUpdate_Quick() + if ( not Chronos.online ) then + return; + end + if ( not ChronosData.variablesLoaded ) then + return; + end + + if ( ChronosData.elapsedTime ) then + ChronosData.elapsedTime = ChronosData.elapsedTime + arg1; + else + ChronosData.elapsedTime = arg1; + end + + -- Execute scheduled tasks that are ready, popping them off the heap. + local now = GetTime(); + local i; + while(ChronosData.sched.n > 0) do + if(ChronosData.sched[1].time <= now) then + i = Chronos.popTask(); + Chronos.run(ChronosData.sched[i].handler,ChronosData.sched[i].args); + else + break; + end + end + + -- Execute named scheduled tasks that are ready. + local k,v = next(ChronosData.byName); + local newK, newV; + while (k ~= nil) do + newK,newV = next(ChronosData.byName, k); + if(v.time <= now) then + if (v.repeating) then + ChronosData.byName[k].time = now + v.period; + v.handler(); + else + local y = v; + ChronosData.byName[k] = nil; + Chronos.run(y.handler,y.arg); + end + end + k,v = newK,newV; + end + end + + function Chronos.OnUpdate_Debug() + if ( not Chronos.online ) then + return; + end + if ( not ChronosData.variablesLoaded ) then + return; + end + local memstart = gcinfo(); + + if ( ChronosData.elapsedTime ) then + ChronosData.elapsedTime = ChronosData.elapsedTime + arg1; + else + ChronosData.elapsedTime = arg1; + end + + local now = GetTime(); + local i; + -- Execute scheduled tasks that are ready, popping them off the heap. + while(ChronosData.sched.n > 0) do + if(ChronosData.sched[1].time <= now) then + i = Chronos.popTask(); + Chronos.run(ChronosData.sched[i].handler,ChronosData.sched[i].args); + else + break; + end + end + + local memend = gcinfo(); + if(memend - memstart > 0) then + Chronos.printError("gcmemleak from ChronosData.sched in OnUpdate: ",memend - memstart); + end + + -- Execute named scheduled tasks that are ready. + memstart = memend; + local k,v = next(ChronosData.byName); + local newK, newV; + while (k ~= nil) do + newK,newV = next(ChronosData.byName, k); + if(v.time <= now) then + local m = gcinfo(); + if (v.repeating) then + ChronosData.byName[k].time = now + v.period; + v.handler(); + else + local y = v; + ChronosData.byName[k] = nil; + Chronos.run(y.handler,y.arg); + end + local mm = gcinfo(); + memstart = memstart + mm - m; + end + k,v = newK,newV; + end + + memend = gcinfo(); + if(memend - memstart > 0) then + Chronos.printError("gcmemleak from ChronosData.byName in OnUpdate: ",memend - memstart); + end + end + + ------------------------------------------------------------------------------ + --[[ Frame Script Assignment ]]-- + ------------------------------------------------------------------------------ + + --Event Driver + if (not ChronosFrame) then + CreateFrame("Frame", "ChronosFrame"); + end + ChronosFrame:Hide(); + --Event Registration + ChronosFrame:RegisterEvent("VARIABLES_LOADED"); + ChronosFrame:RegisterEvent("PLAYER_ENTERING_WORLD"); + ChronosFrame:RegisterEvent("PLAYER_LEAVING_WORLD"); + ChronosFrame:RegisterEvent("UPDATE_CHAT_COLOR"); + --Frame Scripts + ChronosFrame:SetScript("OnEvent", Chronos.OnEvent); + ChronosFrame:SetScript("OnUpdate", Chronos.OnUpdate_Quick); + --OnLoad Call + Chronos.OnLoad(); + +end + diff --git a/Chronos.toc b/Chronos.toc new file mode 100644 index 0000000..a3799ca --- /dev/null +++ b/Chronos.toc @@ -0,0 +1,6 @@ +## Interface: 11000 +## Title: Chronos +## Notes: Embedable Time Keeping and Scheduling System +## Notes-deDE: Sammlung nützlicher Funktionen zum Zeitmanagement, welche von einigen anderen AddOns verwendet werden. +## Author: Alexander Brazie, Thott, AnduinLothar +Chronos.xml \ No newline at end of file diff --git a/Chronos.xml b/Chronos.xml new file mode 100644 index 0000000..df9ad61 --- /dev/null +++ b/Chronos.xml @@ -0,0 +1,12 @@ + + + +