diff --git a/builtin/game/register.lua b/builtin/game/register.lua index dc4aa1ca1..2417a1b8a 100644 --- a/builtin/game/register.lua +++ b/builtin/game/register.lua @@ -129,6 +129,13 @@ function core.register_entity(name, prototype) prototype.mod_origin = core.get_current_modname() or "??" end +local default_tables = { + node = core.nodedef_default, + craft = core.craftitemdef_default, + tool = core.tooldef_default, + none = core.noneitemdef_default, +} + function core.register_item(name, itemdef) -- Check name if name == nil then @@ -140,13 +147,6 @@ function core.register_item(name, itemdef) end itemdef.name = name - local mt = getmetatable(itemdef) - if mt ~= nil and next(mt) ~= nil then - core.log("warning", "Item definition has a metatable, this is ".. - "unsupported and it will be overwritten: " .. name) - end - - -- Apply defaults and add to registered_* table if itemdef.type == "node" then -- Use the nodebox as selection box if it's not set manually if itemdef.drawtype == "nodebox" and not itemdef.selection_box then @@ -162,19 +162,27 @@ function core.register_item(name, itemdef) core.log("warning", "Node 'light_source' value exceeds maximum," .. " limiting to maximum: " ..name) end - setmetatable(itemdef, {__index = core.nodedef_default}) - core.registered_nodes[itemdef.name] = itemdef - elseif itemdef.type == "craft" then - setmetatable(itemdef, {__index = core.craftitemdef_default}) - core.registered_craftitems[itemdef.name] = itemdef - elseif itemdef.type == "tool" then - setmetatable(itemdef, {__index = core.tooldef_default}) - core.registered_tools[itemdef.name] = itemdef - elseif itemdef.type == "none" then - setmetatable(itemdef, {__index = core.noneitemdef_default}) - else + end + + -- Apply defaults + local defaults = default_tables[itemdef.type] + if defaults == nil then error("Unable to register item: Type is invalid: " .. dump(itemdef)) end + local old_mt = getmetatable(itemdef) + -- TODO most of these checks should become an error after a while (maybe in 2026?) + if old_mt ~= nil and next(old_mt) ~= nil then + -- Note that even registering multiple identical items with the same table + -- is not allowed, due to the 'name' property. + if old_mt.__index == defaults then + core.log("warning", "Item definition table was reused between registrations. ".. + "This is unsupported and broken: " .. name) + else + core.log("warning", "Item definition has a metatable, this is ".. + "unsupported and it will be overwritten: " .. name) + end + end + setmetatable(itemdef, {__index = defaults}) -- Flowing liquid uses param2 if itemdef.type == "node" and itemdef.liquidtype == "flowing" then @@ -204,9 +212,17 @@ function core.register_item(name, itemdef) -- Ignore new keys as a failsafe to prevent mistakes getmetatable(itemdef).__newindex = function() end - --core.log("Registering item: " .. itemdef.name) + -- Add to registered_* tables + if itemdef.type == "node" then + core.registered_nodes[itemdef.name] = itemdef + elseif itemdef.type == "craft" then + core.registered_craftitems[itemdef.name] = itemdef + elseif itemdef.type == "tool" then + core.registered_tools[itemdef.name] = itemdef + end core.registered_items[itemdef.name] = itemdef core.registered_aliases[itemdef.name] = nil + register_item_raw(itemdef) end @@ -217,17 +233,11 @@ function core.unregister_item(name) return end -- Erase from registered_* table - local type = core.registered_items[name].type - if type == "node" then - core.registered_nodes[name] = nil - elseif type == "craft" then - core.registered_craftitems[name] = nil - elseif type == "tool" then - core.registered_tools[name] = nil - end + core.registered_nodes[name] = nil + core.registered_craftitems[name] = nil + core.registered_tools[name] = nil core.registered_items[name] = nil - unregister_item_raw(name) end diff --git a/doc/lua_api.md b/doc/lua_api.md index f0d9624d0..765a1d31b 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -5895,16 +5895,23 @@ Call these functions only at load time! ### Environment -* `core.register_node(name, node definition)` -* `core.register_craftitem(name, item definition)` -* `core.register_tool(name, item definition)` +* `core.register_node(name, nodedef)` + * register a node with its definition + * Note: you must pass a clean table that hasn't already been used for + another registration to this function, as it will be modified. +* `core.register_craftitem(name, itemdef)` + * register an item with its definition + * Note: (as above) +* `core.register_tool(name, tooldef)` + * register a tool item with its definition + * Note: (as above) * `core.override_item(name, redefinition, del_fields)` * `redefinition` is a table of fields `[name] = new_value`, overwriting fields of or adding fields to the existing definition. * `del_fields` is a list of field names to be set to `nil` ("deleted from") the original definition. * Overrides fields of an item registered with register_node/tool/craftitem. - * Note: Item must already be defined, (opt)depend on the mod defining it. + * Note: Item must already be defined. * Example: `core.override_item("default:mese", {light_source=core.LIGHT_MAX}, {"sounds"})`: Overwrites the `light_source` field, @@ -5912,7 +5919,7 @@ Call these functions only at load time! * `core.unregister_item(name)` * Unregisters the item from the engine, and deletes the entry with key `name` from `core.registered_items` and from the associated item table - according to its nature: `core.registered_nodes`, etc. + according to its nature (e.g. `core.registered_nodes`) * `core.register_entity(name, entity definition)` * `core.register_abm(abm definition)` * `core.register_lbm(lbm definition)`