From cf3415a1d61542921e3fa772ed03e0d2be39abe1 Mon Sep 17 00:00:00 2001 From: Joachim Stolberg Date: Tue, 2 Nov 2021 21:28:22 +0100 Subject: [PATCH] Add hyperloop support to ta4 chest and tank --- basic_machines/chest.lua | 47 +++++++- basis/hyperloop.lua | 233 +++++++++++++++++++++++++++++++++++++++ init.lua | 4 + liquids/tank.lua | 45 ++++++-- tools/submenu.lua | 15 ++- 5 files changed, 329 insertions(+), 15 deletions(-) create mode 100644 basis/hyperloop.lua diff --git a/basic_machines/chest.lua b/basic_machines/chest.lua index 36312cc..8748a82 100644 --- a/basic_machines/chest.lua +++ b/basic_machines/chest.lua @@ -21,6 +21,9 @@ local TA4_INV_SIZE = 50 local MP = minetest.get_modpath(minetest.get_current_modname()) local mConf = dofile(MP.."/basis/conf_inv.lua") +local hyperloop = techage.hyperloop +local remote_pos = techage.hyperloop.remote_pos + local function allow_metadata_inventory_put(pos, listname, index, stack, player) if minetest.is_protected(pos, player:get_player_name()) then return 0 @@ -195,6 +198,29 @@ local function formspec4(pos) "listring[current_player;main]" end +local function formspec4_client(pos) + local location = "nodemeta:" .. pos.x .. "," .. pos.y .. "," .. pos.z + return "size[10,9]".. + default.gui_bg.. + default.gui_bg_img.. + default.gui_slots.. + "list[" .. location .. ";main;0,0;10,5;]".. + "list[current_player;main;1,5.3;8,4;]".. + "listring[" .. location .. ";main]".. + "listring[current_player;main]" +end + +local function formspec4_server(pos) + return "size[10,9]".. + default.gui_bg.. + default.gui_bg_img.. + default.gui_slots.. + "list[context;main;0,0;10,5;]".. + "list[current_player;main;1,5.3;8,4;]".. + "listring[context;main]".. + "listring[current_player;main]" +end + local function formspec4_pre(pos) return "size[10,9]".. "tabheader[0,0;tab;"..S("Inventory,Pre-Assignment,Config")..";2;;true]".. @@ -286,6 +312,7 @@ minetest.register_node("techage:chest_ta4", { meta:set_string("owner", placer:get_player_name()) meta:set_string("formspec", formspec4(pos)) meta:set_string("infotext", S("TA4 Protected Chest").." "..number) + hyperloop.after_place_node(pos, placer, "chest") end, on_receive_fields = function(pos, formname, fields, player) @@ -324,8 +351,22 @@ minetest.register_node("techage:chest_ta4", { return techage.logic.set_numbers(pos, numbers, player_name, S("TA4 Protected Chest")) end, + on_rightclick = function(pos, node, clicker) + print("on_rightclick") + if hyperloop.is_client(pos) then + M(pos):set_string("formspec", formspec4_client(remote_pos(pos))) + elseif hyperloop.is_server(pos) then + M(pos):set_string("formspec", formspec4_server(pos)) + end + end, + can_dig = can_dig, - after_dig_node = after_dig_node, + after_dig_node = function(pos, oldnode, oldmetadata, digger) + techage.remove_node(pos, oldnode, oldmetadata) + hyperloop.after_dig_node(pos, oldnode, oldmetadata, digger) + end, + ta4_formspec = hyperloop.WRENCH_MENU, + ta_after_formspec = hyperloop.after_formspec, allow_metadata_inventory_put = ta4_allow_metadata_inventory_put, allow_metadata_inventory_take = ta4_allow_metadata_inventory_take, allow_metadata_inventory_move = ta4_allow_metadata_inventory_move, @@ -339,10 +380,12 @@ minetest.register_node("techage:chest_ta4", { techage.register_node({"techage:chest_ta4"}, { on_inv_request = function(pos, in_dir, access_type) + pos = remote_pos(pos) local meta = minetest.get_meta(pos) return meta:get_inventory(), "main" end, on_pull_item = function(pos, in_dir, num, item_name) + pos = remote_pos(pos) local meta = minetest.get_meta(pos) local inv = meta:get_inventory() local mem = techage.get_mem(pos) @@ -370,6 +413,7 @@ techage.register_node({"techage:chest_ta4"}, { end end, on_push_item = function(pos, in_dir, item, idx) + pos = remote_pos(pos) local meta = minetest.get_meta(pos) local inv = meta:get_inventory() local mem = techage.get_mem(pos) @@ -386,6 +430,7 @@ techage.register_node({"techage:chest_ta4"}, { end end, on_unpull_item = function(pos, in_dir, item) + pos = remote_pos(pos) local meta = minetest.get_meta(pos) local inv = meta:get_inventory() local mem = techage.get_mem(pos) diff --git a/basis/hyperloop.lua b/basis/hyperloop.lua new file mode 100644 index 0000000..60fba57 --- /dev/null +++ b/basis/hyperloop.lua @@ -0,0 +1,233 @@ +--[[ + + TechAge + ======= + + Copyright (C) 2019-2021 Joachim Stolberg + + AGPL v3 + See LICENSE.txt for more information + + For chests and tanks with hyperloop support + +]]-- + +-- for lazy programmers +local S2P = minetest.string_to_pos +local P2S = minetest.pos_to_string +local M = minetest.get_meta +local N = techage.get_node_lvm +local S = techage.S + +-- Will be initialized when mods are loaded +local Stations = nil +local Tube = nil +local HYPERLOOP = nil + +techage.hyperloop = {} + +--[[ + + tStations["(x,y,z)"] = { + conn = {dir = "(200,0,20)", ...}, + name = , -- chest/tank + owner = "singleplayer", + conn_name = , + single = true/nil, + } + +]]-- + +minetest.register_on_mods_loaded(function() + if minetest.global_exists("hyperloop") then + Stations = hyperloop.Stations + Tube = hyperloop.Tube + HYPERLOOP = true + Tube:add_secondary_node_names({"techage:ta4_tank", "techage:chest_ta4"}) + else + techage.hyperloop.WRENCH_MENU[2] = nil + techage.hyperloop.WRENCH_MENU[1] = nil + end +end) + +local function get_remote_pos(pos, rmt_name) + local owner = M(pos):get_string("owner") + for key,item in pairs(Stations:get_node_table(pos)) do + if item.owner == owner and item.conn_name == rmt_name then + return S2P(key) + end + end +end + +local function get_free_server_list(pos, owner) + local tbl = {M(pos):get_string("remote_name")} + for key,item in pairs(Stations:get_node_table(pos)) do + if item.single and item.owner == owner then + if M(pos):get_string("node_type") == M(S2P(key)):get_string("node_type") then + tbl[#tbl+1] = item.conn_name + end + end + end + tbl[#tbl+1] = "" + return tbl +end + +local function on_dropdown(pos) + local owner = M(pos):get_string("owner") + return table.concat(get_free_server_list(pos, owner), ",") +end + +local function update_node_data(pos, state, conn_name, remote_name, rmt_pos) + local meta = M(pos) + local nvm = techage.get_nvm(pos) + + if state == "server_connected" then + Stations:update(pos, {conn_name=conn_name, single="nil"}) + meta:set_string("conn_name", conn_name) + meta:set_string("remote_name", "") + nvm.conn_status = P2S(rmt_pos) + nvm.rmt_pos = rmt_pos + elseif state == "client_connected" then + Stations:update(pos, {conn_name="nil", single="nil"}) + meta:set_string("conn_name", "") + meta:set_string("remote_name", remote_name) + nvm.conn_status = P2S(rmt_pos) + nvm.rmt_pos = rmt_pos + elseif state == "server_not_connected" then + Stations:update(pos, {conn_name=conn_name, single=true}) + meta:set_string("conn_name", conn_name) + meta:set_string("remote_name", "") + nvm.conn_status = S("not connected") + nvm.rmt_pos = nil + elseif state == "client_not_connected" then + Stations:update(pos, {conn_name="nil", single=nil}) + meta:set_string("conn_name", "") + meta:set_string("remote_name", "") + nvm.conn_status = S("not connected") + nvm.rmt_pos = nil + end +end + +techage.hyperloop.WRENCH_MENU = { + { + type = "label", + label = S("Provide 'own name' or select a 'remote name' (not both)"), + tooltip = "", + name = "l1", + }, + { + type = "ascii", + name = "conn_name", + label = S("Own name"), + tooltip = S("Connection name for this block"), + default = "", + }, + { + type = "dropdown", + choices = "", + on_dropdown = on_dropdown, + name = "remote_name", + label = S("Remote name"), + tooltip = S("Connection name of the remote block"), + }, + { + type = "output", + name = "conn_status", + label = S("Connected to"), + tooltip = S("Connection status"), + default = S("not connected"), + }, +} + +function techage.hyperloop.is_client(pos) + if HYPERLOOP then + local nvm = techage.get_nvm(pos) + if Stations:get(nvm.rmt_pos) then + if M(pos):contains("remote_name") then + return true + end + end + end +end + +function techage.hyperloop.is_server(pos) + if HYPERLOOP then + local nvm = techage.get_nvm(pos) + if Stations:get(nvm.rmt_pos) then + if M(pos):contains("conn_name") then + return true + end + end + end +end + +function techage.hyperloop.remote_pos(pos) + if HYPERLOOP then + local nvm = techage.get_nvm(pos) + if Stations:get(nvm.rmt_pos) then + if M(pos):contains("remote_name") then + return nvm.rmt_pos + end + end + end + return pos +end + +function techage.hyperloop.after_place_node(pos, placer, node_type) + if HYPERLOOP then + Stations:set(pos, node_type, {owner=placer:get_player_name()}) + M(pos):set_string("node_type", node_type) + Tube:after_place_node(pos) + end +end + +function techage.hyperloop.after_dig_node(pos, oldnode, oldmetadata, digger) + if HYPERLOOP then + local conn_name = oldmetadata.fields.conn_name + local remote_name = oldmetadata.fields.remote_name + local loc_pos, rmt_pos = pos, techage.get_nvm(pos).rmt_pos + + -- Close connections + if remote_name ~= "" and rmt_pos then -- Connected client + update_node_data(rmt_pos, "server_not_connected", remote_name, "") + elseif conn_name ~= "" and rmt_pos then -- Connected server + update_node_data(rmt_pos, "client_not_connected", "", conn_name) + end + + Tube:after_dig_node(pos) + Stations:delete(pos) + end +end + +function techage.hyperloop.after_formspec(pos, fields, playername) + if HYPERLOOP and fields.save then + local meta = M(pos) + local conn_name = meta:get_string("conn_name") + local remote_name = meta:get_string("remote_name") + local loc_pos, rmt_pos = pos, techage.get_nvm(pos).rmt_pos + + -- Close connections + if remote_name ~= "" then -- Connected client + update_node_data(loc_pos, "client_not_connected", "", remote_name) + if rmt_pos then + update_node_data(rmt_pos, "server_not_connected", remote_name, "") + end + elseif conn_name ~= "" and conn_name ~= fields.conn_name then -- Connected server + update_node_data(loc_pos, "server_not_connected", conn_name, "") + if rmt_pos then + update_node_data(rmt_pos, "client_not_connected", "", conn_name) + end + end + + if fields.remote_name ~= "" then -- Client + local rmt_pos = get_remote_pos(pos, fields.remote_name) + if rmt_pos then + update_node_data(loc_pos, "client_connected", "", fields.remote_name, rmt_pos) + update_node_data(rmt_pos, "server_connected", fields.remote_name, "", loc_pos) + end + elseif fields.conn_name ~= "" then -- Server + update_node_data(loc_pos, "server_not_connected", fields.conn_name, "") + end + end +end + diff --git a/init.lua b/init.lua index a53ea37..e91d630 100644 --- a/init.lua +++ b/init.lua @@ -39,6 +39,9 @@ elseif minetest.global_exists("safer_lua") and safer_lua.version < 1.0 then elseif minetest.global_exists("networks") and networks.version < 0.10 then minetest.log("error", "[techage] Techage requires networks version 0.10 or newer!") return +elseif minetest.global_exists("hyperloop") and hyperloop.version < 2.07 then + minetest.log("error", "[techage] Techage requires hyperloop version 2.07 or newer!") + return end -- Test MT 5.4 new string mode @@ -94,6 +97,7 @@ dofile(MP.."/basis/formspec_update.lua") dofile(MP.."/basis/windturbine_lib.lua") dofile(MP.."/basis/laser_lib.lua") dofile(MP.."/basis/legacy.lua") +dofile(MP.."/basis/hyperloop.lua") -- Main doc dofile(MP.."/doc/manual_DE.lua") diff --git a/liquids/tank.lua b/liquids/tank.lua index 51dc523..95d198b 100644 --- a/liquids/tank.lua +++ b/liquids/tank.lua @@ -21,19 +21,24 @@ local S = techage.S local Pipe = techage.LiquidPipe local liquid = networks.liquid +local hyperloop = techage.hyperloop +local remote_pos = techage.hyperloop.remote_pos + local CAPACITY = 1000 -local function on_rightclick(pos, node, clicker) - local nvm = techage.get_nvm(pos) +local function on_rightclick(pos, node, clicker, rmt_pos) + rmt_pos = rmt_pos or pos + local nvm = techage.get_nvm(rmt_pos) techage.set_activeformspec(pos, clicker) - M(pos):set_string("formspec", techage.liquid.formspec(pos, nvm)) + M(pos):set_string("formspec", techage.liquid.formspec(rmt_pos, nvm)) minetest.get_node_timer(pos):start(2) end local function node_timer(pos, elapsed) + local rmt_pos = remote_pos(pos) if techage.is_activeformspec(pos) then - local nvm = techage.get_nvm(pos) - M(pos):set_string("formspec", techage.liquid.formspec(pos, nvm)) + local nvm = techage.get_nvm(rmt_pos) + M(pos):set_string("formspec", techage.liquid.formspec(rmt_pos, nvm)) return true end return false @@ -214,6 +219,7 @@ minetest.register_node("techage:ta4_tank", { meta:set_string("formspec", techage.liquid.formspec(pos, nvm)) meta:set_string("infotext", S("TA4 Tank").." "..number) Pipe:after_place_node(pos) + hyperloop.after_place_node(pos, placer, "tank") end, on_receive_fields = function(pos, formname, fields, player) if minetest.is_protected(pos, player:get_player_name()) then @@ -227,12 +233,19 @@ minetest.register_node("techage:ta4_tank", { end end, on_timer = node_timer, - on_punch = techage.liquid.on_punch, + on_punch = function(pos, node, puncher) + return techage.liquid.on_punch(remote_pos(pos), node, puncher) + end, after_dig_node = function(pos, oldnode, oldmetadata, digger) Pipe:after_dig_node(pos) + hyperloop.after_dig_node(pos, oldnode, oldmetadata, digger) techage.remove_node(pos, oldnode, oldmetadata) end, - on_rightclick = on_rightclick, + on_rightclick = function(pos, node, clicker) + return on_rightclick(pos, node, clicker, remote_pos(pos)) + end, + ta4_formspec = hyperloop.WRENCH_MENU, + ta_after_formspec = hyperloop.after_formspec, can_dig = can_dig, paramtype2 = "facedir", on_rotate = screwdriver.disallow, @@ -244,10 +257,18 @@ minetest.register_node("techage:ta4_tank", { liquid.register_nodes({"techage:ta4_tank"}, Pipe, "tank", nil, { capa = CAPACITY * 2, - peek = peek_liquid, - put = put_liquid, - take = take_liquid, - untake = untake_liquid, + peek = function(pos, indir) + return peek_liquid(remote_pos(pos), indir) + end, + put = function(pos, indir, name, amount) + return put_liquid(remote_pos(pos), indir, name, amount) + end, + take = function(pos, indir, name, amount) + return take_liquid(remote_pos(pos), indir, name, amount) + end, + untake = function(pos, indir, name, amount) + return untake_liquid(remote_pos(pos), indir, name, amount) + end, } ) @@ -295,4 +316,4 @@ minetest.register_lbm({ --tubelib2.del_mem(pos) end end, -}) \ No newline at end of file +}) diff --git a/tools/submenu.lua b/tools/submenu.lua index a06ad7d..07031c6 100644 --- a/tools/submenu.lua +++ b/tools/submenu.lua @@ -48,7 +48,9 @@ local function generate_formspec_substring(pos, meta, form_def, player_name) local offs = (i - 1) * 0.9 - 0.2 tbl[#tbl+1] = "label[0," .. offs .. ";" .. minetest.formspec_escape(elem.label) .. ":]" tbl[#tbl+1] = "tooltip[0," .. offs .. ";4,1;" .. elem.tooltip .. "]" - if elem.type == "number" then + if elem.type == "label" then + -- none + elseif elem.type == "number" then local val = elem.default if meta:contains(elem.name) then val = meta:get_int(elem.name) @@ -104,6 +106,15 @@ local function generate_formspec_substring(pos, meta, form_def, player_name) val = meta:get_string(elem.name) or "" end tbl[#tbl+1] = "label[4.75," .. offs .. ";" .. val .. "]" + elseif elem.on_dropdown then -- block provides a specific list of choice elements + local val = elem.default + if meta:contains(elem.name) then + val = meta:get_string(elem.name) or "" + end + local choices = elem.on_dropdown(pos) + local l = choices:split(",") + local idx = index(l, val) or 1 + tbl[#tbl+1] = "dropdown[4.72," .. (offs) .. ";5.5,1.4;" .. elem.name .. ";" .. choices .. ";" .. idx .. "]" else local val = elem.default if meta:contains(elem.name) then @@ -112,7 +123,7 @@ local function generate_formspec_substring(pos, meta, form_def, player_name) local idx = index(l, val) or 1 tbl[#tbl+1] = "dropdown[4.72," .. (offs) .. ";5.5,1.4;" .. elem.name .. ";" .. elem.choices .. ";" .. idx .. "]" end - elseif elem.type == "items" then + elseif elem.type == "items" then -- inventory tbl[#tbl+1] = "list[detached:" .. minetest.formspec_escape(player_name) .. "_techage_wrench_menu;cfg;4.75," .. offs .. ";" .. elem.size .. ",1;]" player_inv_needed = true end