diff --git a/mods/CORE/vl_scheduler/init.lua b/mods/CORE/vl_scheduler/init.lua index 2c791ed6f..d16d0d7cc 100644 --- a/mods/CORE/vl_scheduler/init.lua +++ b/mods/CORE/vl_scheduler/init.lua @@ -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) diff --git a/mods/ITEMS/REDSTONE/mesecons/actionqueue.lua b/mods/ITEMS/REDSTONE/mesecons/actionqueue.lua index 34202aecd..34f6f863f 100644 --- a/mods/ITEMS/REDSTONE/mesecons/actionqueue.lua +++ b/mods/ITEMS/REDSTONE/mesecons/actionqueue.lua @@ -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 diff --git a/mods/ITEMS/REDSTONE/mesecons/init.lua b/mods/ITEMS/REDSTONE/mesecons/init.lua index 18965287e..8874ff9b2 100644 --- a/mods/ITEMS/REDSTONE/mesecons/init.lua +++ b/mods/ITEMS/REDSTONE/mesecons/init.lua @@ -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 diff --git a/mods/ITEMS/REDSTONE/mesecons_walllever/init.lua b/mods/ITEMS/REDSTONE/mesecons_walllever/init.lua index c251587d5..16df8e297 100644 --- a/mods/ITEMS/REDSTONE/mesecons_walllever/init.lua +++ b/mods/ITEMS/REDSTONE/mesecons_walllever/init.lua @@ -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(), diff --git a/mods/ITEMS/REDSTONE/mesecons_walllever/mod.conf b/mods/ITEMS/REDSTONE/mesecons_walllever/mod.conf index 8512e9d6b..2b6dde532 100644 --- a/mods/ITEMS/REDSTONE/mesecons_walllever/mod.conf +++ b/mods/ITEMS/REDSTONE/mesecons_walllever/mod.conf @@ -1,3 +1,3 @@ name = mesecons_walllever -depends = mesecons +depends = mesecons, vl_redstone optional_depends = doc diff --git a/mods/ITEMS/REDSTONE/vl_redstone/init.lua b/mods/ITEMS/REDSTONE/vl_redstone/init.lua new file mode 100644 index 000000000..efe4fb4a0 --- /dev/null +++ b/mods/ITEMS/REDSTONE/vl_redstone/init.lua @@ -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 + diff --git a/mods/ITEMS/REDSTONE/vl_redstone/mod.conf b/mods/ITEMS/REDSTONE/vl_redstone/mod.conf new file mode 100644 index 000000000..b688409e8 --- /dev/null +++ b/mods/ITEMS/REDSTONE/vl_redstone/mod.conf @@ -0,0 +1,4 @@ +description = Redstone implementation +name = vl_redstone +depends = mcl_sounds, mcl_core, vl_scheduler +optional_depends = doc