From a08ba2bb93d7683b619a0e6b0bf00e3afd614ae4 Mon Sep 17 00:00:00 2001 From: cx384 Date: Mon, 22 Jan 2024 18:27:54 +0100 Subject: [PATCH] Get rid of deprecated metadata (#628) The deprecated metadata gets converted to a proper ItemStackMetaRef. All keys stay the same except for: - Cans that use `can_level` now, since they didn't store a serialized table in the metadata before. - `charge` which is now `technic:charge`, since any item (also from other mods) may have a technic charge which can cause compatibility problems. Backwards compatibility is kept but going back to older `technic` versions might result in misbehaving circuits. --- technic/helpers.lua | 17 ++++++++-- technic/legacy.lua | 37 ++++++++++++++++++++ technic/machines/register/battery_box.lua | 13 +++---- technic/tools/cans.lua | 21 +++++------- technic/tools/chainsaw.lua | 14 ++++---- technic/tools/flashlight.lua | 11 +++--- technic/tools/mining_drill.lua | 31 +++++++++-------- technic/tools/mining_lasers.lua | 15 +++++---- technic/tools/prospector.lua | 41 ++++++++++++----------- technic/tools/sonic_screwdriver.lua | 11 +++--- technic/tools/vacuum.lua | 23 ++++++------- 11 files changed, 136 insertions(+), 98 deletions(-) diff --git a/technic/helpers.lua b/technic/helpers.lua index 5361fa3..e43216d 100644 --- a/technic/helpers.lua +++ b/technic/helpers.lua @@ -65,15 +65,26 @@ function technic.swap_node(pos, name) end +--- Returns the meta of an item +-- Gets overridden when legacy.lua is loaded +function technic.get_stack_meta(itemstack) + return itemstack:get_meta() +end + +--- Same as technic.get_stack_meta for cans +function technic.get_stack_meta_cans(itemstack) + return itemstack:get_meta() +end + + --- Fully charge RE chargeable item. -- Must be defined early to reference in item definitions. function technic.refill_RE_charge(stack) local max_charge = technic.power_tools[stack:get_name()] if not max_charge then return stack end + local meta = technic.get_stack_meta(stack) + meta:set_int("technic:charge", max_charge) technic.set_RE_wear(stack, max_charge, max_charge) - local meta = minetest.deserialize(stack:get_metadata()) or {} - meta.charge = max_charge - stack:set_metadata(minetest.serialize(meta)) return stack end diff --git a/technic/legacy.lua b/technic/legacy.lua index 6a080e1..14453eb 100644 --- a/technic/legacy.lua +++ b/technic/legacy.lua @@ -39,3 +39,40 @@ for i = 0, 64 do minetest.register_alias("technic:lv_cable"..i, "technic:lv_cable") end +-- Item meta + +-- Meta keys that have changed +technic.legacy_meta_keys = { + ["charge"] = "technic:charge", +} + +-- Converts legacy itemstack metadata string to itemstack meta and returns the ItemStackMetaRef +function technic.get_stack_meta(itemstack) + local meta = itemstack:get_meta() + local legacy_string = meta:get("") -- Get deprecated metadata + if legacy_string then + local legacy_table = minetest.deserialize(legacy_string) + if legacy_table then + local table = meta:to_table() + for k, v in pairs(legacy_table) do + table.fields[technic.legacy_meta_keys[k] or k] = v + end + meta:from_table(table) + end + meta:set_string("", "") -- Remove deprecated metadata + end + return meta +end + +-- Same as technic.get_stack_meta for cans. +-- (Cans didn't store a serialized table in the legacy metadata string, but just a number.) +function technic.get_stack_meta_cans(itemstack) + local meta = itemstack:get_meta() + local legacy_string = meta:get("") -- Get deprecated metadata + if legacy_string then + meta:set_string("can_level", legacy_string) + meta:set_string("", "") -- Remove deprecated metadata + return meta + end + return meta +end diff --git a/technic/machines/register/battery_box.lua b/technic/machines/register/battery_box.lua index 190ddbf..f0e67f3 100644 --- a/technic/machines/register/battery_box.lua +++ b/technic/machines/register/battery_box.lua @@ -415,12 +415,8 @@ local function default_get_charge(itemstack) if not technic.power_tools[tool_name] then return 0, 0 end - -- Set meta data for the tool if it didn't do it itself - local item_meta = minetest.deserialize(itemstack:get_metadata()) or {} - if not item_meta.charge then - item_meta.charge = 0 - end - return item_meta.charge, technic.power_tools[tool_name] + local item_meta = technic.get_stack_meta(itemstack) + return item_meta:get_int("technic:charge"), technic.power_tools[tool_name] end local function default_set_charge(itemstack, charge) @@ -428,9 +424,8 @@ local function default_set_charge(itemstack, charge) if technic.power_tools[tool_name] then technic.set_RE_wear(itemstack, charge, technic.power_tools[tool_name]) end - local item_meta = minetest.deserialize(itemstack:get_metadata()) or {} - item_meta.charge = charge - itemstack:set_metadata(minetest.serialize(item_meta)) + local item_meta = technic.get_stack_meta(itemstack) + item_meta:set_int("technic:charge", charge) end function technic.charge_tools(meta, batt_charge, charge_step) diff --git a/technic/tools/cans.lua b/technic/tools/cans.lua index 6507f7a..52d5eab 100644 --- a/technic/tools/cans.lua +++ b/technic/tools/cans.lua @@ -12,14 +12,6 @@ local function set_can_wear(itemstack, level, max_level) itemstack:set_wear(temp) end -local function get_can_level(itemstack) - if itemstack:get_metadata() == "" then - return 0 - else - return tonumber(itemstack:get_metadata()) - end -end - function technic.register_can(d) local data = {} for k, v in pairs(d) do data[k] = v end @@ -33,7 +25,8 @@ function technic.register_can(d) if pointed_thing.type ~= "node" then return end local node = minetest.get_node(pointed_thing.under) if node.name ~= data.liquid_source_name then return end - local charge = get_can_level(itemstack) + local meta = technic.get_stack_meta_cans(itemstack) + local charge = meta:get_int("can_level") if charge == data.can_capacity then return end if minetest.is_protected(pointed_thing.under, user:get_player_name()) then minetest.log("action", user:get_player_name().. @@ -44,7 +37,7 @@ function technic.register_can(d) end minetest.remove_node(pointed_thing.under) charge = charge + 1 - itemstack:set_metadata(tostring(charge)) + meta:set_int("can_level", charge) set_can_wear(itemstack, charge, data.can_capacity) return itemstack end, @@ -63,7 +56,8 @@ function technic.register_can(d) -- Try to place node above the pointed source, or abort. if not def.buildable_to or node_name == data.liquid_source_name then return end end - local charge = get_can_level(itemstack) + local meta = technic.get_stack_meta_cans(itemstack) + local charge = meta:get_int("can_level") if charge == 0 then return end if minetest.is_protected(pos, user:get_player_name()) then minetest.log("action", user:get_player_name().. @@ -74,12 +68,13 @@ function technic.register_can(d) end minetest.set_node(pos, {name=data.liquid_source_name}) charge = charge - 1 - itemstack:set_metadata(tostring(charge)) + meta:set_int("can_level", charge) set_can_wear(itemstack, charge, data.can_capacity) return itemstack end, on_refill = function(stack) - stack:set_metadata(tostring(data.can_capacity)) + local meta = technic.get_stack_meta_cans(stack) + meta:set_int("can_level", data.can_capacity) set_can_wear(stack, data.can_capacity, data.can_capacity) return stack end, diff --git a/technic/tools/chainsaw.lua b/technic/tools/chainsaw.lua index d2ee966..ee8fed7 100644 --- a/technic/tools/chainsaw.lua +++ b/technic/tools/chainsaw.lua @@ -313,10 +313,8 @@ minetest.register_tool("technic:chainsaw", { return itemstack end - local meta = minetest.deserialize(itemstack:get_metadata()) - if not meta or not meta.charge then - return - end + local meta = technic.get_stack_meta(itemstack) + local charge = meta:get_int("technic:charge") local name = user:get_player_name() if minetest.is_protected(pointed_thing.under, name) then @@ -326,14 +324,14 @@ minetest.register_tool("technic:chainsaw", { -- Send current charge to digging function so that the -- chainsaw will stop after digging a number of nodes - chainsaw_dig(user, pointed_thing.under, meta.charge) - meta.charge = cutter.charge + chainsaw_dig(user, pointed_thing.under, charge) + charge = cutter.charge cutter = {} -- Free RAM if not technic.creative_mode then - technic.set_RE_wear(itemstack, meta.charge, chainsaw_max_charge) - itemstack:set_metadata(minetest.serialize(meta)) + meta:set_int("technic:charge", charge) + technic.set_RE_wear(itemstack, charge, chainsaw_max_charge) end return itemstack end, diff --git a/technic/tools/flashlight.lua b/technic/tools/flashlight.lua index 84decbb..91346d2 100644 --- a/technic/tools/flashlight.lua +++ b/technic/tools/flashlight.lua @@ -38,12 +38,13 @@ local function check_for_flashlight(player) local hotbar = inv:get_list("main") for i = 1, 8 do if hotbar[i]:get_name() == "technic:flashlight" then - local meta = minetest.deserialize(hotbar[i]:get_metadata()) - if meta and meta.charge and meta.charge >= 2 then + local meta = technic.get_stack_meta(hotbar[i]) + local charge = meta:get_int("technic:charge") + if charge >= 2 then if not technic.creative_mode then - meta.charge = meta.charge - 2; - technic.set_RE_wear(hotbar[i], meta.charge, flashlight_max_charge) - hotbar[i]:set_metadata(minetest.serialize(meta)) + charge = charge - 2; + meta:set_int("technic:charge", charge) + technic.set_RE_wear(hotbar[i], charge, flashlight_max_charge) inv:set_stack("main", i, hotbar[i]) end return true diff --git a/technic/tools/mining_drill.lua b/technic/tools/mining_drill.lua index dfef394..0fe7135 100644 --- a/technic/tools/mining_drill.lua +++ b/technic/tools/mining_drill.lua @@ -248,54 +248,53 @@ end local function mining_drill_mkX_setmode(user, itemstack, drill_type, max_modes) local player_name = user:get_player_name() - local meta = minetest.deserialize(itemstack:get_metadata()) or {} + local meta = technic.get_stack_meta(itemstack) - if not meta["mode"] then + if not meta:contains("mode") then minetest.chat_send_player(player_name, S("Use while sneaking to change Mining Drill Mk%d modes."):format(drill_type)) end - local mode = (meta["mode"] or 0) + 1 + local mode = meta:get_int("mode") + 1 if mode > max_modes then mode = 1 end minetest.chat_send_player(player_name, S("Mining Drill Mk%d Mode %d"):format(2, mode).. ": "..mining_drill_mode_text[mode][1]) itemstack:set_name(("technic:mining_drill_mk%d_%s"):format(drill_type, mode)) - meta["mode"] = mode - itemstack:set_metadata(minetest.serialize(meta)) + meta:set_int("mode", mode) return itemstack end local function mining_drill_mkX_handler(itemstack, user, pointed_thing, drill_type, max_modes) local keys = user:get_player_control() - local meta = minetest.deserialize(itemstack:get_metadata()) or {} + local meta = technic.get_stack_meta(itemstack) -- Mode switching (if possible) if max_modes > 1 then - if not meta.mode or keys.sneak then + if not meta:contains("mode") or keys.sneak then return mining_drill_mkX_setmode(user, itemstack, drill_type, max_modes) end end if pointed_thing.type ~= "node" or not pos_is_pointable(pointed_thing.under) then return end - if not meta.charge then - return - end + + local charge = meta:get_int("technic:charge") + local mode = meta:contains("mode") and meta:get_int("mode") or 1 -- Check whether the tool has enough charge - local charge_to_take = cost_to_use(drill_type, meta.mode or 1) - if meta.charge < charge_to_take then + local charge_to_take = cost_to_use(drill_type, mode) + if charge < charge_to_take then return end -- Do the actual shoorting action local pos = minetest.get_pointed_thing_position(pointed_thing, false) - drill_dig_it(pos, user, meta.mode or 1) + drill_dig_it(pos, user, mode) if not technic.creative_mode then - meta.charge = meta.charge - charge_to_take - itemstack:set_metadata(minetest.serialize(meta)) - technic.set_RE_wear(itemstack, meta.charge, max_charge[drill_type]) + charge = charge - charge_to_take + meta:set_int("technic:charge", charge) + technic.set_RE_wear(itemstack, charge, max_charge[drill_type]) end return itemstack end diff --git a/technic/tools/mining_lasers.lua b/technic/tools/mining_lasers.lua index e4dd178..47fcc17 100644 --- a/technic/tools/mining_lasers.lua +++ b/technic/tools/mining_lasers.lua @@ -101,25 +101,26 @@ for _, m in pairs(mining_lasers_list) do wear_represents = "technic_RE_charge", on_refill = technic.refill_RE_charge, on_use = function(itemstack, user) - local meta = minetest.deserialize(itemstack:get_metadata()) - if not meta or not meta.charge or meta.charge == 0 then + local meta = technic.get_stack_meta(itemstack) + local charge = meta:get_int("technic:charge") + if charge == 0 then return end local range = m[2] - if meta.charge < m[4] then + if charge < m[4] then if not allow_entire_discharging then return end -- If charge is too low, give the laser a shorter range - range = range * meta.charge / m[4] + range = range * charge / m[4] end laser_shoot(user, range, "technic_laser_beam_mk" .. m[1] .. ".png", "technic_laser_mk" .. m[1]) if not technic.creative_mode then - meta.charge = math.max(meta.charge - m[4], 0) - technic.set_RE_wear(itemstack, meta.charge, m[3]) - itemstack:set_metadata(minetest.serialize(meta)) + charge = math.max(charge - m[4], 0) + meta:set_int("technic:charge", charge) + technic.set_RE_wear(itemstack, charge, m[3]) end return itemstack end, diff --git a/technic/tools/prospector.lua b/technic/tools/prospector.lua index b9bd039..14e518c 100644 --- a/technic/tools/prospector.lua +++ b/technic/tools/prospector.lua @@ -2,14 +2,16 @@ local S = technic.getter technic.register_power_tool("technic:prospector", 300000) -local function get_metadata(toolstack) - local m = minetest.deserialize(toolstack:get_metadata()) - if not m then m = {} end - if not m.charge then m.charge = 0 end - if not m.target then m.target = "" end - if not m.look_depth then m.look_depth = 7 end - if not m.look_radius then m.look_radius = 1 end - return m +-- Helper function to consolidate ItemStackMetaRef access and initialize +local function meta_to_table(meta) + local t = {} + local mt = meta:to_table() + + t.charge = tonumber(mt.fields["technic:charge"]) or 0 + t.target = mt.fields.target or "" + t.look_depth = tonumber(mt.fields.look_depth) or 7 + t.look_radius = tonumber(mt.fields.look_radius) or 1 + return t end minetest.register_tool("technic:prospector", { @@ -20,7 +22,8 @@ minetest.register_tool("technic:prospector", { on_use = function(toolstack, user, pointed_thing) if not user or not user:is_player() or user.is_fake_player then return end if pointed_thing.type ~= "node" then return end - local toolmeta = get_metadata(toolstack) + local meta = technic.get_stack_meta(toolstack) + local toolmeta = meta_to_table(meta) local look_diameter = toolmeta.look_radius * 2 + 1 local charge_to_take = toolmeta.look_depth * (toolmeta.look_depth + 1) * look_diameter * look_diameter if toolmeta.charge < charge_to_take then return end @@ -30,7 +33,7 @@ minetest.register_tool("technic:prospector", { end if not technic.creative_mode then toolmeta.charge = toolmeta.charge - charge_to_take - toolstack:set_metadata(minetest.serialize(toolmeta)) + meta:set_int("technic:charge", toolmeta.charge) technic.set_RE_wear(toolstack, toolmeta.charge, technic.power_tools[toolstack:get_name()]) end -- What in the heaven's name is this evil sorcery ? @@ -77,7 +80,8 @@ minetest.register_tool("technic:prospector", { end, on_place = function(toolstack, user, pointed_thing) if not user or not user:is_player() or user.is_fake_player then return end - local toolmeta = get_metadata(toolstack) + local meta = technic.get_stack_meta(toolstack) + local toolmeta = meta_to_table(meta) local pointed if pointed_thing.type == "node" then local pname = minetest.get_node(pointed_thing.under).name @@ -125,19 +129,16 @@ minetest.register_on_player_receive_fields(function(user, formname, fields) if not user or not user:is_player() or user.is_fake_player then return end local toolstack = user:get_wielded_item() if toolstack:get_name() ~= "technic:prospector" then return true end - local toolmeta = get_metadata(toolstack) + local meta = technic.get_stack_meta(toolstack) for field, value in pairs(fields) do if field:sub(1, 7) == "target_" then - toolmeta.target = field:sub(8) - end - if field:sub(1, 12) == "look_radius_" then - toolmeta.look_radius = field:sub(13) - end - if field:sub(1, 11) == "look_depth_" then - toolmeta.look_depth = field:sub(12) + meta:set_string("target", field:sub(8)) + elseif field:sub(1, 12) == "look_radius_" then + meta:set_string("look_radius", field:sub(13)) + elseif field:sub(1, 11) == "look_depth_" then + meta:set_string("look_depth", field:sub(12)) end end - toolstack:set_metadata(minetest.serialize(toolmeta)) user:set_wielded_item(toolstack) return true end) diff --git a/technic/tools/sonic_screwdriver.lua b/technic/tools/sonic_screwdriver.lua index 536f47c..ceb52a1 100644 --- a/technic/tools/sonic_screwdriver.lua +++ b/technic/tools/sonic_screwdriver.lua @@ -41,8 +41,9 @@ local function screwdriver_handler(itemstack, user, pointed_thing, mode) -- contrary to the default screwdriver, do not check for can_dig, to allow rotating machines with CLU's in them -- this is consistent with the previous sonic screwdriver - local meta1 = minetest.deserialize(itemstack:get_metadata()) - if not meta1 or not meta1.charge or meta1.charge < 100 then + local meta = technic.get_stack_meta(itemstack) + local charge = meta:get_int("technic:charge") + if charge < 100 then return end @@ -64,9 +65,9 @@ local function screwdriver_handler(itemstack, user, pointed_thing, mode) minetest.swap_node(pos, node) if not technic.creative_mode then - meta1.charge = meta1.charge - 100 - itemstack:set_metadata(minetest.serialize(meta1)) - technic.set_RE_wear(itemstack, meta1.charge, sonic_screwdriver_max_charge) + charge = charge - 100 + meta:set_int("technic:charge", charge) + technic.set_RE_wear(itemstack, charge, sonic_screwdriver_max_charge) end return itemstack diff --git a/technic/tools/vacuum.lua b/technic/tools/vacuum.lua index 7b01af8..a715d99 100644 --- a/technic/tools/vacuum.lua +++ b/technic/tools/vacuum.lua @@ -14,24 +14,23 @@ minetest.register_tool("technic:vacuum", { wear_represents = "technic_RE_charge", on_refill = technic.refill_RE_charge, on_use = function(itemstack, user, pointed_thing) - local meta = minetest.deserialize(itemstack:get_metadata()) - if not meta or not meta.charge then + local meta = technic.get_stack_meta(itemstack) + local charge = meta:get_int("technic:charge") + if charge < vacuum_charge_per_object then return end - if meta.charge > vacuum_charge_per_object then - minetest.sound_play("vacuumcleaner", { - to_player = user:get_player_name(), - gain = 0.4, - }) - end + minetest.sound_play("vacuumcleaner", { + to_player = user:get_player_name(), + gain = 0.4, + }) local pos = user:get_pos() local inv = user:get_inventory() for _, object in ipairs(minetest.get_objects_inside_radius(pos, vacuum_range)) do local luaentity = object:get_luaentity() if not object:is_player() and luaentity and luaentity.name == "__builtin:item" and luaentity.itemstring ~= "" then if inv and inv:room_for_item("main", ItemStack(luaentity.itemstring)) then - meta.charge = meta.charge - vacuum_charge_per_object - if meta.charge < vacuum_charge_per_object then + charge = charge - vacuum_charge_per_object + if charge < vacuum_charge_per_object then return end inv:add_item("main", ItemStack(luaentity.itemstring)) @@ -45,8 +44,8 @@ minetest.register_tool("technic:vacuum", { end end - technic.set_RE_wear(itemstack, meta.charge, vacuum_max_charge) - itemstack:set_metadata(minetest.serialize(meta)) + meta:set_int("technic:charge", charge) + technic.set_RE_wear(itemstack, charge, vacuum_max_charge) return itemstack end, })