1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-06-27 16:36:03 +00:00

Prevent registration of certain new content after load time

This commit is contained in:
sfan5 2025-03-16 20:22:05 +01:00
parent ca047c3e58
commit a9a3b05cc3
3 changed files with 55 additions and 6 deletions

View file

@ -59,6 +59,9 @@ end
local alias_metatable = {
__index = function(t, name)
return rawget(t, core.registered_aliases[name])
end,
__newindex = function()
error("table is read-only")
end
}
setmetatable(core.registered_items, alias_metatable)

View file

@ -36,6 +36,9 @@ end
local alias_metatable = {
__index = function(t, name)
return rawget(t, core.registered_aliases[name])
end,
__newindex = function()
error("table is read-only")
end
}
setmetatable(core.registered_items, alias_metatable)

View file

@ -61,7 +61,7 @@ local function check_modname_prefix(name)
return name:sub(2)
else
-- Enforce that the name starts with the correct mod name.
local expected_prefix = core.get_current_modname() .. ":"
local expected_prefix = (core.get_current_modname() or "") .. ":"
if name:sub(1, #expected_prefix) ~= expected_prefix then
error("Name " .. name .. " does not follow naming conventions: " ..
"\"" .. expected_prefix .. "\" or \":\" prefix required")
@ -95,6 +95,7 @@ function core.register_abm(spec)
check_node_list(spec.nodenames, "nodenames")
check_node_list(spec.neighbors, "neighbors")
assert(type(spec.action) == "function", "Required field 'action' of type function")
core.registered_abms[#core.registered_abms + 1] = spec
spec.mod_origin = core.get_current_modname() or "??"
end
@ -581,15 +582,57 @@ core.registered_on_rightclickplayers, core.register_on_rightclickplayer = make_r
core.registered_on_liquid_transformed, core.register_on_liquid_transformed = make_registration()
core.registered_on_mapblocks_changed, core.register_on_mapblocks_changed = make_registration()
-- A bunch of registrations are read by the C++ side once on env init, so we cannot
-- allow them to change afterwards (see s_env.cpp).
-- Nodes and items do not have this problem but there are obvious consistency
-- problems if this would be allowed.
local function freeze_table(t)
-- Freezing a Lua table is not actually possible without some very intrusive
-- metatable hackery, but we can trivially prevent new additions.
local mt = table.copy(getmetatable(t) or {})
mt.__newindex = function()
error("modification forbidden")
end
setmetatable(t, mt)
end
local function generic_reg_error(what)
return function(something)
local described = what
if type(something) == "table" and type(something.name) == "string" then
described = what .. " " .. something.name
elseif type(something) == "string" then
described = what .. " " .. something
end
error("Tried to register " .. described .. " after load time!")
end
end
core.register_on_mods_loaded(function()
core.after(0, function()
itemdefs_finalized = true
setmetatable(core.registered_on_mapblocks_changed, {
__newindex = function()
error("on_mapblocks_changed callbacks must be registered at load time")
end,
})
-- prevent direct modification
freeze_table(core.registered_abms)
freeze_table(core.registered_lbms)
freeze_table(core.registered_items)
freeze_table(core.registered_nodes)
freeze_table(core.registered_craftitems)
freeze_table(core.registered_tools)
freeze_table(core.registered_aliases)
freeze_table(core.registered_on_mapblocks_changed)
-- neutralize registration functions
core.register_abm = generic_reg_error("ABM")
core.register_lbm = generic_reg_error("LBM")
core.register_item = generic_reg_error("item")
core.unregister_item = function(name)
error("Refusing to unregister item " .. name .. " after load time")
end
core.register_alias = generic_reg_error("alias")
core.register_alias_force = generic_reg_error("alias")
core.register_on_mapblocks_changed = generic_reg_error("on_mapblocks_changed callback")
end)
end)