251 lines
6.0 KiB
Lua
Executable File
251 lines
6.0 KiB
Lua
Executable File
TIMERS_VERSION = "1.05"
|
|
|
|
--[[
|
|
|
|
-- A timer running every second that starts immediately on the next frame, respects pauses
|
|
Timers:CreateTimer(function()
|
|
print ("Hello. I'm running immediately and then every second thereafter.")
|
|
return 1.0
|
|
end
|
|
)
|
|
|
|
-- The same timer as above with a shorthand call
|
|
Timers(function()
|
|
print ("Hello. I'm running immediately and then every second thereafter.")
|
|
return 1.0
|
|
end)
|
|
|
|
|
|
-- A timer which calls a function with a table context
|
|
Timers:CreateTimer(GameMode.someFunction, GameMode)
|
|
|
|
-- A timer running every second that starts 5 seconds in the future, respects pauses
|
|
Timers:CreateTimer(5, function()
|
|
print ("Hello. I'm running 5 seconds after you called me and then every second thereafter.")
|
|
return 1.0
|
|
end
|
|
)
|
|
|
|
-- 10 second delayed, run once using gametime (respect pauses)
|
|
Timers:CreateTimer({
|
|
endTime = 10, -- when this timer should first execute, you can omit this if you want it to run first on the next frame
|
|
callback = function()
|
|
print ("Hello. I'm running 10 seconds after when I was started.")
|
|
end
|
|
})
|
|
|
|
-- 10 second delayed, run once regardless of pauses
|
|
Timers:CreateTimer({
|
|
useGameTime = false,
|
|
endTime = 10, -- when this timer should first execute, you can omit this if you want it to run first on the next frame
|
|
callback = function()
|
|
print ("Hello. I'm running 10 seconds after I was started even if someone paused the game.")
|
|
end
|
|
})
|
|
|
|
|
|
-- A timer running every second that starts after 2 minutes regardless of pauses
|
|
Timers:CreateTimer("uniqueTimerString3", {
|
|
useGameTime = false,
|
|
endTime = 120,
|
|
callback = function()
|
|
print ("Hello. I'm running after 2 minutes and then every second thereafter.")
|
|
return 1
|
|
end
|
|
})
|
|
|
|
|
|
-- A timer using the old style to repeat every second starting 5 seconds ahead
|
|
Timers:CreateTimer("uniqueTimerString3", {
|
|
useOldStyle = true,
|
|
endTime = GameRules:GetGameTime() + 5,
|
|
callback = function()
|
|
print ("Hello. I'm running after 5 seconds and then every second thereafter.")
|
|
return GameRules:GetGameTime() + 1
|
|
end
|
|
})
|
|
|
|
]]
|
|
|
|
|
|
|
|
TIMERS_THINK = 0.01
|
|
|
|
if Timers == nil then
|
|
--print ( '[Timers] creating Timers' )
|
|
Timers = {}
|
|
setmetatable(Timers, {
|
|
__call = function(t, ...)
|
|
return t:CreateTimer(...)
|
|
end
|
|
})
|
|
--Timers.__index = Timers
|
|
end
|
|
|
|
function Timers:start()
|
|
Timers = self
|
|
self.timers = {}
|
|
|
|
--local ent = Entities:CreateByClassname("info_target") -- Entities:FindByClassname(nil, 'CWorld')
|
|
local ent = SpawnEntityFromTableSynchronous("info_target", {targetname="timers_lua_thinker"})
|
|
ent:SetThink("Think", self, "timers", TIMERS_THINK)
|
|
end
|
|
|
|
function Timers:Think()
|
|
--if GameRules:State_Get() >= DOTA_GAMERULES_STATE_POST_GAME then
|
|
--return
|
|
--end
|
|
|
|
-- Track game time, since the dt passed in to think is actually wall-clock time not simulation time.
|
|
local now = GameRules:GetGameTime()
|
|
|
|
-- Process timers
|
|
for k,v in pairs(Timers.timers) do
|
|
local bUseGameTime = true
|
|
if v.useGameTime ~= nil and v.useGameTime == false then
|
|
bUseGameTime = false
|
|
end
|
|
local bOldStyle = false
|
|
if v.useOldStyle ~= nil and v.useOldStyle == true then
|
|
bOldStyle = true
|
|
end
|
|
|
|
local now = GameRules:GetGameTime()
|
|
if not bUseGameTime then
|
|
now = Time()
|
|
end
|
|
|
|
if v.endTime == nil then
|
|
v.endTime = now
|
|
end
|
|
-- Check if the timer has finished
|
|
if now >= v.endTime then
|
|
-- Remove from timers list
|
|
Timers.timers[k] = nil
|
|
|
|
Timers.runningTimer = k
|
|
Timers.removeSelf = false
|
|
|
|
-- Run the callback
|
|
local status, nextCall
|
|
if v.context then
|
|
status, nextCall = xpcall(function() return v.callback(v.context, v) end, function (msg)
|
|
return msg..'\n'..debug.traceback()..'\n'
|
|
end)
|
|
else
|
|
status, nextCall = xpcall(function() return v.callback(v) end, function (msg)
|
|
return msg..'\n'..debug.traceback()..'\n'
|
|
end)
|
|
end
|
|
|
|
Timers.runningTimer = nil
|
|
|
|
-- Make sure it worked
|
|
if status then
|
|
-- Check if it needs to loop
|
|
if nextCall and not Timers.removeSelf then
|
|
-- Change its end time
|
|
|
|
if bOldStyle then
|
|
v.endTime = v.endTime + nextCall - now
|
|
else
|
|
v.endTime = v.endTime + nextCall
|
|
end
|
|
|
|
Timers.timers[k] = v
|
|
end
|
|
|
|
-- Update timer data
|
|
--self:UpdateTimerData()
|
|
else
|
|
-- Nope, handle the error
|
|
Timers:HandleEventError('Timer', k, nextCall)
|
|
end
|
|
end
|
|
end
|
|
|
|
return TIMERS_THINK
|
|
end
|
|
|
|
function Timers:HandleEventError(name, event, err)
|
|
--print(err)
|
|
|
|
-- Ensure we have data
|
|
name = tostring(name or 'unknown')
|
|
event = tostring(event or 'unknown')
|
|
err = tostring(err or 'unknown')
|
|
|
|
-- Tell everyone there was an error
|
|
--Say(nil, name .. ' threw an error on event '..event, false)
|
|
--Say(nil, err, false)
|
|
|
|
-- Prevent loop arounds
|
|
if not self.errorHandled then
|
|
-- Store that we handled an error
|
|
self.errorHandled = true
|
|
end
|
|
end
|
|
|
|
function Timers:CreateTimer(name, args, context)
|
|
if type(name) == "function" then
|
|
if args ~= nil then
|
|
context = args
|
|
end
|
|
args = {callback = name}
|
|
name = DoUniqueString("timer")
|
|
elseif type(name) == "table" then
|
|
args = name
|
|
name = DoUniqueString("timer")
|
|
elseif type(name) == "number" then
|
|
args = {endTime = name, callback = args}
|
|
name = DoUniqueString("timer")
|
|
end
|
|
if not args.callback then
|
|
--print("Invalid timer created: "..name)
|
|
return
|
|
end
|
|
|
|
|
|
local now = GameRules:GetGameTime()
|
|
if args.useGameTime ~= nil and args.useGameTime == false then
|
|
now = Time()
|
|
end
|
|
|
|
if args.endTime == nil then
|
|
args.endTime = now
|
|
elseif args.useOldStyle == nil or args.useOldStyle == false then
|
|
args.endTime = now + args.endTime
|
|
end
|
|
|
|
args.context = context
|
|
|
|
Timers.timers[name] = args
|
|
|
|
return name
|
|
end
|
|
|
|
function Timers:RemoveTimer(name)
|
|
Timers.timers[name] = nil
|
|
if Timers.runningTimer == name then
|
|
Timers.removeSelf = true
|
|
end
|
|
end
|
|
|
|
function Timers:RemoveTimers(killAll)
|
|
local timers = {}
|
|
Timers.removeSelf = true
|
|
|
|
if not killAll then
|
|
for k,v in pairs(Timers.timers) do
|
|
if v.persist then
|
|
timers[k] = v
|
|
end
|
|
end
|
|
end
|
|
|
|
Timers.timers = timers
|
|
end
|
|
|
|
if not Timers.timers then Timers:start() end
|
|
|
|
GameRules.Timers = Timers |