Disable mesecons processing, create initial redstone power propigation code, change wall lever to use new code, modify scheduler to provide backtraces when tasks error

This commit is contained in:
teknomunk 2024-04-14 19:05:05 +00:00
parent a958fbbf71
commit 6107bba52f
7 changed files with 167 additions and 9 deletions

View File

@ -100,7 +100,7 @@ if false then
act("test")
end
minetest.register_globalstep(function(dtime)
local function run_scheduler(dtime)
local start_time = minetest_get_us_time()
local end_time = start_time + 50000
time = time + dtime
@ -129,7 +129,10 @@ minetest.register_globalstep(function(dtime)
local func = functions[task.fid]
if func then
--print("Running task "..dump(task)..",func="..dump(func))
local ok,ret = pcall(func.func, task, unpack(task.args or {}))
local function caller()
return func.func(task, unpack(task.args or {}))
end
local ok,ret = xpcall(caller, debug.traceback)
if not ok then
minetest.log("error","Error while running task "..func.name..": "..tostring(ret))
end
@ -149,7 +152,9 @@ minetest.register_globalstep(function(dtime)
end
end
end
print("Total scheduler time: "..tostring(minetest_get_us_time() - start_time).." microseconds")
--print("Total scheduler time: "..tostring(minetest_get_us_time() - start_time).." microseconds")
--print("priority_queue="..dump(priority_queue))
end)
end
minetest.register_globalstep(function(dtime) run_scheduler(dtime) end)

View File

@ -58,9 +58,11 @@ local function get_highest_priority(actions)
return highesti
end
--[[
local m_time = 0
local resumetime = mesecon.setting("resumetime", 4)
minetest.register_globalstep(function (dtime)
m_time = m_time + dtime
-- don't even try if server has not been running for XY seconds; resumetime = time to wait
-- after starting the server before processing the ActionQueue, don't set this too low
@ -87,6 +89,7 @@ minetest.register_globalstep(function (dtime)
table.remove(actions_now, hp)
end
end)
]]
function mesecon.queue:execute(action)
if not action.pos then return end

View File

@ -87,7 +87,8 @@ mesecon.queue:add_function("receptor_on", function (pos, rules)
end)
function mesecon.receptor_on(pos, rules)
mesecon.queue:add_action(pos, "receptor_on", {rules}, nil, rules)
print("receptor_on(pos="..vector.to_string(pos)..",rules="..dump(rules))
--mesecon.queue:add_action(pos, "receptor_on", {rules}, nil, rules)
end
mesecon.queue:add_function("receptor_off", function (pos, rules)
@ -114,7 +115,8 @@ mesecon.queue:add_function("receptor_off", function (pos, rules)
end)
function mesecon.receptor_off(pos, rules)
mesecon.queue:add_action(pos, "receptor_off", {rules}, nil, rules)
print("receptor_off(pos="..vector.to_string(pos)..",rules="..dump(rules))
--mesecon.queue:add_action(pos, "receptor_off", {rules}, nil, rules)
end
--Services like turnoff receptor on dignode and so on

View File

@ -52,7 +52,7 @@ minetest.register_node("mesecons_walllever:wall_lever_off", {
_doc_items_usagehelp = S("Use the lever to flip it on or off."),
on_rightclick = function(pos, node)
minetest.swap_node(pos, {name="mesecons_walllever:wall_lever_on", param2=node.param2})
mesecon.receptor_on(pos, lever_get_output_rules(node))
vl_redstone.set_power(pos, 15)
minetest.sound_play("mesecons_button_push", {pos=pos, max_hear_distance=16}, true)
end,
node_placement_prediction = "",
@ -152,7 +152,7 @@ minetest.register_node("mesecons_walllever:wall_lever_on", {
_doc_items_create_entry = false,
on_rightclick = function(pos, node)
minetest.swap_node(pos, {name="mesecons_walllever:wall_lever_off", param2=node.param2})
mesecon.receptor_off(pos, lever_get_output_rules(node))
vl_redstone.set_power(pos, 0)
minetest.sound_play("mesecons_button_push", {pos=pos, max_hear_distance=16, pitch=0.9}, true)
end,
sounds = mcl_sounds.node_sound_stone_defaults(),

View File

@ -1,3 +1,3 @@
name = mesecons_walllever
depends = mesecons
depends = mesecons, vl_redstone
optional_depends = doc

View File

@ -0,0 +1,144 @@
local modname = minetest.get_current_modname()
local modpath = minetest.get_modpath(modname)
vl_redstone = {}
local mod = vl_redstone
local REDSTONE_POWER_META = modname .. ".power"
local REDSTONE_POWER_META_LAST_STATE = modname .. ".last-power"
local REDSTONE_POWER_META_SOURCE = REDSTONE_POWER_META.."."
local function update_sink(pos)
local node = minetest.get_node(pos)
local nodedef = minetest.registered_nodes[node.name]
-- Only do this processing of signal sinks
if not nodedef.mesecons then return end
local sink = nodedef.mesecons.effector
if not sink then return end
local meta = minetest.get_meta(pos)
-- Calculate the maximum power feeding into this node
local strength = 0
local meta_tbl = meta:to_table()
for k,v in pairs(meta_tbl.fields) do
if string.sub(k,1,#REDSTONE_POWER_META_SOURCE) == REDSTONE_POWER_META_SOURCE then
--local source_pos_str = string.sub(k,#REDSTONE_POWER_META_SOURCE+1)
--print("\tsource_pos_str="..source_pos_str)
local source_strength = tonumber(v)
--print("\tstrength="..source_strength)
if source_strength > strength then
strength = source_strength
end
end
end
local last_strength = meta:get_int(REDSTONE_POWER_META_LAST_STATE)
if last_strength ~= strength then
-- Inform the node of changes
if strength > 0 then
-- Handle activation
if sink.action_on then
sink.action_on(pos, node)
end
else
-- Handle deactivation
if sink.action_off then
sink.action_off(pos, node)
end
end
-- TODO: handle signal level change notification
-- Update the state as the last thing in case there is a crash in the above code
meta:set_int(REDSTONE_POWER_META_LAST_STATE, strength)
end
end
local function get_positions_from_node_rules(pos, rules_type, list)
list = list or {}
local node = minetest.get_node(pos)
local nodedef = minetest.registered_nodes[node.name]
if not nodedef.mesecons then return list end
-- Get mesecons rules
if not nodedef.mesecons[rules_type] then
minetest.log("info","Node "..node.name.." has no mesecons."..rules_type.." rules")
return list
end
local rules = nodedef.mesecons[rules_type].rules
if type(rules) == "function" then rules = rules(node) end
--print("rules="..dump(rules))
-- Convert to absolute positions
for i=1,#rules do
local next_pos = vector.add(pos, rules[i])
local next_pos_str = vector.to_string(next_pos)
list[next_pos_str] = true
end
return list
end
vl_scheduler.register_function("vl_redstone:flow_power",function(task, source_pos, strength, distance)
print("Flowing lv"..tostring(strength).." power from "..vector.to_string(source_pos).." for "..tostring(distance).." blocks")
local processed = {}
local source_pos_str = vector.to_string(source_pos)
-- Update the source node's redstone power
local meta = minetest.get_meta(source_pos)
meta:set_int(REDSTONE_POWER_META, strength)
-- Get rules
local list = {}
get_positions_from_node_rules(source_pos, "receptor", list)
print("initial list="..dump(list))
for i=1,distance do
local next_list = {}
local strength = strength - (i - 1)
if strength < 0 then strength = 0 end
for pos_str,dir in pairs(list) do
print("Processing "..pos_str)
if not processed[pos_str] then
processed[pos_str] = true
local pos = vector.from_string(pos_str)
local meta = minetest.get_meta(pos)
-- Update node power directly
meta:set_int(REDSTONE_POWER_META.."."..source_pos_str, strength)
print("pos="..vector.to_string(pos)..", strength="..tostring(strength))
-- handle spread
local spread_to = get_positions_from_node_rules(pos, "conductor")
for j=1,#spread_to do
next_list[vector.to_string(spread_to[j])] = true
end
-- Update the position
update_sink(pos)
end
end
-- Continue onto the next set of nodes to process
list = next_list
end
end)
function vl_redstone.set_power(pos, strength)
local meta = minetest.get_meta(pos)
local distance = meta:get_int(REDSTONE_POWER_META)
if distance < strength then
distance = strength
end
vl_scheduler.add_task(0, "vl_redstone:flow_power", 2, {pos, strength, distance})
end

View File

@ -0,0 +1,4 @@
description = Redstone implementation
name = vl_redstone
depends = mcl_sounds, mcl_core, vl_scheduler
optional_depends = doc