* building timers * timer spec * debug * wip * err * wip * wip * cleanup --------- Co-authored-by: BuckarooBanzay <BuckarooBanzay@users.noreply.github.com>
152 lines
4.1 KiB
Lua
152 lines
4.1 KiB
Lua
|
|
local BuildingTimer = {}
|
|
local BuildingTimer_mt = { __index = BuildingTimer }
|
|
|
|
|
|
function building_lib.get_building_timer(mapblock_pos)
|
|
local self = {
|
|
mapblock_pos = mapblock_pos
|
|
}
|
|
|
|
return setmetatable(self, BuildingTimer_mt)
|
|
end
|
|
|
|
function BuildingTimer:get_entry()
|
|
local data = building_lib.store:get_group_data(self.mapblock_pos)
|
|
if not data.timers then
|
|
-- create timers table
|
|
data.timers = {}
|
|
building_lib.store:set_group_data(self.mapblock_pos, data)
|
|
end
|
|
|
|
local key = minetest.pos_to_string(self.mapblock_pos)
|
|
return data.timers[key] or {}
|
|
end
|
|
|
|
function BuildingTimer:set_entry(entry)
|
|
local data = building_lib.store:get_group_data(self.mapblock_pos)
|
|
if not data.timers then
|
|
-- create timers table
|
|
data.timers = {}
|
|
end
|
|
|
|
local key = minetest.pos_to_string(self.mapblock_pos)
|
|
data.timers[key] = entry
|
|
building_lib.store:set_group_data(self.mapblock_pos, data)
|
|
end
|
|
|
|
function BuildingTimer:set(timeout, elapsed)
|
|
if timeout > 0 then
|
|
self:set_entry({
|
|
timeout = timeout,
|
|
elapsed = elapsed
|
|
})
|
|
else
|
|
-- stopped, remove entry
|
|
self:set_entry(nil)
|
|
end
|
|
end
|
|
|
|
function BuildingTimer:start(timeout)
|
|
self:set(timeout, 0)
|
|
end
|
|
|
|
function BuildingTimer:stop()
|
|
self:set(0, 0)
|
|
end
|
|
|
|
function BuildingTimer:get_timeout()
|
|
local entry = self:get_entry()
|
|
return entry.timeout or 0
|
|
end
|
|
|
|
function BuildingTimer:get_elapsed()
|
|
local entry = self:get_entry()
|
|
return entry.elapsed or 0
|
|
end
|
|
|
|
function BuildingTimer:is_started()
|
|
local entry = self:get_entry()
|
|
return entry.timeout and entry.timeout > entry.elapsed
|
|
end
|
|
|
|
function building_lib.update_timers(pos, interval)
|
|
local rpos = mapblock_lib.get_mapblock(pos)
|
|
local data = building_lib.store:get_group_data(rpos)
|
|
|
|
if not data.timers then
|
|
-- no timers found in the mapblock
|
|
return
|
|
end
|
|
|
|
for mapblock_pos_str, entry in pairs(data.timers) do
|
|
-- increment active timers and call `on_timer` on buildings
|
|
local mapblock_pos = minetest.string_to_pos(mapblock_pos_str)
|
|
entry.elapsed = entry.elapsed + interval
|
|
|
|
local remove_timer = false
|
|
|
|
if entry.elapsed >= entry.timeout then
|
|
-- timer event
|
|
local def = building_lib.get_building_def_at(mapblock_pos)
|
|
if type(def.on_timer) == "function" then
|
|
local result = def.on_timer(mapblock_pos, entry.elapsed)
|
|
if result then
|
|
-- reschedule
|
|
entry.elapsed = 0
|
|
else
|
|
-- remove
|
|
remove_timer = true
|
|
end
|
|
else
|
|
-- invalid field type
|
|
remove_timer = true
|
|
end
|
|
end
|
|
|
|
if remove_timer then
|
|
data.timers[mapblock_pos_str] = nil
|
|
end
|
|
end
|
|
|
|
-- store timer data
|
|
building_lib.store:set_group_data(rpos, data)
|
|
end
|
|
|
|
local TIMER_INTERVAL = 2
|
|
|
|
-- iterate over active areas and operate on `DataStorage:get_group_data(pos)`
|
|
local function timer_update_loop()
|
|
local visited = {}
|
|
|
|
for _, player in ipairs(minetest.get_connected_players()) do
|
|
local ppos = player:get_pos()
|
|
|
|
local range = building_lib.granularity * building_lib.active_timer_range
|
|
local min = vector.subtract(ppos, range)
|
|
local max = vector.add(ppos, range)
|
|
|
|
for x = min.x, max.x, range do
|
|
for y = min.y, max.y, range do
|
|
for z = min.z, max.z, range do
|
|
local pos = vector.new(x,y,z)
|
|
|
|
-- rounded down position with granularity
|
|
local rpos = vector.floor(vector.divide(ppos, building_lib.granularity))
|
|
local key = minetest.pos_to_string(rpos)
|
|
|
|
-- check if already processed
|
|
if not visited[key] then
|
|
building_lib.update_timers(pos, TIMER_INTERVAL)
|
|
visited[key] = true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
minetest.after(TIMER_INTERVAL, timer_update_loop)
|
|
end
|
|
|
|
minetest.after(1, timer_update_loop)
|