minetest.register_entity(":display", { initial_properties = { visual = "sprite", textures = {"blank.png"}, pointable = false, static_save = false }, on_activate = function(e) e.object:set_armor_groups{immortal = 1} end }) artifact.register_craftitem("cancel", { inventory_image = "artifact_cancel.png" }) --- @param receivers: A list of node positions to notify. --- @param event: The event to send. function artifact.dispatch_event(receivers, event) for _, x in ipairs(receivers) do -- Ensure that nodes are available. minetest.load_area(x.pos) local node = minetest.get_node(x.pos) local def = minetest.registered_nodes[node.name] if def.on_signal then def.on_signal(x.pos, event, x.channel or "gold") end end end include "basics.lua" include "doors.lua" include "large_doors.lua" include "chest.lua" function artifact.load_schematic(dst, path, rot) minetest.place_schematic(dst, path..".mts", rot or "0") local f = io.open(path..".json") local meta = minetest.parse_json(f:read("a")) f:close() -- Load auxiliary metadata. for p, m in pairs(meta or {}) do local pos = dst +vector.from_string(p) -- Transform all position fields back into global space. if m.fields and m.fields.receivers then local receivers = minetest.deserialize(m.fields.receivers) for i, x in ipairs(receivers) do x.pos = vector.add(x.pos, dst) receivers[i] = x end m.fields.receivers = minetest.serialize(receivers) end minetest.get_meta(pos):from_table(m) local def = minetest.registered_nodes[minetest.get_node(pos).name] if def.on_construct then def.on_construct(pos) end end end function artifact.get_schem_size(path) local f = io.open(path..".mts", "rb") local function read_u16(file) local data = file:read(2) if not data or #data < 2 then return nil end local a, b = data:byte(1, 2) return a + b end local magic = f:read(4) if magic ~= "MTSM" then f:close() error("Not a valid .mts file (missing` MTSM` header).") end local version = read_u16(f) if not version or version > 4 then f:close() error("Unsupported .mts version: "..tostring(version)) end local size_x = read_u16(f) local size_y = read_u16(f) local size_z = read_u16(f) f:close() return vector.new(size_x, size_y, size_z) end if artifact.debug then local link_colors = { "gold", "red", "green", "blue" } if minetest.get_modpath("rhotator") then minetest.override_item("rhotator:screwdriver", { pointabilities = { nodes = { -- This gets added to everything in debug mode. ["group:dig_immediate"] = true, air = false, }, objects = { -- The display entities should all be immortal. ["group:immortal"] = false } }, }) minetest.override_item("testtools:remover", { pointabilities = { nodes = { -- This gets added to everything in debug mode. ["group:dig_immediate"] = true, air = false, }, objects = { -- The display entities should all be immortal. ["group:immortal"] = false } }, }) minetest.override_item("testtools:node_meta_editor", { pointabilities = { nodes = { -- This gets added to everything in debug mode. ["group:dig_immediate"] = true, air = false, }, objects = { -- The display entities should all be immortal. ["group:immortal"] = false } }, }) minetest.override_item("testtools:param2tool", { pointabilities = { nodes = { -- This gets added to everything in debug mode. ["group:dig_immediate"] = true, air = false, }, objects = { -- The display entities should all be immortal. ["group:immortal"] = false } }, }) end artifact.register_craftitem("linker_tool", { inventory_image = "artifact_linker_tool.png", stack_max = 1, pointabilities = { nodes = { -- This gets added to everything in debug mode. ["group:dig_immediate"] = true, air = false, }, objects = { -- The display entities should all be immortal. ["group:immortal"] = false } }, on_secondary_use = function(s, p, pt) local m = s:get_meta() -- Just cycle through the colors list. local color = link_colors[table.indexof(link_colors, m:get("color") or "gold") %#link_colors +1] m:set_string("color", color) m:set_string("inventory_image", "[fill:16x16:0,0:"..color.."#00^artifact_linker_tool.png") return s end, on_place = function(s, p, pt) local m = artifact.players[p:get_player_name()] if pt.type == "node" and m._linker_target then local color = s:get_meta():get("color") or "gold" local meta = minetest.get_meta(m._linker_target) local receivers = minetest.deserialize(meta:get("receivers") or "return {}") if m.ctl.sneak then local idx = 0 for i, x in ipairs(receivers) do if vector.equals(x.pos, pt.under) then idx = i end end if idx > 0 then table.remove(receivers, idx) m.object:hud_remove(m._linker_receivers[idx]) table.remove(m._linker_receivers, idx) end else local idx = 0 for i, x in ipairs(receivers) do if vector.equals(x.pos, pt.under) then idx = i end end -- Ensure we haven't added this pos already. if idx == 0 then table.insert(receivers, {pos = pt.under, channel = color}) table.insert(m._linker_receivers, m.object:hud_add { type = "image_waypoint", scale = {x=3, y=3}, world_pos = pt.under, text = "artifact_linker_tool.png^[colorize:"..color..":64" }) end end meta:set_string("receivers", minetest.serialize(receivers)) end end, on_use = function(s, p, pt) local m = artifact.players[p:get_player_name()] if pt.type == "node" then m._linker_target = pt.under if m._linker_target_hud then m.object:hud_remove(m._linker_target_hud) end m._linker_target_hud = m.object:hud_add { type = "image_waypoint", scale = {x=3, y=3}, world_pos = pt.under, text = "artifact_linker_tool.png" } if m._linker_receivers then for _, x in ipairs(m._linker_receivers) do m.object:hud_remove(x) end end m._linker_receivers = {} local receivers = minetest.deserialize(minetest.get_meta(m._linker_target):get("receivers") or "return {}") for _, x in ipairs(receivers) do table.insert(m._linker_receivers, m.object:hud_add { type = "image_waypoint", scale = {x=3, y=3}, world_pos = x.pos, text = "artifact_linker_tool.png^[colorize:"..x.channel..":64" }) end end end }) -- To make life easier, simply require worldedit in order to export an area. if minetest.global_exists("worldedit") then minetest.mkdir(minetest.get_worldpath().."/schems") minetest.register_chatcommand("export", { privs = {server = true}, params = "", description = "Export the selected region as a schematic, with all node metadata stored in an adjacent JSON file.", func = function(name, args) local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] print(dump(minetest.create_schematic(pos1, pos2, nil, minetest.get_worldpath().."/schems/"..args..".mts"))) local minp = vector.sort(pos1, pos2) local meta = {} for _, pos in pairs(minetest.find_nodes_with_meta(pos1, pos2)) do local mt = minetest.get_meta(pos):to_table() mt.fields.initialized = nil -- Transform all position fields into local coordinate space. if mt.fields.receivers then local receivers = minetest.deserialize(mt.fields.receivers) for i, x in ipairs(receivers) do x.pos = vector.subtract(x.pos, minp) receivers[i] = x end mt.fields.receivers = minetest.serialize(receivers) end meta[(pos -minp):to_string()] = mt end local f = io.open(minetest.get_worldpath().."/schems/"..args..".json", "w") f:write(minetest.write_json(meta)) f:flush() f:close() end }) end minetest.register_chatcommand("load", { privs = {server = true}, func = function(name, args) artifact.load_schematic(artifact.players[name].pos:round(), minetest.get_worldpath().."/schems/"..args) end }) end