Liquids: Flow into and destroy 'floodable' nodes
[oweals/minetest.git] / builtin / game / register.lua
index cb084024169d33cc4cebb5ad6ae4fadb50bd3741..ba5f69d67defaab0f7ad940002e3d99255267b77 100644 (file)
@@ -51,20 +51,24 @@ local forbidden_item_names = {
 
 local function check_modname_prefix(name)
        if name:sub(1,1) == ":" then
-               -- Escape the modname prefix enforcement mechanism
+               -- If the name starts with a colon, we can skip the modname prefix
+               -- mechanism.
                return name:sub(2)
        else
-               -- Modname prefix enforcement
+               -- Enforce that the name starts with the correct mod name.
                local expected_prefix = core.get_current_modname() .. ":"
                if name:sub(1, #expected_prefix) ~= expected_prefix then
                        error("Name " .. name .. " does not follow naming conventions: " ..
-                               "\"modname:\" or \":\" prefix required")
+                               "\"" .. expected_prefix .. "\" or \":\" prefix required")
                end
+               
+               -- Enforce that the name only contains letters, numbers and underscores.
                local subname = name:sub(#expected_prefix+1)
-               if subname:find("[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_]") then
+               if subname:find("[^%w_]") then
                        error("Name " .. name .. " does not follow naming conventions: " ..
                                "contains unallowed characters")
                end
+               
                return name
        end
 end
@@ -72,6 +76,7 @@ end
 function core.register_abm(spec)
        -- Add to core.registered_abms
        core.registered_abms[#core.registered_abms+1] = spec
+       spec.mod_origin = core.get_current_modname() or "??"
 end
 
 function core.register_entity(name, prototype)
@@ -86,6 +91,7 @@ function core.register_entity(name, prototype)
 
        -- Add to core.registered_entities
        core.registered_entities[name] = prototype
+       prototype.mod_origin = core.get_current_modname() or "??"
 end
 
 function core.register_item(name, itemdef)
@@ -147,6 +153,8 @@ function core.register_item(name, itemdef)
        end
        -- END Legacy stuff
 
+       itemdef.mod_origin = core.get_current_modname() or "??"
+
        -- Disable all further modifications
        getmetatable(itemdef).__newindex = {}
 
@@ -217,7 +225,7 @@ function core.register_alias(name, convert_to)
                error("Unable to register alias: Name is forbidden: " .. name)
        end
        if core.registered_items[name] ~= nil then
-               core.log("WARNING: Not registering alias, item with same name" ..
+               core.log("warning", "Not registering alias, item with same name" ..
                        " is already defined: " .. name .. " -> " .. convert_to)
        else
                --core.log("Registering alias: " .. name .. " -> " .. convert_to)
@@ -264,6 +272,7 @@ core.register_item(":unknown", {
        description = "Unknown Item",
        inventory_image = "unknown_item.png",
        on_place = core.item_place,
+       on_secondary_use = core.item_secondary_use,
        on_drop = core.item_drop,
        groups = {not_in_creative_inventory=1},
        diggable = true,
@@ -280,6 +289,7 @@ core.register_node(":air", {
        pointable = false,
        diggable = false,
        buildable_to = true,
+       floodable = true,
        air_equivalent = true,
        drop = "",
        groups = {not_in_creative_inventory=1},
@@ -326,6 +336,8 @@ function core.override_item(name, redefinition)
 end
 
 
+core.callback_origins = {}
+
 function core.run_callbacks(callbacks, mode, ...)
        assert(type(callbacks) == "table")
        local cb_len = #callbacks
@@ -338,6 +350,14 @@ function core.run_callbacks(callbacks, mode, ...)
        end
        local ret = nil
        for i = 1, cb_len do
+               local origin = core.callback_origins[callbacks[i]]
+               if origin then
+                       core.set_last_run_mod(origin.mod)
+                       --print("Running " .. tostring(callbacks[i]) ..
+                       --      " (a " .. origin.name .. " callback in " .. origin.mod .. ")")
+               else
+                       --print("No data associated with callback")
+               end
                local cb_ret = callbacks[i](...)
 
                if mode == 0 and i == 1 then
@@ -370,13 +390,29 @@ end
 
 local function make_registration()
        local t = {}
-       local registerfunc = function(func) table.insert(t, func) end
+       local registerfunc = function(func)
+               table.insert(t, func)
+               core.callback_origins[func] = {
+                       mod = core.get_current_modname() or "??",
+                       name = debug.getinfo(1, "n").name or "??"
+               }
+               --local origin = core.callback_origins[func]
+               --print(origin.name .. ": " .. origin.mod .. " registering cbk " .. tostring(func))
+       end
        return t, registerfunc
 end
 
 local function make_registration_reverse()
        local t = {}
-       local registerfunc = function(func) table.insert(t, 1, func) end
+       local registerfunc = function(func)
+               table.insert(t, 1, func)
+               core.callback_origins[func] = {
+                       mod = core.get_current_modname() or "??",
+                       name = debug.getinfo(1, "n").name or "??"
+               }
+               --local origin = core.callback_origins[func]
+               --print(origin.name .. ": " .. origin.mod .. " registering cbk " .. tostring(func))
+       end
        return t, registerfunc
 end
 
@@ -407,6 +443,40 @@ local function make_registration_wrap(reg_fn_name, clear_fn_name)
        return list
 end
 
+core.registered_on_player_hpchanges = { modifiers = { }, loggers = { } }
+
+function core.registered_on_player_hpchange(player, hp_change)
+       local last = false
+       for i = #core.registered_on_player_hpchanges.modifiers, 1, -1 do
+               local func = core.registered_on_player_hpchanges.modifiers[i]
+               hp_change, last = func(player, hp_change)
+               if type(hp_change) ~= "number" then
+                       local debuginfo = debug.getinfo(func)
+                       error("The register_on_hp_changes function has to return a number at " ..
+                               debuginfo.short_src .. " line " .. debuginfo.linedefined)
+               end
+               if last then
+                       break
+               end
+       end
+       for i, func in ipairs(core.registered_on_player_hpchanges.loggers) do
+               func(player, hp_change)
+       end
+       return hp_change
+end
+
+function core.register_on_player_hpchange(func, modifier)
+       if modifier then
+               table.insert(core.registered_on_player_hpchanges.modifiers, func)
+       else
+               table.insert(core.registered_on_player_hpchanges.loggers, func)
+       end
+       core.callback_origins[func] = {
+               mod = core.get_current_modname() or "??",
+               name = debug.getinfo(1, "n").name or "??"
+       }
+end
+
 core.registered_biomes      = make_registration_wrap("register_biome",      "clear_registered_biomes")
 core.registered_ores        = make_registration_wrap("register_ore",        "clear_registered_ores")
 core.registered_decorations = make_registration_wrap("register_decoration", "clear_registered_decorations")
@@ -431,6 +501,7 @@ core.registered_on_crafts, core.register_on_craft = make_registration()
 core.registered_craft_predicts, core.register_craft_predict = make_registration()
 core.registered_on_protection_violation, core.register_on_protection_violation = make_registration()
 core.registered_on_item_eats, core.register_on_item_eat = make_registration()
+core.registered_on_punchplayers, core.register_on_punchplayer = make_registration()
 
 --
 -- Compatibility for on_mapgen_init()