aboutsummaryrefslogtreecommitdiff
path: root/builtin/game
diff options
context:
space:
mode:
Diffstat (limited to 'builtin/game')
-rw-r--r--builtin/game/auth.lua16
-rw-r--r--builtin/game/chatcommands.lua124
-rw-r--r--builtin/game/constants.lua10
-rw-r--r--builtin/game/detached_inventory.lua4
-rw-r--r--builtin/game/falling.lua110
-rw-r--r--builtin/game/forceloading.lua41
-rw-r--r--builtin/game/init.lua14
-rw-r--r--builtin/game/item.lua11
-rw-r--r--builtin/game/item_entity.lua4
-rw-r--r--builtin/game/misc.lua64
-rw-r--r--builtin/game/mod_profiling.lua356
-rw-r--r--builtin/game/privileges.lua64
-rw-r--r--builtin/game/register.lua43
-rw-r--r--builtin/game/voxelarea.lua49
14 files changed, 404 insertions, 506 deletions
diff --git a/builtin/game/auth.lua b/builtin/game/auth.lua
index deb811b14..46fe3d342 100644
--- a/builtin/game/auth.lua
+++ b/builtin/game/auth.lua
@@ -199,3 +199,19 @@ core.register_on_joinplayer(function(player)
record_login(player:get_player_name())
end)
+core.register_on_prejoinplayer(function(name, ip)
+ local auth = core.auth_table
+ if auth[name] ~= nil then
+ return
+ end
+
+ local name_lower = name:lower()
+ for k in pairs(auth) do
+ if k:lower() == name_lower then
+ return string.format("\nCannot create new player called '%s'. "..
+ "Another account called '%s' is already registered. "..
+ "Please check the spelling if it's your account "..
+ "or use a different nickname.", name, k)
+ end
+ end
+end)
diff --git a/builtin/game/chatcommands.lua b/builtin/game/chatcommands.lua
index 3350140ee..2bd93855b 100644
--- a/builtin/game/chatcommands.lua
+++ b/builtin/game/chatcommands.lua
@@ -14,19 +14,6 @@ function core.register_chatcommand(cmd, def)
core.chatcommands[cmd] = def
end
-if core.setting_getbool("mod_profiling") then
- local tracefct = profiling_print_log
- profiling_print_log = nil
- core.register_chatcommand("save_mod_profile",
- {
- params = "",
- description = "save mod profiling data to logfile " ..
- "(depends on default loglevel)",
- func = tracefct,
- privs = { server=true }
- })
-end
-
core.register_on_chat_message(function(name, message)
local cmd, param = string.match(message, "^/([^ ]+) *(.*)")
if not param then
@@ -51,6 +38,12 @@ core.register_on_chat_message(function(name, message)
return true -- Handled chat message
end)
+if core.setting_getbool("profiler.load") then
+ -- Run after register_chatcommand and its register_on_chat_message
+ -- Before any chattcommands that should be profiled
+ profiler.init_chatcommand()
+end
+
-- Parses a "range" string in the format of "here (number)" or
-- "(x1, y1, z1) (x2, y2, z2)", returning two position vectors
local function parse_range_str(player_name, str)
@@ -102,7 +95,7 @@ core.register_chatcommand("help", {
description = "Get help for commands or list privileges",
func = function(name, param)
local function format_help_line(cmd, def)
- local msg = "/"..cmd
+ local msg = core.colorize("#00ffff", "/"..cmd)
if def.params and def.params ~= "" then
msg = msg .. " " .. def.params
end
@@ -154,60 +147,79 @@ core.register_chatcommand("help", {
core.register_chatcommand("privs", {
params = "<name>",
description = "print out privileges of player",
- func = function(name, param)
- param = (param ~= "" and param or name)
- return true, "Privileges of " .. param .. ": "
+ func = function(caller, param)
+ param = param:trim()
+ local name = (param ~= "" and param or caller)
+ return true, "Privileges of " .. name .. ": "
.. core.privs_to_string(
- core.get_player_privs(param), ' ')
+ core.get_player_privs(name), ' ')
end,
})
+
+local function handle_grant_command(caller, grantname, grantprivstr)
+ local caller_privs = minetest.get_player_privs(caller)
+ if not (caller_privs.privs or caller_privs.basic_privs) then
+ return false, "Your privileges are insufficient."
+ end
+
+ if not core.auth_table[grantname] then
+ return false, "Player " .. grantname .. " does not exist."
+ end
+ local grantprivs = core.string_to_privs(grantprivstr)
+ if grantprivstr == "all" then
+ grantprivs = core.registered_privileges
+ end
+ local privs = core.get_player_privs(grantname)
+ local privs_unknown = ""
+ local basic_privs =
+ core.string_to_privs(core.setting_get("basic_privs") or "interact,shout")
+ for priv, _ in pairs(grantprivs) do
+ if not basic_privs[priv] and not caller_privs.privs then
+ return false, "Your privileges are insufficient."
+ end
+ if not core.registered_privileges[priv] then
+ privs_unknown = privs_unknown .. "Unknown privilege: " .. priv .. "\n"
+ end
+ privs[priv] = true
+ end
+ if privs_unknown ~= "" then
+ return false, privs_unknown
+ end
+ core.set_player_privs(grantname, privs)
+ core.log("action", caller..' granted ('..core.privs_to_string(grantprivs, ', ')..') privileges to '..grantname)
+ if grantname ~= caller then
+ core.chat_send_player(grantname, caller
+ .. " granted you privileges: "
+ .. core.privs_to_string(grantprivs, ' '))
+ end
+ return true, "Privileges of " .. grantname .. ": "
+ .. core.privs_to_string(
+ core.get_player_privs(grantname), ' ')
+end
+
core.register_chatcommand("grant", {
params = "<name> <privilege>|all",
description = "Give privilege to player",
func = function(name, param)
- if not core.check_player_privs(name, {privs=true}) and
- not core.check_player_privs(name, {basic_privs=true}) then
- return false, "Your privileges are insufficient."
- end
local grantname, grantprivstr = string.match(param, "([^ ]+) (.+)")
if not grantname or not grantprivstr then
return false, "Invalid parameters (see /help grant)"
- elseif not core.auth_table[grantname] then
- return false, "Player " .. grantname .. " does not exist."
- end
- local grantprivs = core.string_to_privs(grantprivstr)
- if grantprivstr == "all" then
- grantprivs = core.registered_privileges
- end
- local privs = core.get_player_privs(grantname)
- local privs_unknown = ""
- local basic_privs =
- core.string_to_privs(core.setting_get("basic_privs") or "interact,shout")
- for priv, _ in pairs(grantprivs) do
- if not basic_privs[priv] and
- not core.check_player_privs(name, {privs=true}) then
- return false, "Your privileges are insufficient."
- end
- if not core.registered_privileges[priv] then
- privs_unknown = privs_unknown .. "Unknown privilege: " .. priv .. "\n"
- end
- privs[priv] = true
- end
- if privs_unknown ~= "" then
- return false, privs_unknown
- end
- core.set_player_privs(grantname, privs)
- core.log("action", name..' granted ('..core.privs_to_string(grantprivs, ', ')..') privileges to '..grantname)
- if grantname ~= name then
- core.chat_send_player(grantname, name
- .. " granted you privileges: "
- .. core.privs_to_string(grantprivs, ' '))
- end
- return true, "Privileges of " .. grantname .. ": "
- .. core.privs_to_string(
- core.get_player_privs(grantname), ' ')
+ end
+ return handle_grant_command(name, grantname, grantprivstr)
+ end,
+})
+
+core.register_chatcommand("grantme", {
+ params = "<privilege>|all",
+ description = "Grant privileges to yourself",
+ func = function(name, param)
+ if param == "" then
+ return false, "Invalid parameters (see /help grantme)"
+ end
+ return handle_grant_command(name, name, param)
end,
})
+
core.register_chatcommand("revoke", {
params = "<name> <privilege>|all",
description = "Remove privilege from player",
diff --git a/builtin/game/constants.lua b/builtin/game/constants.lua
index d0b7c753c..50c515b24 100644
--- a/builtin/game/constants.lua
+++ b/builtin/game/constants.lua
@@ -4,14 +4,24 @@
-- Constants values for use with the Lua API
--
+-- mapnode.h
-- Built-in Content IDs (for use with VoxelManip API)
core.CONTENT_UNKNOWN = 125
core.CONTENT_AIR = 126
core.CONTENT_IGNORE = 127
+-- emerge.h
-- Block emerge status constants (for use with core.emerge_area)
core.EMERGE_CANCELLED = 0
core.EMERGE_ERRORED = 1
core.EMERGE_FROM_MEMORY = 2
core.EMERGE_FROM_DISK = 3
core.EMERGE_GENERATED = 4
+
+-- constants.h
+-- Size of mapblocks in nodes
+core.MAP_BLOCKSIZE = 16
+
+-- light.h
+-- Maximum value for node 'light_source' parameter
+core.LIGHT_MAX = 14
diff --git a/builtin/game/detached_inventory.lua b/builtin/game/detached_inventory.lua
index b5d106b04..420e89ff2 100644
--- a/builtin/game/detached_inventory.lua
+++ b/builtin/game/detached_inventory.lua
@@ -2,7 +2,7 @@
core.detached_inventories = {}
-function core.create_detached_inventory(name, callbacks)
+function core.create_detached_inventory(name, callbacks, player_name)
local stuff = {}
stuff.name = name
if callbacks then
@@ -15,6 +15,6 @@ function core.create_detached_inventory(name, callbacks)
end
stuff.mod_origin = core.get_current_modname() or "??"
core.detached_inventories[name] = stuff
- return core.create_detached_inventory_raw(name)
+ return core.create_detached_inventory_raw(name, player_name)
end
diff --git a/builtin/game/falling.lua b/builtin/game/falling.lua
index 57bb98cfd..4696ce481 100644
--- a/builtin/game/falling.lua
+++ b/builtin/game/falling.lua
@@ -1,5 +1,7 @@
-- Minetest: builtin/item.lua
+local builtin_shared = ...
+
--
-- Falling stuff
--
@@ -41,19 +43,20 @@ core.register_entity(":__builtin:falling_node", {
end,
on_step = function(self, dtime)
- -- Set gravity
+ -- Set gravity
local acceleration = self.object:getacceleration()
if not vector.equals(acceleration, {x = 0, y = -10, z = 0}) then
self.object:setacceleration({x = 0, y = -10, z = 0})
end
- -- Turn to actual sand when collides to ground or just move
+ -- Turn to actual node when colliding with ground, or continue to move
local pos = self.object:getpos()
- local bcp = {x = pos.x, y = pos.y - 0.7, z = pos.z} -- Position of bottom center point
- local bcn = core.get_node(bcp)
- local bcd = core.registered_nodes[bcn.name]
- -- Note: walkable is in the node definition, not in item groups
- if not bcd or
- (bcd.walkable or
+ -- Position of bottom center point
+ local bcp = {x = pos.x, y = pos.y - 0.7, z = pos.z}
+ -- Avoid bugs caused by an unloaded node below
+ local bcn = core.get_node_or_nil(bcp)
+ local bcd = bcn and core.registered_nodes[bcn.name]
+ if bcn and
+ (not bcd or bcd.walkable or
(core.get_item_group(self.node.name, "float") ~= 0 and
bcd.liquidtype ~= "none")) then
if bcd and bcd.leveled and
@@ -75,20 +78,20 @@ core.register_entity(":__builtin:falling_node", {
local np = {x = bcp.x, y = bcp.y + 1, z = bcp.z}
-- Check what's here
local n2 = core.get_node(np)
+ local nd = core.registered_nodes[n2.name]
-- If it's not air or liquid, remove node and replace it with
-- it's drops
- if n2.name ~= "air" and (not core.registered_nodes[n2.name] or
- core.registered_nodes[n2.name].liquidtype == "none") then
+ if n2.name ~= "air" and (not nd or nd.liquidtype == "none") then
core.remove_node(np)
- if core.registered_nodes[n2.name].buildable_to == false then
+ if nd.buildable_to == false then
-- Add dropped items
local drops = core.get_node_drops(n2.name, "")
- for _, dropped_item in ipairs(drops) do
+ for _, dropped_item in pairs(drops) do
core.add_item(np, dropped_item)
end
end
-- Run script hook
- for _, callback in ipairs(core.registered_on_dignodes) do
+ for _, callback in pairs(core.registered_on_dignodes) do
callback(np, n2)
end
end
@@ -97,7 +100,7 @@ core.register_entity(":__builtin:falling_node", {
core.add_node(np, self.node)
end
self.object:remove()
- nodeupdate(np)
+ core.check_for_falling(np)
return
end
local vel = self.object:getvelocity()
@@ -108,15 +111,17 @@ core.register_entity(":__builtin:falling_node", {
end
})
-function spawn_falling_node(p, node)
+local function spawn_falling_node(p, node)
local obj = core.add_entity(p, "__builtin:falling_node")
- obj:get_luaentity():set_node(node)
+ if obj then
+ obj:get_luaentity():set_node(node)
+ end
end
-function drop_attached_node(p)
+local function drop_attached_node(p)
local nn = core.get_node(p).name
core.remove_node(p)
- for _, item in ipairs(core.get_node_drops(nn, "")) do
+ for _, item in pairs(core.get_node_drops(nn, "")) do
local pos = {
x = p.x + math.random()/2 - 0.25,
y = p.y + math.random()/2 - 0.25,
@@ -126,11 +131,15 @@ function drop_attached_node(p)
end
end
-function check_attached_node(p, n)
+function builtin_shared.check_attached_node(p, n)
local def = core.registered_nodes[n.name]
local d = {x = 0, y = 0, z = 0}
if def.paramtype2 == "wallmounted" then
- d = core.wallmounted_to_dir(n.param2)
+ -- The fallback vector here is in case 'wallmounted to dir' is nil due
+ -- to voxelmanip placing a wallmounted node without resetting a
+ -- pre-existing param2 value that is out-of-range for wallmounted.
+ -- The fallback vector corresponds to param2 = 0.
+ d = core.wallmounted_to_dir(n.param2) or {x = 0, y = 1, z = 0}
else
d.y = -1
end
@@ -147,19 +156,23 @@ end
-- Some common functions
--
-function nodeupdate_single(p)
+function core.check_single_for_falling(p)
local n = core.get_node(p)
if core.get_item_group(n.name, "falling_node") ~= 0 then
local p_bottom = {x = p.x, y = p.y - 1, z = p.z}
- local n_bottom = core.get_node(p_bottom)
- -- Note: walkable is in the node definition, not in item groups
- if core.registered_nodes[n_bottom.name] and
+ -- Only spawn falling node if node below is loaded
+ local n_bottom = core.get_node_or_nil(p_bottom)
+ local d_bottom = n_bottom and core.registered_nodes[n_bottom.name]
+ if d_bottom and
+
(core.get_item_group(n.name, "float") == 0 or
- core.registered_nodes[n_bottom.name].liquidtype == "none") and
- (n.name ~= n_bottom.name or (core.registered_nodes[n_bottom.name].leveled and
- core.get_node_level(p_bottom) < core.get_node_max_level(p_bottom))) and
- (not core.registered_nodes[n_bottom.name].walkable or
- core.registered_nodes[n_bottom.name].buildable_to) then
+ d_bottom.liquidtype == "none") and
+
+ (n.name ~= n_bottom.name or (d_bottom.leveled and
+ core.get_node_level(p_bottom) <
+ core.get_node_max_level(p_bottom))) and
+
+ (not d_bottom.walkable or d_bottom.buildable_to) then
n.level = core.get_node_level(p)
core.remove_node(p)
spawn_falling_node(p, n)
@@ -168,7 +181,7 @@ function nodeupdate_single(p)
end
if core.get_item_group(n.name, "attached_node") ~= 0 then
- if not check_attached_node(p, n) then
+ if not builtin_shared.check_attached_node(p, n) then
drop_attached_node(p)
return true
end
@@ -181,7 +194,7 @@ end
-- We don't walk diagonals, only our direct neighbors, and self.
-- Down first as likely case, but always before self. The same with sides.
-- Up must come last, so that things above self will also fall all at once.
-local nodeupdate_neighbors = {
+local check_for_falling_neighbors = {
{x = -1, y = -1, z = 0},
{x = 1, y = -1, z = 0},
{x = 0, y = -1, z = -1},
@@ -195,7 +208,7 @@ local nodeupdate_neighbors = {
{x = 0, y = 1, z = 0},
}
-function nodeupdate(p)
+function core.check_for_falling(p)
-- Round p to prevent falling entities to get stuck.
p = vector.round(p)
@@ -214,10 +227,10 @@ function nodeupdate(p)
n = n + 1
s[n] = {p = p, v = v}
-- Select next node from neighbor list.
- p = vector.add(p, nodeupdate_neighbors[v])
+ p = vector.add(p, check_for_falling_neighbors[v])
-- Now we check out the node. If it is in need of an update,
-- it will let us know in the return value (true = updated).
- if not nodeupdate_single(p) then
+ if not core.check_single_for_falling(p) then
-- If we don't need to "recurse" (walk) to it then pop
-- our previous pos off the stack and continue from there,
-- with the v value we were at when we last were at that
@@ -249,12 +262,33 @@ end
-- Global callbacks
--
-function on_placenode(p, node)
- nodeupdate(p)
+local function on_placenode(p, node)
+ core.check_for_falling(p)
end
core.register_on_placenode(on_placenode)
-function on_dignode(p, node)
- nodeupdate(p)
+local function on_dignode(p, node)
+ core.check_for_falling(p)
end
core.register_on_dignode(on_dignode)
+
+local function on_punchnode(p, node)
+ core.check_for_falling(p)
+end
+core.register_on_punchnode(on_punchnode)
+
+--
+-- Globally exported functions
+--
+
+-- TODO remove this function after the 0.4.15 release
+function nodeupdate(p)
+ core.log("deprecated", "nodeupdate: deprecated, please use core.check_for_falling instead")
+ core.check_for_falling(p)
+end
+
+-- TODO remove this function after the 0.4.15 release
+function nodeupdate_single(p)
+ core.log("deprecated", "nodeupdate_single: deprecated, please use core.check_single_for_falling instead")
+ core.check_single_for_falling(p)
+end
diff --git a/builtin/game/forceloading.lua b/builtin/game/forceloading.lua
index 8c9fbf512..8a05de36c 100644
--- a/builtin/game/forceloading.lua
+++ b/builtin/game/forceloading.lua
@@ -5,9 +5,10 @@ core.forceload_block = nil
core.forceload_free_block = nil
local blocks_forceloaded
+local blocks_temploaded = {}
local total_forceloaded = 0
-local BLOCKSIZE = 16
+local BLOCKSIZE = core.MAP_BLOCKSIZE
local function get_blockpos(pos)
return {
x = math.floor(pos.x/BLOCKSIZE),
@@ -15,32 +16,52 @@ local function get_blockpos(pos)
z = math.floor(pos.z/BLOCKSIZE)}
end
-function core.forceload_block(pos)
+-- When we create/free a forceload, it's either transient or persistent. We want
+-- to add to/remove from the table that corresponds to the type of forceload, but
+-- we also need the other table because whether we forceload a block depends on
+-- both tables.
+-- This function returns the "primary" table we are adding to/removing from, and
+-- the other table.
+local function get_relevant_tables(transient)
+ if transient then
+ return blocks_temploaded, blocks_forceloaded
+ else
+ return blocks_forceloaded, blocks_temploaded
+ end
+end
+
+function core.forceload_block(pos, transient)
local blockpos = get_blockpos(pos)
local hash = core.hash_node_position(blockpos)
- if blocks_forceloaded[hash] ~= nil then
- blocks_forceloaded[hash] = blocks_forceloaded[hash] + 1
+ local relevant_table, other_table = get_relevant_tables(transient)
+ if relevant_table[hash] ~= nil then
+ relevant_table[hash] = relevant_table[hash] + 1
return true
+ elseif other_table[hash] ~= nil then
+ relevant_table[hash] = 1
else
if total_forceloaded >= (tonumber(core.setting_get("max_forceloaded_blocks")) or 16) then
return false
end
total_forceloaded = total_forceloaded+1
- blocks_forceloaded[hash] = 1
+ relevant_table[hash] = 1
forceload_block(blockpos)
return true
end
end
-function core.forceload_free_block(pos)
+function core.forceload_free_block(pos, transient)
local blockpos = get_blockpos(pos)
local hash = core.hash_node_position(blockpos)
- if blocks_forceloaded[hash] == nil then return end
- if blocks_forceloaded[hash] > 1 then
- blocks_forceloaded[hash] = blocks_forceloaded[hash] - 1
+ local relevant_table, other_table = get_relevant_tables(transient)
+ if relevant_table[hash] == nil then return end
+ if relevant_table[hash] > 1 then
+ relevant_table[hash] = relevant_table[hash] - 1
+ elseif other_table[hash] ~= nil then
+ relevant_table[hash] = nil
else
total_forceloaded = total_forceloaded-1
- blocks_forceloaded[hash] = nil
+ relevant_table[hash] = nil
forceload_free_block(blockpos)
end
end
diff --git a/builtin/game/init.lua b/builtin/game/init.lua
index a6cfa3bf8..b5e2f7cca 100644
--- a/builtin/game/init.lua
+++ b/builtin/game/init.lua
@@ -3,14 +3,18 @@ local scriptpath = core.get_builtin_path()..DIR_DELIM
local commonpath = scriptpath.."common"..DIR_DELIM
local gamepath = scriptpath.."game"..DIR_DELIM
+-- Shared between builtin files, but
+-- not exposed to outer context
+local builtin_shared = {}
+
dofile(commonpath.."vector.lua")
dofile(gamepath.."constants.lua")
-dofile(gamepath.."item.lua")
+assert(loadfile(gamepath.."item.lua"))(builtin_shared)
dofile(gamepath.."register.lua")
-if core.setting_getbool("mod_profiling") then
- dofile(gamepath.."mod_profiling.lua")
+if core.setting_getbool("profiler.load") then
+ profiler = dofile(scriptpath.."profiler"..DIR_DELIM.."init.lua")
end
dofile(gamepath.."item_entity.lua")
@@ -21,8 +25,10 @@ dofile(gamepath.."auth.lua")
dofile(gamepath.."chatcommands.lua")
dofile(gamepath.."static_spawn.lua")
dofile(gamepath.."detached_inventory.lua")
-dofile(gamepath.."falling.lua")
+assert(loadfile(gamepath.."falling.lua"))(builtin_shared)
dofile(gamepath.."features.lua")
dofile(gamepath.."voxelarea.lua")
dofile(gamepath.."forceloading.lua")
dofile(gamepath.."statbars.lua")
+
+profiler = nil
diff --git a/builtin/game/item.lua b/builtin/game/item.lua
index 36c2c1a68..bf456a4e0 100644
--- a/builtin/game/item.lua
+++ b/builtin/game/item.lua
@@ -1,5 +1,7 @@
-- Minetest: builtin/item.lua
+local builtin_shared = ...
+
local function copy_pointed_thing(pointed_thing)
return {
type = pointed_thing.type,
@@ -250,7 +252,9 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2)
local newnode = {name = def.name, param1 = 0, param2 = param2}
-- Calculate direction for wall mounted stuff like torches and signs
- if def.paramtype2 == 'wallmounted' and not param2 then
+ if def.place_param2 ~= nil then
+ newnode.param2 = def.place_param2
+ elseif def.paramtype2 == 'wallmounted' and not param2 then
local dir = {
x = under.x - above.x,
y = under.y - above.y,
@@ -273,7 +277,7 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2)
-- Check if the node is attached and if it can be placed there
if core.get_item_group(def.name, "attached_node") ~= 0 and
- not check_attached_node(place_to, newnode) then
+ not builtin_shared.check_attached_node(place_to, newnode) then
core.log("action", "attached node " .. def.name ..
" can not be placed at " .. core.pos_to_string(place_to))
return itemstack, false
@@ -470,6 +474,9 @@ function core.node_dig(pos, node, digger)
-- Wear out tool
if not core.setting_getbool("creative_mode") then
wielded:add_wear(dp.wear)
+ if wielded:get_count() == 0 and wdef.sound and wdef.sound.breaks then
+ core.sound_play(wdef.sound.breaks, {pos = pos, gain = 0.5})
+ end
end
end
digger:set_wielded_item(wielded)
diff --git a/builtin/game/item_entity.lua b/builtin/game/item_entity.lua
index a66bf33d0..be158c119 100644
--- a/builtin/game/item_entity.lua
+++ b/builtin/game/item_entity.lua
@@ -31,7 +31,6 @@ core.register_entity(":__builtin:item", {
spritediv = {x = 1, y = 1},
initial_sprite_basepos = {x = 0, y = 0},
is_visible = false,
- infotext = "",
},
itemstring = '',
@@ -51,7 +50,6 @@ core.register_entity(":__builtin:item", {
local c = s
local itemtable = stack:to_table()
local itemname = nil
- local description = ""
if itemtable then
itemname = stack:to_table().name
end
@@ -60,7 +58,6 @@ core.register_entity(":__builtin:item", {
if core.registered_items[itemname] then
item_texture = core.registered_items[itemname].inventory_image
item_type = core.registered_items[itemname].type
- description = core.registered_items[itemname].description
end
local prop = {
is_visible = true,
@@ -69,7 +66,6 @@ core.register_entity(":__builtin:item", {
visual_size = {x = s, y = s},
collisionbox = {-c, -c, -c, c, c, c},
automatic_rotate = math.pi * 0.5,
- infotext = description,
}
self.object:set_properties(prop)
end,
diff --git a/builtin/game/misc.lua b/builtin/game/misc.lua
index de41cfc91..7caa9e7ba 100644
--- a/builtin/game/misc.lua
+++ b/builtin/game/misc.lua
@@ -38,7 +38,7 @@ core.register_globalstep(function(dtime)
end)
function core.after(after, func, ...)
- assert(tonumber(time) and type(func) == "function",
+ assert(tonumber(after) and type(func) == "function",
"Invalid core.after invocation")
jobs[#jobs + 1] = {
func = func,
@@ -48,11 +48,13 @@ function core.after(after, func, ...)
}
end
-function core.check_player_privs(player_or_name, ...)
- local name = player_or_name
- -- Check if we have been provided with a Player object.
- if type(name) ~= "string" then
+function core.check_player_privs(name, ...)
+ local arg_type = type(name)
+ if (arg_type == "userdata" or arg_type == "table") and
+ name.get_player_name then -- If it quacks like a Player...
name = name:get_player_name()
+ elseif arg_type ~= "string" then
+ error("Invalid core.check_player_privs argument type: " .. arg_type, 2)
end
local requested_privs = {...}
@@ -85,11 +87,21 @@ end
local player_list = {}
core.register_on_joinplayer(function(player)
- player_list[player:get_player_name()] = player
+ local player_name = player:get_player_name()
+ player_list[player_name] = player
+ if not minetest.is_singleplayer() then
+ core.chat_send_all("*** " .. player_name .. " joined the game.")
+ end
end)
-core.register_on_leaveplayer(function(player)
- player_list[player:get_player_name()] = nil
+core.register_on_leaveplayer(function(player, timed_out)
+ local player_name = player:get_player_name()
+ player_list[player_name] = nil
+ local announcement = "*** " .. player_name .. " left the game."
+ if timed_out then
+ announcement = announcement .. " (timed out)"
+ end
+ core.chat_send_all(announcement)
end)
function core.get_connected_players()
@@ -197,3 +209,39 @@ function core.http_add_fetch(httpenv)
return httpenv
end
+
+if minetest.setting_getbool("disable_escape_sequences") then
+
+ function core.get_color_escape_sequence(color)
+ return ""
+ end
+
+ function core.get_background_escape_sequence(color)
+ return ""
+ end
+
+ function core.colorize(color, message)
+ return message
+ end
+
+else
+
+ local ESCAPE_CHAR = string.char(0x1b)
+ function core.get_color_escape_sequence(color)
+ return ESCAPE_CHAR .. "(c@" .. color .. ")"
+ end
+
+ function core.get_background_escape_sequence(color)
+ return ESCAPE_CHAR .. "(b@" .. color .. ")"
+ end
+
+ function core.colorize(color, message)
+ return core.get_color_escape_sequence(color) .. message .. core.get_color_escape_sequence("#ffffff")
+ end
+
+end
+
+function core.close_formspec(player_name, formname)
+ return minetest.show_formspec(player_name, formname, "")
+end
+
diff --git a/builtin/game/mod_profiling.lua b/builtin/game/mod_profiling.lua
deleted file mode 100644
index df2d10221..000000000
--- a/builtin/game/mod_profiling.lua
+++ /dev/null
@@ -1,356 +0,0 @@
--- Minetest: builtin/game/mod_profiling.lua
-
-local mod_statistics = {}
-mod_statistics.step_total = 0
-mod_statistics.data = {}
-mod_statistics.stats = {}
-mod_statistics.stats["total"] = {
- min_us = math.huge,
- max_us = 0,
- avg_us = 0,
- min_per = 100,
- max_per = 100,
- avg_per = 100
-}
-
-local replacement_table = {
- "register_globalstep",
- "register_on_placenode",
- "register_on_dignode",
- "register_on_punchnode",
- "register_on_generated",
- "register_on_newplayer",
- "register_on_dieplayer",
- "register_on_respawnplayer",
- "register_on_prejoinplayer",
- "register_on_joinplayer",
- "register_on_leaveplayer",
- "register_on_cheat",
- "register_on_chat_message",
- "register_on_player_receive_fields",
- "register_on_mapgen_init",
- "register_on_craft",
- "register_craft_predict",
- "register_on_item_eat"
-}
-
---------------------------------------------------------------------------------
-function mod_statistics.log_time(type, modname, time_in_us)
-
- if modname == nil then
- modname = "builtin"
- end
-
- if mod_statistics.data[modname] == nil then
- mod_statistics.data[modname] = {}
- end
-
- if mod_statistics.data[modname][type] == nil then
- mod_statistics.data[modname][type] = 0
- end
-
- mod_statistics.data[modname][type] =
- mod_statistics.data[modname][type] + time_in_us
- mod_statistics.step_total = mod_statistics.step_total + time_in_us
-end
-
---------------------------------------------------------------------------------
-function mod_statistics.update_statistics(dtime)
- for modname,types in pairs(mod_statistics.data) do
-
- if mod_statistics.stats[modname] == nil then
- mod_statistics.stats[modname] = {
- min_us = math.huge,
- max_us = 0,
- avg_us = 0,
- min_per = 100,
- max_per = 0,
- avg_per = 0
- }
- end
-
- local modtime = 0
- for type,time in pairs(types) do
- modtime = modtime + time
- if mod_statistics.stats[modname].types == nil then
- mod_statistics.stats[modname].types = {}
- end
- if mod_statistics.stats[modname].types[type] == nil then
- mod_statistics.stats[modname].types[type] = {
- min_us = math.huge,
- max_us = 0,
- avg_us = 0,
- min_per = 100,
- max_per = 0,
- avg_per = 0
- }
- end
-
- local toupdate = mod_statistics.stats[modname].types[type]
-
- --update us values
- toupdate.min_us = math.min(time, toupdate.min_us)
- toupdate.max_us = math.max(time, toupdate.max_us)
- --TODO find better algorithm
- toupdate.avg_us = toupdate.avg_us * 0.99 + modtime * 0.01
-
- --update percentage values
- local cur_per = (time/mod_statistics.step_total) * 100
- toupdate.min_per = math.min(toupdate.min_per, cur_per)
-
- toupdate.max_per = math.max(toupdate.max_per, cur_per)
-
- --TODO find better algorithm
- toupdate.avg_per = toupdate.avg_per * 0.99 + cur_per * 0.01
-
- mod_statistics.data[modname][type] = 0
- end
-
- --per mod statistics
- --update us values
- mod_statistics.stats[modname].min_us =
- math.min(modtime, mod_statistics.stats[modname].min_us)
- mod_statistics.stats[modname].max_us =
- math.max(modtime, mod_statistics.stats[modname].max_us)
- --TODO find better algorithm
- mod_statistics.stats[modname].avg_us =
- mod_statistics.stats[modname].avg_us * 0.99 + modtime * 0.01
-
- --update percentage values
- local cur_per = (modtime/mod_statistics.step_total) * 100
- mod_statistics.stats[modname].min_per =
- math.min(mod_statistics.stats[modname].min_per, cur_per)
-
- mod_statistics.stats[modname].max_per =
- math.max(mod_statistics.stats[modname].max_per, cur_per)
-
- --TODO find better algorithm
- mod_statistics.stats[modname].avg_per =
- mod_statistics.stats[modname].avg_per * 0.99 + cur_per * 0.01
- end
-
- --update "total"
- mod_statistics.stats["total"].min_us =
- math.min(mod_statistics.step_total, mod_statistics.stats["total"].min_us)
- mod_statistics.stats["total"].max_us =
- math.max(mod_statistics.step_total, mod_statistics.stats["total"].max_us)
- --TODO find better algorithm
- mod_statistics.stats["total"].avg_us =
- mod_statistics.stats["total"].avg_us * 0.99 +
- mod_statistics.step_total * 0.01
-
- mod_statistics.step_total = 0
-end
-
---------------------------------------------------------------------------------
-local function build_callback(log_id, fct)
- return function( toregister )
- local modname = core.get_current_modname()
-
- fct(function(...)
- local starttime = core.get_us_time()
- -- note maximum 10 return values are supported unless someone finds
- -- a way to store a variable lenght return value list
- local r0, r1, r2, r3, r4, r5, r6, r7, r8, r9 = toregister(...)
- local delta = core.get_us_time() - starttime
- mod_statistics.log_time(log_id, modname, delta)
- return r0, r1, r2, r3, r4, r5, r6, r7, r8, r9
- end
- )
- end
-end
-
---------------------------------------------------------------------------------
-function profiling_print_log(cmd, filter)
-
- print("Filter:" .. dump(filter))
-
- core.log("action", "Values below show times/percentages per server step.")
- core.log("action", "Following suffixes are used for entities:")
- core.log("action", "\t#oa := on_activate, #os := on_step, #op := on_punch, #or := on_rightclick, #gs := get_staticdata")
- core.log("action",
- string.format("%16s | %25s | %10s | %10s | %10s | %9s | %9s | %9s",
- "modname", "type" , "min µs", "max µs", "avg µs", "min %", "max %", "avg %")
- )
- core.log("action",
- "-----------------+---------------------------+-----------+" ..
- "-----------+-----------+-----------+-----------+-----------")
- for modname,statistics in pairs(mod_statistics.stats) do
- if modname ~= "total" then
-
- if (filter == "") or (modname == filter) then
- if modname:len() > 16 then
- modname = "..." .. modname:sub(-13)
- end
-
- core.log("action",
- string.format("%16s | %25s | %9d | %9d | %9d | %9d | %9d | %9d",
- modname,
- " ",
- statistics.min_us,
- statistics.max_us,
- statistics.avg_us,
- statistics.min_per,
- statistics.max_per,
- statistics.avg_per)
- )
- if core.setting_getbool("detailed_profiling") then
- if statistics.types ~= nil then
- for type,typestats in pairs(statistics.types) do
-
- if type:len() > 25 then
- type = "..." .. type:sub(-22)
- end
-
- core.log("action",
- string.format(
- "%16s | %25s | %9d | %9d | %9d | %9d | %9d | %9d",
- " ",
- type,
- typestats.min_us,
- typestats.max_us,
- typestats.avg_us,
- typestats.min_per,
- typestats.max_per,
- typestats.avg_per)
- )
- end
- end
- end
- end
- end
- end
- core.log("action",
- "-----------------+---------------------------+-----------+" ..
- "-----------+-----------+-----------+-----------+-----------")
-
- if filter == "" then
- core.log("action",
- string.format("%16s | %25s | %9d | %9d | %9d | %9d | %9d | %9d",
- "total",
- " ",
- mod_statistics.stats["total"].min_us,
- mod_statistics.stats["total"].max_us,
- mod_statistics.stats["total"].avg_us,
- mod_statistics.stats["total"].min_per,
- mod_statistics.stats["total"].max_per,
- mod_statistics.stats["total"].avg_per)
- )
- end
- core.log("action", " ")
-
- return true
-end
-
---------------------------------------------------------------------------------
-local function initialize_profiling()
- core.log("action", "Initialize tracing")
-
- mod_statistics.entity_callbacks = {}
-
- -- first register our own globalstep handler
- core.register_globalstep(mod_statistics.update_statistics)
-
- local rp_register_entity = core.register_entity
- core.register_entity = function(name, prototype)
- local modname = core.get_current_modname()
- local new_on_activate = nil
- local new_on_step = nil
- local new_on_punch = nil
- local new_rightclick = nil
- local new_get_staticdata = nil
-
- if prototype.on_activate ~= nil then
- local cbid = name .. "#oa"
- mod_statistics.entity_callbacks[cbid] = prototype.on_activate
- new_on_activate = function(self, staticdata, dtime_s)
- local starttime = core.get_us_time()
- mod_statistics.entity_callbacks[cbid](self, staticdata, dtime_s)
- local delta = core.get_us_time() -starttime
- mod_statistics.log_time(cbid, modname, delta)
- end
- end
-
- if prototype.on_step ~= nil then
- local cbid = name .. "#os"
- mod_statistics.entity_callbacks[cbid] = prototype.on_step
- new_on_step = function(self, dtime)
- local starttime = core.get_us_time()
- mod_statistics.entity_callbacks[cbid](self, dtime)
- local delta = core.get_us_time() -starttime
- mod_statistics.log_time(cbid, modname, delta)
- end
- end
-
- if prototype.on_punch ~= nil then
- local cbid = name .. "#op"
- mod_statistics.entity_callbacks[cbid] = prototype.on_punch
- new_on_punch = function(self, hitter)
- local starttime = core.get_us_time()
- mod_statistics.entity_callbacks[cbid](self, hitter)
- local delta = core.get_us_time() -starttime
- mod_statistics.log_time(cbid, modname, delta)
- end
- end
-
- if prototype.rightclick ~= nil then
- local cbid = name .. "#rc"
- mod_statistics.entity_callbacks[cbid] = prototype.rightclick
- new_rightclick = function(self, clicker)
- local starttime = core.get_us_time()
- mod_statistics.entity_callbacks[cbid](self, clicker)
- local delta = core.get_us_time() -starttime
- mod_statistics.log_time(cbid, modname, delta)
- end
- end
-
- if prototype.get_staticdata ~= nil then
- local cbid = name .. "#gs"
- mod_statistics.entity_callbacks[cbid] = prototype.get_staticdata
- new_get_staticdata = function(self)
- local starttime = core.get_us_time()
- local retval = mod_statistics.entity_callbacks[cbid](self)
- local delta = core.get_us_time() -starttime
- mod_statistics.log_time(cbid, modname, delta)
- return retval
- end
- end
-
- prototype.on_activate = new_on_activate
- prototype.on_step = new_on_step
- prototype.on_punch = new_on_punch
- prototype.rightclick = new_rightclick
- prototype.get_staticdata = new_get_staticdata
-
- rp_register_entity(name,prototype)
- end
-
- for i,v in ipairs(replacement_table) do
- local to_replace = core[v]
- core[v] = build_callback(v, to_replace)
- end
-
- local rp_register_abm = core.register_abm
- core.register_abm = function(spec)
-
- local modname = core.get_current_modname()
-
- local replacement_spec = {
- nodenames = spec.nodenames,
- neighbors = spec.neighbors,
- interval = spec.interval,
- chance = spec.chance,
- action = function(pos, node, active_object_count, active_object_count_wider)
- local starttime = core.get_us_time()
- spec.action(pos, node, active_object_count, active_object_count_wider)
- local delta = core.get_us_time() - starttime
- mod_statistics.log_time("abm", modname, delta)
- end
- }
- rp_register_abm(replacement_spec)
- end
-
- core.log("action", "Mod profiling initialized")
-end
-
-initialize_profiling()
diff --git a/builtin/game/privileges.lua b/builtin/game/privileges.lua
index bd5ead624..56e090f4c 100644
--- a/builtin/game/privileges.lua
+++ b/builtin/game/privileges.lua
@@ -26,18 +26,46 @@ function core.register_privilege(name, param)
end
core.register_privilege("interact", "Can interact with things and modify the world")
-core.register_privilege("teleport", "Can use /teleport command")
-core.register_privilege("bring", "Can teleport other players")
-core.register_privilege("settime", "Can use /time")
-core.register_privilege("privs", "Can modify privileges")
-core.register_privilege("basic_privs", "Can modify 'shout' and 'interact' privileges")
-core.register_privilege("server", "Can do server maintenance stuff")
-core.register_privilege("protection_bypass", "Can bypass node protection in the world")
core.register_privilege("shout", "Can speak in chat")
-core.register_privilege("ban", "Can ban and unban players")
-core.register_privilege("kick", "Can kick players")
-core.register_privilege("give", "Can use /give and /giveme")
-core.register_privilege("password", "Can use /setpassword and /clearpassword")
+core.register_privilege("basic_privs", "Can modify 'shout' and 'interact' privileges")
+core.register_privilege("privs", "Can modify privileges")
+
+core.register_privilege("teleport", {
+ description = "Can use /teleport command",
+ give_to_singleplayer = false,
+})
+core.register_privilege("bring", {
+ description = "Can teleport other players",
+ give_to_singleplayer = false,
+})
+core.register_privilege("settime", {
+ description = "Can use /time",
+ give_to_singleplayer = false,
+})
+core.register_privilege("server", {
+ description = "Can do server maintenance stuff",
+ give_to_singleplayer = false,
+})
+core.register_privilege("protection_bypass", {
+ description = "Can bypass node protection in the world",
+ give_to_singleplayer = false,
+})
+core.register_privilege("ban", {
+ description = "Can ban and unban players",
+ give_to_singleplayer = false,
+})
+core.register_privilege("kick", {
+ description = "Can kick players",
+ give_to_singleplayer = false,
+})
+core.register_privilege("give", {
+ description = "Can use /give and /giveme",
+ give_to_singleplayer = false,
+})
+core.register_privilege("password", {
+ description = "Can use /setpassword and /clearpassword",
+ give_to_singleplayer = false,
+})
core.register_privilege("fly", {
description = "Can fly using the free_move mode",
give_to_singleplayer = false,
@@ -50,5 +78,15 @@ core.register_privilege("noclip", {
description = "Can fly through walls",
give_to_singleplayer = false,
})
-core.register_privilege("rollback", "Can use the rollback functionality")
-
+core.register_privilege("rollback", {
+ description = "Can use the rollback functionality",
+ give_to_singleplayer = false,
+})
+core.register_privilege("zoom", {
+ description = "Can zoom the camera",
+ give_to_singleplayer = false,
+})
+core.register_privilege("debug", {
+ description = "Allows enabling various debug options that may affect gameplay",
+ give_to_singleplayer = false,
+})
diff --git a/builtin/game/register.lua b/builtin/game/register.lua
index f330491a2..90f095e9f 100644
--- a/builtin/game/register.lua
+++ b/builtin/game/register.lua
@@ -7,6 +7,9 @@
local register_item_raw = core.register_item_raw
core.register_item_raw = nil
+local unregister_item_raw = core.unregister_item_raw
+core.unregister_item_raw = nil
+
local register_alias_raw = core.register_alias_raw
core.register_alias_raw = nil
@@ -124,6 +127,11 @@ function core.register_item(name, itemdef)
fixed = {-1/8, -1/2, -1/8, 1/8, 1/2, 1/8},
}
end
+ if itemdef.light_source and itemdef.light_source > core.LIGHT_MAX then
+ itemdef.light_source = core.LIGHT_MAX
+ 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
@@ -172,6 +180,27 @@ function core.register_item(name, itemdef)
register_item_raw(itemdef)
end
+function core.unregister_item(name)
+ if not core.registered_items[name] then
+ core.log("warning", "Not unregistering item " ..name..
+ " because it doesn't exist.")
+ 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_items[name] = nil
+
+
+ unregister_item_raw(name)
+end
+
function core.register_node(name, nodedef)
nodedef.type = "node"
core.register_item(name, nodedef)
@@ -242,6 +271,20 @@ function core.register_alias(name, convert_to)
end
end
+function core.register_alias_force(name, convert_to)
+ if forbidden_item_names[name] then
+ error("Unable to register alias: Name is forbidden: " .. name)
+ end
+ if core.registered_items[name] ~= nil then
+ core.unregister_item(name)
+ core.log("info", "Removed item " ..name..
+ " while attempting to force add an alias")
+ end
+ --core.log("Registering alias: " .. name .. " -> " .. convert_to)
+ core.registered_aliases[name] = convert_to
+ register_alias_raw(name, convert_to)
+end
+
function core.on_craft(itemstack, player, old_craft_list, craft_inv)
for _, func in ipairs(core.registered_on_crafts) do
itemstack = func(itemstack, player, old_craft_list, craft_inv) or itemstack
diff --git a/builtin/game/voxelarea.lua b/builtin/game/voxelarea.lua
index 6d926c940..724761414 100644
--- a/builtin/game/voxelarea.lua
+++ b/builtin/game/voxelarea.lua
@@ -50,7 +50,7 @@ end
function VoxelArea:position(i)
local p = {}
local MinEdge = self.MinEdge
-
+
i = i - 1
p.z = math.floor(i / self.zstride) + MinEdge.z
@@ -84,23 +84,46 @@ end
function VoxelArea:iter(minx, miny, minz, maxx, maxy, maxz)
local i = self:index(minx, miny, minz) - 1
- local last = self:index(maxx, maxy, maxz)
- local ystride = self.ystride
- local zstride = self.zstride
- local yoff = (last+1) % ystride
- local zoff = (last+1) % zstride
- local ystridediff = (i - last) % ystride
- local zstridediff = (i - last) % zstride
+ local xrange = maxx - minx + 1
+ local nextaction = i + 1 + xrange
+
+ local y = 0
+ local yrange = maxy - miny + 1
+ local yreqstride = self.ystride - xrange
+
+ local z = 0
+ local zrange = maxz - minz + 1
+ local multistride = self.zstride - ((yrange - 1) * self.ystride + xrange)
+
return function()
+ -- continue i until it needs to jump
i = i + 1
- if i % zstride == zoff then
- i = i + zstridediff
- elseif i % ystride == yoff then
- i = i + ystridediff
+ if i ~= nextaction then
+ return i
end
- if i <= last then
+
+ -- continue y until maxy is exceeded
+ y = y + 1
+ if y ~= yrange then
+ -- set i to index(minx, miny + y, minz + z) - 1
+ i = i + yreqstride
+ nextaction = i + xrange
return i
end
+
+ -- continue z until maxz is exceeded
+ z = z + 1
+ if z == zrange then
+ -- cuboid finished, return nil
+ return
+ end
+
+ -- set i to index(minx, miny, minz + z) - 1
+ i = i + multistride
+
+ y = 0
+ nextaction = i + xrange
+ return i
end
end