2024-12-30 00:33:03 -06:00

388 lines
13 KiB
Lua
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- teleporter_plates/init.lua
local modname = minetest.get_current_modname()
--------------------------------------------------------------------------
-- 0) Mod Storage + Global table
--------------------------------------------------------------------------
-- 0a) Get reference to this mods storage
local mod_storage = minetest.get_mod_storage()
-- 0b) Global ephemeral storage for all networks (read from mod_storage if possible)
teleporter_plates = teleporter_plates or {}
teleporter_plates.networks = teleporter_plates.networks or {}
-- 0c) Try to load previously saved networks from JSON
local stored_json = mod_storage:get_string("networks")
if stored_json and stored_json ~= "" then
local parsed = minetest.parse_json(stored_json)
if parsed then
teleporter_plates.networks = parsed
end
end
-- 0d) Helper function to save networks to mod_storage
local function save_networks()
local data_str = minetest.write_json(teleporter_plates.networks)
mod_storage:set_string("networks", data_str)
end
--------------------------------------------------------------------------
-- 0e) Get or create a list for a given network name
--------------------------------------------------------------------------
local function get_network_destinations(netname)
if not teleporter_plates.networks[netname] then
teleporter_plates.networks[netname] = {}
end
return teleporter_plates.networks[netname]
end
--------------------------------------------------------------------------
-- 1) Build the textlist items string
--------------------------------------------------------------------------
local function build_textlist(dest_table)
local items = {}
for _, dest in ipairs(dest_table) do
-- Show only the destination name
local label = dest.name
table.insert(items, label)
end
return table.concat(items, ",")
end
--------------------------------------------------------------------------
-- 2) Show the formspec
--------------------------------------------------------------------------
local function show_network_formspec(player, pos)
if not player then return end
local pname = player:get_player_name()
local meta = minetest.get_meta(pos)
local network = meta:get_string("network_name")
if network == "" then
network = "default"
end
local selected = meta:get_int("selected_index")
local editing = meta:get_int("editing_index")
local list = get_network_destinations(network)
-- Validate
if selected < 1 or selected > #list then
selected = 0
end
if editing < 1 or editing > #list then
editing = 0
end
-- If editing, populate fields
local def_name, def_x, def_y, def_z = "", "", "", ""
if editing > 0 then
local e = list[editing]
if e then
def_name = e.name or ""
def_x = tostring(e.x or "")
def_y = tostring(e.y or "")
def_z = tostring(e.z or "")
end
end
local textlist_str = build_textlist(list)
local formname = "teleporter_plates:netplate_form_"..pos.x.."_"..pos.y.."_"..pos.z
local fs = ([[
size[12,9.5]
label[0.2,0.2;VoxeLibre Teleporter]
button_exit[10.9,8.76;1,0.8;close;Close]
label[9,0.09;Network:]
field[10.2,0.2;2,0.8;net_name;;%s]
button[9.9,0.7;2.0,0.9;set_net;Set Network]
label[0.3,1.1;Destinations in Network:]
textlist[0.3,1.6;6,5;dlist;%s;%d;true]
button[0.3,7.1;2,0.9;teleport_sel;Teleport]
button[2.4,7.1;1.8,0.9;edit_sel;Edit]
button[4.3,7.1;2,0.9;delete_sel;Delete]
label[6.7,1.0;Add / Update Destination:]
field[7.0,2.0;3,0.8;dest_name;Name;%s]
field[7.0,3.0;2,0.8;dest_x;X;%s]
field[7.0,4.0;2,0.8;dest_y;Z;%s]
field[7.0,5.0;2,0.8;dest_z;Y;%s]
button[6.7,5.7;3,0.9;add_update;Add / Update]
label[0.1,8.0;Manual Teleport (not saved):]
field[0.3,9.0;2,0.8;man_x;X;]
field[2.4,9.0;2,0.8;man_y;Z;]
field[4.5,9.0;2,0.8;man_z;Y;]
button[6.5,8.62;2,1;man_teleport;Teleport]
]]):format(
network, textlist_str, selected,
def_name, def_x, def_y, def_z
)
minetest.show_formspec(pname, formname, fs)
end
--------------------------------------------------------------------------
-- 3) Register the node
--------------------------------------------------------------------------
minetest.register_node(modname..":net_plate", {
description = "Network Teleporter Plate",
tiles = {"mcl_end_crystal_item.png"}, -- Example texture
drawtype = "nodebox",
paramtype = "light",
light_source = 14,
sunlight_propagates = true,
node_box = {
type = "fixed",
fixed = {{-0.5, -0.5, -0.5, 0.5, -0.45, 0.5}},
},
selection_box = {
type = "fixed",
fixed = {{-0.5, -0.5, -0.5, 0.5, -0.45, 0.5}},
},
collision_box = {
type = "fixed",
fixed = {{-0.5, -0.5, -0.5, 0.5, -0.45, 0.5}},
},
groups = {cracky=3, stone=1, pick=1},
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
show_network_formspec(clicker, pos)
end,
})
--------------------------------------------------------------------------
-- 4) Handle all formspec events
--------------------------------------------------------------------------
minetest.register_on_player_receive_fields(function(player, formname, fields)
-- We only care about forms named like "teleporter_plates:netplate_form_x_y_z"
local prefix = "teleporter_plates:netplate_form_"
if formname:sub(1, #prefix) ~= prefix then
return
end
if not player then return end
local pname = player:get_player_name()
local coords = formname:sub(#prefix+1)
local x, y, z = coords:match("^(%-?%d+)_(%-?%d+)_(%-?%d+)$")
if not (x and y and z) then return end
local pos = {x=tonumber(x), y=tonumber(y), z=tonumber(z)}
local meta = minetest.get_meta(pos)
if not meta then return end
local network_name = meta:get_string("network_name")
if network_name == "" then
network_name = "default"
end
local list = get_network_destinations(network_name)
local sel_idx = meta:get_int("selected_index")
local edt_idx = meta:get_int("editing_index")
------------------------------------------------------------------
-- (A) Set Network
------------------------------------------------------------------
if fields.set_net and fields.net_name then
local newnet = fields.net_name
if newnet == "" then
newnet = "default"
end
meta:set_string("network_name", newnet)
meta:set_int("selected_index", 0)
meta:set_int("editing_index", 0)
-- Save the updated networks table
save_networks()
minetest.after(0, function()
show_network_formspec(player, pos)
end)
return
end
------------------------------------------------------------------
-- (B) Textlist selection
------------------------------------------------------------------
if fields.dlist then
local event = fields.dlist -- Example: "CHG:2"
local etype, idx_str = event:match("^(%u+):(%d+)$")
if idx_str then
local idx = tonumber(idx_str)
if idx and idx >= 1 and idx <= #list then
meta:set_int("selected_index", idx)
else
meta:set_int("selected_index", 0)
end
end
minetest.after(0, function()
show_network_formspec(player, pos)
end)
return
end
------------------------------------------------------------------
-- (C) Teleport to Selected
------------------------------------------------------------------
if fields.teleport_sel then
local sidx = meta:get_int("selected_index")
local entry = list[sidx]
if entry then
player:set_pos({x=entry.x, y=entry.y, z=entry.z})
minetest.chat_send_player(pname,
("Teleported to '%s' (%s, %s, %s)"):format(entry.name, entry.x, entry.y, entry.z)
)
else
minetest.chat_send_player(pname, "No valid destination selected!")
end
minetest.close_formspec(pname, formname)
return
end
------------------------------------------------------------------
-- (D) Edit Selected
------------------------------------------------------------------
if fields.edit_sel then
local sidx = meta:get_int("selected_index")
if sidx >= 1 and sidx <= #list then
meta:set_int("editing_index", sidx)
else
minetest.chat_send_player(pname, "No valid destination selected!")
end
minetest.after(0, function()
show_network_formspec(player, pos)
end)
return
end
------------------------------------------------------------------
-- (E) Delete Selected
------------------------------------------------------------------
if fields.delete_sel then
local sidx = meta:get_int("selected_index")
if sidx >= 1 and sidx <= #list then
local removed = table.remove(list, sidx)
if removed then
minetest.chat_send_player(pname, "Deleted '"..removed.name.."'")
end
-- Reset selection & editing
meta:set_int("selected_index", 0)
meta:set_int("editing_index", 0)
-- Save changes
save_networks()
else
minetest.chat_send_player(pname, "No valid destination selected!")
end
minetest.after(0, function()
show_network_formspec(player, pos)
end)
return
end
------------------------------------------------------------------
-- (F) Add / Update Destination
------------------------------------------------------------------
if fields.add_update then
local dname = fields.dest_name or ""
local dx = tonumber(fields.dest_x)
local dy = tonumber(fields.dest_y)
local dz = tonumber(fields.dest_z)
if not (dx and dy and dz) then
minetest.chat_send_player(pname, "Coordinates must be numbers!")
return
end
-- Additional checks
if dx < -1000 or dx > 1000 or dy < 1 or dy > 30000 or dz < -1000 or dz > 1000 then
minetest.chat_send_player(pname, "Coordinates are out of acceptable range!")
return
end
if dname == "" or not dx or not dy or not dz then
minetest.chat_send_player(pname, "Invalid name or coordinates!")
else
local eidx = meta:get_int("editing_index")
if eidx >= 1 and eidx <= #list then
-- Update existing entry
local entry = list[eidx]
entry.name = dname
entry.x = dx
entry.y = dy
entry.z = dz
minetest.chat_send_player(pname,
("Updated entry #%d to '%s'"):format(eidx, dname)
)
-- Auto-select updated entry
meta:set_int("selected_index", eidx)
else
-- Add new
table.insert(list, {
name = dname,
x = dx,
y = dy,
z = dz,
})
local new_idx = #list
meta:set_int("selected_index", new_idx)
minetest.chat_send_player(pname, ("Added new entry '%s'"):format(dname))
end
-- Save changes
save_networks()
end
-- Clear editing
meta:set_int("editing_index", 0)
minetest.after(0, function()
show_network_formspec(player, pos)
end)
return
end
------------------------------------------------------------------
-- (G) Manual Teleport (not saved)
------------------------------------------------------------------
if fields.man_teleport then
local mx = tonumber(fields.man_x)
local my = tonumber(fields.man_y)
local mz = tonumber(fields.man_z)
if mx and my and mz then
player:set_pos({x=mx, y=my, z=mz})
minetest.chat_send_player(pname,
("Teleported to (%d, %d, %d)"):format(mx, my, mz)
)
else
minetest.chat_send_player(pname, "Invalid manual coordinates!")
end
minetest.close_formspec(pname, formname)
return
end
end)
------------------------------------------------------------
--RECIPE
--5) Register Crafting Recipe for Teleporter Plate
------------------------------------------------------------
minetest.register_craft({
output = "teleporter_plates:net_plate",
recipe = {
{"mcl_core:glass", "", "mcl_core:glass"},
{"", "mcl_ocean:sea_lantern", ""},
{"mcl_core:glass", "", "mcl_core:glass"},
},
description = "Network Teleporter Plate",
group = {teleporter_plate = 1},
})