From 041d6a684db2dd28b7aeac05b2ac1193ab1c1a52 Mon Sep 17 00:00:00 2001 From: Joachim Stolberg Date: Sat, 22 Dec 2018 16:58:11 +0100 Subject: [PATCH] work in progress to v2 --- README.md | 25 +- gravelsieve/hammer.lua | 14 +- gravelsieve/init.lua | 8 +- sl_controller/controller.lua | 6 + sl_controller/server.lua | 3 + smartline/controller.lua | 6 + smartline/depends.txt | 1 + smartline/icta/battery.lua | 7 + smartline/icta/controller.lua | 6 + smartline/playerdetector.lua | 3 + smartline/repeater.lua | 3 + smartline/sequencer.lua | 9 +- smartline/timer.lua | 28 +- tubelib/README.md | 7 +- tubelib/command.lua | 111 +++-- tubelib/depends.txt | 3 + tubelib/distributor.lua | 283 ++++++------ tubelib/init.lua | 10 +- tubelib/migrate.lua | 74 +++ tubelib/node_states.lua | 427 ++++++++++++++++++ tubelib/pusher.lua | 175 ++++--- tubelib/repairkit.lua | 82 ++++ tubelib/states.lua | 28 +- tubelib/textures/tubelib_blue.png | Bin 114 -> 113 bytes tubelib/textures/tubelib_defect.png | Bin 0 -> 503 bytes tubelib/textures/tubelib_distributor_blue.png | Bin 470 -> 488 bytes .../textures/tubelib_distributor_green.png | Bin 486 -> 499 bytes tubelib/textures/tubelib_distributor_red.png | Bin 476 -> 480 bytes .../textures/tubelib_distributor_yellow.png | Bin 2071 -> 479 bytes tubelib/textures/tubelib_end_wrench.png | Bin 0 -> 819 bytes tubelib/textures/tubelib_front.png | Bin 449 -> 456 bytes tubelib/textures/tubelib_green.png | Bin 114 -> 113 bytes tubelib/textures/tubelib_gui_arrow.png | Bin 168 -> 158 bytes tubelib/textures/tubelib_hole.png | Bin 206 -> 194 bytes tubelib/textures/tubelib_red.png | Bin 114 -> 113 bytes tubelib/textures/tubelib_repairkit.png | Bin 0 -> 649 bytes tubelib/textures/tubelib_yellow.png | Bin 114 -> 113 bytes tubelib/tubes.lua | 130 ++++++ tubelib/tubes1.lua | 294 ------------ tubelib/tubes2.lua | 230 ---------- tubelib_addons1/autocrafter.lua | 25 +- tubelib_addons1/fermenter.lua | 7 + tubelib_addons1/funnel.lua | 4 + tubelib_addons1/grinder.lua | 227 +++++----- tubelib_addons1/harvester.lua | 9 + tubelib_addons1/liquidsampler.lua | 7 + tubelib_addons1/pusher_fast.lua | 183 ++++---- tubelib_addons1/quarry.lua | 7 + tubelib_addons1/reformer.lua | 7 + .../tubelib_addons1_grinder_active.png | Bin 3433 -> 3430 bytes tubelib_addons2/accesscontrol.lua | 1 + tubelib_addons2/repeater.lua | 3 + tubelib_addons2/sequencer.lua | 7 + tubelib_addons2/timer.lua | 28 +- tubelib_addons3/distributor.lua | 7 + tubelib_addons3/pusher.lua | 173 ++++--- tubelib_addons3/pushing_chest.lua | 3 + tubelib_addons3/teleporter.lua | 91 +--- 58 files changed, 1509 insertions(+), 1253 deletions(-) create mode 100644 tubelib/migrate.lua create mode 100644 tubelib/node_states.lua create mode 100644 tubelib/repairkit.lua create mode 100644 tubelib/textures/tubelib_defect.png create mode 100644 tubelib/textures/tubelib_end_wrench.png create mode 100644 tubelib/textures/tubelib_repairkit.png create mode 100644 tubelib/tubes.lua delete mode 100644 tubelib/tubes1.lua delete mode 100644 tubelib/tubes2.lua diff --git a/README.md b/README.md index 22612d2..64abfb4 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,27 @@ -# TechPack V1.16 +# TechPack V2.00 (WIP) + +**THIS IS WORK IN PROGRESS** + +**For your world use the stable release ![v1.16](https://github.com/joe7575/techpack/releases/tag/v1.16)** + + +## Planned for v2 +- switch to library tubelib2 +- introduce a new machine state model +- add new machine state "defect" +- add a tubelib Repair Kit for defect blocks +- Forceload block as part of tubelib +- support for intllib + +## Current state +- Switch to tubelib2 is done (not fully tested). +- Pusher, Distributor, and Grinder already support the new state 'defect'. The AGING_VALUE is currently much to low. This is for testing only. +- The Repair Kit is available and can be used to repair defect machines. +- The mod 'basic_materials' is now needed for the Repair Kit. +- Due to server crashes I can happen that all loaded nodes loose their timers. Therefore, all "timed" nodes got an "on_node_load" function, which is used to restart the timer. + + + TechPack, a Mining, Crafting, & Farming Modpack for Minetest. diff --git a/gravelsieve/hammer.lua b/gravelsieve/hammer.lua index 5809e49..bcd8214 100644 --- a/gravelsieve/hammer.lua +++ b/gravelsieve/hammer.lua @@ -3,16 +3,6 @@ Gravel Sieve Mod ================ - v0.01 by JoSt - Derived from the work of RealBadAngel, Maciej Kasatkin (screwdriver) - - Copyright (C) 2017 Joachim Stolberg - Copyright (C) 2013-2016 RealBadAngel, Maciej Kasatkin - Copyright (C) 2013-2016 Various Minetest developers and contributors - - LGPLv2.1+ - See LICENSE.txt for more information - ]]-- @@ -45,6 +35,7 @@ gravelsieve.handler = function(itemstack, user, pointed_thing) loop=false}) end + itemstack:add_wear(65535 / (500 - 1)) return itemstack end @@ -52,8 +43,7 @@ minetest.register_tool("gravelsieve:hammer", { description = "Hammer converts Cobblestone into Gravel", inventory_image = "gravelsieve_hammer.png", on_use = function(itemstack, user, pointed_thing) - gravelsieve.handler(itemstack, user, pointed_thing) - return itemstack + return gravelsieve.handler(itemstack, user, pointed_thing) end, }) diff --git a/gravelsieve/init.lua b/gravelsieve/init.lua index d29a88a..69b38fc 100644 --- a/gravelsieve/init.lua +++ b/gravelsieve/init.lua @@ -424,12 +424,8 @@ if minetest.global_exists("tubelib") then local meta = minetest.get_meta(pos) return tubelib.put_item(meta, "dst", item) end, - on_recv_message = function(pos, topic, payload) - if topic == "on" then - start_the_machine(pos) - elseif topic == "off" then - stop_the_machine(pos) - end + on_node_load = function(pos) + minetest.get_node_timer(pos):start(1.0) end, }) end diff --git a/sl_controller/controller.lua b/sl_controller/controller.lua index a3fdf0c..5e747fa 100644 --- a/sl_controller/controller.lua +++ b/sl_controller/controller.lua @@ -491,4 +491,10 @@ tubelib.register_node("sl_controller:controller", {}, { return "unsupported" end end, + on_node_load = function(pos) + local meta = minetest.get_meta(pos) + if meta:get_int("running") ~= tubelib.STATE_STOPPED then + minetest.get_node_timer(pos):start(1) + end + end, }) diff --git a/sl_controller/server.lua b/sl_controller/server.lua index c653b3d..783b5a8 100644 --- a/sl_controller/server.lua +++ b/sl_controller/server.lua @@ -150,6 +150,9 @@ tubelib.register_node("sl_controller:server", {}, { end end end, + on_node_load = function(pos) + minetest.get_node_timer(pos):start(20) + end, }) diff --git a/smartline/controller.lua b/smartline/controller.lua index f9b10f7..22b40f8 100644 --- a/smartline/controller.lua +++ b/smartline/controller.lua @@ -885,6 +885,12 @@ tubelib.register_node("smartline:controller", {}, { return "unsupported" end end, + on_node_load = function(pos) + local meta = minetest.get_meta(pos) + if meta:get_int("state") == tubelib.RUNNING then + minetest.get_node_timer(pos):start(1) + end + end, }) -- List of Controller actions and conditions is dependent on loaded mods. diff --git a/smartline/depends.txt b/smartline/depends.txt index 064149e..32cfef9 100644 --- a/smartline/depends.txt +++ b/smartline/depends.txt @@ -2,5 +2,6 @@ default doors tubelib lcdlib +sl_controller mail? diff --git a/smartline/icta/battery.lua b/smartline/icta/battery.lua index 6380664..cca063c 100644 --- a/smartline/icta/battery.lua +++ b/smartline/icta/battery.lua @@ -156,3 +156,10 @@ else }) end +tubelib.register_node("smartline:battery", + {"smartline:battery25", "smartline:battery50", "smartline:battery75"}, + { + on_node_load = function(pos) + minetest.get_node_timer(pos):start(30) + end, +}) diff --git a/smartline/icta/controller.lua b/smartline/icta/controller.lua index e7a86f0..661553f 100644 --- a/smartline/icta/controller.lua +++ b/smartline/icta/controller.lua @@ -505,5 +505,11 @@ tubelib.register_node("smartline:controller2", {}, { return "unsupported" end end, + on_node_load = function(pos) + local meta = minetest.get_meta(pos) + if meta:get_int("state") == tubelib.RUNNING then + minetest.get_node_timer(pos):start(1) + end + end, }) diff --git a/smartline/playerdetector.lua b/smartline/playerdetector.lua index 26a7dac..8c3f751 100644 --- a/smartline/playerdetector.lua +++ b/smartline/playerdetector.lua @@ -220,5 +220,8 @@ tubelib.register_node("smartline:playerdetector", {"smartline:playerdetector_act return meta:get_string("player_name") end end, + on_node_load = function(pos) + minetest.get_node_timer(pos):start(1.0) + end, }) diff --git a/smartline/repeater.lua b/smartline/repeater.lua index b44d604..7ba153e 100644 --- a/smartline/repeater.lua +++ b/smartline/repeater.lua @@ -124,4 +124,7 @@ tubelib.register_node("smartline:repeater", {}, { return tubelib.send_message(numbers, owner, nil, topic, payload) end end, + on_node_load = function(pos) + minetest.get_node_timer(pos):start(1) + end, }) diff --git a/smartline/sequencer.lua b/smartline/sequencer.lua index 64cff76..440b624 100644 --- a/smartline/sequencer.lua +++ b/smartline/sequencer.lua @@ -137,7 +137,7 @@ local function start_the_sequencer(pos) local node = minetest.get_node(pos) local meta = minetest.get_meta(pos) local number = meta:get_string("number") - meta:set_int("running", 1) + meta:set_int("running", RUNNING_STATE) meta:set_int("index", 1) meta:set_string("infotext", "SmartLine Sequencer "..number..": running (1/"..NUM_SLOTS..")") local rules = minetest.deserialize(meta:get_string("rules")) @@ -282,4 +282,11 @@ tubelib.register_node("smartline:sequencer", {}, { meta:set_int("endless", 0) end end, + on_node_load = function(pos) + local meta = minetest.get_meta(pos) + if meta:get_int("running") ~= STOP_STATE then + meta:set_int("running", RUNNING_STATE) + minetest.get_node_timer(pos):start(1) + end + end, }) diff --git a/smartline/timer.lua b/smartline/timer.lua index 0053b15..5315676 100644 --- a/smartline/timer.lua +++ b/smartline/timer.lua @@ -215,6 +215,17 @@ minetest.register_node("smartline:timer", { is_ground_content = false, }) +tubelib.register_node("smartline:timer", {}, { + on_node_load = function(pos) + local meta = minetest.get_meta(pos) + minetest.get_node_timer(pos):start(CYCLE_TIME) + -- check rules for just loaded areas + local done = {false,false,false,false,false,false} + meta:set_string("done", minetest.serialize(done)) + check_rules(pos,0) + end, +}) + minetest.register_craft({ output = "smartline:timer", @@ -224,20 +235,3 @@ minetest.register_craft({ {"", "default:mese_crystal", ""}, }, }) - -minetest.register_lbm({ - label = "[SmartLine] Timer update", - name = "smartline:update", - nodenames = {"smartline:timer"}, - run_at_every_load = true, - action = function(pos, node) - local meta = minetest.get_meta(pos) - -- check rules for just loaded areas - local done = {false,false,false,false,false,false} - meta:set_string("done", minetest.serialize(done)) - check_rules(pos,0) - end -}) - - - diff --git a/tubelib/README.md b/tubelib/README.md index 63ded96..b2687ee 100644 --- a/tubelib/README.md +++ b/tubelib/README.md @@ -29,12 +29,11 @@ Download: ![GitHub](https://github.com/joe7575/Minetest-Tubelib/archive/master.z ## Dependencies default +tubelib2 +basic_materials + # License Copyright (C) 2017-2018 Joachim Stolberg Code: Licensed under the GNU LGPL version 2.1 or later. See LICENSE.txt and http://www.gnu.org/licenses/lgpl-2.1.txt Textures: CC0 - -## Dependencies -default - diff --git a/tubelib/command.lua b/tubelib/command.lua index 7b59e53..50aea26 100644 --- a/tubelib/command.lua +++ b/tubelib/command.lua @@ -14,7 +14,12 @@ ]]-- -------------------------------------------------------------------- +--- for lazy programmers +local S = function(pos) if pos then return minetest.pos_to_string(pos) end end +local P = minetest.string_to_pos +local M = minetest.get_meta + +------------------------------------------------------------------ -- Data base storage ------------------------------------------------------------------- local storage = minetest.get_mod_storage() @@ -53,12 +58,7 @@ local Name2Name = {} -- translation table local string_find = string.find local string_split = string.split local tubelib_NodeDef = tubelib.NodeDef -local get_neighbor_pos = tubelib.get_neighbor_pos -local read_node_with_vm = tubelib.read_node_with_vm - --- Translate from facedir to contact side of the other node --- (left for one is right for the other node) -local FacedirToSide = {[0] = "F", "L", "B", "R", "U", "D"} +local Tube = tubelib.Tube -- Generate a key string based on the given pos table, -- Used internaly as table key, @@ -77,16 +77,6 @@ local function get_number(pos) return string.format("%.04u", Key2Number[key]) end --- Determine the contact side of the node at the given pos --- param facedir: facedir to the node -local function get_node_side(npos, facedir) - local node = minetest.get_node_or_nil(npos) or read_node_with_vm(npos) - if facedir < 4 then - facedir = (facedir - node.param2 + 4) % 4 - end - return FacedirToSide[facedir], node -end - local function generate_Key2Number() local key for num,item in pairs(Number2Pos) do @@ -109,6 +99,50 @@ local function not_protected(pos, placer_name, clicker_name) return false end +local function register_lbm(name, nodenames) + minetest.register_lbm({ + label = "[Tubelib] Node update", + name = name.."update", + nodenames = nodenames, + run_at_every_load = true, + action = function(pos, node) + local name = Name2Name[node.name] + if tubelib_NodeDef[name] and tubelib_NodeDef[name].on_node_load then + tubelib_NodeDef[name].on_node_load(pos) + end + end + }) +end + + +local DirToSide = {"B", "R", "F", "L", "D", "U"} + +local function dir_to_side(dir, param2) + if dir < 5 then + dir = (((dir - 1) - (param2 % 4)) % 4) + 1 + end + return DirToSide[dir] +end + +local SideToDir = {B=1, R=2, F=3, L=4, D=5, U=6} + +local function side_to_dir(side, param2) + local dir = SideToDir[side] + if dir < 5 then + dir = (((dir - 1) + (param2 % 4)) % 4) + 1 + end + return dir +end + +local function get_dest_node(pos, side) + local _,node = Tube:get_node(pos) + local dir = side_to_dir(side, node.param2) + local spos, sdir = Tube:get_connected_node_pos(pos, dir) + _,node = Tube:get_node(spos) + local in_side = dir_to_side(sdir, node.param2) + return spos, in_side, Name2Name[node.name] or node.name +end + ------------------------------------------------------------------- -- API helper functions ------------------------------------------------------------------- @@ -213,6 +247,8 @@ end -- on_push_item = func(pos, side, item, player_name), -- on_unpull_item = func(pos, side, item, player_name), -- on_recv_message = func(pos, topic, payload), +-- on_node_load = func(pos), -- LBM function +-- on_node_repair = func(pos), -- repair defect (feature!) nodes -- } function tubelib.register_node(name, add_names, node_definition) tubelib_NodeDef[name] = node_definition @@ -223,11 +259,22 @@ function tubelib.register_node(name, add_names, node_definition) end if node_definition.on_pull_item or node_definition.on_push_item or node_definition.is_pusher then + Tube:add_secondary_node_names({name}) + Tube:add_secondary_node_names(add_names) + tubelib.KnownNodes[name] = true for _,n in ipairs(add_names) do tubelib.KnownNodes[n] = true end end + -- register LBM + if node_definition.on_node_load then + local nodenames = {name} + for _,n in ipairs(add_names) do + nodenames[#nodenames + 1] = n + end + register_lbm(name, nodenames) + end end ------------------------------------------------------------------- @@ -257,15 +304,23 @@ function tubelib.send_request(number, topic, payload) return false end +-- for defect nodes +function tubelib.repair_node(pos) + local node = minetest.get_node(pos) + local name = Name2Name[node.name] + if tubelib_NodeDef[name] and tubelib_NodeDef[name].on_node_repair then + return tubelib_NodeDef[name].on_node_repair(pos) + end + return false +end + ------------------------------------------------------------------- -- Client side Push/Pull item functions ------------------------------------------------------------------- function tubelib.pull_items(pos, side, player_name) - local npos, facedir = get_neighbor_pos(pos, side) + local npos, nside, name = get_dest_node(pos, side) if npos == nil then return end - local nside, node = get_node_side(npos, facedir) - local name = Name2Name[node.name] if tubelib_NodeDef[name] and tubelib_NodeDef[name].on_pull_item then return tubelib_NodeDef[name].on_pull_item(npos, nside, player_name) end @@ -273,13 +328,11 @@ function tubelib.pull_items(pos, side, player_name) end function tubelib.push_items(pos, side, items, player_name) - local npos, facedir = get_neighbor_pos(pos, side) + local npos, nside, name = get_dest_node(pos, side) if npos == nil then return end - local nside, node = get_node_side(npos, facedir) - local name = Name2Name[node.name] if tubelib_NodeDef[name] and tubelib_NodeDef[name].on_push_item then return tubelib_NodeDef[name].on_push_item(npos, nside, items, player_name) - elseif node.name == "air" then + elseif name == "air" then minetest.add_item(npos, items) return true end @@ -287,10 +340,8 @@ function tubelib.push_items(pos, side, items, player_name) end function tubelib.unpull_items(pos, side, items, player_name) - local npos, facedir = get_neighbor_pos(pos, side) + local npos, nside, name = get_dest_node(pos, side) if npos == nil then return end - local nside, node = get_node_side(npos, facedir) - local name = Name2Name[node.name] if tubelib_NodeDef[name] and tubelib_NodeDef[name].on_unpull_item then return tubelib_NodeDef[name].on_unpull_item(npos, nside, items, player_name) end @@ -298,10 +349,8 @@ function tubelib.unpull_items(pos, side, items, player_name) end function tubelib.pull_stack(pos, side, player_name) - local npos, facedir = get_neighbor_pos(pos, side) + local npos, nside, name = get_dest_node(pos, side) if npos == nil then return end - local nside, node = get_node_side(npos, facedir) - local name = Name2Name[node.name] if tubelib_NodeDef[name] then if tubelib_NodeDef[name].on_pull_stack then return tubelib_NodeDef[name].on_pull_stack(npos, nside, player_name) @@ -483,6 +532,6 @@ generate_Key2Number() -- maintain data after one minute -- (minetest.get_day_count() will not be valid at start time) -minetest.after(60, data_maintenance) +minetest.after(5, data_maintenance) diff --git a/tubelib/depends.txt b/tubelib/depends.txt index 4ad96d5..6bd4325 100644 --- a/tubelib/depends.txt +++ b/tubelib/depends.txt @@ -1 +1,4 @@ default +tubelib2 +basic_materials + diff --git a/tubelib/distributor.lua b/tubelib/distributor.lua index 5715e9e..396b385 100644 --- a/tubelib/distributor.lua +++ b/tubelib/distributor.lua @@ -12,20 +12,63 @@ A more complex node acting as server and client. This node claims a position number and registers its message and items interface. - The Distributor supports the following messages: + The Distributor is based on the class NodeStates and supports the following messages: - topic = "on", payload = nil - topic = "off" , payload = nil - topic = "state", payload = nil, response is "running", "stopped", "standby", or "not supported" ]]-- +-- for lazy programmers +local S = function(pos) if pos then return minetest.pos_to_string(pos) end end +local P = minetest.string_to_pos +local M = minetest.get_meta + local MAX_NUM_PER_CYC = 20 -- maximum number of items, which can be pushed per slot local NUM_FILTER_ELEM = 6 local NUM_FILTER_SLOTS = 4 -local TICKS_TO_SLEEP = 5 + +local COUNTDOWN_TICKS = 6 +local STANDBY_TICKS = 4 local CYCLE_TIME = 2 -local STOP_STATE = 0 -local STANDBY_STATE = -1 + +local State = tubelib.NodeStates:new({ + node_name_passive = "tubelib:distributor", + node_name_active = "tubelib:distributor_active", + node_name_defect = "tubelib:distributor_defect", + infotext_name = "Tubelib Distributor", + cycle_time = CYCLE_TIME, + standby_ticks = STANDBY_TICKS, + aging_factor = 10, +}) + +local function formspec(pos, meta) + local filter = minetest.deserialize(meta:get_string("filter")) + return "size[10.5,8.5]".. + default.gui_bg.. + default.gui_bg_img.. + default.gui_slots.. + "list[context;src;0,0;2,4;]".. + "image[2,1.5;1,1;tubelib_gui_arrow.png]".. + "image_button[2,3;1,1;"..State:get_state_button_image(meta)..";state_button;]".. + "checkbox[3,0;filter1;On;"..dump(filter[1]).."]".. + "checkbox[3,1;filter2;On;"..dump(filter[2]).."]".. + "checkbox[3,2;filter3;On;"..dump(filter[3]).."]".. + "checkbox[3,3;filter4;On;"..dump(filter[4]).."]".. + "image[4,0;0.3,1;tubelib_red.png]".. + "image[4,1;0.3,1;tubelib_green.png]".. + "image[4,2;0.3,1;tubelib_blue.png]".. + "image[4,3;0.3,1;tubelib_yellow.png]".. + "list[context;red;4.5,0;6,1;]".. + "list[context;green;4.5,1;6,1;]".. + "list[context;blue;4.5,2;6,1;]".. + "list[context;yellow;4.5,3;6,1;]".. + "list[current_player;main;1.25,4.5;8,4;]".. + "listring[context;src]".. + "listring[current_player;main]" +end + +State:register_formspec_func(formspec) -- Return a key/value table with all items and the corresponding stack numbers local function invlist_content_as_kvlist(list) @@ -83,34 +126,9 @@ local function num_items(moved_items, name, filter_item_names, rejected_item_nam end end end - -local function distributor_formspec(state, filter) - return "size[10.5,8.5]".. - default.gui_bg.. - default.gui_bg_img.. - default.gui_slots.. - "list[context;src;0,0;2,4;]".. - "image[2,1.5;1,1;tubelib_gui_arrow.png]".. - "image_button[2,3;1,1;".. tubelib.state_button(state) ..";button;]".. - "checkbox[3,0;filter1;On;"..dump(filter[1]).."]".. - "checkbox[3,1;filter2;On;"..dump(filter[2]).."]".. - "checkbox[3,2;filter3;On;"..dump(filter[3]).."]".. - "checkbox[3,3;filter4;On;"..dump(filter[4]).."]".. - "image[4,0;0.3,1;tubelib_red.png]".. - "image[4,1;0.3,1;tubelib_green.png]".. - "image[4,2;0.3,1;tubelib_blue.png]".. - "image[4,3;0.3,1;tubelib_yellow.png]".. - "list[context;red;4.5,0;6,1;]".. - "list[context;green;4.5,1;6,1;]".. - "list[context;blue;4.5,2;6,1;]".. - "list[context;yellow;4.5,3;6,1;]".. - "list[current_player;main;1.25,4.5;8,4;]".. - "listring[context;src]".. - "listring[current_player;main]" -end local function allow_metadata_inventory_put(pos, listname, index, stack, player) - local meta = minetest.get_meta(pos) + local meta = M(pos) local inv = meta:get_inventory() local list = inv:get_list(listname) @@ -118,6 +136,9 @@ local function allow_metadata_inventory_put(pos, listname, index, stack, player) return 0 end if listname == "src" then + if State:get_state(M(pos)) == tubelib.STANDBY then + State:start(pos, meta) + end return stack:get_count() elseif invlist_num_entries(list) < MAX_NUM_PER_CYC then return stack:get_count() @@ -133,7 +154,7 @@ local function allow_metadata_inventory_take(pos, listname, index, stack, player end local function allow_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player) - local meta = minetest.get_meta(pos) + local meta = M(pos) local inv = meta:get_inventory() local stack = inv:get_stack(from_list, from_index) return allow_metadata_inventory_put(pos, to_list, to_index, stack, player) @@ -145,7 +166,7 @@ local FilterCache = {} -- local cache for filter settings local function filter_settings(pos) local hash = minetest.hash_node_position(pos) - local meta = minetest.get_meta(pos) + local meta = M(pos) local inv = meta:get_inventory() local filter = minetest.deserialize(meta:get_string("filter")) or {false,false,false,false} local kvFilterItemNames = {} -- { = true,...} @@ -169,54 +190,9 @@ local function filter_settings(pos) } end -local function start_the_machine(pos) - local node = minetest.get_node(pos) - local meta = minetest.get_meta(pos) - local number = meta:get_string("number") - meta:set_int("running", TICKS_TO_SLEEP) - node.name = "tubelib:distributor_active" - minetest.swap_node(pos, node) - meta:set_string("infotext", "Tubelib Distributor "..number..": running") - local filter = minetest.deserialize(meta:get_string("filter")) - meta:set_string("formspec", distributor_formspec(tubelib.RUNNING, filter)) - minetest.get_node_timer(pos):start(CYCLE_TIME) - return false -end - -local function stop_the_machine(pos) - local node = minetest.get_node(pos) - local meta = minetest.get_meta(pos) - local number = meta:get_string("number") - meta:set_int("running", STOP_STATE) - node.name = "tubelib:distributor" - minetest.swap_node(pos, node) - meta:set_string("infotext", "Tubelib Distributor "..number..": stopped") - local filter = minetest.deserialize(meta:get_string("filter")) - meta:set_string("formspec", distributor_formspec(tubelib.STOPPED, filter)) - minetest.get_node_timer(pos):stop() - return false -end - -local function goto_sleep(pos) - local node = minetest.get_node(pos) - local meta = minetest.get_meta(pos) - local number = meta:get_string("number") - meta:set_int("running", STANDBY_STATE) - node.name = "tubelib:distributor" - minetest.swap_node(pos, node) - meta:set_string("infotext", "Tubelib Distributor "..number..": standby") - local filter = minetest.deserialize(meta:get_string("filter")) - meta:set_string("formspec", distributor_formspec(tubelib.STANDBY, filter)) - minetest.get_node_timer(pos):start(CYCLE_TIME * TICKS_TO_SLEEP) - return false -end - --- move items to the output slots -local function keep_running(pos, elapsed) - local meta = minetest.get_meta(pos) - local running = meta:get_int("running") - 1 +-- move items from configured filters to the output +local function distributing(pos, meta) local player_name = meta:get_string("player_name") - --print("running", running) local slot_idx = meta:get_int("slot_idx") or 1 meta:set_int("slot_idx", (slot_idx + 1) % NUM_FILTER_SLOTS) local side = Num2Ascii[slot_idx+1] @@ -243,11 +219,10 @@ local function keep_running(pos, elapsed) if items == nil then -- this slot is empty - return true + return false end local busy = false - -- move items from configured filters to the output if next(items) then for _,item in ipairs(items) do local name, num = item[1], item[2] @@ -289,30 +264,26 @@ local function keep_running(pos, elapsed) FilterCache[hash].kvRejectedItemNames = {} end end - - if busy == true then - if running <= 0 then - return start_the_machine(pos) - else - running = TICKS_TO_SLEEP - end - else - if running <= 0 then - return goto_sleep(pos) - end - end - meta:set_string("item_counter", minetest.serialize(counter)) - meta:set_int("running", running) - return true + return busy +end + +-- move items to the output slots +local function keep_running(pos, elapsed) + local meta = M(pos) + if distributing(pos, meta) then + State:keep_running(pos, meta, COUNTDOWN_TICKS) + else + State:idle(pos, meta) + end + return State:is_active(meta) end local function on_receive_fields(pos, formname, fields, player) if minetest.is_protected(pos, player:get_player_name()) then return end - local meta = minetest.get_meta(pos) - local running = meta:get_int("running") + local meta = M(pos) local filter = minetest.deserialize(meta:get_string("filter")) if fields.filter1 ~= nil then filter[1] = fields.filter1 == "true" @@ -327,21 +298,13 @@ local function on_receive_fields(pos, formname, fields, player) filter_settings(pos) - if fields.button ~= nil then - if running > STOP_STATE then - stop_the_machine(pos) - else - start_the_machine(pos) - end - else - meta:set_string("formspec", distributor_formspec(tubelib.state(running), filter)) - end + State:state_button_event(pos, fields) end -- tubelib command to turn on/off filter channels local function change_filter_settings(pos, slot, val) local slots = {["red"] = 1, ["green"] = 2, ["blue"] = 3, ["yellow"] = 4} - local meta = minetest.get_meta(pos) + local meta = M(pos) local filter = minetest.deserialize(meta:get_string("filter")) local num = slots[slot] or 1 if num >= 1 and num <= 4 then @@ -351,8 +314,7 @@ local function change_filter_settings(pos, slot, val) filter_settings(pos) - local running = meta:get_int("running") - meta:set_string("formspec", distributor_formspec(tubelib.state(running), filter)) + meta:set_string("formspec", formspec(pos, meta)) return true end @@ -369,15 +331,13 @@ minetest.register_node("tubelib:distributor", { }, after_place_node = function(pos, placer) + local meta = M(pos) local number = tubelib.add_node(pos, "tubelib:distributor") -- <<=== tubelib - local meta = minetest.get_meta(pos) + local filter = {false,false,false,false} + meta:set_string("filter", minetest.serialize(filter)) + State:node_init(pos, number) meta:set_string("player_name", placer:get_player_name()) - local filter = {false,false,false,false} - meta:set_string("formspec", distributor_formspec(tubelib.STOPPED, filter)) - meta:set_string("filter", minetest.serialize(filter)) - meta:set_string("number", number) - meta:set_string("infotext", "Tubelib Distributor "..number..": stopped") local inv = meta:get_inventory() inv:set_size('src', 8) inv:set_size('yellow', 6) @@ -393,7 +353,7 @@ minetest.register_node("tubelib:distributor", { if minetest.is_protected(pos, puncher:get_player_name()) then return end - local meta = minetest.get_meta(pos) + local meta = M(pos) local inv = meta:get_inventory() if inv:is_empty("src") then minetest.node_dig(pos, node, puncher, pointed_thing) @@ -401,6 +361,10 @@ minetest.register_node("tubelib:distributor", { end end, + after_dig_node = function(pos, oldnode, oldmetadata, digger) + State:after_dig_node(pos, oldnode, oldmetadata, digger) + end, + allow_metadata_inventory_put = allow_metadata_inventory_put, allow_metadata_inventory_take = allow_metadata_inventory_take, allow_metadata_inventory_move = allow_metadata_inventory_move, @@ -455,6 +419,53 @@ minetest.register_node("tubelib:distributor_active", { sounds = default.node_sound_wood_defaults(), }) +minetest.register_node("tubelib:distributor_defect", { + description = "Tubelib Distributor", + tiles = { + -- up, down, right, left, back, front + 'tubelib_distributor.png', + 'tubelib_distributor.png', + 'tubelib_distributor_yellow.png^tubelib_defect.png', + 'tubelib_distributor_green.png^tubelib_defect.png', + "tubelib_distributor_red.png^tubelib_defect.png", + "tubelib_distributor_blue.png^tubelib_defect.png", + }, + + after_place_node = function(pos, placer) + local meta = M(pos) + local number = tubelib.add_node(pos, "tubelib:distributor") -- <<=== tubelib + State:node_init(pos, number) + meta:set_string("player_name", placer:get_player_name()) + + local filter = {false,false,false,false} + meta:set_string("filter", minetest.serialize(filter)) + local inv = meta:get_inventory() + inv:set_size('src', 8) + inv:set_size('yellow', 6) + inv:set_size('green', 6) + inv:set_size('red', 6) + inv:set_size('blue', 6) + meta:set_string("item_counter", minetest.serialize({red=0, green=0, blue=0, yellow=0})) + State:defect(pos, meta) + end, + + on_receive_fields = on_receive_fields, + + allow_metadata_inventory_put = allow_metadata_inventory_put, + allow_metadata_inventory_take = allow_metadata_inventory_take, + allow_metadata_inventory_move = allow_metadata_inventory_move, + + on_rotate = screwdriver.disallow, + + paramtype = "light", + sunlight_propagates = true, + paramtype2 = "facedir", + groups = {crumbly=0, not_in_creative_inventory=1}, + is_ground_content = false, + sounds = default.node_sound_wood_defaults(), +}) + + minetest.register_craft({ output = "tubelib:distributor 2", recipe = { @@ -466,29 +477,19 @@ minetest.register_craft({ --------------------------------------------------------------- tubelib -tubelib.register_node("tubelib:distributor", {"tubelib:distributor_active"}, { +tubelib.register_node("tubelib:distributor", + {"tubelib:distributor_active", "tubelib:distributor_defect"}, { on_pull_item = function(pos, side) - local meta = minetest.get_meta(pos) - return tubelib.get_item(meta, "src") + return tubelib.get_item(M(pos), "src") end, on_push_item = function(pos, side, item) - local meta = minetest.get_meta(pos) - return tubelib.put_item(meta, "src", item) + return tubelib.put_item(M(pos), "src", item) end, on_unpull_item = function(pos, side, item) - local meta = minetest.get_meta(pos) - return tubelib.put_item(meta, "src", item) + return tubelib.put_item(M(pos), "src", item) end, on_recv_message = function(pos, topic, payload) - if topic == "on" then - return start_the_machine(pos) - elseif topic == "off" then - return stop_the_machine(pos) - elseif topic == "state" then - local meta = minetest.get_meta(pos) - local running = meta:get_int("running") - return tubelib.statestring(running) - elseif topic == "filter" then + if topic == "filter" then return change_filter_settings(pos, payload.slot, payload.val) elseif topic == "counter" then local meta = minetest.get_meta(pos) @@ -497,9 +498,21 @@ tubelib.register_node("tubelib:distributor", {"tubelib:distributor_active"}, { elseif topic == "clear_counter" then local meta = minetest.get_meta(pos) meta:set_string("item_counter", minetest.serialize({red=0, green=0, blue=0, yellow=0})) - else - return "unsupported" + else + local resp = State:on_receive_message(pos, topic, payload) + if resp then + return resp + else + return "unsupported" + end end end, + + on_node_load = function(pos) + State:on_node_load(pos) + end, + on_node_repair = function(pos) + return State:on_node_repair(pos) + end, }) --------------------------------------------------------------- tubelib diff --git a/tubelib/init.lua b/tubelib/init.lua index 9621d6a..e8e1444 100644 --- a/tubelib/init.lua +++ b/tubelib/init.lua @@ -24,6 +24,7 @@ - new tubing algorithm - tubelib.pull_stack()/tubelib.get_stack() added - item counter for pusher/distributor added + 2018-12-21 v2.00 Switch to tubelib2, "defect" nodes and "repair kit" added ]]-- @@ -32,7 +33,7 @@ tubelib = { NodeDef = {}, -- node registration info } -tubelib.version = 1.00 +tubelib.version = 2.00 --------------------------- conversion to v0.04 @@ -87,14 +88,17 @@ minetest.register_craft({ }) -dofile(minetest.get_modpath("tubelib") .. "/tubes1.lua") -dofile(minetest.get_modpath("tubelib") .. "/tubes2.lua") +dofile(minetest.get_modpath("tubelib") .. "/tubes.lua") dofile(minetest.get_modpath("tubelib") .. "/command.lua") +-- conversion from v1.16 to v2.00 +dofile(minetest.get_modpath("tubelib") .. "/migrate.lua") dofile(minetest.get_modpath("tubelib") .. "/states.lua") +dofile(minetest.get_modpath("tubelib") .. "/node_states.lua") dofile(minetest.get_modpath("tubelib") .. "/pusher.lua") dofile(minetest.get_modpath("tubelib") .. "/blackhole.lua") dofile(minetest.get_modpath("tubelib") .. "/button.lua") dofile(minetest.get_modpath("tubelib") .. "/lamp.lua") dofile(minetest.get_modpath("tubelib") .. "/distributor.lua") dofile(minetest.get_modpath("tubelib") .. "/legacy_nodes.lua") +dofile(minetest.get_modpath("tubelib") .. "/repairkit.lua") diff --git a/tubelib/migrate.lua b/tubelib/migrate.lua new file mode 100644 index 0000000..c8a3172 --- /dev/null +++ b/tubelib/migrate.lua @@ -0,0 +1,74 @@ +-- for lazy programmers +local S = function(pos) if pos then return minetest.pos_to_string(pos) end end +local P = minetest.string_to_pos +local M = minetest.get_meta + +local Tube = tubelib.Tube + +local TubesTranslation = { + ["tubelib:tube1"] = {[0]= + {12, "S"}, + {21, "S"}, + }, + ["tubelib:tube2"] = {[0]= + { 4, "S"}, + }, + ["tubelib:tube3"] = {[0]= + { 5, "A"}, + {14, "A"}, + {11, "A"}, + { 7, "A"}, + }, + ["tubelib:tube4"] = {[0]= + { 0, "A"}, + {15, "A"}, + { 8, "A"}, + { 3, "A"}, + }, + ["tubelib:tube5"] = {[0]= + {20, "A"}, + {13, "A"}, + {10, "A"}, + {19, "A"}, + }, +} + +minetest.register_lbm({ + label = "[Tubelib] tubes migration", + name = "tubelib:migrate", + nodenames = { + "tubelib:tube1", + "tubelib:tube2", + "tubelib:tube3", + "tubelib:tube4", + "tubelib:tube5", + "tubelib_addons3:teleporter", + }, + run_at_every_load = true, + action = function(pos, node) + if node.name == "tubelib_addons3:teleporter" then + local meta = M(pos) + local peer = meta:get_string("peer") + if peer ~= "" then + meta:set_string("tele_pos", peer) + local peer_pos = P(peer) + local _,node = Tube:get_node(peer_pos) + local tube_dir = ((3 + (node.param2 % 4)) % 4) + 1 + print("migration", peer, tube_dir) + if tube_dir then + meta:set_int("tube_dir", tube_dir) + end + tube_dir = Tube:get_primary_dir(pos) + Tube:tool_repair_tube(Tube:get_pos(pos, tube_dir)) + end + else + local items = TubesTranslation[node.name][node.param2] + if items then + local param2, ntype = items[1], items[2] + minetest.set_node(pos, {name = "tubelib:tube"..ntype, param2 = param2}) + end + end + end +}) + +minetest.register_node("tubelib:tube1", minetest.registered_nodes["tubelib:tubeS"]) diff --git a/tubelib/node_states.lua b/tubelib/node_states.lua new file mode 100644 index 0000000..e1cf36b --- /dev/null +++ b/tubelib/node_states.lua @@ -0,0 +1,427 @@ +--[[ + + Tube Library + ============ + + Copyright (C) 2017 Joachim Stolberg + + LGPLv2.1+ + See LICENSE.txt for more information + + node_states.lua: + + A state model/class for tubelib nodes. + +]]-- + + +--[[ + +Node states: + + +-----------------------------------+ +------------+ + | | | | + | V V | + | +---------+ | + | | | | + | +---------| STOPPED | | + | | | | | + | button | +---------+ | + | | ^ | + repair | V | button | + | +---------+ | | button + | | |---------+ | + | | RUNNING | | + | +--------| |---------+ | + | | +---------+ | | + | | ^ | | | + | | | | | | + | V | V V | + | +---------+ +----------+ +---------+ | + | | | | | | | | + +---| DEFECT | | STANDBY/ | | FAULT |----------+ + | | | BLOCKED | | | + +---------+ +----------+ +---------+ + +Node metadata: + "tubelib_number" - string with tubelib number, like "0123" + "tubelib_state" - node state, like "RUNNING" + "tubelib_item_meter" - node item/runtime counter + "tubelib_countdown" - countdown to stadby mode + "tubelib_aging" - aging counter +]]-- + +-- for lazy programmers +local S = function(pos) if pos then return minetest.pos_to_string(pos) end end +local P = minetest.string_to_pos +local M = minetest.get_meta + + +local AGING_VALUE = 10 -- start aging value +local AGING_FACTOR = 3 -- defect random factor + +-- +-- Local States +-- +local STOPPED = tubelib.STOPPED +local RUNNING = tubelib.RUNNING +local STANDBY = tubelib.STANDBY +local FAULT = tubelib.FAULT +local BLOCKED = tubelib.BLOCKED +local DEFECT = tubelib.DEFECT + + +-- +-- NodeStates Class Functions +-- +tubelib.NodeStates = {} +local NodeStates = tubelib.NodeStates + +function NodeStates:new(attr) + local o = { + -- mandatory + cycle_time = attr.cycle_time, -- for running state + standby_ticks = attr.standby_ticks, -- for standby state + has_item_meter = attr.has_item_meter, -- true/false + -- optional + node_name_passive = attr.node_name_passive, + node_name_active = attr.node_name_active, + node_name_defect = attr.node_name_defect, + infotext_name = attr.infotext_name, + } + if attr.aging_factor then + o.aging_level1 = attr.aging_factor * AGING_VALUE + o.aging_level2 = attr.aging_factor * AGING_VALUE * AGING_FACTOR + end + setmetatable(o, self) + self.__index = self + return o +end + +function NodeStates:register_formspec_func(func) + self.formspec_func = func +end + +function NodeStates:node_init(pos, number) + local meta = M(pos) + meta:set_int("tubelib_state", STOPPED) + meta:set_string("tubelib_number", number) + if self.infotext_name then + meta:set_string("infotext", self.infotext_name.." "..number..": stopped") + end + if self.has_item_meter then + meta:set_int("tubelib_item_meter", 0) + end + if self.aging_level1 then + meta:set_int("tubelib_aging", 0) + end + if self.formspec_func then + meta:set_string("formspec", self.formspec_func(pos, meta)) + end +end + +function NodeStates:stop(pos, meta) + if meta:get_int("tubelib_state") ~= DEFECT then + meta:set_int("tubelib_state", STOPPED) + if self.node_name_passive then + local node = minetest.get_node(pos) + node.name = self.node_name_passive + minetest.swap_node(pos, node) + end + if self.infotext_name then + local number = meta:get_string("tubelib_number") + meta:set_string("infotext", self.infotext_name.." "..number..": stopped") + end + if self.formspec_func then + meta:set_string("formspec", self.formspec_func(pos, meta)) + end + minetest.get_node_timer(pos):stop() + return true + end + return false +end + +function NodeStates:start(pos, meta, called_from_on_timer) + local state = meta:get_int("tubelib_state") + if state == STOPPED or state == STANDBY or state == BLOCKED then + meta:set_int("tubelib_state", RUNNING) + if called_from_on_timer then + -- timer has to be stopped once to be able to be restarted + self.stop_timer = true + end + if self.node_name_active then + local node = minetest.get_node(pos) + node.name = self.node_name_active + minetest.swap_node(pos, node) + end + if self.infotext_name then + local number = meta:get_string("tubelib_number") + meta:set_string("infotext", self.infotext_name.." "..number..": running") + end + if self.formspec_func then + meta:set_string("formspec", self.formspec_func(pos, meta)) + end + minetest.get_node_timer(pos):start(self.cycle_time) + return true + end + return false +end + +function NodeStates:standby(pos, meta) + if meta:get_int("tubelib_state") == RUNNING then + meta:set_int("tubelib_state", STANDBY) + -- timer has to be stopped once to be able to be restarted + self.stop_timer = true + if self.node_name_passive then + local node = minetest.get_node(pos) + node.name = self.node_name_passive + minetest.swap_node(pos, node) + end + if self.infotext_name then + local number = meta:get_string("tubelib_number") + meta:set_string("infotext", self.infotext_name.." "..number..": standby") + end + if self.formspec_func then + meta:set_string("formspec", self.formspec_func(pos, meta)) + end + minetest.get_node_timer(pos):start(self.cycle_time * self.standby_ticks) + return true + end + return false +end + +-- special case of standby for pushing nodes +function NodeStates:blocked(pos, meta) + if meta:get_int("tubelib_state") == RUNNING then + meta:set_int("tubelib_state", BLOCKED) + -- timer has to be stopped once to be able to be restarted + self.stop_timer = true + if self.node_name_passive then + local node = minetest.get_node(pos) + node.name = self.node_name_passive + minetest.swap_node(pos, node) + end + if self.infotext_name then + local number = meta:get_string("tubelib_number") + meta:set_string("infotext", self.infotext_name.." "..number..": blocked") + end + if self.formspec_func then + meta:set_string("formspec", self.formspec_func(pos, meta)) + end + minetest.get_node_timer(pos):start(self.cycle_time * self.standby_ticks) + return true + end + return false +end + +function NodeStates:fault(pos, meta) + if meta:get_int("tubelib_state") == RUNNING then + meta:set_int("tubelib_state", FAULT) + if self.node_name_passive then + local node = minetest.get_node(pos) + node.name = self.node_name_passive + minetest.swap_node(pos, node) + end + if self.infotext_name then + local number = meta:get_string("tubelib_number") + meta:set_string("infotext", self.infotext_name.." "..number..": fault") + end + if self.formspec_func then + meta:set_string("formspec", self.formspec_func(pos, meta)) + end + minetest.get_node_timer(pos):stop() + return true + end + return false +end + +function NodeStates:defect(pos, meta) + meta:set_int("tubelib_state", DEFECT) + if self.node_name_defect then + local node = minetest.get_node(pos) + node.name = self.node_name_defect + minetest.swap_node(pos, node) + end + if self.infotext_name then + local number = meta:get_string("tubelib_number") + meta:set_string("infotext", self.infotext_name.." "..number..": defect") + end + if self.formspec_func then + meta:set_string("formspec", self.formspec_func(pos, meta)) + end + minetest.get_node_timer(pos):stop() + return true +end + +function NodeStates:get_state(meta) + return meta:get_int("tubelib_state") +end + +function NodeStates:get_state_string(meta) + return tubelib.StateStrings[meta:get_int("tubelib_state")] +end + +function NodeStates:is_active(meta) + local state = meta:get_int("tubelib_state") + if self.stop_timer == true then + self.stop_timer = false + return false + end + return state == RUNNING or state == STANDBY or state == BLOCKED +end + +-- To be called if node is idle. +-- If countdown reaches zero, the node is set to STANDBY. +function NodeStates:idle(pos, meta) + local countdown = meta:get_int("tubelib_countdown") - 1 + meta:set_int("tubelib_countdown", countdown) + if countdown < 0 then + self:standby(pos, meta) + end +end + +-- To be called after successful node action to raise the timer +-- and keep the node in state RUNNING +function NodeStates:keep_running(pos, meta, val) + -- set to RUNNING if not already done + self:start(pos, meta, true) + meta:set_int("tubelib_countdown", val) + meta:set_int("tubelib_item_meter", meta:get_int("tubelib_item_meter") + 1) + if self.aging_level1 then + local cnt = meta:get_int("tubelib_aging") + 1 + meta:set_int("tubelib_aging", cnt) + if cnt > (self.aging_level1) and math.random(self.aging_level2) == 1 then + self:defect(pos, meta) + end + end +end + +-- Start/stop node based on button events. +-- if function returns false, no button was pressed +function NodeStates:state_button_event(pos, fields) + if fields.state_button ~= nil then + local state = self:get_state(M(pos)) + if state == STOPPED or state == STANDBY or state == BLOCKED then + self:start(pos, M(pos)) + elseif state == RUNNING or state == FAULT then + self:stop(pos, M(pos)) + end + return true + end + return false +end + +function NodeStates:get_state_button_image(meta) + local state = meta:get_int("tubelib_state") + return tubelib.state_button(state) +end + +-- command interface +function NodeStates:on_receive_message(pos, topic, payload) + if topic == "on" then + self:start(pos, M(pos)) + return true + elseif topic == "off" then + self:stop(pos, M(pos)) + return true + elseif topic == "state" then + local node = minetest.get_node(pos) + if node.name == "ignore" then -- unloaded node? + return "blocked" + end + return self:get_state_string(M(pos)) + elseif self.has_item_meter and topic == "counter" then + return M(pos):get_int("tubelib_item_meter") + elseif self.has_item_meter and topic == "clear_counter" then + M(pos):set_int("tubelib_item_meter", 0) + return true + elseif self.aging_level1 and topic == "aging" then + return M(pos):get_int("tubelib_aging") + end +end + +-- repair corrupt node data and/or migrate node to state2 +function NodeStates:on_node_load(pos) + local meta = minetest.get_meta(pos) + + -- legacy node number/state/counter? + local number = meta:get_string("number") + if number ~= "" then + meta:set_string("tubelib_number", number) + meta:set_int("tubelib_state", tubelib.state(meta:get_int("running"))) + if self.has_item_meter then + meta:set_int("tubelib_item_meter", meta:get_int("counter")) + end + if self.aging_level1 then + meta:set_int("tubelib_aging", 0) + end + meta:set_string("number", nil) + meta:set_int("running", 0) + meta:set_int("counter", 0) + end + + -- node number corrupt? + number = meta:get_string("tubelib_number") + if number == "" then + number = tubelib.add_node(pos, self.node_name_passive) + meta:set_string("tubelib_number", number) + else + local info = tubelib.get_node_info(number) + if not info or info.pos ~= pos then + number = tubelib.add_node(pos, self.node_name_passive) + meta:set_string("tubelib_number", number) + end + end + + -- state corrupt? + local state = meta:get_int("tubelib_state") + if state == 0 then + if minetest.get_node_timer(pos):is_started() then + meta:set_int("tubelib_state", RUNNING) + else + meta:set_int("tubelib_state", STOPPED) + end + elseif state == RUNNING then + minetest.get_node_timer(pos):start(self.cycle_time) + elseif state == STANDBY then + minetest.get_node_timer(pos):start(self.cycle_time * self.standby_ticks) + elseif state == BLOCKED then + minetest.get_node_timer(pos):start(self.cycle_time * self.standby_ticks) + end +end + +-- Repair of defect (feature!) nodes +function NodeStates:on_node_repair(pos) + local meta = M(pos) + if meta:get_int("tubelib_state") == DEFECT then + meta:set_int("tubelib_state", STOPPED) + if self.node_name_passive then + local node = minetest.get_node(pos) + node.name = self.node_name_passive + minetest.swap_node(pos, node) + end + if self.aging_level1 then + meta:set_int("tubelib_aging", 0) + end + if self.infotext_name then + local number = meta:get_string("tubelib_number") + meta:set_string("infotext", self.infotext_name.." "..number..": stopped") + end + if self.formspec_func then + meta:set_string("formspec", self.formspec_func(pos, meta)) + end + return true + end + return false +end + +function NodeStates:after_dig_node(pos, oldnode, oldmetadata, digger) + local inv = minetest.get_inventory({type="player", name=digger:get_player_name()}) + local cnt = oldmetadata.fields.tubelib_aging and tonumber(oldmetadata.fields.tubelib_aging) or 0 + local is_defect = cnt > self.aging_level1 and math.random(self.aging_level2 / cnt) == 1 + if self.node_name_defect and is_defect then + inv:add_item("main", ItemStack(self.node_name_defect)) + else + inv:add_item("main", ItemStack(self.node_name_passive)) + end +end diff --git a/tubelib/pusher.lua b/tubelib/pusher.lua index 693a303..58fb4fa 100644 --- a/tubelib/pusher.lua +++ b/tubelib/pusher.lua @@ -13,7 +13,7 @@ Simple node for push/pull operation of StackItems from chests or other inventory/server nodes to tubes or other inventory/server nodes. - The Pusher supports the following messages: + The Pusher is based on the class NodeStates and supports the following messages: - topic = "on", payload = nil - topic = "off", payload = nil - topic = "state", payload = nil, @@ -29,83 +29,48 @@ -- | |/ -- +--------+ -local RUNNING_STATE = 10 +-- for lazy programmers +local S = function(pos) if pos then return minetest.pos_to_string(pos) end end +local P = minetest.string_to_pos +local M = minetest.get_meta -local function switch_on(pos, node) - local meta = minetest.get_meta(pos) - local number = meta:get_string("number") - meta:set_int("running", RUNNING_STATE) - meta:set_string("infotext", "Pusher "..number..": running") - node.name = "tubelib:pusher_active" - minetest.swap_node(pos, node) - minetest.get_node_timer(pos):start(2) - return false -end +local STANDBY_TICKS = 5 +local COUNTDOWN_TICKS = 5 +local CYCLE_TIME = 2 -local function switch_off(pos, node) - local meta = minetest.get_meta(pos) - local number = meta:get_string("number") - meta:set_int("running", tubelib.STATE_STOPPED) - meta:set_string("infotext", "Pusher "..number..": stopped") - node.name = "tubelib:pusher" - minetest.swap_node(pos, node) - minetest.get_node_timer(pos):stop() - return false -end +local State = tubelib.NodeStates:new({ + node_name_passive = "tubelib:pusher", + node_name_active = "tubelib:pusher_active", + node_name_defect = "tubelib:pusher_defect", + infotext_name = "Tubelib Pusher", + cycle_time = CYCLE_TIME, + standby_ticks = STANDBY_TICKS, + has_item_meter = true, + aging_factor = 10, +}) -local function goto_standby(pos, node) - local meta = minetest.get_meta(pos) - local number = meta:get_string("number") - meta:set_int("running", tubelib.STATE_STANDBY) - meta:set_string("infotext", "Pusher "..number..": standby") - node.name = "tubelib:pusher" - minetest.swap_node(pos, node) - minetest.get_node_timer(pos):start(20) - return false -end - -local function goto_blocked(pos, node) - local meta = minetest.get_meta(pos) - local number = meta:get_string("number") - meta:set_int("running", tubelib.STATE_BLOCKED) - meta:set_string("infotext", "Pusher "..number..": blocked") - node.name = "tubelib:pusher" - minetest.swap_node(pos, node) - minetest.get_node_timer(pos):start(20) - return false -end - -local function keep_running(pos, elapsed) - local meta = minetest.get_meta(pos) - local number = meta:get_string("number") - local running = meta:get_int("running") - 1 +local function pushing(pos, meta) local player_name = meta:get_string("player_name") local items = tubelib.pull_items(pos, "L", player_name) -- <<=== tubelib if items ~= nil then if tubelib.push_items(pos, "R", items, player_name) == false then -- <<=== tubelib -- place item back tubelib.unpull_items(pos, "L", items, player_name) -- <<=== tubelib - local node = minetest.get_node(pos) - return goto_blocked(pos, node) - end - meta:set_int("item_counter", meta:get_int("item_counter") + 1) - if running <= 0 then - local node = minetest.get_node(pos) - return switch_on(pos, node) - else - -- reload running state - running = RUNNING_STATE - end - else - if running <= 0 then - local node = minetest.get_node(pos) - return goto_standby(pos, node) + State:blocked(pos, meta) + return end + State:keep_running(pos, meta, COUNTDOWN_TICKS) + return end - meta:set_int("running", running) - return true + State:idle(pos, meta) end +local function keep_running(pos, elapsed) + local meta = M(pos) + pushing(pos, meta) + return State:is_active(meta) +end + minetest.register_node("tubelib:pusher", { description = "Tubelib Pusher", tiles = { @@ -122,24 +87,24 @@ minetest.register_node("tubelib:pusher", { local meta = minetest.get_meta(pos) meta:set_string("player_name", placer:get_player_name()) local number = tubelib.add_node(pos, "tubelib:pusher") -- <<=== tubelib - meta:set_string("number", number) - meta:set_string("infotext", "Pusher "..number..": stopped") - meta:set_int("item_counter", 0) + State:node_init(pos, number) end, on_rightclick = function(pos, node, clicker) if not minetest.is_protected(pos, clicker:get_player_name()) then - switch_on(pos, node) + State:start(pos, M(pos)) end end, - after_dig_node = function(pos) + after_dig_node = function(pos, oldnode, oldmetadata, digger) tubelib.remove_node(pos) -- <<=== tubelib + State:after_dig_node(pos, oldnode, oldmetadata, digger) end, on_timer = keep_running, on_rotate = screwdriver.disallow, + drop = "", paramtype = "light", sunlight_propagates = true, paramtype2 = "facedir", @@ -199,7 +164,7 @@ minetest.register_node("tubelib:pusher_active", { on_rightclick = function(pos, node, clicker) if not minetest.is_protected(pos, clicker:get_player_name()) then - switch_off(pos, node) + State:stop(pos, M(pos)) end end, @@ -214,6 +179,42 @@ minetest.register_node("tubelib:pusher_active", { sounds = default.node_sound_wood_defaults(), }) +minetest.register_node("tubelib:pusher_defect", { + description = "Tubelib Pusher", + tiles = { + -- up, down, right, left, back, front + 'tubelib_pusher1.png', + 'tubelib_pusher1.png', + 'tubelib_outp.png^tubelib_defect.png', + 'tubelib_inp.png^tubelib_defect.png', + "tubelib_pusher1.png^[transformR180]^tubelib_defect.png", + "tubelib_pusher1.png^tubelib_defect.png", + }, + + after_place_node = function(pos, placer) + local meta = minetest.get_meta(pos) + meta:set_string("player_name", placer:get_player_name()) + local number = tubelib.add_node(pos, "tubelib:pusher") -- <<=== tubelib + State:node_init(pos, number) + State:defect(pos, meta) + end, + + after_dig_node = function(pos) + tubelib.remove_node(pos) -- <<=== tubelib + end, + + on_timer = keep_running, + on_rotate = screwdriver.disallow, + + paramtype = "light", + sunlight_propagates = true, + paramtype2 = "facedir", + groups = {choppy=2, cracky=2, crumbly=2, not_in_creative_inventory=1}, + is_ground_content = false, + sounds = default.node_sound_wood_defaults(), +}) + + minetest.register_craft({ output = "tubelib:pusher 2", recipe = { @@ -224,34 +225,26 @@ minetest.register_craft({ }) --------------------------------------------------------------- tubelib -tubelib.register_node("tubelib:pusher", {"tubelib:pusher_active"}, { +tubelib.register_node("tubelib:pusher", + {"tubelib:pusher_active", "tubelib:pusher_defect"}, { on_pull_item = nil, -- pusher has no inventory on_push_item = nil, -- pusher has no inventory on_unpull_item = nil, -- pusher has no inventory is_pusher = true, -- is a pulling/pushing node on_recv_message = function(pos, topic, payload) - local node = minetest.get_node(pos) - if topic == "on" then - return switch_on(pos, node) - elseif topic == "off" then - return switch_off(pos, node) - elseif topic == "state" then - if node.name == "ignore" then -- unloaded pusher? - return "blocked" - end - local meta = minetest.get_meta(pos) - local running = meta:get_int("running") or tubelib.STATE_STOPPED - return tubelib.statestring(running) - elseif topic == "counter" then - local meta = minetest.get_meta(pos) - return meta:get_int("item_counter") - elseif topic == "clear_counter" then - local meta = minetest.get_meta(pos) - return meta:set_int("item_counter", 0) + local resp = State:on_receive_message(pos, topic, payload) + if resp then + return resp else - return "not supported" + return "unsupported" end end, + on_node_load = function(pos) + State:on_node_load(pos) + end, + on_node_repair = function(pos) + return State:on_node_repair(pos) + end, }) --------------------------------------------------------------- tubelib diff --git a/tubelib/repairkit.lua b/tubelib/repairkit.lua new file mode 100644 index 0000000..7d6f126 --- /dev/null +++ b/tubelib/repairkit.lua @@ -0,0 +1,82 @@ +--[[ + + Tube Library + ============ + + Copyright (C) 2017-2018 Joachim Stolberg + + LGPLv2.1+ + See LICENSE.txt for more information + + repairkit.lua: +]]-- + +-- for lazy programmers +local S = function(pos) if pos then return minetest.pos_to_string(pos) end end +local P = minetest.string_to_pos +local M = minetest.get_meta + + +local function repair_node(itemstack, user, pointed_thing) + local pos = pointed_thing.under + if pos then + if tubelib.repair_node(pos) then + minetest.chat_send_player(user:get_player_name(), "[Tubelib] Node repaired") + itemstack:take_item() + return itemstack + end + end + return +end + +local function read_state(itemstack, user, pointed_thing) + local pos = pointed_thing.under + if pos then + local number = tubelib.get_node_number(pos) + if number then + local state = tubelib.send_request(number, "state", nil) + local counter = tubelib.send_request(number, "counter", nil) + local aging = tubelib.send_request(number, "aging", nil) + if state and counter and aging then + minetest.chat_send_player(user:get_player_name(), "[Tubelib] state ="..state..", counter = "..counter..", aging = "..aging) + end + end + end +end + +minetest.register_craftitem("tubelib:repairkit", { + description = "Tubelib Repair Kit", + inventory_image = "tubelib_repairkit.png", + wield_image = "tubelib_repairkit.png^[transformR270", + groups = {cracky=1, book=1}, + on_use = repair_node, + node_placement_prediction = "", +}) + + +minetest.register_node("tubelib:end_wrench", { + description = "Tubelib End Wrench", + inventory_image = "tubelib_end_wrench.png", + wield_image = "tubelib_end_wrench.png", + groups = {cracky=1, book=1}, + on_use = read_state, + node_placement_prediction = "", +}) + +minetest.register_craft({ + output = "tubelib:repairkit", + recipe = { + {"", "basic_materials:gear_steel", ""}, + {"", "tubelib:end_wrench", ""}, + {"", "basic_materials:oil_extract", ""}, + }, +}) + +minetest.register_craft({ + output = "tubelib:end_wrench 4", + recipe = { + {"", "", "default:steel_ingot"}, + {"", "default:tin_ingot", ""}, + {"default:steel_ingot", "", ""}, + }, +}) diff --git a/tubelib/states.lua b/tubelib/states.lua index a3dbe27..bae0b9a 100644 --- a/tubelib/states.lua +++ b/tubelib/states.lua @@ -15,35 +15,41 @@ ]]-- -- --- Inventory Button States +-- Tubelib machine states -- - -tubelib.STOPPED = 1 -- not operational -tubelib.RUNNING = 2 -- in normal operation -tubelib.STANDBY = 3 -- nothing to do or blocked anyhow -tubelib.FAULT = 4 -- any fault state, which has to be fixed by the player +tubelib.STOPPED = 1 -- not operational/turned off +tubelib.RUNNING = 2 -- in normal operation/turned on +tubelib.STANDBY = 3 -- nothing to do (e.g. no input items), or blocked anyhow (output jammed), + -- or node (world) not loaded +tubelib.FAULT = 4 -- any fault state (e.g. no fuel), which can be fixed by the player +tubelib.BLOCKED = 5 -- a pushing node is blocked due to a full destination inventory +tubelib.DEFECT = 6 -- a defect (broken), which has to be repaired by the player tubelib.StatesImg = { "tubelib_inv_button_off.png", "tubelib_inv_button_on.png", "tubelib_inv_button_standby.png", - "tubelib_inv_button_error.png" + "tubelib_inv_button_error.png", + "tubelib_inv_button_error.png", + "tubelib_inv_button_off.png", } -- Return state button image for the node inventory function tubelib.state_button(state) - if state and state < 5 and state > 0 then + if state and state < 7 and state > 0 then return tubelib.StatesImg[state] end - return tubelib.StatesImg[tubelib.FAULT] + return "tubelib_inv_button_off.png" end -- State string based on button states -tubelib.states = {"stopped", "running", "standby", "fault"} +tubelib.StateStrings = {"stopped", "running", "standby", "fault", "blocked", "defect"} + + -- --- 'running' variable States +-- 'running' variable States (deprecated) -- tubelib.STATE_RUNNING = 1 -- in normal operation diff --git a/tubelib/textures/tubelib_blue.png b/tubelib/textures/tubelib_blue.png index 71c47fa466905f28859a27978209f7b39f07326c..b8d75c17a492bfc50f36dd921b5c092fe61427ae 100644 GIT binary patch delta 51 zcmXRaoFKu;$jrdNplX||G*MAsk;l`;F@)oKa)JUcP}G2d@%XCNJ|K(1)78&qol`;+ E03g5&FaQ7m delta 52 zcmXRcnjpc+!OXzGprOkjJW)|!iPzJ`F+}2Wa)Jcw2?hp60S3l5(;rs>6)~bp9zYIffk$L90|U1(2s1Lwnj--eWH0gbb!C6V!z`q$YvrZv1Qe3Z42dXl z&d<$F%_{+N85o?4QWHy3QxwWGOEMJPJ$(aG^itV@hKqZ;IEHAPZ=JZ`?@)k9JHMy2 za3|+?(>W5p2@_a_OA`#0N)iqVEK}p*`NXnhmxPL8d4VCzAq}G~+7~X}XZ|5_%>BbZ z?HfiF)1G~QI`7{5Io?aUH!>~l+E{W)iTUO!uI-E)0u%Il z{q{Ai-G24Kw>0VT0 zvQL&uV=KSynm?!df*1SQXlWf#HvYdgKy1Or+cRYozT}n)>^^zwT|>m3znkK-*kAgD oy#0QA=JF*zPyex>y#0^q)P)ScKDTecNMm5|boFyt=akR{0D9@S^8f$< literal 0 HcmV?d00001 diff --git a/tubelib/textures/tubelib_distributor_blue.png b/tubelib/textures/tubelib_distributor_blue.png index fb3d47c54931d839ff5e927bf5fff9fa711dd2e6..f43e2b672c8d50a8e778ab190858853e51490822 100644 GIT binary patch delta 428 zcmV;d0aO0g1Ly;g7zqRe0001iRAfI{J1~geFx$}Ao|i*3JI<#g=Hs_0ZV@= zN)hxd=)pUvFlQHm7ioVl2PJ?A0t6|gNCAK{uG^E2YGYqR888dd`uTSIaey%pg6pRd zWKrxgb~(?|O%`pq1Ku8zo@dvhI3A0yB5snwcIDaY`xtL=gT9@^v+p}tP*Ae^&-jR2 zE5tRumsGnPl5SQ~B|RwQQ%Qv@y99sNQw9Ps!u8Z+>!!?sLJ0S>lE!<1V2Ea5`3Z~~ zJqbew2xb!I01;+t+6rl<8(kcWtKI)vx6Y5w=<`Xpb!Dwhtsex8PAxc%Ksn!ybG@zI zmof@#cAh}?Xk7<^lqgB9|A6CdWiqf*`sFt0{%%XcgS{y$mRPHWSgaTsxcCJE W50IAA8dRSE00009D>000DMK}|sb0I`n?{9y$E0004VQb$4nuFf3k zks&gF0Z>UqK~y-)byJCU!ypXv0WM+x|G$$&=(1PpHiScwjV)VRSem)HXYzqzg~tP% zX4WsPvR~N3;A!{NVHnM>j&Jo2Z@iu%NSOZB(_^qDm9K zM~oUgUVw(J_9Kf8;28rn0pbA|Q9%IxBmx0{V6>ti9JF`?5Tx^hbTQ`aw22@8od8{) zIU=CH{+R$w-nt1HP5?x~Ja~OFOaMxm*g<}}s7PfJwK%&d2I1yDMu{1+EWbx1~0UjY45xs3`qB}#{k6o6ALZU7=VFbDvxEIkOID$jXn z7km~OZaoNqb(1njZH3m-Ln;Ppask={khikMP;Z94D#b|Yj&THxEU8*v)_vHWT1#pE z*PG68T)nAjU}}%vwA>BJFYh+>XK&`xuc#w@wrr7zqRe0001iRAZhfcvU6grnewn7SpE`5MJRL^O_sUoxSD($AbEb%kY%5cRQ_e^4hVGK?ukd{cGAc0t{>ICGN zUZ2n32yL?fpN2MCUNzFz0AIkiy>!a#8QaC!ICUTpyf$+rPi zphA#;ibrZ|b}=1VutHO(1uN~jEne{ z{F_pP$6ODu0j>r>EH2W2JzwWX-2b>4_j&B8EH~29KH4$n!A*&YVbOy?8(;`9^%4~& z3DOF_PNfVGkPDc6fnv%tT!)4!#f0f^JB`}9m~M;7$Nu-W@qC$fA?uRes_7ta8*&k& eeDT?^{`~+U_mY9~awGQu00009D>000DMK}|sb0I`n?{9y$E0004VQb$4nuFf3k zks&pI0bNN%K~y-)byJC!#2^R*L5Irz|MzZ!wtKuvr;JL9;S$qSQxA1F^Dqi_rV)ul z744UsTEBpT!g?>m1KLHe&Tp;`FIX-e!M($#0xKLTG~DtHhY2TqA(Eah(%PVEB2o+d z;{;Di0KRRbeU&W07!u(r3R*`1?h_-C1!(1ewcXwa0|0=b;AqZHnRxi?1Tc6ZTLSv$ zj}$;N0AMKaKHmYzgIY!L&%-Q|NX0|)?TWH(lCM{k4LOd}6$k){+JIM*j1ZZ&BL|79 zrXK+)v^djwy5j07Y@=5I3WDZJa?o=WsHTP<6NSbNVY9sga7C5jNp)3u&Ry_1&>?qq zKPY;sjRD2Z98ZVtelXXvRa?>U00vTo!O;a+T|LJ3FsM9`$;|ZaeF54Jz+ja%EgToE zvGm&Wl%=|7Gf0P{h@mTH3F^OQ(>a?~Qwax%jY|^Pv+10Fx8>S1kw1Op8x}tiRv|+8 Qr2qf`07*qoM6N<$g0_{n8UO$Q diff --git a/tubelib/textures/tubelib_distributor_red.png b/tubelib/textures/tubelib_distributor_red.png index cd11bb9aa6bab75b9f7df27852733127d3cf4cd0..6ec1e03b85b76248114551642131e92cc034aded 100644 GIT binary patch delta 466 zcmV;@0WJRA1Kez3N9i0u&TK$r z>KJuRVuYs-Zk+gX#cn0jf8*184|qS=t!1iecFr*)3nAc`+BQ>NV>^3Tu|o>=!|i*P zTbW-sJ+FIkRv2rvk%9{)w1%>z2q%aVifDq%5;&)5LEZqKJj9HFvLO&9TzU_Zh$J*3 z1lKocQyQIy;eUP~J_mx^43wbJ*Yh;51j`+0P0_~;w%{6y{uD0+mwF1FEth@_4J>U6 zPKFl6z{pUcH1I0SIE(NW51fMiEwt3%aL8tm;NuFo_;*VQN{1P;0Apv6VB1VjAMV4+ z|NpdHjD4&LikAqJvD$_2!-&{7<_{x?oB-{CZ$0*kI7^Ax7K$=Pkq5~H&IMR)r7*4$ z+FGrq-Co;_ch_BaeqaCYw%R{f-sqffZfx4EQI(goqR`{~0M&!C%Z6RA?f?J)07*qo IM6N<$g4YMjQvd(} delta 462 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 diff --git a/tubelib/textures/tubelib_hole.png b/tubelib/textures/tubelib_hole.png index 125b0550d5ddb866bf0d6045d5ea1775264cfafd..6d61205f2bd97aaef66afdbe4d8180561b50b68a 100644 GIT binary patch delta 109 zcmX@dc!+U=1SbnK0|P^2Nc!=KiXM?Jo-U3d8t0P}BwQR^0$f}qIvz5$9cog@;1CxG zVPbY{;p$+J6IBvm6uhJ5qrjxLBb39LrDf%7zK;BfIgLNUDhymX8KzI<>y}#gKo@8( NgQu&X%Q~loCIH-4AprmY delta 121 zcmV-<0EYj<0nP!C7zqdi0000)q>9FoAxLFVNklA>Qw>bj#K;a00000NkvXXu0mjf+p07H diff --git a/tubelib/textures/tubelib_red.png b/tubelib/textures/tubelib_red.png index 04c293f04847cb251d6789e490f288ca77397801..4e4cd2abea8de0f409984b373b28814b61a21529 100644 GIT binary patch delta 51 zcmXRaoFKu;$jrdNplX||G*MAsk;l`;F@)oKa)JUcP}G2d@%XCNJ|K(1)78&qol`;+ E03g5&FaQ7m delta 52 zcmXRcnjpc+!OXzGprOkjJW)|!iPzJ`F+}2Wa)Jcw2?hp60S3l5(;rs>6)OrzHT0004WQchC)7y#u37GtOgU;;#FN|6B}cZm)tgi!ne zNI%E`%ml_iSO7T%j6XyZU@2z#jMxDB10}`K_g5wo>u;J!WDKyUTL67;9iaMaIZ*xk zfL`*9eW3a)o!I!}MgZ~WgAf5E{;g#s1;7ncnJ*wukY^%o0JOKV&;ZDkv$LI<20+@8 z(smZsA-yB6HnNSF1=HEi(hmvRMp}s=@cpF&g4lX!8S8l^1o0a+_JKU6)J{Zk0wo3e jP~H2Z`3C@(>#)87YmU*-N6@+M00000NkvXXu0mjf(_#LP literal 0 HcmV?d00001 diff --git a/tubelib/textures/tubelib_yellow.png b/tubelib/textures/tubelib_yellow.png index e92f942283ce785e2179f25b0a50996af0e11ad1..8ac93436cf5c8bfac4d0533ab0b3604f7c9b7bd5 100644 GIT binary patch delta 51 zcmXRaoFKu;$jrdNplX||G*MAsk;l`;F@)oKa)JUcP}G2d@%XCNJ|K(1)78&qol`;+ E03g5&FaQ7m delta 52 zcmXRcnjpc+!OXzGprOkjJW)|!iPzJ`F+}2Wa)Jcw2?hp60S3l5(;rs>6) dir2 then - dir1, dir2 = dir2, dir1 - end - local item = TubeNodeAttr[dir1*10 + dir2] - return item.number, item.param2 -end - --- convert 6D-dir to position -local function get_tube_pos(pos, dir) - return vector.add(pos, Dir2Offset[dir]) -end - --- Tube open sides -local function get_tube_dirs(pos, node) - if node == nil then - node = minetest.get_node_or_nil(pos) or tubelib.read_node_with_vm(pos) - end - if tubelib.TubeNames[node.name] then - local ttype = (string.byte(node.name, -1) - 48) * 10 + node.param2 - return TubeDirs[ttype][1], TubeDirs[ttype][2] - end - return nil, nil -end - -function tubelib.get_next_tube(pos, dir) - pos = get_tube_pos(pos, dir) - local dir1, dir2 = get_tube_dirs(pos) - - if dir1 then - dir = Turn180Deg[dir] - if dir == dir1 then - return pos, dir2 - elseif dir == dir2 then - return pos, dir1 - end - end - return pos, nil -end - -local function is_known_node(pos, dir) - if dir then - pos = get_tube_pos(pos, dir) - local node = minetest.get_node_or_nil(pos) or tubelib.read_node_with_vm(pos) - if tubelib.KnownNodes[node.name] and not tubelib.TubeNames[node.name] then - return true - end - end - return false -end - - --- Walk to the other end of the tube line, starting at 'pos/dir'. --- Returns: cnt - number of tube nodes --- pos - the peer tube node --- dir - dir to the drop position, next after 'pos' -function tubelib.walk_to_peer(pos, dir) - local cnt = 0 - while cnt < MAX_TUBE_LENGTH do - local new_pos, new_dir = tubelib.get_next_tube(pos, dir) - if not new_dir then - break - end - cnt = cnt + 1 - pos, dir = new_pos, new_dir - end - return cnt, pos, dir -end - --- Delete meta data of the peer node -function tubelib.delete_meta_data(pos, node) - local dir1, dir2 = get_tube_dirs(pos, node) - local cnt1 = 0 - local dir, npos - if dir1 then - cnt1, npos, dir = tubelib.walk_to_peer(pos, dir1) - -- delete meta on peer tube - if cnt1 > 0 then - minetest.get_meta(npos):from_table(nil) - end - end - local cnt2 = 0 - if dir2 then - cnt2, npos, dir = tubelib.walk_to_peer(pos, dir2) - -- delete meta on peer tube - if cnt2 > 0 then - minetest.get_meta(npos):from_table(nil) - end - end - return cnt1 + cnt2 -end - -local function swap_node(pos, node_num, param2) - local node = minetest.get_node(pos) - node.name = "tubelib:tube"..node_num - node.param2 = param2 - minetest.swap_node(pos, node) -end - -local function is_connected(pos, dir) - if dir then - pos = get_tube_pos(pos, dir) - local dir1,dir2 = get_tube_dirs(pos) - -- return true if connected - dir = Turn180Deg[dir] - return dir == dir1 or dir == dir2 - end - return false -end - -local function is_tubelib_block(pos, dir) - if dir then - pos = get_tube_pos(pos, dir) - local dir1,dir2 = get_tube_dirs(pos) - -- return true if connected - dir = Turn180Deg[dir] - return dir == dir1 or dir == dir2 - end - return false -end -local function update_next_tube(dir, pos) - -- test if tube is connected with neighbor tubes - local dir1, dir2 = get_tube_dirs(pos) - local conn1 = is_connected(pos, dir1) or is_known_node(pos, dir1) - local conn2 = is_connected(pos, dir2) or is_known_node(pos, dir2) - -- already connected or no tube arround? - if (conn1 and conn2) or (not dir1 and not dir2) then - return - elseif not conn1 and not conn2 then - if dir1 ~= dir and dir2 ~= dir then - dir1 = Turn90Deg[dir1] - dir2 = Turn180Deg[dir1] - end - elseif conn1 then - dir2 = Turn180Deg[dir] - else - dir1 = Turn180Deg[dir] - end - local node_num, param2 = get_tube_number_and_param2(dir1, dir2) - swap_node(pos, node_num, param2) -end - --- update new placed tube -local function update_tube(pos, dir, force_dir) - local dir1 = nil - local dir2 = nil - -- use the predefined direction? - if force_dir then - dir1 = force_dir - end - -- search on all 6 pos for up to 2 tubes with open holes or - -- other tubelib compatible nodes - for ndir = 1,6 do - if not dir1 and is_connected(pos, ndir) then - dir1 = ndir - elseif not dir2 and is_connected(pos, ndir) and ndir ~= dir1 then - dir2 = ndir - end - end - if not force_dir and (not dir1 or not dir2) then - for ndir = 1,6 do - if not dir1 and is_known_node(pos, ndir) then - dir1 = ndir - elseif not dir2 and is_known_node(pos, ndir) and ndir ~= dir1 then - dir2 = ndir - end - end - end - dir1 = dir1 or dir - dir2 = dir2 or Turn180Deg[dir] - local node_num, param2 = get_tube_number_and_param2(dir1, dir2) - swap_node(pos, node_num, param2) -end - -function tubelib.update_tubes(pos, dir, force_dir, straight_ahead) - -- Update all tubes arround the currently placed tube - update_next_tube(1, {x=pos.x , y=pos.y , z=pos.z+1}) - update_next_tube(2, {x=pos.x+1, y=pos.y , z=pos.z }) - update_next_tube(3, {x=pos.x , y=pos.y , z=pos.z-1}) - update_next_tube(4, {x=pos.x-1, y=pos.y , z=pos.z }) - update_next_tube(5, {x=pos.x , y=pos.y-1, z=pos.z }) - update_next_tube(6, {x=pos.x , y=pos.y+1, z=pos.z }) - if not straight_ahead then - -- Update the placed tube - update_tube(pos, dir, force_dir) - end - return tubelib.delete_meta_data(pos, minetest.get_node(pos)) < MAX_TUBE_LENGTH -end - - diff --git a/tubelib/tubes2.lua b/tubelib/tubes2.lua deleted file mode 100644 index 9f9f56f..0000000 --- a/tubelib/tubes2.lua +++ /dev/null @@ -1,230 +0,0 @@ ---[[ - - Tube Library - ============ - - Copyright (C) 2017-2018 Joachim Stolberg - - LGPLv2.1+ - See LICENSE.txt for more information - - History: - see init.lua - - tubes2.lua: Node registration and API functions to move items via tubes - -]]-- - --- Convertion of contact side to facedir -local SideToFacedir = {B=0, R=1, F=2, L=3, D=4, U=5} - --- Calculate the facedir to the other node, based on both node positions -local function dir_to_facedir(my_pos, other_pos) - if my_pos.z ~= other_pos.z then return my_pos.z - other_pos.z + 1 end - if my_pos.x ~= other_pos.x then return my_pos.x - other_pos.x + 2 end - if my_pos.y > other_pos.y then return 5 else return 4 end -end - -local function remote_node(pos, dir) - local meta = minetest.get_meta(pos) - local cnt - - -- legacy tube? - if meta:get_string("dest_pos2") ~= "" then - meta:from_table(nil) - end - - -- data available - local dest_pos = meta:get_string("dest_pos") - if dest_pos ~= "" then - local npos = minetest.string_to_pos(dest_pos) - local facedir = meta:get_int("facedir") - return npos, facedir+1 - end - - -- determine data and store as meta - cnt, pos, dir = tubelib.walk_to_peer(pos, dir) - local pos1,_ = tubelib.get_next_tube(pos, dir) - meta:set_string("dest_pos", minetest.pos_to_string(pos1)) - meta:set_int("facedir", dir - 1) - - return pos1, dir -end - -local function is_known_node(pointed_thing) - if pointed_thing.type == "node" then - local node = minetest.get_node(pointed_thing.under) - if tubelib.KnownNodes[node.name] then - return pointed_thing.under - end - end - return nil -end - --- Determine neighbor position and own facedir to the node. --- based on own pos and contact side 'B' - 'U'. --- Function considers also tube connections. -function tubelib.get_neighbor_pos(pos, side) - local facedir = SideToFacedir[side] - local dir - if facedir < 4 then - local node = minetest.get_node(pos) - dir = ((facedir + node.param2) % 4) + 1 - end - local npos, ndir = tubelib.get_next_tube(pos, dir) - local node = minetest.get_node(npos) - if tubelib.TubeNames[node.name] then - if ndir then - npos, ndir = remote_node(npos, ndir) - end - return npos, (ndir or 1) -1 - end - return npos, facedir -end - - -------------------------------------------------------------------------------- --- Node registration -------------------------------------------------------------------------------- - -local DefNodeboxes = { - -- x1 y1 z1 x2 y2 z2 - { -1/4, -1/4, -1/4, 1/4, 1/4, 1/4 }, - { -1/4, -1/4, -1/4, 1/4, 1/4, 1/4 }, -} - -local DirCorrections = { - {3, 6}, {2, 5}, -- standard tubes - {3, 1}, {3, 2}, {3, 5}, -- knees from front to.. -} - -local SelectBoxes = { - { -1/4, -1/4, -1/2, 1/4, 1/4, 1/2 }, - { -1/4, -1/2, -1/4, 1/4, 1/2, 1/4 }, - { -1/2, -1/4, -1/2, 1/4, 1/4, 1/4 }, - { -1/4, -1/2, -1/2, 1/4, 1/4, 1/4 }, - { -1/4, -1/4, -1/2, 1/4, 1/2, 1/4 }, -} - -local TilesData = { - -- up, down, right, left, back, front - { - "tubelib_tube.png^[transformR90", - "tubelib_tube.png^[transformR90", - "tubelib_tube.png", - "tubelib_tube.png", - "tubelib_hole.png", - "tubelib_hole.png", - }, - { - "tubelib_hole.png", - "tubelib_hole.png", - "tubelib_tube.png^[transformR90", - "tubelib_tube.png^[transformR90", - "tubelib_tube.png^[transformR90", - "tubelib_tube.png^[transformR90", - }, - { - "tubelib_knee.png^[transformR270", - "tubelib_knee.png^[transformR180", - "tubelib_knee2.png^[transformR270", - "tubelib_hole2.png^[transformR90", - "tubelib_knee2.png^[transformR90", - "tubelib_hole2.png^[transformR270", - }, - { - "tubelib_knee2.png", - "tubelib_hole2.png^[transformR180", - "tubelib_knee.png^[transformR270", - "tubelib_knee.png", - "tubelib_knee2.png", - "tubelib_hole2.png", - }, - { - "tubelib_hole2.png", - "tubelib_knee2.png^[transformR180", - "tubelib_knee.png^[transformR180", - "tubelib_knee.png^[transformR90", - "tubelib_knee2.png^[transformR180", - "tubelib_hole2.png^[transformR180", - }, -} - - -for idx,pos in ipairs(DirCorrections) do - local node_box_data = table.copy(DefNodeboxes) - node_box_data[1][pos[1]] = node_box_data[1][pos[1]] * 2 - node_box_data[2][pos[2]] = node_box_data[2][pos[2]] * 2 - - local tiles_data = TilesData[idx] - local hidden - - if idx == 1 then - hidden = 0 - else - hidden = 1 - end - minetest.register_node("tubelib:tube"..idx, { - description = "Tubelib Tube", - tiles = tiles_data, - drawtype = "nodebox", - node_box = { - type = "fixed", - fixed = node_box_data, - }, - selection_box = { - type = "fixed", - fixed = SelectBoxes[idx], - }, - collision_box = { - type = "fixed", - fixed = SelectBoxes[idx], - }, - - after_place_node = function(pos, placer, itemstack, pointed_thing) - local dir1 = nil - local dir2 = nil - local pitch = placer:get_look_pitch() - local known_pos = is_known_node(pointed_thing) - local straight_ahead = placer:get_player_control().sneak and not known_pos - if known_pos and placer:get_player_control().sneak then -- placer pointed to a known node (chest) - dir2 = dir_to_facedir(pos, known_pos) + 1 - end - if pitch > 1 then -- up? - dir1 = 6 - elseif pitch < -1 then -- down? - dir1 = 5 - else - dir1 = minetest.dir_to_facedir(placer:get_look_dir()) + 1 - end - if not tubelib.update_tubes(pos, dir1, dir2, straight_ahead) then - tubelib.delete_meta_data(pos, minetest.get_node(pos)) - minetest.remove_node(pos) - return itemstack - end - end, - - after_dig_node = function(pos, oldnode, oldmetadata, digger) - tubelib.delete_meta_data(pos, oldnode) - end, - - on_rotate = screwdriver.disallow, - paramtype2 = "facedir", - paramtype = "light", - sunlight_propagates = true, - is_ground_content = false, - groups = {choppy=2, cracky=3, stone=1, not_in_creative_inventory=hidden}, - drop = "tubelib:tube1", - sounds = default.node_sound_wood_defaults(), - }) -end - - -minetest.register_craft({ - output = "tubelib:tube1 4", - recipe = { - {"default:steel_ingot", "", "group:wood"}, - {"", "group:wood", ""}, - {"group:wood", "", "default:tin_ingot"}, - }, -}) diff --git a/tubelib_addons1/autocrafter.lua b/tubelib_addons1/autocrafter.lua index fa631ac..9401211 100644 --- a/tubelib_addons1/autocrafter.lua +++ b/tubelib_addons1/autocrafter.lua @@ -116,7 +116,7 @@ local function stop_crafter(pos) local node = minetest.get_node(pos) local meta = minetest.get_meta(pos) local number = meta:get_string("number") or "" - meta:set_int("running", 0) + meta:set_int("running", tubelib.STATE_STOPPED) meta:set_string("formspec",formspec(tubelib.STOPPED)) meta:set_string("infotext", "Tubelib Autocrafter "..number..": stopped") node.name = "tubelib_addons1:autocrafter" @@ -129,7 +129,7 @@ local function goto_sleep(pos) local node = minetest.get_node(pos) local meta = minetest.get_meta(pos) local number = meta:get_string("number") or "" - meta:set_int("running", -1) + meta:set_int("running", tubelib.STATE_STANDBY) meta:set_string("formspec",formspec(tubelib.STANDBY)) meta:set_string("infotext", "Tubelib Autocrafter "..number..": standby") node.name = "tubelib_addons1:autocrafter" @@ -149,7 +149,7 @@ local function run_autocrafter(pos, elapsed) -- only use crafts that have an actual result if output_item:is_empty() then - if running <= 0 then + if running <= tubelib.STATE_STOPPED then return goto_sleep(pos) end meta:set_int("running", running) @@ -157,7 +157,7 @@ local function run_autocrafter(pos, elapsed) end if not autocraft(inventory, craft) then - if running <= 0 then + if running <= tubelib.STATE_STOPPED then return goto_sleep(pos) end meta:set_int("running", running) @@ -166,7 +166,7 @@ local function run_autocrafter(pos, elapsed) meta:set_int("item_counter", meta:get_int("item_counter") + output_item:get_count()) - if running <= 0 then + if running <= tubelib.STATE_STOPPED then return start_crafter(pos) else running = SLEEP_CNT_START_VAL @@ -351,17 +351,17 @@ local function on_receive_fields(pos, formname, fields, sender) local meta = minetest.get_meta(pos) local running = meta:get_int("running") if fields.button ~= nil then - if running > 0 then + if running > tubelib.STATE_STOPPED then update_meta(meta, tubelib.STOPPED) stop_crafter(pos) - meta:set_int("running", 0) + meta:set_int("running", tubelib.STATE_STOPPED) else if update_meta(meta, tubelib.RUNNING) then - meta:set_int("running", 1) + meta:set_int("running", tubelib.STATE_RUNNING) start_crafter(pos) else stop_crafter(pos) - meta:set_int("running", 0) + meta:set_int("running", tubelib.STATE_STOPPED) end end end @@ -486,4 +486,11 @@ tubelib.register_node("tubelib_addons1:autocrafter", {"tubelib_addons1:autocraft return "unsupported" end end, + on_server_restart = function(pos) + local meta = minetest.get_meta(pos) + if meta:get_int("running") ~= tubelib.STATE_STOPPED then + meta:set_int("running", tubelib.STATE_STANDBY) + minetest.get_node_timer(pos):start(craft_time*SLEEP_CNT_START_VAL) + end + end, }) diff --git a/tubelib_addons1/fermenter.lua b/tubelib_addons1/fermenter.lua index ff9f085..e77d427 100644 --- a/tubelib_addons1/fermenter.lua +++ b/tubelib_addons1/fermenter.lua @@ -353,4 +353,11 @@ tubelib.register_node("tubelib_addons1:fermenter", {}, { return "unsupported" end end, + on_node_load = function(pos) + local meta = minetest.get_meta(pos) + if meta:get_int("running") ~= STOP_STATE then + meta:set_int("running", STANDBY_STATE) + minetest.get_node_timer(pos):start(CYCLE_TIME * TICKS_TO_SLEEP) + end + end, }) diff --git a/tubelib_addons1/funnel.lua b/tubelib_addons1/funnel.lua index 965cd20..2c6a123 100644 --- a/tubelib_addons1/funnel.lua +++ b/tubelib_addons1/funnel.lua @@ -154,6 +154,10 @@ tubelib.register_node("tubelib_addons1:funnel", {}, { return "unsupported" end end, + on_node_load = function(pos) + minetest.get_node_timer(pos):start(1) + end, + }) diff --git a/tubelib_addons1/grinder.lua b/tubelib_addons1/grinder.lua index 2a19916..7ae6f8a 100644 --- a/tubelib_addons1/grinder.lua +++ b/tubelib_addons1/grinder.lua @@ -14,16 +14,31 @@ ]]-- -local TICKS_TO_SLEEP = 10 +-- for lazy programmers +local S = function(pos) if pos then return minetest.pos_to_string(pos) end end +local P = minetest.string_to_pos +local M = minetest.get_meta + +local STANDBY_TICKS = 4 +local COUNTDOWN_TICKS = 4 local CYCLE_TIME = 2 -local STOP_STATE = 0 -local STANDBY_STATE = -1 -local FAULT_STATE = -3 + -- Grinder recipes local Recipes = {} -local function formspec(state) +local State = tubelib.NodeStates:new({ + node_name_passive = "tubelib_addons1:grinder", + node_name_active = "tubelib_addons1:grinder_active", + node_name_defect = "tubelib_addons1:grinder_defect", + infotext_name = "Tubelib Grinder", + cycle_time = CYCLE_TIME, + standby_ticks = STANDBY_TICKS, + has_item_meter = true, + aging_factor = 10, +}) + +local function formspec(pos, meta) return "size[8,8]".. default.gui_bg.. default.gui_bg_img.. @@ -31,7 +46,7 @@ local function formspec(state) "list[context;src;0,0;3,3;]".. "item_image[0,0;1,1;default:cobble]".. "image[3.5,1;1,1;tubelib_gui_arrow.png]".. - "image_button[3.5,2;1,1;".. tubelib.state_button(state) ..";button;]".. + "image_button[3.5,2;1,1;".. State:get_state_button_image(meta) ..";state_button;]".. "list[context;dst;5,0;3,3;]".. "item_image[5,0;1,1;default:gravel]".. "list[current_player;main;0,4;8,4;]".. @@ -41,23 +56,21 @@ local function formspec(state) "listring[current_player;main]" end +State:register_formspec_func(formspec) + local function allow_metadata_inventory_put(pos, listname, index, stack, player) if minetest.is_protected(pos, player:get_player_name()) then return 0 end - local meta = minetest.get_meta(pos) - local inv = meta:get_inventory() - if listname == "src" then - return stack:get_count() - elseif listname == "dst" then - return 0 + local inv = M(pos):get_inventory() + if listname == "src" and State:get_state(M(pos)) == tubelib.STANDBY then + State:start(pos, M(pos)) end - return 0 + return stack:get_count() end local function allow_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player) - local meta = minetest.get_meta(pos) - local inv = meta:get_inventory() + local inv = M(pos):get_inventory() local stack = inv:get_stack(from_list, from_index) return allow_metadata_inventory_put(pos, to_list, to_index, stack, player) end @@ -69,7 +82,7 @@ local function allow_metadata_inventory_take(pos, listname, index, stack, player return stack:get_count() end -local function grinding(inv) +local function grinding(pos, meta, inv) for _,stack in ipairs(inv:get_list("src")) do if not stack:is_empty() then local name = stack:get_name() @@ -78,104 +91,31 @@ local function grinding(inv) if inv:room_for_item("dst", output) then inv:add_item("dst", output) inv:remove_item("src", ItemStack(name)) - return true + State:keep_running(pos, meta, COUNTDOWN_TICKS) + else + State:blocked(pos, meta) end + else + State:fault(pos, meta) end + return end end - return false -end - - -local function start_the_machine(pos) - local meta = minetest.get_meta(pos) - local node = minetest.get_node(pos) - local number = meta:get_string("number") - meta:set_int("running", TICKS_TO_SLEEP) - meta:set_string("infotext", "Tubelib Grinder "..number..": running") - meta:set_string("formspec", formspec(tubelib.RUNNING)) - node.name = "tubelib_addons1:grinder_active" - minetest.swap_node(pos, node) - minetest.get_node_timer(pos):start(CYCLE_TIME) - return false -end - -local function stop_the_machine(pos) - local meta = minetest.get_meta(pos) - local node = minetest.get_node(pos) - local number = meta:get_string("number") - meta:set_int("running", STOP_STATE) - meta:set_string("infotext", "Tubelib Grinder "..number..": stopped") - meta:set_string("formspec", formspec(tubelib.STOPPED)) - node.name = "tubelib_addons1:grinder" - minetest.swap_node(pos, node) - minetest.get_node_timer(pos):stop() - return false -end - -local function goto_sleep(pos) - local meta = minetest.get_meta(pos) - local node = minetest.get_node(pos) - local number = meta:get_string("number") - meta:set_int("running", STANDBY_STATE) - meta:set_string("infotext", "Tubelib Grinder "..number..": standby") - meta:set_string("formspec", formspec(tubelib.STANDBY)) - node.name = "tubelib_addons1:grinder" - minetest.swap_node(pos, node) - minetest.get_node_timer(pos):start(CYCLE_TIME * TICKS_TO_SLEEP) - return false -end - -local function goto_fault(pos) - local meta = minetest.get_meta(pos) - local node = minetest.get_node(pos) - local number = meta:get_string("number") - meta:set_int("running", FAULT_STATE) - meta:set_string("infotext", "Tubelib Grinder "..number..": fault") - meta:set_string("formspec", formspec(tubelib.FAULT)) - node.name = "tubelib_addons1:grinder" - minetest.swap_node(pos, node) - minetest.get_node_timer(pos):stop() - return false + State:idle(pos, meta) end local function keep_running(pos, elapsed) - local meta = minetest.get_meta(pos) - local running = meta:get_int("running") - 1 - --print("running", running) + local meta = M(pos) local inv = meta:get_inventory() - local busy = grinding(inv) - - if busy == true then - if running <= STOP_STATE then - return start_the_machine(pos) - else - running = TICKS_TO_SLEEP - end - elseif not inv:is_empty("src") then - return goto_fault(pos) - else - if running <= STOP_STATE then - return goto_sleep(pos) - end - end - meta:set_int("running", running) - return true + grinding(pos, meta, inv) + return State:is_active(meta) end local function on_receive_fields(pos, formname, fields, player) if minetest.is_protected(pos, player:get_player_name()) then return end - local meta = minetest.get_meta(pos) - local running = meta:get_int("running") or 1 - if fields.button ~= nil then - if running > STOP_STATE or running == FAULT_STATE then - stop_the_machine(pos) - else - start_the_machine(pos) - end - end + State:state_button_event(pos, fields) end minetest.register_node("tubelib_addons1:grinder", { @@ -192,17 +132,15 @@ minetest.register_node("tubelib_addons1:grinder", { after_place_node = function(pos, placer) local number = tubelib.add_node(pos, "tubelib_addons1:grinder") - local meta = minetest.get_meta(pos) + State:node_init(pos, number) + local meta = M(pos) local inv = meta:get_inventory() inv:set_size('src', 9) inv:set_size('dst', 9) - meta:set_string("number", number) - meta:set_string("infotext", "Tubelib Grinder "..number..": stopped") - meta:set_string("formspec", formspec(tubelib.STOPPED)) end, on_dig = function(pos, node, puncher, pointed_thing) - local meta = minetest.get_meta(pos) + local meta = M(pos) local inv = meta:get_inventory() if inv:is_empty("dst") and inv:is_empty("src") then minetest.node_dig(pos, node, puncher, pointed_thing) @@ -210,6 +148,10 @@ minetest.register_node("tubelib_addons1:grinder", { end end, + after_dig_node = function(pos, oldnode, oldmetadata, digger) + State:after_dig_node(pos, oldnode, oldmetadata, digger) + end, + on_rotate = screwdriver.disallow, on_timer = keep_running, on_receive_fields = on_receive_fields, @@ -217,6 +159,7 @@ minetest.register_node("tubelib_addons1:grinder", { allow_metadata_inventory_move = allow_metadata_inventory_move, allow_metadata_inventory_take = allow_metadata_inventory_take, + drop = "", paramtype = "light", sunlight_propagates = true, paramtype2 = "facedir", @@ -263,6 +206,49 @@ minetest.register_node("tubelib_addons1:grinder_active", { sounds = default.node_sound_wood_defaults(), }) +minetest.register_node("tubelib_addons1:grinder_defect", { + description = "Tubelib Grinder", + tiles = { + -- up, down, right, left, back, front + 'tubelib_addons1_grinder.png', + 'tubelib_front.png^tubelib_defect.png', + 'tubelib_front.png^tubelib_defect.png', + 'tubelib_front.png^tubelib_defect.png', + "tubelib_front.png^tubelib_defect.png", + "tubelib_front.png^tubelib_defect.png", + }, + + after_place_node = function(pos, placer) + local number = tubelib.add_node(pos, "tubelib_addons1:grinder") + State:node_init(pos, number) + local meta = M(pos) + local inv = meta:get_inventory() + inv:set_size('src', 9) + inv:set_size('dst', 9) + State:defect(pos, meta) + end, + + on_dig = function(pos, node, puncher, pointed_thing) + local meta = M(pos) + local inv = meta:get_inventory() + if inv:is_empty("dst") and inv:is_empty("src") then + minetest.node_dig(pos, node, puncher, pointed_thing) + tubelib.remove_node(pos) + end + end, + + allow_metadata_inventory_put = allow_metadata_inventory_put, + allow_metadata_inventory_move = allow_metadata_inventory_move, + allow_metadata_inventory_take = allow_metadata_inventory_take, + + paramtype = "light", + sunlight_propagates = true, + paramtype2 = "facedir", + groups = {choppy=2, cracky=2, crumbly=2, not_in_creative_inventory=1}, + is_ground_content = false, + sounds = default.node_sound_wood_defaults(), +}) + minetest.register_craft({ output = "tubelib_addons1:grinder", recipe = { @@ -273,32 +259,33 @@ minetest.register_craft({ }) -tubelib.register_node("tubelib_addons1:grinder", {"tubelib_addons1:grinder_active"}, { +tubelib.register_node("tubelib_addons1:grinder", + {"tubelib_addons1:grinder_active", "tubelib_addons1:grinder_defect"}, { on_pull_item = function(pos, side) - local meta = minetest.get_meta(pos) - return tubelib.get_item(meta, "dst") + return tubelib.get_item(M(pos), "dst") end, on_push_item = function(pos, side, item) - local meta = minetest.get_meta(pos) - return tubelib.put_item(meta, "src", item) + return tubelib.put_item(M(pos), "src", item) end, on_unpull_item = function(pos, side, item) - local meta = minetest.get_meta(pos) - return tubelib.put_item(meta, "dst", item) + return tubelib.put_item(M(pos), "dst", item) end, on_recv_message = function(pos, topic, payload) - if topic == "on" then - start_the_machine(pos) - elseif topic == "off" then - stop_the_machine(pos) - elseif topic == "state" then - local meta = minetest.get_meta(pos) - local running = meta:get_int("running") - return tubelib.statestring(running) + local resp = State:on_receive_message(pos, topic, payload) + if resp then + return resp else return "unsupported" end end, + on_node_load = function(pos) + print("on_node_load") + return State:on_node_load(pos) + end, + on_node_repair = function(pos) + print("on_node_repair") + return State:on_node_repair(pos) + end, }) diff --git a/tubelib_addons1/harvester.lua b/tubelib_addons1/harvester.lua index dfef16e..9931da8 100644 --- a/tubelib_addons1/harvester.lua +++ b/tubelib_addons1/harvester.lua @@ -449,6 +449,15 @@ tubelib.register_node("tubelib_addons1:harvester_base", {}, { return "unsupported" end end, + on_node_load = function(pos) + local meta = minetest.get_meta(pos) + local this = minetest.deserialize(meta:get_string("this")) + if this and this.running ~= tubelib.STATE_STOPPED then + this.running = tubelib.STATE_STANDBY + meta:set_string("this", minetest.serialize(this)) + minetest.get_node_timer(pos):start(CYCLE_TIME * TICKS_TO_SLEEP) + end + end, }) diff --git a/tubelib_addons1/liquidsampler.lua b/tubelib_addons1/liquidsampler.lua index 01a769f..8e550df 100644 --- a/tubelib_addons1/liquidsampler.lua +++ b/tubelib_addons1/liquidsampler.lua @@ -304,5 +304,12 @@ tubelib.register_node("tubelib_addons1:liquidsampler", {"tubelib_addons1:liquids return "not supported" end end, + on_node_load = function(pos) + local meta = minetest.get_meta(pos) + if meta:get_int("running") ~= tubelib.STATE_STOPPED then + meta:set_int("running", tubelib.STATE_STANDBY) + minetest.get_node_timer(pos):start(20) + end + end, }) --------------------------------------------------------------- tubelib diff --git a/tubelib_addons1/pusher_fast.lua b/tubelib_addons1/pusher_fast.lua index ebf00a4..83bdc6f 100644 --- a/tubelib_addons1/pusher_fast.lua +++ b/tubelib_addons1/pusher_fast.lua @@ -13,7 +13,7 @@ Fast pusher for push/pull operation of StackItems from chests or other inventory/server nodes to tubes or other inventory/server nodes. - The Pusher supports the following messages: + The Pusher is based on the class NodeStates and supports the following messages: - topic = "on", payload = nil - topic = "off", payload = nil - topic = "state", payload = nil, @@ -29,85 +29,50 @@ -- | |/ -- +--------+ -local RUNNING_STATE = 10 +-- for lazy programmers +local S = function(pos) if pos then return minetest.pos_to_string(pos) end end +local P = minetest.string_to_pos +local M = minetest.get_meta -local function switch_on(pos, node) - local meta = minetest.get_meta(pos) - local number = meta:get_string("number") - meta:set_int("running", RUNNING_STATE) - meta:set_string("infotext", "Fast Pusher "..number..": running") - node.name = "tubelib_addons1:pusher_fast_active" - minetest.swap_node(pos, node) - minetest.get_node_timer(pos):start(1) - return false -end +local STANDBY_TICKS = 5 +local COUNTDOWN_TICKS = 5 +local CYCLE_TIME = 1 -local function switch_off(pos, node) - local meta = minetest.get_meta(pos) - local number = meta:get_string("number") - meta:set_int("running", tubelib.STATE_STOPPED) - meta:set_string("infotext", "Fast Pusher "..number..": stopped") - node.name = "tubelib_addons1:pusher_fast" - minetest.swap_node(pos, node) - minetest.get_node_timer(pos):stop() - return false -end +local State = tubelib.NodeStates:new({ + node_name_passive = "tubelib_addons1:pusher", + node_name_active = "tubelib_addons1:pusher_active", + node_name_defect = "tubelib_addons1:pusher_defect", + infotext_name = "Fast Pusher", + cycle_time = CYCLE_TIME, + standby_ticks = STANDBY_TICKS, + has_item_meter = true, + aging_factor = 10, +}) -local function goto_standby(pos, node) - local meta = minetest.get_meta(pos) - local number = meta:get_string("number") - meta:set_int("running", tubelib.STATE_STANDBY) - meta:set_string("infotext", "Fast Pusher "..number..": standby") - node.name = "tubelib_addons1:pusher_fast" - minetest.swap_node(pos, node) - minetest.get_node_timer(pos):start(20) - return false -end - -local function goto_blocked(pos, node) - local meta = minetest.get_meta(pos) - local number = meta:get_string("number") - meta:set_int("running", tubelib.STATE_BLOCKED) - meta:set_string("infotext", "Fast Pusher "..number..": blocked") - node.name = "tubelib_addons1:pusher_fast" - minetest.swap_node(pos, node) - minetest.get_node_timer(pos):start(20) - return false -end - -local function keep_running(pos, elapsed) - local meta = minetest.get_meta(pos) - local number = meta:get_string("number") - local running = meta:get_int("running") - 1 +local function pushing(pos, meta) local player_name = meta:get_string("player_name") local items = tubelib.pull_items(pos, "L", player_name) -- <<=== tubelib if items ~= nil then if tubelib.push_items(pos, "R", items, player_name) == false then -- <<=== tubelib -- place item back tubelib.unpull_items(pos, "L", items, player_name) -- <<=== tubelib - local node = minetest.get_node(pos) - return goto_blocked(pos, node) - end - meta:set_int("item_counter", meta:get_int("item_counter") + 1) - if running <= 0 then - local node = minetest.get_node(pos) - return switch_on(pos, node) - else - -- reload running state - running = RUNNING_STATE - end - else - if running <= 0 then - local node = minetest.get_node(pos) - return goto_standby(pos, node) + State:blocked(pos, meta) + return end + State:keep_running(pos, meta, COUNTDOWN_TICKS) + return end - meta:set_int("running", running) - return true + State:idle(pos, meta) end +local function keep_running(pos, elapsed) + local meta = M(pos) + pushing(pos, meta) + return State:is_active(meta) +end + minetest.register_node("tubelib_addons1:pusher_fast", { - description = "Tubelib Fast Pusher", + description = "Fast Pusher", tiles = { -- up, down, right, left, back, front 'tubelib_addons1_pusher.png', @@ -121,25 +86,25 @@ minetest.register_node("tubelib_addons1:pusher_fast", { after_place_node = function(pos, placer) local meta = minetest.get_meta(pos) meta:set_string("player_name", placer:get_player_name()) - local number = tubelib.add_node(pos, "tubelib_addons1:pusher_fast") - meta:set_string("number", number) - meta:set_string("infotext", "Pusher "..number..": stopped") - meta:set_int("item_counter", 0) + local number = tubelib.add_node(pos, "tubelib_addons1:pusher_fast") -- <<=== tubelib + State:node_init(pos, number) end, on_rightclick = function(pos, node, clicker) if not minetest.is_protected(pos, clicker:get_player_name()) then - switch_on(pos, node) + State:start(pos, M(pos)) end end, - after_dig_node = function(pos) - tubelib.remove_node(pos) + after_dig_node = function(pos, oldnode, oldmetadata, digger) + tubelib.remove_node(pos) -- <<=== tubelib + State:after_dig_node(pos, oldnode, oldmetadata, digger) end, on_timer = keep_running, on_rotate = screwdriver.disallow, + drop = "", paramtype = "light", sunlight_propagates = true, paramtype2 = "facedir", @@ -150,7 +115,7 @@ minetest.register_node("tubelib_addons1:pusher_fast", { minetest.register_node("tubelib_addons1:pusher_fast_active", { - description = "Tubelib Fast Pusher", + description = "Fast Pusher", tiles = { -- up, down, right, left, back, front { @@ -199,7 +164,7 @@ minetest.register_node("tubelib_addons1:pusher_fast_active", { on_rightclick = function(pos, node, clicker) if not minetest.is_protected(pos, clicker:get_player_name()) then - switch_off(pos, node) + State:stop(pos, M(pos)) end end, @@ -214,6 +179,42 @@ minetest.register_node("tubelib_addons1:pusher_fast_active", { sounds = default.node_sound_wood_defaults(), }) +minetest.register_node("tubelib_addons1:pusher_fast_defect", { + description = "Fast Pusher", + tiles = { + -- up, down, right, left, back, front + 'tubelib_addons1_pusher.png', + 'tubelib_addons1_pusher.png', + 'tubelib_outp.png^tubelib_defect.png', + 'tubelib_inp.png^tubelib_defect.png', + "tubelib_addons1_pusher.png^[transformR180]^tubelib_defect.png", + "tubelib_addons1_pusher.png^tubelib_defect.png", + }, + + after_place_node = function(pos, placer) + local meta = minetest.get_meta(pos) + meta:set_string("player_name", placer:get_player_name()) + local number = tubelib.add_node(pos, "tubelib_addons1:pusher") -- <<=== tubelib + State:node_init(pos, number) + State:defect(pos, meta) + end, + + after_dig_node = function(pos) + tubelib.remove_node(pos) -- <<=== tubelib + end, + + on_timer = keep_running, + on_rotate = screwdriver.disallow, + + paramtype = "light", + sunlight_propagates = true, + paramtype2 = "facedir", + groups = {choppy=2, cracky=2, crumbly=2, not_in_creative_inventory=1}, + is_ground_content = false, + sounds = default.node_sound_wood_defaults(), +}) + + minetest.register_craft({ output = "tubelib_addons1:pusher_fast", recipe = { @@ -224,34 +225,26 @@ minetest.register_craft({ }) --------------------------------------------------------------- tubelib -tubelib.register_node("tubelib_addons1:pusher_fast", {"tubelib_addons1:pusher_fast_active"}, { +tubelib.register_node("tubelib_addons1:pusher_fast", + {"tubelib_addons1:pusher_fast_active", "tubelib_addons1:pusher_fast_defect"}, { on_pull_item = nil, -- pusher has no inventory on_push_item = nil, -- pusher has no inventory on_unpull_item = nil, -- pusher has no inventory is_pusher = true, -- is a pulling/pushing node on_recv_message = function(pos, topic, payload) - local node = minetest.get_node(pos) - if topic == "on" then - return switch_on(pos, node) - elseif topic == "off" then - return switch_off(pos, node) - elseif topic == "state" then - if node.name == "ignore" then -- unloaded pusher? - return "blocked" - end - local meta = minetest.get_meta(pos) - local running = meta:get_int("running") or tubelib.STATE_STOPPED - return tubelib.statestring(running) - elseif topic == "counter" then - local meta = minetest.get_meta(pos) - return meta:get_int("item_counter") - elseif topic == "clear_counter" then - local meta = minetest.get_meta(pos) - return meta:set_int("item_counter", 0) + local resp = State:on_receive_message(pos, topic, payload) + if resp then + return resp else - return "not supported" + return "unsupported" end end, + on_node_load = function(pos) + State:on_node_load(pos) + end, + on_node_repair = function(pos) + return State:on_node_repair(pos) + end, }) --------------------------------------------------------------- tubelib diff --git a/tubelib_addons1/quarry.lua b/tubelib_addons1/quarry.lua index 9b2c227..4198779 100644 --- a/tubelib_addons1/quarry.lua +++ b/tubelib_addons1/quarry.lua @@ -427,5 +427,12 @@ tubelib.register_node("tubelib_addons1:quarry", {"tubelib_addons1:quarry_active" return "unsupported" end end, + on_node_load = function(pos) + local meta = minetest.get_meta(pos) + if meta:get_int("running") ~= STOP_STATE then + meta:set_int("running", TICKS_TO_SLEEP) + minetest.get_node_timer(pos):start(CYCLE_TIME) + end + end, }) diff --git a/tubelib_addons1/reformer.lua b/tubelib_addons1/reformer.lua index db842aa..bb9f05f 100644 --- a/tubelib_addons1/reformer.lua +++ b/tubelib_addons1/reformer.lua @@ -314,4 +314,11 @@ tubelib.register_node("tubelib_addons1:reformer", {}, { return "unsupported" end end, + on_node_load = function(pos) + local meta = minetest.get_meta(pos) + if meta:get_int("running") ~= STOP_STATE then + meta:set_int("running", STANDBY_STATE) + minetest.get_node_timer(pos):start(CYCLE_TIME * TICKS_TO_SLEEP) + end + end, }) diff --git a/tubelib_addons1/textures/tubelib_addons1_grinder_active.png b/tubelib_addons1/textures/tubelib_addons1_grinder_active.png index 1707d23951d7ee13e870f8bce2cb887c8a439c33..11f8bd36146735ed787b0fd476c1aa8c40f355e6 100644 GIT binary patch delta 2646 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