diff options
Diffstat (limited to 'builtin/game')
-rw-r--r-- | builtin/game/auth.lua | 1 | ||||
-rw-r--r-- | builtin/game/chatcommands.lua | 109 | ||||
-rw-r--r-- | builtin/game/detached_inventory.lua | 1 | ||||
-rw-r--r-- | builtin/game/item.lua | 61 | ||||
-rw-r--r-- | builtin/game/item_entity.lua | 113 | ||||
-rw-r--r-- | builtin/game/misc.lua | 90 | ||||
-rw-r--r-- | builtin/game/register.lua | 73 |
7 files changed, 335 insertions, 113 deletions
diff --git a/builtin/game/auth.lua b/builtin/game/auth.lua index 93b009981..423eb3134 100644 --- a/builtin/game/auth.lua +++ b/builtin/game/auth.lua @@ -171,6 +171,7 @@ function core.register_authentication_handler(handler) end core.registered_auth_handler = handler core.registered_auth_handler_modname = core.get_current_modname() + handler.mod_origin = core.registered_auth_handler_modname end function core.get_auth_handler() diff --git a/builtin/game/chatcommands.lua b/builtin/game/chatcommands.lua index 91b685fdf..5d317de4b 100644 --- a/builtin/game/chatcommands.lua +++ b/builtin/game/chatcommands.lua @@ -10,6 +10,7 @@ function core.register_chatcommand(cmd, def) def.params = def.params or "" def.description = def.description or "" def.privs = def.privs or {} + def.mod_origin = core.get_current_modname() or "??" core.chatcommands[cmd] = def end @@ -37,6 +38,7 @@ core.register_on_chat_message(function(name, message) end local has_privs, missing_privs = core.check_player_privs(name, cmd_def.privs) if has_privs then + core.set_last_run_mod(cmd_def.mod_origin) local success, message = cmd_def.func(name, param) if message then core.chat_send_player(name, message) @@ -189,7 +191,7 @@ core.register_chatcommand("revoke", { local revoke_privs = core.string_to_privs(revoke_priv_str) local privs = core.get_player_privs(revoke_name) for priv, _ in pairs(revoke_privs) do - if priv ~= "interact" and priv ~= "shout" and priv ~= "interact_extra" and + if priv ~= "interact" and priv ~= "shout" and not core.check_player_privs(name, {privs=true}) then return false, "Your privileges are insufficient." end @@ -229,21 +231,28 @@ core.register_chatcommand("setpassword", { if not toname then return false, "Name field required" end - local actstr = "?" + local act_str_past = "?" + local act_str_pres = "?" if not raw_password then core.set_player_password(toname, "") - actstr = "cleared" + act_str_past = "cleared" + act_str_pres = "clears" else core.set_player_password(toname, core.get_password_hash(toname, raw_password)) - actstr = "set" + act_str_past = "set" + act_str_pres = "sets" end if toname ~= name then core.chat_send_player(toname, "Your password was " - .. actstr .. " by " .. name) + .. act_str_past .. " by " .. name) end - return true, "Password of player \"" .. toname .. "\" " .. actstr + + core.log("action", name .. " " .. act_str_pres + .. " password of " .. toname .. ".") + + return true, "Password of player \"" .. toname .. "\" " .. act_str_past end, }) @@ -257,6 +266,9 @@ core.register_chatcommand("clearpassword", { return false, "Name field required" end core.set_player_password(toname, '') + + core.log("action", name .. " clears password of " .. toname .. ".") + return true, "Password of player \"" .. toname .. "\" cleared" end, }) @@ -308,7 +320,7 @@ core.register_chatcommand("teleport", { teleportee:setpos(p) return true, "Teleporting to "..core.pos_to_string(p) end - + local teleportee = nil local p = nil local target_name = nil @@ -345,7 +357,7 @@ core.register_chatcommand("teleport", { return true, "Teleporting " .. teleportee_name .. " to " .. core.pos_to_string(p) end - + local teleportee = nil local p = nil local teleportee_name = nil @@ -367,7 +379,7 @@ core.register_chatcommand("teleport", { .. " to " .. target_name .. " at " .. core.pos_to_string(p) end - + return false, 'Invalid parameters ("' .. param .. '") or player not found (see /help teleport)' end, @@ -404,13 +416,14 @@ core.register_chatcommand("set", { }) core.register_chatcommand("deleteblocks", { - params = "[here] [<pos1> <pos2>]", + params = "(here [radius]) | (<pos1> <pos2>)", description = "delete map blocks contained in area pos1 to pos2", privs = {server=true}, func = function(name, param) local p1 = {} local p2 = {} - if param == "here" then + local args = param:split(" ") + if args[1] == "here" then local player = core.get_player_by_name(name) if player == nil then core.log("error", "player is nil") @@ -418,6 +431,12 @@ core.register_chatcommand("deleteblocks", { end p1 = player:getpos() p2 = p1 + + if #args >= 2 then + local radius = tonumber(args[2]) or 0 + p1 = vector.add(p1, radius) + p2 = vector.subtract(p2, radius) + end else local pos1, pos2 = unpack(param:split(") (")) if pos1 == nil or pos2 == nil then @@ -513,22 +532,29 @@ core.register_chatcommand("giveme", { }) core.register_chatcommand("spawnentity", { - params = "<EntityName>", - description = "Spawn entity at your position", + params = "<EntityName> [<X>,<Y>,<Z>]", + description = "Spawn entity at given (or your) position", privs = {give=true, interact=true}, func = function(name, param) - local entityname = string.match(param, "(.+)$") + local entityname, p = string.match(param, "^([^ ]+) *(.*)$") if not entityname then return false, "EntityName required" end - core.log("action", ("/spawnentity invoked, entityname=%q") - :format(entityname)) + core.log("action", ("%s invokes /spawnentity, entityname=%q") + :format(name, entityname)) local player = core.get_player_by_name(name) if player == nil then core.log("error", "Unable to spawn entity, player is nil") return false, "Unable to spawn entity, player is nil" end - local p = player:getpos() + if p == "" then + p = player:getpos() + else + p = core.string_to_pos(p) + if p == nil then + return false, "Invalid parameters ('" .. param .. "')" + end + end p.y = p.y + 1 core.add_entity(p, entityname) return true, ("%q spawned."):format(entityname) @@ -662,19 +688,41 @@ core.register_chatcommand("status", { }) core.register_chatcommand("time", { - params = "<0...24000>", + params = "<0..23>:<0..59> | <0..24000>", description = "set time of day", - privs = {settime=true}, + privs = {}, func = function(name, param) if param == "" then - return false, "Missing time." - end - local newtime = tonumber(param) - if newtime == nil then - return false, "Invalid time." - end - core.set_timeofday((newtime % 24000) / 24000) - core.log("action", name .. " sets time " .. newtime) + local current_time = math.floor(core.get_timeofday() * 1440) + local minutes = current_time % 60 + local hour = (current_time - minutes) / 60 + return true, ("Current time is %d:%02d"):format(hour, minutes) + end + local player_privs = minetest.get_player_privs(name) + if not player_privs.settime then + return false, "You don't have permission to run this command " .. + "(missing privilege: settime)." + end + local hour, minute = param:match("^(%d+):(%d+)$") + if not hour then + local new_time = tonumber(param) + if not new_time then + return false, "Invalid time." + end + -- Backward compatibility. + core.set_timeofday((new_time % 24000) / 24000) + core.log("action", name .. " sets time to " .. new_time) + return true, "Time of day changed." + end + hour = tonumber(hour) + minute = tonumber(minute) + if hour < 0 or hour > 23 then + return false, "Invalid hour (must be between 0 and 23 inclusive)." + elseif minute < 0 or minute > 59 then + return false, "Invalid minute (must be between 0 and 59 inclusive)." + end + core.set_timeofday((hour * 60 + minute) / 1440) + core.log("action", ("%s sets time to %d:%02d"):format(name, hour, minute)) return true, "Time of day changed." end, }) @@ -732,7 +780,11 @@ core.register_chatcommand("kick", { if not core.kick_player(tokick, reason) then return false, "Failed to kick player " .. tokick end - core.log("action", name .. " kicked " .. tokick) + local log_reason = "" + if reason then + log_reason = " with reason \"" .. reason .. "\"" + end + core.log("action", name .. " kicks " .. tokick .. log_reason) return true, "Kicked " .. tokick end, }) @@ -788,4 +840,3 @@ core.register_chatcommand("last-login", { return false, "Last login time is unknown" end, }) - diff --git a/builtin/game/detached_inventory.lua b/builtin/game/detached_inventory.lua index e8f03b56c..b5d106b04 100644 --- a/builtin/game/detached_inventory.lua +++ b/builtin/game/detached_inventory.lua @@ -13,6 +13,7 @@ function core.create_detached_inventory(name, callbacks) stuff.on_put = callbacks.on_put stuff.on_take = callbacks.on_take end + stuff.mod_origin = core.get_current_modname() or "??" core.detached_inventories[name] = stuff return core.create_detached_inventory_raw(name) end diff --git a/builtin/game/item.lua b/builtin/game/item.lua index e136d4f4c..6628a4081 100644 --- a/builtin/game/item.lua +++ b/builtin/game/item.lua @@ -106,7 +106,7 @@ function core.facedir_to_dir(facedir) {x=0, y=1, z=0}}) --indexed into by a table of correlating facedirs - [({[0]=1, 2, 3, 4, + [({[0]=1, 2, 3, 4, 5, 2, 6, 4, 6, 2, 5, 4, 1, 5, 3, 6, @@ -238,7 +238,7 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2) core.log("action", placer:get_player_name() .. " places node " .. def.name .. " at " .. core.pos_to_string(place_to)) - + local oldnode = core.get_node(place_to) local newnode = {name = def.name, param1 = 0, param2 = param2} @@ -357,19 +357,37 @@ function core.item_drop(itemstack, dropper, pos) return itemstack end -function core.item_eat(hp_change, replace_with_item) - return function(itemstack, user, pointed_thing) -- closure - for _, callback in pairs(core.registered_on_item_eats) do - local result = callback(hp_change, replace_with_item, itemstack, user, pointed_thing) - if result then - return result - end +function core.do_item_eat(hp_change, replace_with_item, itemstack, user, pointed_thing) + for _, callback in pairs(core.registered_on_item_eats) do + local result = callback(hp_change, replace_with_item, itemstack, user, pointed_thing) + if result then + return result end - if itemstack:take_item() ~= nil then - user:set_hp(user:get_hp() + hp_change) - itemstack:add_item(replace_with_item) -- note: replace_with_item is optional + end + if itemstack:take_item() ~= nil then + user:set_hp(user:get_hp() + hp_change) + + if replace_with_item then + if itemstack:is_empty() then + itemstack:add_item(replace_with_item) + else + local inv = user:get_inventory() + if inv:room_for_item("main", {name=replace_with_item}) then + inv:add_item("main", replace_with_item) + else + local pos = user:getpos() + pos.y = math.floor(pos.y + 0.5) + core.add_item(pos, replace_with_item) + end + end end - return itemstack + end + return itemstack +end + +function core.item_eat(hp_change, replace_with_item) + return function(itemstack, user, pointed_thing) -- closure + return core.do_item_eat(hp_change, replace_with_item, itemstack, user, pointed_thing) end end @@ -425,7 +443,7 @@ function core.node_dig(pos, node, digger) local wielded = digger:get_wielded_item() local drops = core.get_node_drops(node.name, wielded:get_name()) - + local wdef = wielded:get_definition() local tp = wielded:get_tool_capabilities() local dp = core.get_dig_params(def.groups, tp) @@ -438,7 +456,7 @@ function core.node_dig(pos, node, digger) end end digger:set_wielded_item(wielded) - + -- Handle drops core.handle_node_drops(pos, drops, digger) @@ -449,7 +467,7 @@ function core.node_dig(pos, node, digger) -- Remove node and update core.remove_node(pos) - + -- Run callback if def.after_dig_node then -- Copy pos and node because callback can modify them @@ -461,6 +479,15 @@ function core.node_dig(pos, node, digger) -- Run script hook local _, callback for _, callback in ipairs(core.registered_on_dignodes) do + local origin = core.callback_origins[callback] + if origin then + core.set_last_run_mod(origin.mod) + --print("Running " .. tostring(callback) .. + -- " (a " .. origin.name .. " callback in " .. origin.mod .. ")") + else + --print("No data associated with callback") + end + -- Copy pos and node because callback can modify them local pos_copy = {x=pos.x, y=pos.y, z=pos.z} local node_copy = {name=node.name, param1=node.param1, param2=node.param2} @@ -507,7 +534,7 @@ core.nodedef_default = { on_dig = redef_wrapper(core, 'node_dig'), -- core.node_dig on_receive_fields = nil, - + on_metadata_inventory_move = core.node_metadata_inventory_move_allow_all, on_metadata_inventory_offer = core.node_metadata_inventory_offer_allow_all, on_metadata_inventory_take = core.node_metadata_inventory_take_allow_all, diff --git a/builtin/game/item_entity.lua b/builtin/game/item_entity.lua index d6781feca..6425a10aa 100644 --- a/builtin/game/item_entity.lua +++ b/builtin/game/item_entity.lua @@ -96,6 +96,56 @@ core.register_entity(":__builtin:item", { self:set_item(self.itemstring) end, + try_merge_with = function(self, own_stack, object, obj) + local stack = ItemStack(obj.itemstring) + if own_stack:get_name() == stack:get_name() and stack:get_free_space() > 0 then + local overflow = false + local count = stack:get_count() + own_stack:get_count() + local max_count = stack:get_stack_max() + if count > max_count then + overflow = true + count = count - max_count + else + self.itemstring = '' + end + local pos = object:getpos() + pos.y = pos.y + (count - stack:get_count()) / max_count * 0.15 + object:moveto(pos, false) + local s, c + local max_count = stack:get_stack_max() + local name = stack:get_name() + if not overflow then + obj.itemstring = name .. " " .. count + s = 0.2 + 0.1 * (count / max_count) + c = s + object:set_properties({ + visual_size = {x = s, y = s}, + collisionbox = {-c, -c, -c, c, c, c} + }) + self.object:remove() + -- merging succeeded + return true + else + s = 0.4 + c = 0.3 + object:set_properties({ + visual_size = {x = s, y = s}, + collisionbox = {-c, -c, -c, c, c, c} + }) + obj.itemstring = name .. " " .. max_count + s = 0.2 + 0.1 * (count / max_count) + c = s + self.object:set_properties({ + visual_size = {x = s, y = s}, + collisionbox = {-c, -c, -c, c, c, c} + }) + self.itemstring = name .. " " .. count + end + end + -- merging didn't succeed + return false + end, + on_step = function(self, dtime) self.age = self.age + dtime if time_to_live > 0 and self.age > time_to_live then @@ -105,58 +155,29 @@ core.register_entity(":__builtin:item", { end local p = self.object:getpos() p.y = p.y - 0.5 - local nn = core.get_node(p).name + local node = core.get_node_or_nil(p) + local in_unloaded = (node == nil) + if in_unloaded then + -- Don't infinetly fall into unloaded map + self.object:setvelocity({x = 0, y = 0, z = 0}) + self.object:setacceleration({x = 0, y = 0, z = 0}) + self.physical_state = false + self.object:set_properties({physical = false}) + return + end + local nn = node.name -- If node is not registered or node is walkably solid and resting on nodebox local v = self.object:getvelocity() if not core.registered_nodes[nn] or core.registered_nodes[nn].walkable and v.y == 0 then if self.physical_state then local own_stack = ItemStack(self.object:get_luaentity().itemstring) - for _,object in ipairs(core.get_objects_inside_radius(p, 0.8)) do + -- Merge with close entities of the same item + for _, object in ipairs(core.get_objects_inside_radius(p, 0.8)) do local obj = object:get_luaentity() - if obj and obj.name == "__builtin:item" and obj.physical_state == false then - local stack = ItemStack(obj.itemstring) - if own_stack:get_name() == stack:get_name() and stack:get_free_space() > 0 then - local overflow = false - local count = stack:get_count() + own_stack:get_count() - local max_count = stack:get_stack_max() - if count>max_count then - overflow = true - count = count - max_count - else - self.itemstring = '' - end - local pos=object:getpos() - pos.y = pos.y + (count - stack:get_count()) / max_count * 0.15 - object:moveto(pos, false) - local s, c - local max_count = stack:get_stack_max() - local name = stack:get_name() - if not overflow then - obj.itemstring = name.." "..count - s = 0.2 + 0.1 * (count / max_count) - c = s - object:set_properties({ - visual_size = {x = s, y = s}, - collisionbox = {-c, -c, -c, c, c, c} - }) - self.object:remove() - return - else - s = 0.4 - c = 0.3 - object:set_properties({ - visual_size = {x = s, y = s}, - collisionbox = {-c, -c, -c, c, c, c} - }) - obj.itemstring = name.." "..max_count - s = 0.2 + 0.1 * (count / max_count) - c = s - self.object:set_properties({ - visual_size = {x = s, y = s}, - collisionbox = {-c, -c, -c, c, c, c} - }) - self.itemstring = name.." "..count - end + if obj and obj.name == "__builtin:item" + and obj.physical_state == false then + if self:try_merge_with(own_stack, object, obj) then + return end end end diff --git a/builtin/game/misc.lua b/builtin/game/misc.lua index c31df541d..e3b7d82bc 100644 --- a/builtin/game/misc.lua +++ b/builtin/game/misc.lua @@ -4,40 +4,83 @@ -- Misc. API functions -- -core.timers_to_add = {} -core.timers = {} -core.register_globalstep(function(dtime) - for _, timer in ipairs(core.timers_to_add) do - table.insert(core.timers, timer) - end - core.timers_to_add = {} - local index = 1 - while index <= #core.timers do - local timer = core.timers[index] - timer.time = timer.time - dtime +local timers = {} +local mintime +local function update_timers(delay) + mintime = false + local sub = 0 + for index = 1, #timers do + index = index - sub + local timer = timers[index] + timer.time = timer.time - delay if timer.time <= 0 then + core.set_last_run_mod(timer.mod_origin) timer.func(unpack(timer.args or {})) - table.remove(core.timers,index) + table.remove(timers, index) + sub = sub + 1 + elseif mintime then + mintime = math.min(mintime, timer.time) else - index = index + 1 + mintime = timer.time end end +end + +local timers_to_add +local function add_timers() + for _, timer in ipairs(timers_to_add) do + table.insert(timers, timer) + end + timers_to_add = false +end + +local delay = 0 +core.register_globalstep(function(dtime) + if not mintime then + -- abort if no timers are running + return + end + if timers_to_add then + add_timers() + end + delay = delay + dtime + if delay < mintime then + return + end + update_timers(delay) + delay = 0 end) function core.after(time, func, ...) assert(tonumber(time) and type(func) == "function", "Invalid core.after invocation") - table.insert(core.timers_to_add, {time=time, func=func, args={...}}) + if not mintime then + mintime = time + timers_to_add = {{ + time = time+delay, + func = func, + args = {...}, + mod_origin = core.get_last_run_mod(), + }} + return + end + mintime = math.min(mintime, time) + timers_to_add = timers_to_add or {} + timers_to_add[#timers_to_add+1] = { + time = time+delay, + func = func, + args = {...}, + mod_origin = core.get_last_run_mod(), + } end function core.check_player_privs(name, privs) local player_privs = core.get_player_privs(name) local missing_privileges = {} for priv, val in pairs(privs) do - if val then - if not player_privs[priv] then - table.insert(missing_privileges, priv) - end + if val + and not player_privs[priv] then + table.insert(missing_privileges, priv) end end if #missing_privileges > 0 then @@ -112,3 +155,14 @@ function core.record_protection_violation(pos, name) end end +local raillike_ids = {} +local raillike_cur_id = 0 +function core.raillike_group(name) + local id = raillike_ids[name] + if not id then + raillike_cur_id = raillike_cur_id + 1 + raillike_ids[name] = raillike_cur_id + id = raillike_cur_id + end + return id +end diff --git a/builtin/game/register.lua b/builtin/game/register.lua index f286113ec..d0e04bfc3 100644 --- a/builtin/game/register.lua +++ b/builtin/game/register.lua @@ -72,6 +72,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 +87,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 +149,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 = {} @@ -326,6 +330,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 +344,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 +384,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 @@ -398,13 +428,49 @@ local function make_registration_wrap(reg_fn_name, clear_fn_name) local orig_clear_fn = core[clear_fn_name] core[clear_fn_name] = function() - list = {} + for k in pairs(list) do + list[k] = nil + end return orig_clear_fn() end 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") @@ -429,6 +495,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() |