diff --git a/controller.lua b/controller.lua index b3f54db..ff1e6a3 100644 --- a/controller.lua +++ b/controller.lua @@ -570,17 +570,40 @@ minetest.register_node("digtron:controller", combine_defs(base_def, { local digtron_id = meta:get_string("digtron_id") local player_name = clicker:get_player_name() - if digtron_id == "" then - minetest.log("error", "[Digtron] The digtron:controller node at " .. minetest.pos_to_string(pos) - .. " had no digtron id associated with it when " .. player_name - .. "right-clicked on it. Converting it into a digtron:controller_unassembled.") - node.name = "digtron:controller_unassembled" - minetest.set_node(pos, node) - else - player_interacting_with_digtron_id[player_name] = {digtron_id = digtron_id} - minetest.show_formspec(player_name, - "digtron:controller_assembled", - get_controller_assembled_formspec(digtron_id, player_name)) + + if digtron_id == "" then + if not digtron.recover_digtron_id(pos) then + minetest.log("error", "[Digtron] The digtron:controller node at " .. minetest.pos_to_string(pos) + .. " had no digtron id associated with it when " .. player_name + .. "right-clicked on it. Converting it into a digtron:controller_unassembled.") + node.name = "digtron:controller_unassembled" + minetest.set_node(pos, node) + return + end end + + player_interacting_with_digtron_id[player_name] = {digtron_id = digtron_id} + minetest.show_formspec(player_name, + "digtron:controller_assembled", + get_controller_assembled_formspec(digtron_id, player_name)) end, -})) \ No newline at end of file +})) + +minetest.register_lbm({ + label = "Validate and repair Digtron controller metadata", + name = "digtron:validate_controller_metadata", + nodenames = {"digtron:controller"}, + run_at_every_load = true, + action = function(pos, node) + local meta = minetest.get_meta(pos) + local digtron_id = meta:get_string("digtron_id") + if digtron_id == "" then + if not digtron.recover_digtron_id(pos) then + minetest.log("error", "[Digtron] The digtron:controller node at " .. minetest.pos_to_string(pos) + .. " had no digtron id associated with it. Converting it into a digtron:controller_unassembled.") + node.name = "digtron:controller_unassembled" + minetest.set_node(pos, node) + end + end + end, +}) \ No newline at end of file diff --git a/functions.lua b/functions.lua index d7182c5..c4eba9e 100644 --- a/functions.lua +++ b/functions.lua @@ -394,6 +394,8 @@ local get_valid_data = function(digtron_id, root_pos, hash, data, function_name) .. " but the node at that location had no digtron_id in its metadata. " .. "Since the node type matched the layout, however, it was included anyway. It's possible " .. "its metadata was not written correctly by a previous Digtron activity.") + node_meta:set_string("digtron_id", digtron_id) + node_meta:mark_as_private("digtron_id") return node_pos, node, node_meta end end @@ -421,7 +423,7 @@ local disassemble = function(digtron_id, player_name) -- Write metadata and inventory to in-world node at this location for hash, data in pairs(layout) do - local node_pos, node, node_meta = get_valid_data(digtron_id, root_pos, hash, data, "digtron.disassemble") + local node_pos, node, node_meta = get_valid_data(digtron_id, root_pos, hash, data, "disassemble") if node_pos then local node_inv = node_meta:get_inventory() @@ -503,7 +505,7 @@ local remove_from_world = function(digtron_id, player_name) local nodes_to_destroy = {} for hash, data in pairs(layout) do - local node_pos = get_valid_data(digtron_id, root_pos, hash, data, "digtron.remove_from_world") + local node_pos = get_valid_data(digtron_id, root_pos, hash, data, "remove_from_world") if node_pos then table.insert(nodes_to_destroy, node_pos) end @@ -1139,7 +1141,30 @@ if minetest.get_modpath("creative") then end end +-------------------------------------------------------------------------------------- +-- Fallback method for recovering missing metadata +-- If this gets called frequently then something's wrong. +local recover_digtron_id = function(root_pos) + for field, value in pairs(mod_meta:to_table().fields) do + local fields = field:split(":") + if #fields == 2 and fields[2] == "pos" and vector.equals(root_pos, minetest.deserialize(value)) then + local digtron_id = fields[1] + minetest.log("warning", "[Digtron] had to use recover_digtron_id to restore " + ..digtron_id .. " to the controller at " .. minetest.pos_to_string(root_pos) + ..". If this happens frequently please file an issue with Digtron's developers. " + .."recover_digtron_id will now attempt to restore the digtron_id metadata key to all " + .."nodes in this Digtron's layout.") + local layout = retrieve_layout(digtron_id) + for hash, data in pairs(layout) do + -- get_valid_data will attempt to repair node metadata that's missing digtron_id + local node_pos, node, node_meta = get_valid_data(digtron_id, root_pos, hash, data, "recover_digtron_id") + end + return true + end + end + return false +end --------------------------------------------------------------------------------------------------------------------------- -- External API @@ -1169,4 +1194,6 @@ digtron.is_buildable_to = is_buildable_to digtron.build_to_world = build_to_world digtron.move = move digtron.rotate = rotate -digtron.execute_cycle = execute_cycle \ No newline at end of file +digtron.execute_cycle = execute_cycle + +digtron.recover_digtron_id = recover_digtron_id \ No newline at end of file