building timers (#1)

* building timers

* timer spec

* debug

* wip

* err

* wip

* wip

* cleanup

---------

Co-authored-by: BuckarooBanzay <BuckarooBanzay@users.noreply.github.com>
This commit is contained in:
Buckaroo Banzai 2024-10-15 11:10:48 +02:00 committed by GitHub
parent 22d4f081ca
commit 9eda9b2203
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 113 additions and 27 deletions

View File

@ -49,4 +49,5 @@ if minetest.get_modpath("mtt") and mtt.enabled then
dofile(MP .. "/conditions.spec.lua")
dofile(MP .. "/build.spec.lua")
dofile(MP .. "/build_over.spec.lua")
dofile(MP .. "/timer.spec.lua")
end

View File

@ -11,36 +11,40 @@ function building_lib.get_building_timer(mapblock_pos)
return setmetatable(self, BuildingTimer_mt)
end
local function get_timer_key(mapblock_pos)
return "timer_" .. minetest.pos_to_string(mapblock_pos)
end
function BuildingTimer:get_entry()
local data = building_lib.store:get_group_data(self.mapblock_pos)
local key = get_timer_key(self.mapblock_pos)
return data[key] or {}
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)
-- TODO: move timers to own field for better lookup
local data = building_lib.store:get_group_data(self.mapblock_pos)
local key = get_timer_key(self.mapblock_pos)
if timeout > 0 then
-- started, update entry
local entry = data[key]
if not entry then
entry = {}
data[key] = entry
end
entry.timeout = timeout
entry.elapsed = elapsed
self:set_entry({
timeout = timeout,
elapsed = elapsed
})
else
-- stopped, remove entry
data[key] = nil
self:set_entry(nil)
end
building_lib.store:set_group_data(self.mapblock_pos, data)
end
function BuildingTimer:start(timeout)
@ -66,12 +70,52 @@ function BuildingTimer:is_started()
return entry.timeout and entry.timeout > entry.elapsed
end
function building_lib.update_timers(pos)
-- TODO
print(dump(pos))
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
-- TODO: iterate over active areas and operate on `DataStorage:get_group_data(pos)`
local TIMER_INTERVAL = 2
-- iterate over active areas and operate on `DataStorage:get_group_data(pos)`
local function timer_update_loop()
local visited = {}
@ -93,7 +137,7 @@ local function timer_update_loop()
-- check if already processed
if not visited[key] then
building_lib.update_timers(pos)
building_lib.update_timers(pos, TIMER_INTERVAL)
visited[key] = true
end
end
@ -101,7 +145,7 @@ local function timer_update_loop()
end
end
minetest.after(2, timer_update_loop)
minetest.after(TIMER_INTERVAL, timer_update_loop)
end
minetest.after(1, timer_update_loop)

41
timer.spec.lua Normal file
View File

@ -0,0 +1,41 @@
local building_mapblock_pos = {x=0, y=0, z=0}
local building_name = "building_lib:dummy_timer"
local rotation = 0
local playername = "singleplayer"
local timer_mapblock_pos, timer_elapsed
building_lib.register_building(building_name, {
placement = "dummy",
on_timer = function(mapblock_pos, elapsed)
timer_mapblock_pos = mapblock_pos
timer_elapsed = elapsed
end
})
mtt.register("building_lib.get_building_timer", function()
-- clear store
building_lib.store:clear()
-- try to build
local success, err = building_lib.can_build(building_mapblock_pos, playername, building_name, rotation)
assert(not err)
assert(success)
-- build
return building_lib.build(building_mapblock_pos, playername, building_name, rotation)
:next(function()
local timer = building_lib.get_building_timer(building_mapblock_pos)
timer:start(10)
local pos = { x=0, y=0, z=0 }
building_lib.update_timers(pos, 5)
assert(not timer_mapblock_pos)
assert(not timer_elapsed)
building_lib.update_timers(pos, 5)
assert(vector.equals(timer_mapblock_pos, building_mapblock_pos))
assert(timer_elapsed >= 10)
end)
end)