SX 88b8a2bb17
Update power tool compatibility shims (#276)
* Update tool compatibility shims

* Tool compatibility tests

* No forced override if technic_get_charge or technic_set_charge is defined
2022-06-16 17:58:18 +03:00

117 lines
5.0 KiB
Lua

--
-- This allows using old style technic.register_power_tool tool registration function.
--
-- To make tool fully compatible replace `minetest.register_tool` with `technic.register_power_tool`
-- and add `technic_max_charge` field for tool definition.
-- Fields `wear_represents` and `on_refill` can be removed if using defaults.
--
-- Does not offer compatibility for charger mods: mods that charge or discharge registered power tools.
-- Compatibility for those can be achieved by using `<tooldef>.technic_get_charge` / `<tooldef>.technic_set_charge`.
--
local function compat_set_RE_wear(stack, charge)
local def = stack:get_definition()
if def.technic_wear_factor then
local wear = math.floor(charge * def.technic_wear_factor + 0.5)
stack:set_wear(wear > 0 and 65536 - wear or 0)
end
end
local function compat_technic_get_charge(stack)
local def = stack:get_definition()
if def.technic_max_charge then
local legacy_fields = minetest.deserialize(stack:get_meta():get_string("")) or {}
return legacy_fields.charge or 0, def.technic_max_charge
end
return 0, 0
end
local function compat_technic_set_charge(stack, charge)
compat_set_RE_wear(stack, charge)
local meta = stack:get_meta()
local legacy_fields = minetest.deserialize(meta:get_string("")) or {}
legacy_fields.charge = charge
meta:set_string("", minetest.serialize(legacy_fields))
end
-- This attempts to find out if mod is aware of technic.plus version property and marks mod as `plus_aware` if
-- it tries to read `technic.plus` value. Marked tools wont receive automatic metadata compatibility functions.
local plus_aware = {}
do
local original_mt = getmetatable(technic)
local mt = original_mt and table.copy(original_mt) or {}
local mt_index = mt.__index or rawget
local plus = technic.plus
rawset(technic, "plus", nil)
-- Extend `__index` lookup function for `technic` to collect mod names that are reading `technic.plus` property
function mt:__index(key)
if key == "plus" then
local modname = minetest.get_current_modname()
if modname then
plus_aware[modname] = true
end
return plus
end
return mt_index(self, key)
end
setmetatable(technic, mt)
-- Restore version and metatable, this must happen after handling register_on_mods_loaded callbacks
minetest.after(0, function()
rawset(technic, "plus", plus)
setmetatable(technic, original_mt)
end)
end
-- Override `technic.register_power_tool` to handle old style registration that was only setting max charge value.
local register_power_tool = technic.register_power_tool
function technic.register_power_tool(itemname, def_or_max_charge)
if type(def_or_max_charge) == "number" then
minetest.log("warning", "Deprecated technic.register_power_tool use. Setting max_charge for "..itemname)
technic.power_tools[itemname] = def_or_max_charge
minetest.register_on_mods_loaded(function()
minetest.log("warning", "Deprecated technic.register_power_tool use. Ensuring fields for "..itemname)
local redef = minetest.registered_items[itemname]
if redef and redef.wear_represents == "technic_RE_charge" then
-- Override power tools that called register_power_tool but do not have on_refill function defined
local overrides = {
technic_max_charge = def_or_max_charge,
technic_wear_factor = 65535 / def_or_max_charge,
on_refill = function(stack)
local tooldef = stack:get_definition()
tooldef.technic_set_charge(stack, def_or_max_charge)
return stack
end,
}
-- Add legacy meta handlers if mod did not attempt to read technic.plus value
local modname = itemname:match(":?(.+):")
if plus_aware[modname] then
overrides.technic_get_charge = redef.technic_get_charge or technic.get_RE_charge
overrides.technic_set_charge = redef.technic_set_charge or technic.set_RE_charge
minetest.log("warning", "Mod "..modname.." seems to be aware of technic.plus but "..
itemname.." is still using deprecated registration, skipping meta charge compatibility.")
elseif not redef.technic_get_charge and not redef.technic_set_charge then
overrides.technic_get_charge = compat_technic_get_charge
overrides.technic_set_charge = compat_technic_set_charge
minetest.log("warning", "Using metadata charge values for "..itemname)
end
-- Override tool definition with added / new values
minetest.override_item(itemname, overrides)
minetest.log("warning", "Updated legacy Technic power tool definition for "..itemname)
else
minetest.log("error", "Technic compatibility overrides skipped for "..itemname..", charging might "..
'cause crash. Upgrading to technic.register_power_tool("'..itemname..'", {itemdef}) recommended.')
end
end)
else
return register_power_tool(itemname, def_or_max_charge)
end
end
-- Same as `technic.set_RE_charge` but without calling through `itemdef.technic_set_charge`.
function technic.set_RE_wear(stack, charge)
minetest.log("warning", "Use of deprecated function technic.set_RE_wear with stack: "..stack:get_name())
compat_set_RE_wear(stack, charge)
end