mirror of
https://github.com/luanti-org/luanti.git
synced 2025-09-15 18:57:08 +00:00
Organize builtin into subdirectories
This commit is contained in:
parent
fef2729fd0
commit
1cd512913e
44 changed files with 206 additions and 203 deletions
188
builtin/game/auth.lua
Normal file
188
builtin/game/auth.lua
Normal file
|
@ -0,0 +1,188 @@
|
|||
-- Minetest: builtin/auth.lua
|
||||
|
||||
--
|
||||
-- Authentication handler
|
||||
--
|
||||
|
||||
function minetest.string_to_privs(str, delim)
|
||||
assert(type(str) == "string")
|
||||
delim = delim or ','
|
||||
privs = {}
|
||||
for _, priv in pairs(string.split(str, delim)) do
|
||||
privs[priv:trim()] = true
|
||||
end
|
||||
return privs
|
||||
end
|
||||
|
||||
function minetest.privs_to_string(privs, delim)
|
||||
assert(type(privs) == "table")
|
||||
delim = delim or ','
|
||||
list = {}
|
||||
for priv, bool in pairs(privs) do
|
||||
if bool then
|
||||
table.insert(list, priv)
|
||||
end
|
||||
end
|
||||
return table.concat(list, delim)
|
||||
end
|
||||
|
||||
assert(minetest.string_to_privs("a,b").b == true)
|
||||
assert(minetest.privs_to_string({a=true,b=true}) == "a,b")
|
||||
|
||||
minetest.auth_file_path = minetest.get_worldpath().."/auth.txt"
|
||||
minetest.auth_table = {}
|
||||
|
||||
local function read_auth_file()
|
||||
local newtable = {}
|
||||
local file, errmsg = io.open(minetest.auth_file_path, 'rb')
|
||||
if not file then
|
||||
minetest.log("info", minetest.auth_file_path.." could not be opened for reading ("..errmsg.."); assuming new world")
|
||||
return
|
||||
end
|
||||
for line in file:lines() do
|
||||
if line ~= "" then
|
||||
local name, password, privilegestring = string.match(line, "([^:]*):([^:]*):([^:]*)")
|
||||
if not name or not password or not privilegestring then
|
||||
error("Invalid line in auth.txt: "..dump(line))
|
||||
end
|
||||
local privileges = minetest.string_to_privs(privilegestring)
|
||||
newtable[name] = {password=password, privileges=privileges}
|
||||
end
|
||||
end
|
||||
io.close(file)
|
||||
minetest.auth_table = newtable
|
||||
minetest.notify_authentication_modified()
|
||||
end
|
||||
|
||||
local function save_auth_file()
|
||||
local newtable = {}
|
||||
-- Check table for validness before attempting to save
|
||||
for name, stuff in pairs(minetest.auth_table) do
|
||||
assert(type(name) == "string")
|
||||
assert(name ~= "")
|
||||
assert(type(stuff) == "table")
|
||||
assert(type(stuff.password) == "string")
|
||||
assert(type(stuff.privileges) == "table")
|
||||
end
|
||||
local file, errmsg = io.open(minetest.auth_file_path, 'w+b')
|
||||
if not file then
|
||||
error(minetest.auth_file_path.." could not be opened for writing: "..errmsg)
|
||||
end
|
||||
for name, stuff in pairs(minetest.auth_table) do
|
||||
local privstring = minetest.privs_to_string(stuff.privileges)
|
||||
file:write(name..":"..stuff.password..":"..privstring..'\n')
|
||||
end
|
||||
io.close(file)
|
||||
end
|
||||
|
||||
read_auth_file()
|
||||
|
||||
minetest.builtin_auth_handler = {
|
||||
get_auth = function(name)
|
||||
assert(type(name) == "string")
|
||||
-- Figure out what password to use for a new player (singleplayer
|
||||
-- always has an empty password, otherwise use default, which is
|
||||
-- usually empty too)
|
||||
local new_password_hash = ""
|
||||
-- If not in authentication table, return nil
|
||||
if not minetest.auth_table[name] then
|
||||
return nil
|
||||
end
|
||||
-- Figure out what privileges the player should have.
|
||||
-- Take a copy of the privilege table
|
||||
local privileges = {}
|
||||
for priv, _ in pairs(minetest.auth_table[name].privileges) do
|
||||
privileges[priv] = true
|
||||
end
|
||||
-- If singleplayer, give all privileges except those marked as give_to_singleplayer = false
|
||||
if minetest.is_singleplayer() then
|
||||
for priv, def in pairs(minetest.registered_privileges) do
|
||||
if def.give_to_singleplayer then
|
||||
privileges[priv] = true
|
||||
end
|
||||
end
|
||||
-- For the admin, give everything
|
||||
elseif name == minetest.setting_get("name") then
|
||||
for priv, def in pairs(minetest.registered_privileges) do
|
||||
privileges[priv] = true
|
||||
end
|
||||
end
|
||||
-- All done
|
||||
return {
|
||||
password = minetest.auth_table[name].password,
|
||||
privileges = privileges,
|
||||
}
|
||||
end,
|
||||
create_auth = function(name, password)
|
||||
assert(type(name) == "string")
|
||||
assert(type(password) == "string")
|
||||
minetest.log('info', "Built-in authentication handler adding player '"..name.."'")
|
||||
minetest.auth_table[name] = {
|
||||
password = password,
|
||||
privileges = minetest.string_to_privs(minetest.setting_get("default_privs")),
|
||||
}
|
||||
save_auth_file()
|
||||
end,
|
||||
set_password = function(name, password)
|
||||
assert(type(name) == "string")
|
||||
assert(type(password) == "string")
|
||||
if not minetest.auth_table[name] then
|
||||
minetest.builtin_auth_handler.create_auth(name, password)
|
||||
else
|
||||
minetest.log('info', "Built-in authentication handler setting password of player '"..name.."'")
|
||||
minetest.auth_table[name].password = password
|
||||
save_auth_file()
|
||||
end
|
||||
return true
|
||||
end,
|
||||
set_privileges = function(name, privileges)
|
||||
assert(type(name) == "string")
|
||||
assert(type(privileges) == "table")
|
||||
if not minetest.auth_table[name] then
|
||||
minetest.builtin_auth_handler.create_auth(name, minetest.get_password_hash(name, minetest.setting_get("default_password")))
|
||||
end
|
||||
minetest.auth_table[name].privileges = privileges
|
||||
minetest.notify_authentication_modified(name)
|
||||
save_auth_file()
|
||||
end,
|
||||
reload = function()
|
||||
read_auth_file()
|
||||
return true
|
||||
end,
|
||||
}
|
||||
|
||||
function minetest.register_authentication_handler(handler)
|
||||
if minetest.registered_auth_handler then
|
||||
error("Add-on authentication handler already registered by "..minetest.registered_auth_handler_modname)
|
||||
end
|
||||
minetest.registered_auth_handler = handler
|
||||
minetest.registered_auth_handler_modname = minetest.get_current_modname()
|
||||
end
|
||||
|
||||
function minetest.get_auth_handler()
|
||||
if minetest.registered_auth_handler then
|
||||
return minetest.registered_auth_handler
|
||||
end
|
||||
return minetest.builtin_auth_handler
|
||||
end
|
||||
|
||||
function minetest.set_player_password(name, password)
|
||||
if minetest.get_auth_handler().set_password then
|
||||
minetest.get_auth_handler().set_password(name, password)
|
||||
end
|
||||
end
|
||||
|
||||
function minetest.set_player_privs(name, privs)
|
||||
if minetest.get_auth_handler().set_privileges then
|
||||
minetest.get_auth_handler().set_privileges(name, privs)
|
||||
end
|
||||
end
|
||||
|
||||
function minetest.auth_reload()
|
||||
if minetest.get_auth_handler().reload then
|
||||
return minetest.get_auth_handler().reload()
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
|
725
builtin/game/chatcommands.lua
Normal file
725
builtin/game/chatcommands.lua
Normal file
|
@ -0,0 +1,725 @@
|
|||
-- Minetest: builtin/chatcommands.lua
|
||||
|
||||
--
|
||||
-- Chat command handler
|
||||
--
|
||||
|
||||
minetest.chatcommands = {}
|
||||
function minetest.register_chatcommand(cmd, def)
|
||||
def = def or {}
|
||||
def.params = def.params or ""
|
||||
def.description = def.description or ""
|
||||
def.privs = def.privs or {}
|
||||
minetest.chatcommands[cmd] = def
|
||||
end
|
||||
|
||||
minetest.register_on_chat_message(function(name, message)
|
||||
local cmd, param = string.match(message, "^/([^ ]+) *(.*)")
|
||||
if not param then
|
||||
param = ""
|
||||
end
|
||||
local cmd_def = minetest.chatcommands[cmd]
|
||||
if cmd_def then
|
||||
local has_privs, missing_privs = minetest.check_player_privs(name, cmd_def.privs)
|
||||
if has_privs then
|
||||
cmd_def.func(name, param)
|
||||
else
|
||||
minetest.chat_send_player(name, "You don't have permission to run this command (missing privileges: "..table.concat(missing_privs, ", ")..")")
|
||||
end
|
||||
return true -- handled chat message
|
||||
end
|
||||
return false
|
||||
end)
|
||||
|
||||
--
|
||||
-- Chat commands
|
||||
--
|
||||
minetest.register_chatcommand("me", {
|
||||
params = "<action>",
|
||||
description = "chat action (eg. /me orders a pizza)",
|
||||
privs = {shout=true},
|
||||
func = function(name, param)
|
||||
minetest.chat_send_all("* " .. name .. " " .. param)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("help", {
|
||||
privs = {},
|
||||
params = "(nothing)/all/privs/<cmd>",
|
||||
description = "Get help for commands or list privileges",
|
||||
func = function(name, param)
|
||||
local format_help_line = function(cmd, def)
|
||||
local msg = "/"..cmd
|
||||
if def.params and def.params ~= "" then msg = msg .. " " .. def.params end
|
||||
if def.description and def.description ~= "" then msg = msg .. ": " .. def.description end
|
||||
return msg
|
||||
end
|
||||
if param == "" then
|
||||
local msg = ""
|
||||
cmds = {}
|
||||
for cmd, def in pairs(minetest.chatcommands) do
|
||||
if minetest.check_player_privs(name, def.privs) then
|
||||
table.insert(cmds, cmd)
|
||||
end
|
||||
end
|
||||
minetest.chat_send_player(name, "Available commands: "..table.concat(cmds, " "))
|
||||
minetest.chat_send_player(name, "Use '/help <cmd>' to get more information, or '/help all' to list everything.")
|
||||
elseif param == "all" then
|
||||
minetest.chat_send_player(name, "Available commands:")
|
||||
for cmd, def in pairs(minetest.chatcommands) do
|
||||
if minetest.check_player_privs(name, def.privs) then
|
||||
minetest.chat_send_player(name, format_help_line(cmd, def))
|
||||
end
|
||||
end
|
||||
elseif param == "privs" then
|
||||
minetest.chat_send_player(name, "Available privileges:")
|
||||
for priv, def in pairs(minetest.registered_privileges) do
|
||||
minetest.chat_send_player(name, priv..": "..def.description)
|
||||
end
|
||||
else
|
||||
local cmd = param
|
||||
def = minetest.chatcommands[cmd]
|
||||
if not def then
|
||||
minetest.chat_send_player(name, "Command not available: "..cmd)
|
||||
else
|
||||
minetest.chat_send_player(name, format_help_line(cmd, def))
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
minetest.register_chatcommand("privs", {
|
||||
params = "<name>",
|
||||
description = "print out privileges of player",
|
||||
func = function(name, param)
|
||||
if param == "" then
|
||||
param = name
|
||||
else
|
||||
--[[if not minetest.check_player_privs(name, {privs=true}) then
|
||||
minetest.chat_send_player(name, "Privileges of "..param.." are hidden from you.")
|
||||
return
|
||||
end]]
|
||||
end
|
||||
minetest.chat_send_player(name, "Privileges of "..param..": "..minetest.privs_to_string(minetest.get_player_privs(param), ' '))
|
||||
end,
|
||||
})
|
||||
minetest.register_chatcommand("grant", {
|
||||
params = "<name> <privilege>|all",
|
||||
description = "Give privilege to player",
|
||||
privs = {},
|
||||
func = function(name, param)
|
||||
if not minetest.check_player_privs(name, {privs=true}) and
|
||||
not minetest.check_player_privs(name, {basic_privs=true}) then
|
||||
minetest.chat_send_player(name, "Your privileges are insufficient.")
|
||||
return
|
||||
end
|
||||
local grantname, grantprivstr = string.match(param, "([^ ]+) (.+)")
|
||||
if not grantname or not grantprivstr then
|
||||
minetest.chat_send_player(name, "Invalid parameters (see /help grant)")
|
||||
return
|
||||
elseif not minetest.auth_table[grantname] then
|
||||
minetest.chat_send_player(name, "Player "..grantname.." does not exist.")
|
||||
return
|
||||
end
|
||||
local grantprivs = minetest.string_to_privs(grantprivstr)
|
||||
if grantprivstr == "all" then
|
||||
grantprivs = minetest.registered_privileges
|
||||
end
|
||||
local privs = minetest.get_player_privs(grantname)
|
||||
local privs_known = true
|
||||
for priv, _ in pairs(grantprivs) do
|
||||
if priv ~= "interact" and priv ~= "shout" and priv ~= "interact_extra" and not minetest.check_player_privs(name, {privs=true}) then
|
||||
minetest.chat_send_player(name, "Your privileges are insufficient.")
|
||||
return
|
||||
end
|
||||
if not minetest.registered_privileges[priv] then
|
||||
minetest.chat_send_player(name, "Unknown privilege: "..priv)
|
||||
privs_known = false
|
||||
end
|
||||
privs[priv] = true
|
||||
end
|
||||
if not privs_known then
|
||||
return
|
||||
end
|
||||
minetest.set_player_privs(grantname, privs)
|
||||
minetest.log(name..' granted ('..minetest.privs_to_string(grantprivs, ', ')..') privileges to '..grantname)
|
||||
minetest.chat_send_player(name, "Privileges of "..grantname..": "..minetest.privs_to_string(minetest.get_player_privs(grantname), ' '))
|
||||
if grantname ~= name then
|
||||
minetest.chat_send_player(grantname, name.." granted you privileges: "..minetest.privs_to_string(grantprivs, ' '))
|
||||
end
|
||||
end,
|
||||
})
|
||||
minetest.register_chatcommand("revoke", {
|
||||
params = "<name> <privilege>|all",
|
||||
description = "Remove privilege from player",
|
||||
privs = {},
|
||||
func = function(name, param)
|
||||
if not minetest.check_player_privs(name, {privs=true}) and
|
||||
not minetest.check_player_privs(name, {basic_privs=true}) then
|
||||
minetest.chat_send_player(name, "Your privileges are insufficient.")
|
||||
return
|
||||
end
|
||||
local revokename, revokeprivstr = string.match(param, "([^ ]+) (.+)")
|
||||
if not revokename or not revokeprivstr then
|
||||
minetest.chat_send_player(name, "Invalid parameters (see /help revoke)")
|
||||
return
|
||||
elseif not minetest.auth_table[revokename] then
|
||||
minetest.chat_send_player(name, "Player "..revokename.." does not exist.")
|
||||
return
|
||||
end
|
||||
local revokeprivs = minetest.string_to_privs(revokeprivstr)
|
||||
local privs = minetest.get_player_privs(revokename)
|
||||
for priv, _ in pairs(revokeprivs) do
|
||||
if priv ~= "interact" and priv ~= "shout" and priv ~= "interact_extra" and not minetest.check_player_privs(name, {privs=true}) then
|
||||
minetest.chat_send_player(name, "Your privileges are insufficient.")
|
||||
return
|
||||
end
|
||||
end
|
||||
if revokeprivstr == "all" then
|
||||
privs = {}
|
||||
else
|
||||
for priv, _ in pairs(revokeprivs) do
|
||||
privs[priv] = nil
|
||||
end
|
||||
end
|
||||
minetest.set_player_privs(revokename, privs)
|
||||
minetest.log(name..' revoked ('..minetest.privs_to_string(revokeprivs, ', ')..') privileges from '..revokename)
|
||||
minetest.chat_send_player(name, "Privileges of "..revokename..": "..minetest.privs_to_string(minetest.get_player_privs(revokename), ' '))
|
||||
if revokename ~= name then
|
||||
minetest.chat_send_player(revokename, name.." revoked privileges from you: "..minetest.privs_to_string(revokeprivs, ' '))
|
||||
end
|
||||
end,
|
||||
})
|
||||
minetest.register_chatcommand("setpassword", {
|
||||
params = "<name> <password>",
|
||||
description = "set given password",
|
||||
privs = {password=true},
|
||||
func = function(name, param)
|
||||
local toname, raw_password = string.match(param, "^([^ ]+) +(.+)$")
|
||||
if not toname then
|
||||
toname = string.match(param, "^([^ ]+) *$")
|
||||
raw_password = nil
|
||||
end
|
||||
if not toname then
|
||||
minetest.chat_send_player(name, "Name field required")
|
||||
return
|
||||
end
|
||||
local actstr = "?"
|
||||
if not raw_password then
|
||||
minetest.set_player_password(toname, "")
|
||||
actstr = "cleared"
|
||||
else
|
||||
minetest.set_player_password(toname, minetest.get_password_hash(toname, raw_password))
|
||||
actstr = "set"
|
||||
end
|
||||
minetest.chat_send_player(name, "Password of player \""..toname.."\" "..actstr)
|
||||
if toname ~= name then
|
||||
minetest.chat_send_player(toname, "Your password was "..actstr.." by "..name)
|
||||
end
|
||||
end,
|
||||
})
|
||||
minetest.register_chatcommand("clearpassword", {
|
||||
params = "<name>",
|
||||
description = "set empty password",
|
||||
privs = {password=true},
|
||||
func = function(name, param)
|
||||
toname = param
|
||||
if toname == "" then
|
||||
minetest.chat_send_player(name, "Name field required")
|
||||
return
|
||||
end
|
||||
minetest.set_player_password(toname, '')
|
||||
minetest.chat_send_player(name, "Password of player \""..toname.."\" cleared")
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("auth_reload", {
|
||||
params = "",
|
||||
description = "reload authentication data",
|
||||
privs = {server=true},
|
||||
func = function(name, param)
|
||||
local done = minetest.auth_reload()
|
||||
if done then
|
||||
minetest.chat_send_player(name, "Done.")
|
||||
else
|
||||
minetest.chat_send_player(name, "Failed.")
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("teleport", {
|
||||
params = "<X>,<Y>,<Z> | <to_name> | <name> <X>,<Y>,<Z> | <name> <to_name>",
|
||||
description = "teleport to given position",
|
||||
privs = {teleport=true},
|
||||
func = function(name, param)
|
||||
-- Returns (pos, true) if found, otherwise (pos, false)
|
||||
local function find_free_position_near(pos)
|
||||
local tries = {
|
||||
{x=1,y=0,z=0},
|
||||
{x=-1,y=0,z=0},
|
||||
{x=0,y=0,z=1},
|
||||
{x=0,y=0,z=-1},
|
||||
}
|
||||
for _, d in ipairs(tries) do
|
||||
local p = {x = pos.x+d.x, y = pos.y+d.y, z = pos.z+d.z}
|
||||
local n = minetest.get_node_or_nil(p)
|
||||
if n and n.name then
|
||||
local def = minetest.registered_nodes[n.name]
|
||||
if def and not def.walkable then
|
||||
return p, true
|
||||
end
|
||||
end
|
||||
end
|
||||
return pos, false
|
||||
end
|
||||
|
||||
local teleportee = nil
|
||||
local p = {}
|
||||
p.x, p.y, p.z = string.match(param, "^([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+)$")
|
||||
p.x = tonumber(p.x)
|
||||
p.y = tonumber(p.y)
|
||||
p.z = tonumber(p.z)
|
||||
teleportee = minetest.get_player_by_name(name)
|
||||
if teleportee and p.x and p.y and p.z then
|
||||
minetest.chat_send_player(name, "Teleporting to ("..p.x..", "..p.y..", "..p.z..")")
|
||||
teleportee:setpos(p)
|
||||
return
|
||||
end
|
||||
|
||||
local teleportee = nil
|
||||
local p = nil
|
||||
local target_name = nil
|
||||
target_name = string.match(param, "^([^ ]+)$")
|
||||
teleportee = minetest.get_player_by_name(name)
|
||||
if target_name then
|
||||
local target = minetest.get_player_by_name(target_name)
|
||||
if target then
|
||||
p = target:getpos()
|
||||
end
|
||||
end
|
||||
if teleportee and p then
|
||||
p = find_free_position_near(p)
|
||||
minetest.chat_send_player(name, "Teleporting to "..target_name.." at ("..p.x..", "..p.y..", "..p.z..")")
|
||||
teleportee:setpos(p)
|
||||
return
|
||||
end
|
||||
|
||||
if minetest.check_player_privs(name, {bring=true}) then
|
||||
local teleportee = nil
|
||||
local p = {}
|
||||
local teleportee_name = nil
|
||||
teleportee_name, p.x, p.y, p.z = string.match(param, "^([^ ]+) +([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+)$")
|
||||
p.x = tonumber(p.x)
|
||||
p.y = tonumber(p.y)
|
||||
p.z = tonumber(p.z)
|
||||
if teleportee_name then
|
||||
teleportee = minetest.get_player_by_name(teleportee_name)
|
||||
end
|
||||
if teleportee and p.x and p.y and p.z then
|
||||
minetest.chat_send_player(name, "Teleporting "..teleportee_name.." to ("..p.x..", "..p.y..", "..p.z..")")
|
||||
teleportee:setpos(p)
|
||||
return
|
||||
end
|
||||
|
||||
local teleportee = nil
|
||||
local p = nil
|
||||
local teleportee_name = nil
|
||||
local target_name = nil
|
||||
teleportee_name, target_name = string.match(param, "^([^ ]+) +([^ ]+)$")
|
||||
if teleportee_name then
|
||||
teleportee = minetest.get_player_by_name(teleportee_name)
|
||||
end
|
||||
if target_name then
|
||||
local target = minetest.get_player_by_name(target_name)
|
||||
if target then
|
||||
p = target:getpos()
|
||||
end
|
||||
end
|
||||
if teleportee and p then
|
||||
p = find_free_position_near(p)
|
||||
minetest.chat_send_player(name, "Teleporting "..teleportee_name.." to "..target_name.." at ("..p.x..", "..p.y..", "..p.z..")")
|
||||
teleportee:setpos(p)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
minetest.chat_send_player(name, "Invalid parameters (\""..param.."\") or player not found (see /help teleport)")
|
||||
return
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("set", {
|
||||
params = "[-n] <name> <value> | <name>",
|
||||
description = "set or read server configuration setting",
|
||||
privs = {server=true},
|
||||
func = function(name, param)
|
||||
local arg, setname, setvalue = string.match(param, "(-[n]) ([^ ]+) (.+)")
|
||||
if arg and arg == "-n" and setname and setvalue then
|
||||
minetest.setting_set(setname, setvalue)
|
||||
minetest.chat_send_player(name, setname.." = "..setvalue)
|
||||
return
|
||||
end
|
||||
local setname, setvalue = string.match(param, "([^ ]+) (.+)")
|
||||
if setname and setvalue then
|
||||
if not minetest.setting_get(setname) then
|
||||
minetest.chat_send_player(name, "Failed. Use '/set -n <name> <value>' to create a new setting.")
|
||||
return
|
||||
end
|
||||
minetest.setting_set(setname, setvalue)
|
||||
minetest.chat_send_player(name, setname.." = "..setvalue)
|
||||
return
|
||||
end
|
||||
local setname = string.match(param, "([^ ]+)")
|
||||
if setname then
|
||||
local setvalue = minetest.setting_get(setname)
|
||||
if not setvalue then
|
||||
setvalue = "<not set>"
|
||||
end
|
||||
minetest.chat_send_player(name, setname.." = "..setvalue)
|
||||
return
|
||||
end
|
||||
minetest.chat_send_player(name, "Invalid parameters (see /help set)")
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("mods", {
|
||||
params = "",
|
||||
description = "lists mods installed on the server",
|
||||
privs = {},
|
||||
func = function(name, param)
|
||||
local response = ""
|
||||
local modnames = minetest.get_modnames()
|
||||
for i, mod in ipairs(modnames) do
|
||||
response = response .. mod
|
||||
-- Add space if not at the end
|
||||
if i ~= #modnames then
|
||||
response = response .. " "
|
||||
end
|
||||
end
|
||||
minetest.chat_send_player(name, response)
|
||||
end,
|
||||
})
|
||||
|
||||
local function handle_give_command(cmd, giver, receiver, stackstring)
|
||||
minetest.log("action", giver.." invoked "..cmd..', stackstring="'
|
||||
..stackstring..'"')
|
||||
minetest.log(cmd..' invoked, stackstring="'..stackstring..'"')
|
||||
local itemstack = ItemStack(stackstring)
|
||||
if itemstack:is_empty() then
|
||||
minetest.chat_send_player(giver, 'error: cannot give an empty item')
|
||||
return
|
||||
elseif not itemstack:is_known() then
|
||||
minetest.chat_send_player(giver, 'error: cannot give an unknown item')
|
||||
return
|
||||
end
|
||||
local receiverref = minetest.get_player_by_name(receiver)
|
||||
if receiverref == nil then
|
||||
minetest.chat_send_player(giver, receiver..' is not a known player')
|
||||
return
|
||||
end
|
||||
local leftover = receiverref:get_inventory():add_item("main", itemstack)
|
||||
if leftover:is_empty() then
|
||||
partiality = ""
|
||||
elseif leftover:get_count() == itemstack:get_count() then
|
||||
partiality = "could not be "
|
||||
else
|
||||
partiality = "partially "
|
||||
end
|
||||
-- The actual item stack string may be different from what the "giver"
|
||||
-- entered (e.g. big numbers are always interpreted as 2^16-1).
|
||||
stackstring = itemstack:to_string()
|
||||
if giver == receiver then
|
||||
minetest.chat_send_player(giver, '"'..stackstring
|
||||
..'" '..partiality..'added to inventory.');
|
||||
else
|
||||
minetest.chat_send_player(giver, '"'..stackstring
|
||||
..'" '..partiality..'added to '..receiver..'\'s inventory.');
|
||||
minetest.chat_send_player(receiver, '"'..stackstring
|
||||
..'" '..partiality..'added to inventory.');
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_chatcommand("give", {
|
||||
params = "<name> <itemstring>",
|
||||
description = "give item to player",
|
||||
privs = {give=true},
|
||||
func = function(name, param)
|
||||
local toname, itemstring = string.match(param, "^([^ ]+) +(.+)$")
|
||||
if not toname or not itemstring then
|
||||
minetest.chat_send_player(name, "name and itemstring required")
|
||||
return
|
||||
end
|
||||
handle_give_command("/give", name, toname, itemstring)
|
||||
end,
|
||||
})
|
||||
minetest.register_chatcommand("giveme", {
|
||||
params = "<itemstring>",
|
||||
description = "give item to yourself",
|
||||
privs = {give=true},
|
||||
func = function(name, param)
|
||||
local itemstring = string.match(param, "(.+)$")
|
||||
if not itemstring then
|
||||
minetest.chat_send_player(name, "itemstring required")
|
||||
return
|
||||
end
|
||||
handle_give_command("/giveme", name, name, itemstring)
|
||||
end,
|
||||
})
|
||||
minetest.register_chatcommand("spawnentity", {
|
||||
params = "<entityname>",
|
||||
description = "spawn entity at your position",
|
||||
privs = {give=true, interact=true},
|
||||
func = function(name, param)
|
||||
local entityname = string.match(param, "(.+)$")
|
||||
if not entityname then
|
||||
minetest.chat_send_player(name, "entityname required")
|
||||
return
|
||||
end
|
||||
minetest.log("action", '/spawnentity invoked, entityname="'..entityname..'"')
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if player == nil then
|
||||
minetest.log("error", "Unable to spawn entity, player is nil")
|
||||
return true -- Handled chat message
|
||||
end
|
||||
local p = player:getpos()
|
||||
p.y = p.y + 1
|
||||
minetest.add_entity(p, entityname)
|
||||
minetest.chat_send_player(name, '"'..entityname
|
||||
..'" spawned.');
|
||||
end,
|
||||
})
|
||||
minetest.register_chatcommand("pulverize", {
|
||||
params = "",
|
||||
description = "delete item in hand",
|
||||
privs = {},
|
||||
func = function(name, param)
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if player == nil then
|
||||
minetest.log("error", "Unable to pulverize, player is nil")
|
||||
return true -- Handled chat message
|
||||
end
|
||||
if player:get_wielded_item():is_empty() then
|
||||
minetest.chat_send_player(name, 'Unable to pulverize, no item in hand.')
|
||||
else
|
||||
player:set_wielded_item(nil)
|
||||
minetest.chat_send_player(name, 'An item was pulverized.')
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
-- Key = player name
|
||||
minetest.rollback_punch_callbacks = {}
|
||||
|
||||
minetest.register_on_punchnode(function(pos, node, puncher)
|
||||
local name = puncher:get_player_name()
|
||||
if minetest.rollback_punch_callbacks[name] then
|
||||
minetest.rollback_punch_callbacks[name](pos, node, puncher)
|
||||
minetest.rollback_punch_callbacks[name] = nil
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_chatcommand("rollback_check", {
|
||||
params = "[<range>] [<seconds>] [limit]",
|
||||
description = "check who has last touched a node or near it, "..
|
||||
"max. <seconds> ago (default range=0, seconds=86400=24h, limit=5)",
|
||||
privs = {rollback=true},
|
||||
func = function(name, param)
|
||||
local range, seconds, limit =
|
||||
param:match("(%d+) *(%d*) *(%d*)")
|
||||
range = tonumber(range) or 0
|
||||
seconds = tonumber(seconds) or 86400
|
||||
limit = tonumber(limit) or 5
|
||||
if limit > 100 then
|
||||
minetest.chat_send_player(name, "That limit is too high!")
|
||||
return
|
||||
end
|
||||
minetest.chat_send_player(name, "Punch a node (range="..
|
||||
range..", seconds="..seconds.."s, limit="..limit..")")
|
||||
|
||||
minetest.rollback_punch_callbacks[name] = function(pos, node, puncher)
|
||||
local name = puncher:get_player_name()
|
||||
minetest.chat_send_player(name, "Checking "..minetest.pos_to_string(pos).."...")
|
||||
local actions = minetest.rollback_get_node_actions(pos, range, seconds, limit)
|
||||
local num_actions = #actions
|
||||
if num_actions == 0 then
|
||||
minetest.chat_send_player(name, "Nobody has touched the "..
|
||||
"specified location in "..seconds.." seconds")
|
||||
return
|
||||
end
|
||||
local time = os.time()
|
||||
for i = num_actions, 1, -1 do
|
||||
local action = actions[i]
|
||||
minetest.chat_send_player(name,
|
||||
("%s %s %s -> %s %d seconds ago.")
|
||||
:format(
|
||||
minetest.pos_to_string(action.pos),
|
||||
action.actor,
|
||||
action.oldnode.name,
|
||||
action.newnode.name,
|
||||
time - action.time))
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("rollback", {
|
||||
params = "<player name> [<seconds>] | :<actor> [<seconds>]",
|
||||
description = "revert actions of a player; default for <seconds> is 60",
|
||||
privs = {rollback=true},
|
||||
func = function(name, param)
|
||||
local target_name, seconds = string.match(param, ":([^ ]+) *(%d*)")
|
||||
if not target_name then
|
||||
local player_name = nil
|
||||
player_name, seconds = string.match(param, "([^ ]+) *(%d*)")
|
||||
if not player_name then
|
||||
minetest.chat_send_player(name, "Invalid parameters. See /help rollback and /help rollback_check")
|
||||
return
|
||||
end
|
||||
target_name = "player:"..player_name
|
||||
end
|
||||
seconds = tonumber(seconds) or 60
|
||||
minetest.chat_send_player(name, "Reverting actions of "..
|
||||
target_name.." since "..seconds.." seconds.")
|
||||
local success, log = minetest.rollback_revert_actions_by(
|
||||
target_name, seconds)
|
||||
if #log > 100 then
|
||||
minetest.chat_send_player(name, "(log is too long to show)")
|
||||
else
|
||||
for _, line in pairs(log) do
|
||||
minetest.chat_send_player(name, line)
|
||||
end
|
||||
end
|
||||
if success then
|
||||
minetest.chat_send_player(name, "Reverting actions succeeded.")
|
||||
else
|
||||
minetest.chat_send_player(name, "Reverting actions FAILED.")
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("status", {
|
||||
params = "",
|
||||
description = "print server status line",
|
||||
privs = {},
|
||||
func = function(name, param)
|
||||
minetest.chat_send_player(name, minetest.get_server_status())
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("time", {
|
||||
params = "<0...24000>",
|
||||
description = "set time of day",
|
||||
privs = {settime=true},
|
||||
func = function(name, param)
|
||||
if param == "" then
|
||||
minetest.chat_send_player(name, "Missing parameter")
|
||||
return
|
||||
end
|
||||
local newtime = tonumber(param)
|
||||
if newtime == nil then
|
||||
minetest.chat_send_player(name, "Invalid time")
|
||||
else
|
||||
minetest.set_timeofday((newtime % 24000) / 24000)
|
||||
minetest.chat_send_player(name, "Time of day changed.")
|
||||
minetest.log("action", name .. " sets time " .. newtime)
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("shutdown", {
|
||||
params = "",
|
||||
description = "shutdown server",
|
||||
privs = {server=true},
|
||||
func = function(name, param)
|
||||
minetest.log("action", name .. " shuts down server")
|
||||
minetest.request_shutdown()
|
||||
minetest.chat_send_all("*** Server shutting down (operator request).")
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("ban", {
|
||||
params = "<name>",
|
||||
description = "ban IP of player",
|
||||
privs = {ban=true},
|
||||
func = function(name, param)
|
||||
if param == "" then
|
||||
minetest.chat_send_player(name, "Ban list: " .. minetest.get_ban_list())
|
||||
return
|
||||
end
|
||||
if not minetest.get_player_by_name(param) then
|
||||
minetest.chat_send_player(name, "No such player")
|
||||
return
|
||||
end
|
||||
if not minetest.ban_player(param) then
|
||||
minetest.chat_send_player(name, "Failed to ban player")
|
||||
else
|
||||
local desc = minetest.get_ban_description(param)
|
||||
minetest.chat_send_player(name, "Banned " .. desc .. ".")
|
||||
minetest.log("action", name .. " bans " .. desc .. ".")
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("unban", {
|
||||
params = "<name/ip>",
|
||||
description = "remove IP ban",
|
||||
privs = {ban=true},
|
||||
func = function(name, param)
|
||||
if not minetest.unban_player_or_ip(param) then
|
||||
minetest.chat_send_player(name, "Failed to unban player/IP")
|
||||
else
|
||||
minetest.chat_send_player(name, "Unbanned " .. param)
|
||||
minetest.log("action", name .. " unbans " .. param)
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("kick", {
|
||||
params = "<name> [reason]",
|
||||
description = "kick a player",
|
||||
privs = {kick=true},
|
||||
func = function(name, param)
|
||||
local tokick, reason = string.match(param, "([^ ]+) (.+)")
|
||||
if not tokick then
|
||||
tokick = param
|
||||
end
|
||||
if not minetest.kick_player(tokick, reason) then
|
||||
minetest.chat_send_player(name, "Failed to kick player " .. tokick)
|
||||
else
|
||||
minetest.chat_send_player(name, "kicked " .. tokick)
|
||||
minetest.log("action", name .. " kicked " .. tokick)
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("clearobjects", {
|
||||
params = "",
|
||||
description = "clear all objects in world",
|
||||
privs = {server=true},
|
||||
func = function(name, param)
|
||||
minetest.log("action", name .. " clears all objects")
|
||||
minetest.chat_send_all("Clearing all objects. This may take long. You may experience a timeout. (by " .. name .. ")")
|
||||
minetest.clear_objects()
|
||||
minetest.log("action", "object clearing done")
|
||||
minetest.chat_send_all("*** Cleared all objects.")
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("msg", {
|
||||
params = "<name> <message>",
|
||||
description = "Send a private message",
|
||||
privs = {shout=true},
|
||||
func = function(name, param)
|
||||
local found, _, sendto, message = param:find("^([^%s]+)%s(.+)$")
|
||||
if found then
|
||||
if minetest.get_player_by_name(sendto) then
|
||||
minetest.log("action", "PM from "..name.." to "..sendto..": "..message)
|
||||
minetest.chat_send_player(sendto, "PM from "..name..": "..message)
|
||||
minetest.chat_send_player(name, "Message sent")
|
||||
else
|
||||
minetest.chat_send_player(name, "The player "..sendto.." is not online")
|
||||
end
|
||||
else
|
||||
minetest.chat_send_player(name, "Invalid usage, see /help msg")
|
||||
end
|
||||
end,
|
||||
})
|
53
builtin/game/deprecated.lua
Normal file
53
builtin/game/deprecated.lua
Normal file
|
@ -0,0 +1,53 @@
|
|||
-- Minetest: builtin/deprecated.lua
|
||||
|
||||
--
|
||||
-- Default material types
|
||||
--
|
||||
function digprop_err()
|
||||
minetest.log("info", debug.traceback())
|
||||
minetest.log("info", "WARNING: The minetest.digprop_* functions are obsolete and need to be replaced by item groups.")
|
||||
end
|
||||
|
||||
minetest.digprop_constanttime = digprop_err
|
||||
minetest.digprop_stonelike = digprop_err
|
||||
minetest.digprop_dirtlike = digprop_err
|
||||
minetest.digprop_gravellike = digprop_err
|
||||
minetest.digprop_woodlike = digprop_err
|
||||
minetest.digprop_leaveslike = digprop_err
|
||||
minetest.digprop_glasslike = digprop_err
|
||||
|
||||
minetest.node_metadata_inventory_move_allow_all = function()
|
||||
minetest.log("info", "WARNING: minetest.node_metadata_inventory_move_allow_all is obsolete and does nothing.")
|
||||
end
|
||||
|
||||
minetest.add_to_creative_inventory = function(itemstring)
|
||||
minetest.log('info', "WARNING: minetest.add_to_creative_inventory: This function is deprecated and does nothing.")
|
||||
end
|
||||
|
||||
--
|
||||
-- EnvRef
|
||||
--
|
||||
minetest.env = {}
|
||||
local envref_deprecation_message_printed = false
|
||||
setmetatable(minetest.env, {
|
||||
__index = function(table, key)
|
||||
if not envref_deprecation_message_printed then
|
||||
minetest.log("info", "WARNING: minetest.env:[...] is deprecated and should be replaced with minetest.[...]")
|
||||
envref_deprecation_message_printed = true
|
||||
end
|
||||
local func = minetest[key]
|
||||
if type(func) == "function" then
|
||||
rawset(table, key, function(self, ...)
|
||||
return func(...)
|
||||
end)
|
||||
else
|
||||
rawset(table, key, nil)
|
||||
end
|
||||
return rawget(table, key)
|
||||
end
|
||||
})
|
||||
|
||||
function minetest.rollback_get_last_node_actor(pos, range, seconds)
|
||||
return minetest.rollback_get_node_actions(pos, range, seconds, 1)[1]
|
||||
end
|
||||
|
19
builtin/game/detached_inventory.lua
Normal file
19
builtin/game/detached_inventory.lua
Normal file
|
@ -0,0 +1,19 @@
|
|||
-- Minetest: builtin/detached_inventory.lua
|
||||
|
||||
minetest.detached_inventories = {}
|
||||
|
||||
function minetest.create_detached_inventory(name, callbacks)
|
||||
local stuff = {}
|
||||
stuff.name = name
|
||||
if callbacks then
|
||||
stuff.allow_move = callbacks.allow_move
|
||||
stuff.allow_put = callbacks.allow_put
|
||||
stuff.allow_take = callbacks.allow_take
|
||||
stuff.on_move = callbacks.on_move
|
||||
stuff.on_put = callbacks.on_put
|
||||
stuff.on_take = callbacks.on_take
|
||||
end
|
||||
minetest.detached_inventories[name] = stuff
|
||||
return minetest.create_detached_inventory_raw(name)
|
||||
end
|
||||
|
217
builtin/game/falling.lua
Normal file
217
builtin/game/falling.lua
Normal file
|
@ -0,0 +1,217 @@
|
|||
-- Minetest: builtin/item.lua
|
||||
|
||||
--
|
||||
-- Falling stuff
|
||||
--
|
||||
|
||||
minetest.register_entity(":__builtin:falling_node", {
|
||||
initial_properties = {
|
||||
physical = true,
|
||||
collide_with_objects = false,
|
||||
collisionbox = {-0.5,-0.5,-0.5, 0.5,0.5,0.5},
|
||||
visual = "wielditem",
|
||||
textures = {},
|
||||
visual_size = {x=0.667, y=0.667},
|
||||
},
|
||||
|
||||
node = {},
|
||||
|
||||
set_node = function(self, node)
|
||||
self.node = node
|
||||
local stack = ItemStack(node.name)
|
||||
local itemtable = stack:to_table()
|
||||
local itemname = nil
|
||||
if itemtable then
|
||||
itemname = stack:to_table().name
|
||||
end
|
||||
local item_texture = nil
|
||||
local item_type = ""
|
||||
if minetest.registered_items[itemname] then
|
||||
item_texture = minetest.registered_items[itemname].inventory_image
|
||||
item_type = minetest.registered_items[itemname].type
|
||||
end
|
||||
prop = {
|
||||
is_visible = true,
|
||||
textures = {node.name},
|
||||
}
|
||||
self.object:set_properties(prop)
|
||||
end,
|
||||
|
||||
get_staticdata = function(self)
|
||||
return self.node.name
|
||||
end,
|
||||
|
||||
on_activate = function(self, staticdata)
|
||||
self.object:set_armor_groups({immortal=1})
|
||||
--self.object:setacceleration({x=0, y=-10, z=0})
|
||||
self:set_node({name=staticdata})
|
||||
end,
|
||||
|
||||
on_step = function(self, dtime)
|
||||
-- Set gravity
|
||||
self.object:setacceleration({x=0, y=-10, z=0})
|
||||
-- Turn to actual sand when collides to ground or just 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 = minetest.get_node(bcp)
|
||||
local bcd = minetest.registered_nodes[bcn.name]
|
||||
-- Note: walkable is in the node definition, not in item groups
|
||||
if not bcd or
|
||||
(bcd.walkable or
|
||||
(minetest.get_item_group(self.node.name, "float") ~= 0 and
|
||||
bcd.liquidtype ~= "none")) then
|
||||
if bcd and bcd.leveled and
|
||||
bcn.name == self.node.name then
|
||||
local addlevel = self.node.level
|
||||
if addlevel == nil or addlevel <= 0 then
|
||||
addlevel = bcd.leveled
|
||||
end
|
||||
if minetest.add_node_level(bcp, addlevel) == 0 then
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
elseif bcd and bcd.buildable_to and
|
||||
(minetest.get_item_group(self.node.name, "float") == 0 or
|
||||
bcd.liquidtype == "none") then
|
||||
minetest.remove_node(bcp)
|
||||
return
|
||||
end
|
||||
local np = {x=bcp.x, y=bcp.y+1, z=bcp.z}
|
||||
-- Check what's here
|
||||
local n2 = minetest.get_node(np)
|
||||
-- If it's not air or liquid, remove node and replace it with
|
||||
-- it's drops
|
||||
if n2.name ~= "air" and (not minetest.registered_nodes[n2.name] or
|
||||
minetest.registered_nodes[n2.name].liquidtype == "none") then
|
||||
local drops = minetest.get_node_drops(n2.name, "")
|
||||
minetest.remove_node(np)
|
||||
-- Add dropped items
|
||||
local _, dropped_item
|
||||
for _, dropped_item in ipairs(drops) do
|
||||
minetest.add_item(np, dropped_item)
|
||||
end
|
||||
-- Run script hook
|
||||
local _, callback
|
||||
for _, callback in ipairs(minetest.registered_on_dignodes) do
|
||||
callback(np, n2, nil)
|
||||
end
|
||||
end
|
||||
-- Create node and remove entity
|
||||
minetest.add_node(np, self.node)
|
||||
self.object:remove()
|
||||
nodeupdate(np)
|
||||
else
|
||||
-- Do nothing
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
function spawn_falling_node(p, node)
|
||||
obj = minetest.add_entity(p, "__builtin:falling_node")
|
||||
obj:get_luaentity():set_node(node)
|
||||
end
|
||||
|
||||
function drop_attached_node(p)
|
||||
local nn = minetest.get_node(p).name
|
||||
minetest.remove_node(p)
|
||||
for _,item in ipairs(minetest.get_node_drops(nn, "")) do
|
||||
local pos = {
|
||||
x = p.x + math.random()/2 - 0.25,
|
||||
y = p.y + math.random()/2 - 0.25,
|
||||
z = p.z + math.random()/2 - 0.25,
|
||||
}
|
||||
minetest.add_item(pos, item)
|
||||
end
|
||||
end
|
||||
|
||||
function check_attached_node(p, n)
|
||||
local def = minetest.registered_nodes[n.name]
|
||||
local d = {x=0, y=0, z=0}
|
||||
if def.paramtype2 == "wallmounted" then
|
||||
if n.param2 == 0 then
|
||||
d.y = 1
|
||||
elseif n.param2 == 1 then
|
||||
d.y = -1
|
||||
elseif n.param2 == 2 then
|
||||
d.x = 1
|
||||
elseif n.param2 == 3 then
|
||||
d.x = -1
|
||||
elseif n.param2 == 4 then
|
||||
d.z = 1
|
||||
elseif n.param2 == 5 then
|
||||
d.z = -1
|
||||
end
|
||||
else
|
||||
d.y = -1
|
||||
end
|
||||
local p2 = {x=p.x+d.x, y=p.y+d.y, z=p.z+d.z}
|
||||
local nn = minetest.get_node(p2).name
|
||||
local def2 = minetest.registered_nodes[nn]
|
||||
if def2 and not def2.walkable then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
--
|
||||
-- Some common functions
|
||||
--
|
||||
|
||||
function nodeupdate_single(p, delay)
|
||||
n = minetest.get_node(p)
|
||||
if minetest.get_item_group(n.name, "falling_node") ~= 0 then
|
||||
p_bottom = {x=p.x, y=p.y-1, z=p.z}
|
||||
n_bottom = minetest.get_node(p_bottom)
|
||||
-- Note: walkable is in the node definition, not in item groups
|
||||
if minetest.registered_nodes[n_bottom.name] and
|
||||
(minetest.get_item_group(n.name, "float") == 0 or minetest.registered_nodes[n_bottom.name].liquidtype == "none") and
|
||||
(n.name ~= n_bottom.name or (minetest.registered_nodes[n_bottom.name].leveled and minetest.env:get_node_level(p_bottom) < minetest.env:get_node_max_level(p_bottom))) and
|
||||
(not minetest.registered_nodes[n_bottom.name].walkable or
|
||||
minetest.registered_nodes[n_bottom.name].buildable_to) then
|
||||
if delay then
|
||||
minetest.after(0.1, nodeupdate_single, {x=p.x, y=p.y, z=p.z}, false)
|
||||
else
|
||||
n.level = minetest.env:get_node_level(p)
|
||||
minetest.remove_node(p)
|
||||
spawn_falling_node(p, n)
|
||||
nodeupdate(p)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if minetest.get_item_group(n.name, "attached_node") ~= 0 then
|
||||
if not check_attached_node(p, n) then
|
||||
drop_attached_node(p)
|
||||
nodeupdate(p)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function nodeupdate(p, delay)
|
||||
-- Round p to prevent falling entities to get stuck
|
||||
p.x = math.floor(p.x+0.5)
|
||||
p.y = math.floor(p.y+0.5)
|
||||
p.z = math.floor(p.z+0.5)
|
||||
|
||||
for x = -1,1 do
|
||||
for y = -1,1 do
|
||||
for z = -1,1 do
|
||||
nodeupdate_single({x=p.x+x, y=p.y+y, z=p.z+z}, delay or not (x==0 and y==0 and z==0))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- Global callbacks
|
||||
--
|
||||
|
||||
function on_placenode(p, node)
|
||||
nodeupdate(p)
|
||||
end
|
||||
minetest.register_on_placenode(on_placenode)
|
||||
|
||||
function on_dignode(p, node)
|
||||
nodeupdate(p)
|
||||
end
|
||||
minetest.register_on_dignode(on_dignode)
|
29
builtin/game/features.lua
Normal file
29
builtin/game/features.lua
Normal file
|
@ -0,0 +1,29 @@
|
|||
-- Minetest: builtin/features.lua
|
||||
|
||||
minetest.features = {
|
||||
glasslike_framed = true,
|
||||
nodebox_as_selectionbox = true,
|
||||
chat_send_player_param3 = true,
|
||||
get_all_craft_recipes_works = true,
|
||||
use_texture_alpha = true,
|
||||
no_legacy_abms = true,
|
||||
}
|
||||
|
||||
function minetest.has_feature(arg)
|
||||
if type(arg) == "table" then
|
||||
missing_features = {}
|
||||
result = true
|
||||
for ft, _ in pairs(arg) do
|
||||
if not minetest.features[ftr] then
|
||||
missing_features[ftr] = true
|
||||
result = false
|
||||
end
|
||||
end
|
||||
return result, missing_features
|
||||
elseif type(arg) == "string" then
|
||||
if not minetest.features[arg] then
|
||||
return false, {[arg]=true}
|
||||
end
|
||||
return true, {}
|
||||
end
|
||||
end
|
79
builtin/game/forceloading.lua
Normal file
79
builtin/game/forceloading.lua
Normal file
|
@ -0,0 +1,79 @@
|
|||
-- Prevent anyone else accessing those functions
|
||||
local forceload_block = minetest.forceload_block
|
||||
local forceload_free_block = minetest.forceload_free_block
|
||||
minetest.forceload_block = nil
|
||||
minetest.forceload_free_block = nil
|
||||
|
||||
local blocks_forceloaded
|
||||
local total_forceloaded = 0
|
||||
|
||||
local BLOCKSIZE = 16
|
||||
local function get_blockpos(pos)
|
||||
return {
|
||||
x = math.floor(pos.x/BLOCKSIZE),
|
||||
y = math.floor(pos.y/BLOCKSIZE),
|
||||
z = math.floor(pos.z/BLOCKSIZE)}
|
||||
end
|
||||
|
||||
function minetest.forceload_block(pos)
|
||||
local blockpos = get_blockpos(pos)
|
||||
local hash = minetest.hash_node_position(blockpos)
|
||||
if blocks_forceloaded[hash] ~= nil then
|
||||
blocks_forceloaded[hash] = blocks_forceloaded[hash] + 1
|
||||
return true
|
||||
else
|
||||
if total_forceloaded >= (tonumber(minetest.setting_get("max_forceloaded_blocks")) or 16) then
|
||||
return false
|
||||
end
|
||||
total_forceloaded = total_forceloaded+1
|
||||
blocks_forceloaded[hash] = 1
|
||||
forceload_block(blockpos)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
function minetest.forceload_free_block(pos)
|
||||
local blockpos = get_blockpos(pos)
|
||||
local hash = minetest.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
|
||||
else
|
||||
total_forceloaded = total_forceloaded-1
|
||||
blocks_forceloaded[hash] = nil
|
||||
forceload_free_block(blockpos)
|
||||
end
|
||||
end
|
||||
|
||||
-- Keep the forceloaded areas after restart
|
||||
local wpath = minetest.get_worldpath()
|
||||
local function read_file(filename)
|
||||
local f = io.open(filename, "r")
|
||||
if f==nil then return {} end
|
||||
local t = f:read("*all")
|
||||
f:close()
|
||||
if t=="" or t==nil then return {} end
|
||||
return minetest.deserialize(t)
|
||||
end
|
||||
|
||||
local function write_file(filename, table)
|
||||
local f = io.open(filename, "w")
|
||||
f:write(minetest.serialize(table))
|
||||
f:close()
|
||||
end
|
||||
|
||||
blocks_forceloaded = read_file(wpath.."/force_loaded.txt")
|
||||
for _, __ in pairs(blocks_forceloaded) do
|
||||
total_forceloaded = total_forceloaded + 1
|
||||
end
|
||||
|
||||
minetest.after(5, function()
|
||||
for hash, _ in pairs(blocks_forceloaded) do
|
||||
local blockpos = minetest.get_position_from_hash(hash)
|
||||
forceload_block(blockpos)
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_on_shutdown(function()
|
||||
write_file(wpath.."/force_loaded.txt", blocks_forceloaded)
|
||||
end)
|
23
builtin/game/init.lua
Normal file
23
builtin/game/init.lua
Normal file
|
@ -0,0 +1,23 @@
|
|||
|
||||
local scriptpath = minetest.get_builtin_path()..DIR_DELIM
|
||||
local commonpath = scriptpath.."common"..DIR_DELIM
|
||||
local gamepath = scriptpath.."game"..DIR_DELIM
|
||||
|
||||
dofile(commonpath.."vector.lua")
|
||||
|
||||
dofile(gamepath.."item.lua")
|
||||
dofile(gamepath.."register.lua")
|
||||
dofile(gamepath.."item_entity.lua")
|
||||
dofile(gamepath.."deprecated.lua")
|
||||
dofile(gamepath.."misc.lua")
|
||||
dofile(gamepath.."privileges.lua")
|
||||
dofile(gamepath.."auth.lua")
|
||||
dofile(gamepath.."chatcommands.lua")
|
||||
dofile(gamepath.."static_spawn.lua")
|
||||
dofile(gamepath.."detached_inventory.lua")
|
||||
dofile(gamepath.."falling.lua")
|
||||
dofile(gamepath.."features.lua")
|
||||
dofile(gamepath.."voxelarea.lua")
|
||||
dofile(gamepath.."forceloading.lua")
|
||||
dofile(gamepath.."statbars.lua")
|
||||
|
589
builtin/game/item.lua
Normal file
589
builtin/game/item.lua
Normal file
|
@ -0,0 +1,589 @@
|
|||
-- Minetest: builtin/item.lua
|
||||
|
||||
local function copy_pointed_thing(pointed_thing)
|
||||
return {
|
||||
type = pointed_thing.type,
|
||||
above = vector.new(pointed_thing.above),
|
||||
under = vector.new(pointed_thing.under),
|
||||
ref = pointed_thing.ref,
|
||||
}
|
||||
end
|
||||
|
||||
--
|
||||
-- Item definition helpers
|
||||
--
|
||||
|
||||
function minetest.inventorycube(img1, img2, img3)
|
||||
img2 = img2 or img1
|
||||
img3 = img3 or img1
|
||||
return "[inventorycube"
|
||||
.. "{" .. img1:gsub("%^", "&")
|
||||
.. "{" .. img2:gsub("%^", "&")
|
||||
.. "{" .. img3:gsub("%^", "&")
|
||||
end
|
||||
|
||||
function minetest.get_pointed_thing_position(pointed_thing, above)
|
||||
if pointed_thing.type == "node" then
|
||||
if above then
|
||||
-- The position where a node would be placed
|
||||
return pointed_thing.above
|
||||
else
|
||||
-- The position where a node would be dug
|
||||
return pointed_thing.under
|
||||
end
|
||||
elseif pointed_thing.type == "object" then
|
||||
obj = pointed_thing.ref
|
||||
if obj ~= nil then
|
||||
return obj:getpos()
|
||||
else
|
||||
return nil
|
||||
end
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
function minetest.dir_to_facedir(dir, is6d)
|
||||
--account for y if requested
|
||||
if is6d and math.abs(dir.y) > math.abs(dir.x) and math.abs(dir.y) > math.abs(dir.z) then
|
||||
|
||||
--from above
|
||||
if dir.y < 0 then
|
||||
if math.abs(dir.x) > math.abs(dir.z) then
|
||||
if dir.x < 0 then
|
||||
return 19
|
||||
else
|
||||
return 13
|
||||
end
|
||||
else
|
||||
if dir.z < 0 then
|
||||
return 10
|
||||
else
|
||||
return 4
|
||||
end
|
||||
end
|
||||
|
||||
--from below
|
||||
else
|
||||
if math.abs(dir.x) > math.abs(dir.z) then
|
||||
if dir.x < 0 then
|
||||
return 15
|
||||
else
|
||||
return 17
|
||||
end
|
||||
else
|
||||
if dir.z < 0 then
|
||||
return 6
|
||||
else
|
||||
return 8
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--otherwise, place horizontally
|
||||
elseif math.abs(dir.x) > math.abs(dir.z) then
|
||||
if dir.x < 0 then
|
||||
return 3
|
||||
else
|
||||
return 1
|
||||
end
|
||||
else
|
||||
if dir.z < 0 then
|
||||
return 2
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function minetest.facedir_to_dir(facedir)
|
||||
--a table of possible dirs
|
||||
return ({{x=0, y=0, z=1},
|
||||
{x=1, y=0, z=0},
|
||||
{x=0, y=0, z=-1},
|
||||
{x=-1, y=0, z=0},
|
||||
{x=0, y=-1, z=0},
|
||||
{x=0, y=1, z=0}})
|
||||
|
||||
--indexed into by a table of correlating facedirs
|
||||
[({[0]=1, 2, 3, 4,
|
||||
5, 2, 6, 4,
|
||||
6, 2, 5, 4,
|
||||
1, 5, 3, 6,
|
||||
1, 6, 3, 5,
|
||||
1, 4, 3, 2})
|
||||
|
||||
--indexed into by the facedir in question
|
||||
[facedir]]
|
||||
end
|
||||
|
||||
function minetest.dir_to_wallmounted(dir)
|
||||
if math.abs(dir.y) > math.max(math.abs(dir.x), math.abs(dir.z)) then
|
||||
if dir.y < 0 then
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
end
|
||||
elseif math.abs(dir.x) > math.abs(dir.z) then
|
||||
if dir.x < 0 then
|
||||
return 3
|
||||
else
|
||||
return 2
|
||||
end
|
||||
else
|
||||
if dir.z < 0 then
|
||||
return 5
|
||||
else
|
||||
return 4
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function minetest.get_node_drops(nodename, toolname)
|
||||
local drop = ItemStack({name=nodename}):get_definition().drop
|
||||
if drop == nil then
|
||||
-- default drop
|
||||
return {nodename}
|
||||
elseif type(drop) == "string" then
|
||||
-- itemstring drop
|
||||
return {drop}
|
||||
elseif drop.items == nil then
|
||||
-- drop = {} to disable default drop
|
||||
return {}
|
||||
end
|
||||
|
||||
-- Extended drop table
|
||||
local got_items = {}
|
||||
local got_count = 0
|
||||
local _, item, tool
|
||||
for _, item in ipairs(drop.items) do
|
||||
local good_rarity = true
|
||||
local good_tool = true
|
||||
if item.rarity ~= nil then
|
||||
good_rarity = item.rarity < 1 or math.random(item.rarity) == 1
|
||||
end
|
||||
if item.tools ~= nil then
|
||||
good_tool = false
|
||||
for _, tool in ipairs(item.tools) do
|
||||
if tool:sub(1, 1) == '~' then
|
||||
good_tool = toolname:find(tool:sub(2)) ~= nil
|
||||
else
|
||||
good_tool = toolname == tool
|
||||
end
|
||||
if good_tool then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
if good_rarity and good_tool then
|
||||
got_count = got_count + 1
|
||||
for _, add_item in ipairs(item.items) do
|
||||
got_items[#got_items+1] = add_item
|
||||
end
|
||||
if drop.max_items ~= nil and got_count == drop.max_items then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
return got_items
|
||||
end
|
||||
|
||||
function minetest.item_place_node(itemstack, placer, pointed_thing, param2)
|
||||
local item = itemstack:peek_item()
|
||||
local def = itemstack:get_definition()
|
||||
if def.type ~= "node" or pointed_thing.type ~= "node" then
|
||||
return itemstack, false
|
||||
end
|
||||
|
||||
local under = pointed_thing.under
|
||||
local oldnode_under = minetest.get_node_or_nil(under)
|
||||
local above = pointed_thing.above
|
||||
local oldnode_above = minetest.get_node_or_nil(above)
|
||||
|
||||
if not oldnode_under or not oldnode_above then
|
||||
minetest.log("info", placer:get_player_name() .. " tried to place"
|
||||
.. " node in unloaded position " .. minetest.pos_to_string(above))
|
||||
return itemstack, false
|
||||
end
|
||||
|
||||
local olddef_under = ItemStack({name=oldnode_under.name}):get_definition()
|
||||
olddef_under = olddef_under or minetest.nodedef_default
|
||||
local olddef_above = ItemStack({name=oldnode_above.name}):get_definition()
|
||||
olddef_above = olddef_above or minetest.nodedef_default
|
||||
|
||||
if not olddef_above.buildable_to and not olddef_under.buildable_to then
|
||||
minetest.log("info", placer:get_player_name() .. " tried to place"
|
||||
.. " node in invalid position " .. minetest.pos_to_string(above)
|
||||
.. ", replacing " .. oldnode_above.name)
|
||||
return itemstack, false
|
||||
end
|
||||
|
||||
-- Place above pointed node
|
||||
local place_to = {x = above.x, y = above.y, z = above.z}
|
||||
|
||||
-- If node under is buildable_to, place into it instead (eg. snow)
|
||||
if olddef_under.buildable_to then
|
||||
minetest.log("info", "node under is buildable to")
|
||||
place_to = {x = under.x, y = under.y, z = under.z}
|
||||
end
|
||||
|
||||
if minetest.is_protected(place_to, placer:get_player_name()) then
|
||||
minetest.log("action", placer:get_player_name()
|
||||
.. " tried to place " .. def.name
|
||||
.. " at protected position "
|
||||
.. minetest.pos_to_string(place_to))
|
||||
minetest.record_protection_violation(place_to, placer:get_player_name())
|
||||
return itemstack
|
||||
end
|
||||
|
||||
minetest.log("action", placer:get_player_name() .. " places node "
|
||||
.. def.name .. " at " .. minetest.pos_to_string(place_to))
|
||||
|
||||
local oldnode = minetest.get_node(place_to)
|
||||
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
|
||||
local dir = {
|
||||
x = under.x - above.x,
|
||||
y = under.y - above.y,
|
||||
z = under.z - above.z
|
||||
}
|
||||
newnode.param2 = minetest.dir_to_wallmounted(dir)
|
||||
-- Calculate the direction for furnaces and chests and stuff
|
||||
elseif def.paramtype2 == 'facedir' and not param2 then
|
||||
local placer_pos = placer:getpos()
|
||||
if placer_pos then
|
||||
local dir = {
|
||||
x = above.x - placer_pos.x,
|
||||
y = above.y - placer_pos.y,
|
||||
z = above.z - placer_pos.z
|
||||
}
|
||||
newnode.param2 = minetest.dir_to_facedir(dir)
|
||||
minetest.log("action", "facedir: " .. newnode.param2)
|
||||
end
|
||||
end
|
||||
|
||||
-- Check if the node is attached and if it can be placed there
|
||||
if minetest.get_item_group(def.name, "attached_node") ~= 0 and
|
||||
not check_attached_node(place_to, newnode) then
|
||||
minetest.log("action", "attached node " .. def.name ..
|
||||
" can not be placed at " .. minetest.pos_to_string(place_to))
|
||||
return itemstack, false
|
||||
end
|
||||
|
||||
-- Add node and update
|
||||
minetest.add_node(place_to, newnode)
|
||||
|
||||
local take_item = true
|
||||
|
||||
-- Run callback
|
||||
if def.after_place_node then
|
||||
-- Deepcopy place_to and pointed_thing because callback can modify it
|
||||
local place_to_copy = {x=place_to.x, y=place_to.y, z=place_to.z}
|
||||
local pointed_thing_copy = copy_pointed_thing(pointed_thing)
|
||||
if def.after_place_node(place_to_copy, placer, itemstack,
|
||||
pointed_thing_copy) then
|
||||
take_item = false
|
||||
end
|
||||
end
|
||||
|
||||
-- Run script hook
|
||||
local _, callback
|
||||
for _, callback in ipairs(minetest.registered_on_placenodes) do
|
||||
-- Deepcopy pos, node and pointed_thing because callback can modify them
|
||||
local place_to_copy = {x=place_to.x, y=place_to.y, z=place_to.z}
|
||||
local newnode_copy = {name=newnode.name, param1=newnode.param1, param2=newnode.param2}
|
||||
local oldnode_copy = {name=oldnode.name, param1=oldnode.param1, param2=oldnode.param2}
|
||||
local pointed_thing_copy = copy_pointed_thing(pointed_thing)
|
||||
if callback(place_to_copy, newnode_copy, placer, oldnode_copy, itemstack, pointed_thing_copy) then
|
||||
take_item = false
|
||||
end
|
||||
end
|
||||
|
||||
if take_item then
|
||||
itemstack:take_item()
|
||||
end
|
||||
return itemstack, true
|
||||
end
|
||||
|
||||
function minetest.item_place_object(itemstack, placer, pointed_thing)
|
||||
local pos = minetest.get_pointed_thing_position(pointed_thing, true)
|
||||
if pos ~= nil then
|
||||
local item = itemstack:take_item()
|
||||
minetest.add_item(pos, item)
|
||||
end
|
||||
return itemstack
|
||||
end
|
||||
|
||||
function minetest.item_place(itemstack, placer, pointed_thing, param2)
|
||||
-- Call on_rightclick if the pointed node defines it
|
||||
if pointed_thing.type == "node" and placer and
|
||||
not placer:get_player_control().sneak then
|
||||
local n = minetest.get_node(pointed_thing.under)
|
||||
local nn = n.name
|
||||
if minetest.registered_nodes[nn] and minetest.registered_nodes[nn].on_rightclick then
|
||||
return minetest.registered_nodes[nn].on_rightclick(pointed_thing.under, n,
|
||||
placer, itemstack, pointed_thing) or itemstack, false
|
||||
end
|
||||
end
|
||||
|
||||
if itemstack:get_definition().type == "node" then
|
||||
return minetest.item_place_node(itemstack, placer, pointed_thing, param2)
|
||||
end
|
||||
return itemstack
|
||||
end
|
||||
|
||||
function minetest.item_drop(itemstack, dropper, pos)
|
||||
if dropper.get_player_name then
|
||||
local v = dropper:get_look_dir()
|
||||
local p = {x=pos.x+v.x, y=pos.y+1.5+v.y, z=pos.z+v.z}
|
||||
local obj = minetest.add_item(p, itemstack)
|
||||
if obj then
|
||||
v.x = v.x*2
|
||||
v.y = v.y*2 + 1
|
||||
v.z = v.z*2
|
||||
obj:setvelocity(v)
|
||||
end
|
||||
else
|
||||
minetest.add_item(pos, itemstack)
|
||||
end
|
||||
return ItemStack("")
|
||||
end
|
||||
|
||||
function minetest.item_eat(hp_change, replace_with_item)
|
||||
return function(itemstack, user, pointed_thing) -- closure
|
||||
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
|
||||
return itemstack
|
||||
end
|
||||
end
|
||||
|
||||
function minetest.node_punch(pos, node, puncher, pointed_thing)
|
||||
-- Run script hook
|
||||
for _, callback in ipairs(minetest.registered_on_punchnodes) do
|
||||
-- Copy pos and node because callback can modify them
|
||||
local pos_copy = vector.new(pos)
|
||||
local node_copy = {name=node.name, param1=node.param1, param2=node.param2}
|
||||
local pointed_thing_copy = pointed_thing and copy_pointed_thing(pointed_thing) or nil
|
||||
callback(pos_copy, node_copy, puncher, pointed_thing_copy)
|
||||
end
|
||||
end
|
||||
|
||||
function minetest.handle_node_drops(pos, drops, digger)
|
||||
-- Add dropped items to object's inventory
|
||||
if digger:get_inventory() then
|
||||
local _, dropped_item
|
||||
for _, dropped_item in ipairs(drops) do
|
||||
local left = digger:get_inventory():add_item("main", dropped_item)
|
||||
if not left:is_empty() then
|
||||
local p = {
|
||||
x = pos.x + math.random()/2-0.25,
|
||||
y = pos.y + math.random()/2-0.25,
|
||||
z = pos.z + math.random()/2-0.25,
|
||||
}
|
||||
minetest.add_item(p, left)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function minetest.node_dig(pos, node, digger)
|
||||
local def = ItemStack({name=node.name}):get_definition()
|
||||
if not def.diggable or (def.can_dig and not def.can_dig(pos,digger)) then
|
||||
minetest.log("info", digger:get_player_name() .. " tried to dig "
|
||||
.. node.name .. " which is not diggable "
|
||||
.. minetest.pos_to_string(pos))
|
||||
return
|
||||
end
|
||||
|
||||
if minetest.is_protected(pos, digger:get_player_name()) then
|
||||
minetest.log("action", digger:get_player_name()
|
||||
.. " tried to dig " .. node.name
|
||||
.. " at protected position "
|
||||
.. minetest.pos_to_string(pos))
|
||||
minetest.record_protection_violation(pos, digger:get_player_name())
|
||||
return
|
||||
end
|
||||
|
||||
minetest.log('action', digger:get_player_name() .. " digs "
|
||||
.. node.name .. " at " .. minetest.pos_to_string(pos))
|
||||
|
||||
local wielded = digger:get_wielded_item()
|
||||
local drops = minetest.get_node_drops(node.name, wielded:get_name())
|
||||
|
||||
local wdef = wielded:get_definition()
|
||||
local tp = wielded:get_tool_capabilities()
|
||||
local dp = minetest.get_dig_params(def.groups, tp)
|
||||
if wdef and wdef.after_use then
|
||||
wielded = wdef.after_use(wielded, digger, node, dp) or wielded
|
||||
else
|
||||
-- Wear out tool
|
||||
if not minetest.setting_getbool("creative_mode") then
|
||||
wielded:add_wear(dp.wear)
|
||||
end
|
||||
end
|
||||
digger:set_wielded_item(wielded)
|
||||
|
||||
-- Handle drops
|
||||
minetest.handle_node_drops(pos, drops, digger)
|
||||
|
||||
local oldmetadata = nil
|
||||
if def.after_dig_node then
|
||||
oldmetadata = minetest.get_meta(pos):to_table()
|
||||
end
|
||||
|
||||
-- Remove node and update
|
||||
minetest.remove_node(pos)
|
||||
|
||||
-- Run callback
|
||||
if def.after_dig_node then
|
||||
-- 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}
|
||||
def.after_dig_node(pos_copy, node_copy, oldmetadata, digger)
|
||||
end
|
||||
|
||||
-- Run script hook
|
||||
local _, callback
|
||||
for _, callback in ipairs(minetest.registered_on_dignodes) do
|
||||
-- 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}
|
||||
callback(pos_copy, node_copy, digger)
|
||||
end
|
||||
end
|
||||
|
||||
-- This is used to allow mods to redefine minetest.item_place and so on
|
||||
-- NOTE: This is not the preferred way. Preferred way is to provide enough
|
||||
-- callbacks to not require redefining global functions. -celeron55
|
||||
local function redef_wrapper(table, name)
|
||||
return function(...)
|
||||
return table[name](...)
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- Item definition defaults
|
||||
--
|
||||
|
||||
minetest.nodedef_default = {
|
||||
-- Item properties
|
||||
type="node",
|
||||
-- name intentionally not defined here
|
||||
description = "",
|
||||
groups = {},
|
||||
inventory_image = "",
|
||||
wield_image = "",
|
||||
wield_scale = {x=1,y=1,z=1},
|
||||
stack_max = 99,
|
||||
usable = false,
|
||||
liquids_pointable = false,
|
||||
tool_capabilities = nil,
|
||||
node_placement_prediction = nil,
|
||||
|
||||
-- Interaction callbacks
|
||||
on_place = redef_wrapper(minetest, 'item_place'), -- minetest.item_place
|
||||
on_drop = redef_wrapper(minetest, 'item_drop'), -- minetest.item_drop
|
||||
on_use = nil,
|
||||
can_dig = nil,
|
||||
|
||||
on_punch = redef_wrapper(minetest, 'node_punch'), -- minetest.node_punch
|
||||
on_rightclick = nil,
|
||||
on_dig = redef_wrapper(minetest, 'node_dig'), -- minetest.node_dig
|
||||
|
||||
on_receive_fields = nil,
|
||||
|
||||
on_metadata_inventory_move = minetest.node_metadata_inventory_move_allow_all,
|
||||
on_metadata_inventory_offer = minetest.node_metadata_inventory_offer_allow_all,
|
||||
on_metadata_inventory_take = minetest.node_metadata_inventory_take_allow_all,
|
||||
|
||||
-- Node properties
|
||||
drawtype = "normal",
|
||||
visual_scale = 1.0,
|
||||
-- Don't define these because otherwise the old tile_images and
|
||||
-- special_materials wouldn't be read
|
||||
--tiles ={""},
|
||||
--special_tiles = {
|
||||
-- {name="", backface_culling=true},
|
||||
-- {name="", backface_culling=true},
|
||||
--},
|
||||
alpha = 255,
|
||||
post_effect_color = {a=0, r=0, g=0, b=0},
|
||||
paramtype = "none",
|
||||
paramtype2 = "none",
|
||||
is_ground_content = true,
|
||||
sunlight_propagates = false,
|
||||
walkable = true,
|
||||
pointable = true,
|
||||
diggable = true,
|
||||
climbable = false,
|
||||
buildable_to = false,
|
||||
liquidtype = "none",
|
||||
liquid_alternative_flowing = "",
|
||||
liquid_alternative_source = "",
|
||||
liquid_viscosity = 0,
|
||||
drowning = 0,
|
||||
light_source = 0,
|
||||
damage_per_second = 0,
|
||||
selection_box = {type="regular"},
|
||||
legacy_facedir_simple = false,
|
||||
legacy_wallmounted = false,
|
||||
}
|
||||
|
||||
minetest.craftitemdef_default = {
|
||||
type="craft",
|
||||
-- name intentionally not defined here
|
||||
description = "",
|
||||
groups = {},
|
||||
inventory_image = "",
|
||||
wield_image = "",
|
||||
wield_scale = {x=1,y=1,z=1},
|
||||
stack_max = 99,
|
||||
liquids_pointable = false,
|
||||
tool_capabilities = nil,
|
||||
|
||||
-- Interaction callbacks
|
||||
on_place = redef_wrapper(minetest, 'item_place'), -- minetest.item_place
|
||||
on_drop = redef_wrapper(minetest, 'item_drop'), -- minetest.item_drop
|
||||
on_use = nil,
|
||||
}
|
||||
|
||||
minetest.tooldef_default = {
|
||||
type="tool",
|
||||
-- name intentionally not defined here
|
||||
description = "",
|
||||
groups = {},
|
||||
inventory_image = "",
|
||||
wield_image = "",
|
||||
wield_scale = {x=1,y=1,z=1},
|
||||
stack_max = 1,
|
||||
liquids_pointable = false,
|
||||
tool_capabilities = nil,
|
||||
|
||||
-- Interaction callbacks
|
||||
on_place = redef_wrapper(minetest, 'item_place'), -- minetest.item_place
|
||||
on_drop = redef_wrapper(minetest, 'item_drop'), -- minetest.item_drop
|
||||
on_use = nil,
|
||||
}
|
||||
|
||||
minetest.noneitemdef_default = { -- This is used for the hand and unknown items
|
||||
type="none",
|
||||
-- name intentionally not defined here
|
||||
description = "",
|
||||
groups = {},
|
||||
inventory_image = "",
|
||||
wield_image = "",
|
||||
wield_scale = {x=1,y=1,z=1},
|
||||
stack_max = 99,
|
||||
liquids_pointable = false,
|
||||
tool_capabilities = nil,
|
||||
|
||||
-- Interaction callbacks
|
||||
on_place = redef_wrapper(minetest, 'item_place'),
|
||||
on_drop = nil,
|
||||
on_use = nil,
|
||||
}
|
||||
|
123
builtin/game/item_entity.lua
Normal file
123
builtin/game/item_entity.lua
Normal file
|
@ -0,0 +1,123 @@
|
|||
-- Minetest: builtin/item_entity.lua
|
||||
|
||||
function minetest.spawn_item(pos, item)
|
||||
-- Take item in any format
|
||||
local stack = ItemStack(item)
|
||||
local obj = minetest.add_entity(pos, "__builtin:item")
|
||||
obj:get_luaentity():set_item(stack:to_string())
|
||||
return obj
|
||||
end
|
||||
|
||||
minetest.register_entity(":__builtin:item", {
|
||||
initial_properties = {
|
||||
hp_max = 1,
|
||||
physical = true,
|
||||
collide_with_objects = false,
|
||||
collisionbox = {-0.17,-0.17,-0.17, 0.17,0.17,0.17},
|
||||
visual = "sprite",
|
||||
visual_size = {x=0.5, y=0.5},
|
||||
textures = {""},
|
||||
spritediv = {x=1, y=1},
|
||||
initial_sprite_basepos = {x=0, y=0},
|
||||
is_visible = false,
|
||||
},
|
||||
|
||||
itemstring = '',
|
||||
physical_state = true,
|
||||
|
||||
set_item = function(self, itemstring)
|
||||
self.itemstring = itemstring
|
||||
local stack = ItemStack(itemstring)
|
||||
local itemtable = stack:to_table()
|
||||
local itemname = nil
|
||||
if itemtable then
|
||||
itemname = stack:to_table().name
|
||||
end
|
||||
local item_texture = nil
|
||||
local item_type = ""
|
||||
if minetest.registered_items[itemname] then
|
||||
item_texture = minetest.registered_items[itemname].inventory_image
|
||||
item_type = minetest.registered_items[itemname].type
|
||||
end
|
||||
prop = {
|
||||
is_visible = true,
|
||||
visual = "sprite",
|
||||
textures = {"unknown_item.png"}
|
||||
}
|
||||
if item_texture and item_texture ~= "" then
|
||||
prop.visual = "sprite"
|
||||
prop.textures = {item_texture}
|
||||
prop.visual_size = {x=0.50, y=0.50}
|
||||
else
|
||||
prop.visual = "wielditem"
|
||||
prop.textures = {itemname}
|
||||
prop.visual_size = {x=0.20, y=0.20}
|
||||
prop.automatic_rotate = math.pi * 0.25
|
||||
end
|
||||
self.object:set_properties(prop)
|
||||
end,
|
||||
|
||||
get_staticdata = function(self)
|
||||
--return self.itemstring
|
||||
return minetest.serialize({
|
||||
itemstring = self.itemstring,
|
||||
always_collect = self.always_collect,
|
||||
})
|
||||
end,
|
||||
|
||||
on_activate = function(self, staticdata)
|
||||
if string.sub(staticdata, 1, string.len("return")) == "return" then
|
||||
local data = minetest.deserialize(staticdata)
|
||||
if data and type(data) == "table" then
|
||||
self.itemstring = data.itemstring
|
||||
self.always_collect = data.always_collect
|
||||
end
|
||||
else
|
||||
self.itemstring = staticdata
|
||||
end
|
||||
self.object:set_armor_groups({immortal=1})
|
||||
self.object:setvelocity({x=0, y=2, z=0})
|
||||
self.object:setacceleration({x=0, y=-10, z=0})
|
||||
self:set_item(self.itemstring)
|
||||
end,
|
||||
|
||||
on_step = function(self, dtime)
|
||||
local p = self.object:getpos()
|
||||
p.y = p.y - 0.3
|
||||
local nn = minetest.get_node(p).name
|
||||
-- If node is not registered or node is walkably solid and resting on nodebox
|
||||
local v = self.object:getvelocity()
|
||||
if not minetest.registered_nodes[nn] or minetest.registered_nodes[nn].walkable and v.y == 0 then
|
||||
if self.physical_state then
|
||||
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
|
||||
})
|
||||
end
|
||||
else
|
||||
if not self.physical_state then
|
||||
self.object:setvelocity({x=0,y=0,z=0})
|
||||
self.object:setacceleration({x=0, y=-10, z=0})
|
||||
self.physical_state = true
|
||||
self.object:set_properties({
|
||||
physical = true
|
||||
})
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
on_punch = function(self, hitter)
|
||||
if self.itemstring ~= '' then
|
||||
local left = hitter:get_inventory():add_item("main", self.itemstring)
|
||||
if not left:is_empty() then
|
||||
self.itemstring = left:to_string()
|
||||
return
|
||||
end
|
||||
end
|
||||
self.itemstring = ''
|
||||
self.object:remove()
|
||||
end,
|
||||
})
|
||||
|
134
builtin/game/misc.lua
Normal file
134
builtin/game/misc.lua
Normal file
|
@ -0,0 +1,134 @@
|
|||
-- Minetest: builtin/misc.lua
|
||||
|
||||
--
|
||||
-- Misc. API functions
|
||||
--
|
||||
|
||||
minetest.timers_to_add = {}
|
||||
minetest.timers = {}
|
||||
minetest.register_globalstep(function(dtime)
|
||||
for _, timer in ipairs(minetest.timers_to_add) do
|
||||
table.insert(minetest.timers, timer)
|
||||
end
|
||||
minetest.timers_to_add = {}
|
||||
for index, timer in ipairs(minetest.timers) do
|
||||
timer.time = timer.time - dtime
|
||||
if timer.time <= 0 then
|
||||
timer.func(unpack(timer.args or {}))
|
||||
table.remove(minetest.timers,index)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
function minetest.after(time, func, ...)
|
||||
assert(tonumber(time) and type(func) == "function",
|
||||
"Invalid minetest.after invocation")
|
||||
table.insert(minetest.timers_to_add, {time=time, func=func, args={...}})
|
||||
end
|
||||
|
||||
function minetest.check_player_privs(name, privs)
|
||||
local player_privs = minetest.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
|
||||
end
|
||||
end
|
||||
if #missing_privileges > 0 then
|
||||
return false, missing_privileges
|
||||
end
|
||||
return true, ""
|
||||
end
|
||||
|
||||
local player_list = {}
|
||||
|
||||
minetest.register_on_joinplayer(function(player)
|
||||
player_list[player:get_player_name()] = player
|
||||
end)
|
||||
|
||||
minetest.register_on_leaveplayer(function(player)
|
||||
player_list[player:get_player_name()] = nil
|
||||
end)
|
||||
|
||||
function minetest.get_connected_players()
|
||||
local temp_table = {}
|
||||
for index, value in pairs(player_list) do
|
||||
if value:is_player_connected() then
|
||||
table.insert(temp_table, value)
|
||||
end
|
||||
end
|
||||
return temp_table
|
||||
end
|
||||
|
||||
function minetest.hash_node_position(pos)
|
||||
return (pos.z+32768)*65536*65536 + (pos.y+32768)*65536 + pos.x+32768
|
||||
end
|
||||
|
||||
function minetest.get_position_from_hash(hash)
|
||||
local pos = {}
|
||||
pos.x = (hash%65536) - 32768
|
||||
hash = math.floor(hash/65536)
|
||||
pos.y = (hash%65536) - 32768
|
||||
hash = math.floor(hash/65536)
|
||||
pos.z = (hash%65536) - 32768
|
||||
return pos
|
||||
end
|
||||
|
||||
function minetest.get_item_group(name, group)
|
||||
if not minetest.registered_items[name] or not
|
||||
minetest.registered_items[name].groups[group] then
|
||||
return 0
|
||||
end
|
||||
return minetest.registered_items[name].groups[group]
|
||||
end
|
||||
|
||||
function minetest.get_node_group(name, group)
|
||||
minetest.log("deprecated", "Deprecated usage of get_node_group, use get_item_group instead")
|
||||
return minetest.get_item_group(name, group)
|
||||
end
|
||||
|
||||
function minetest.string_to_pos(value)
|
||||
local p = {}
|
||||
p.x, p.y, p.z = string.match(value, "^([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+)$")
|
||||
if p.x and p.y and p.z then
|
||||
p.x = tonumber(p.x)
|
||||
p.y = tonumber(p.y)
|
||||
p.z = tonumber(p.z)
|
||||
return p
|
||||
end
|
||||
local p = {}
|
||||
p.x, p.y, p.z = string.match(value, "^%( *([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+) *%)$")
|
||||
if p.x and p.y and p.z then
|
||||
p.x = tonumber(p.x)
|
||||
p.y = tonumber(p.y)
|
||||
p.z = tonumber(p.z)
|
||||
return p
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
assert(minetest.string_to_pos("10.0, 5, -2").x == 10)
|
||||
assert(minetest.string_to_pos("( 10.0, 5, -2)").z == -2)
|
||||
assert(minetest.string_to_pos("asd, 5, -2)") == nil)
|
||||
|
||||
function minetest.setting_get_pos(name)
|
||||
local value = minetest.setting_get(name)
|
||||
if not value then
|
||||
return nil
|
||||
end
|
||||
return minetest.string_to_pos(value)
|
||||
end
|
||||
|
||||
-- To be overriden by protection mods
|
||||
function minetest.is_protected(pos, name)
|
||||
return false
|
||||
end
|
||||
|
||||
function minetest.record_protection_violation(pos, name)
|
||||
for _, func in pairs(minetest.registered_on_protection_violation) do
|
||||
func(pos, name)
|
||||
end
|
||||
end
|
||||
|
53
builtin/game/privileges.lua
Normal file
53
builtin/game/privileges.lua
Normal file
|
@ -0,0 +1,53 @@
|
|||
-- Minetest: builtin/privileges.lua
|
||||
|
||||
--
|
||||
-- Privileges
|
||||
--
|
||||
|
||||
minetest.registered_privileges = {}
|
||||
|
||||
function minetest.register_privilege(name, param)
|
||||
local function fill_defaults(def)
|
||||
if def.give_to_singleplayer == nil then
|
||||
def.give_to_singleplayer = true
|
||||
end
|
||||
if def.description == nil then
|
||||
def.description = "(no description)"
|
||||
end
|
||||
end
|
||||
local def = {}
|
||||
if type(param) == "table" then
|
||||
def = param
|
||||
else
|
||||
def = {description = param}
|
||||
end
|
||||
fill_defaults(def)
|
||||
minetest.registered_privileges[name] = def
|
||||
end
|
||||
|
||||
minetest.register_privilege("interact", "Can interact with things and modify the world")
|
||||
minetest.register_privilege("teleport", "Can use /teleport command")
|
||||
minetest.register_privilege("bring", "Can teleport other players")
|
||||
minetest.register_privilege("settime", "Can use /time")
|
||||
minetest.register_privilege("privs", "Can modify privileges")
|
||||
minetest.register_privilege("basic_privs", "Can modify 'shout' and 'interact' privileges")
|
||||
minetest.register_privilege("server", "Can do server maintenance stuff")
|
||||
minetest.register_privilege("shout", "Can speak in chat")
|
||||
minetest.register_privilege("ban", "Can ban and unban players")
|
||||
minetest.register_privilege("kick", "Can kick players")
|
||||
minetest.register_privilege("give", "Can use /give and /giveme")
|
||||
minetest.register_privilege("password", "Can use /setpassword and /clearpassword")
|
||||
minetest.register_privilege("fly", {
|
||||
description = "Can fly using the free_move mode",
|
||||
give_to_singleplayer = false,
|
||||
})
|
||||
minetest.register_privilege("fast", {
|
||||
description = "Can walk fast using the fast_move mode",
|
||||
give_to_singleplayer = false,
|
||||
})
|
||||
minetest.register_privilege("noclip", {
|
||||
description = "Can fly through walls",
|
||||
give_to_singleplayer = false,
|
||||
})
|
||||
minetest.register_privilege("rollback", "Can use the rollback functionality")
|
||||
|
410
builtin/game/register.lua
Normal file
410
builtin/game/register.lua
Normal file
|
@ -0,0 +1,410 @@
|
|||
-- Minetest: builtin/misc_register.lua
|
||||
|
||||
--
|
||||
-- Make raw registration functions inaccessible to anyone except this file
|
||||
--
|
||||
|
||||
local register_item_raw = minetest.register_item_raw
|
||||
minetest.register_item_raw = nil
|
||||
|
||||
local register_alias_raw = minetest.register_alias_raw
|
||||
minetest.register_item_raw = nil
|
||||
|
||||
--
|
||||
-- Item / entity / ABM registration functions
|
||||
--
|
||||
|
||||
minetest.registered_abms = {}
|
||||
minetest.registered_entities = {}
|
||||
minetest.registered_items = {}
|
||||
minetest.registered_nodes = {}
|
||||
minetest.registered_craftitems = {}
|
||||
minetest.registered_tools = {}
|
||||
minetest.registered_aliases = {}
|
||||
|
||||
-- For tables that are indexed by item name:
|
||||
-- If table[X] does not exist, default to table[minetest.registered_aliases[X]]
|
||||
local alias_metatable = {
|
||||
__index = function(t, name)
|
||||
return rawget(t, minetest.registered_aliases[name])
|
||||
end
|
||||
}
|
||||
setmetatable(minetest.registered_items, alias_metatable)
|
||||
setmetatable(minetest.registered_nodes, alias_metatable)
|
||||
setmetatable(minetest.registered_craftitems, alias_metatable)
|
||||
setmetatable(minetest.registered_tools, alias_metatable)
|
||||
|
||||
-- These item names may not be used because they would interfere
|
||||
-- with legacy itemstrings
|
||||
local forbidden_item_names = {
|
||||
MaterialItem = true,
|
||||
MaterialItem2 = true,
|
||||
MaterialItem3 = true,
|
||||
NodeItem = true,
|
||||
node = true,
|
||||
CraftItem = true,
|
||||
craft = true,
|
||||
MBOItem = true,
|
||||
ToolItem = true,
|
||||
tool = true,
|
||||
}
|
||||
|
||||
local function check_modname_prefix(name)
|
||||
if name:sub(1,1) == ":" then
|
||||
-- Escape the modname prefix enforcement mechanism
|
||||
return name:sub(2)
|
||||
else
|
||||
-- Modname prefix enforcement
|
||||
local expected_prefix = minetest.get_current_modname() .. ":"
|
||||
if name:sub(1, #expected_prefix) ~= expected_prefix then
|
||||
error("Name " .. name .. " does not follow naming conventions: " ..
|
||||
"\"modname:\" or \":\" prefix required")
|
||||
end
|
||||
local subname = name:sub(#expected_prefix+1)
|
||||
if subname:find("[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_]") then
|
||||
error("Name " .. name .. " does not follow naming conventions: " ..
|
||||
"contains unallowed characters")
|
||||
end
|
||||
return name
|
||||
end
|
||||
end
|
||||
|
||||
function minetest.register_abm(spec)
|
||||
-- Add to minetest.registered_abms
|
||||
minetest.registered_abms[#minetest.registered_abms+1] = spec
|
||||
end
|
||||
|
||||
function minetest.register_entity(name, prototype)
|
||||
-- Check name
|
||||
if name == nil then
|
||||
error("Unable to register entity: Name is nil")
|
||||
end
|
||||
name = check_modname_prefix(tostring(name))
|
||||
|
||||
prototype.name = name
|
||||
prototype.__index = prototype -- so that it can be used as a metatable
|
||||
|
||||
-- Add to minetest.registered_entities
|
||||
minetest.registered_entities[name] = prototype
|
||||
end
|
||||
|
||||
function minetest.register_item(name, itemdef)
|
||||
-- Check name
|
||||
if name == nil then
|
||||
error("Unable to register item: Name is nil")
|
||||
end
|
||||
name = check_modname_prefix(tostring(name))
|
||||
if forbidden_item_names[name] then
|
||||
error("Unable to register item: Name is forbidden: " .. name)
|
||||
end
|
||||
itemdef.name = name
|
||||
|
||||
-- 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
|
||||
itemdef.selection_box = itemdef.node_box
|
||||
elseif itemdef.drawtype == "fencelike" and not itemdef.selection_box then
|
||||
itemdef.selection_box = {
|
||||
type = "fixed",
|
||||
fixed = {-1/8, -1/2, -1/8, 1/8, 1/2, 1/8},
|
||||
}
|
||||
end
|
||||
setmetatable(itemdef, {__index = minetest.nodedef_default})
|
||||
minetest.registered_nodes[itemdef.name] = itemdef
|
||||
elseif itemdef.type == "craft" then
|
||||
setmetatable(itemdef, {__index = minetest.craftitemdef_default})
|
||||
minetest.registered_craftitems[itemdef.name] = itemdef
|
||||
elseif itemdef.type == "tool" then
|
||||
setmetatable(itemdef, {__index = minetest.tooldef_default})
|
||||
minetest.registered_tools[itemdef.name] = itemdef
|
||||
elseif itemdef.type == "none" then
|
||||
setmetatable(itemdef, {__index = minetest.noneitemdef_default})
|
||||
else
|
||||
error("Unable to register item: Type is invalid: " .. dump(itemdef))
|
||||
end
|
||||
|
||||
-- Flowing liquid uses param2
|
||||
if itemdef.type == "node" and itemdef.liquidtype == "flowing" then
|
||||
itemdef.paramtype2 = "flowingliquid"
|
||||
end
|
||||
|
||||
-- BEGIN Legacy stuff
|
||||
if itemdef.cookresult_itemstring ~= nil and itemdef.cookresult_itemstring ~= "" then
|
||||
minetest.register_craft({
|
||||
type="cooking",
|
||||
output=itemdef.cookresult_itemstring,
|
||||
recipe=itemdef.name,
|
||||
cooktime=itemdef.furnace_cooktime
|
||||
})
|
||||
end
|
||||
if itemdef.furnace_burntime ~= nil and itemdef.furnace_burntime >= 0 then
|
||||
minetest.register_craft({
|
||||
type="fuel",
|
||||
recipe=itemdef.name,
|
||||
burntime=itemdef.furnace_burntime
|
||||
})
|
||||
end
|
||||
-- END Legacy stuff
|
||||
|
||||
-- Disable all further modifications
|
||||
getmetatable(itemdef).__newindex = {}
|
||||
|
||||
--minetest.log("Registering item: " .. itemdef.name)
|
||||
minetest.registered_items[itemdef.name] = itemdef
|
||||
minetest.registered_aliases[itemdef.name] = nil
|
||||
register_item_raw(itemdef)
|
||||
end
|
||||
|
||||
function minetest.register_node(name, nodedef)
|
||||
nodedef.type = "node"
|
||||
minetest.register_item(name, nodedef)
|
||||
end
|
||||
|
||||
function minetest.register_craftitem(name, craftitemdef)
|
||||
craftitemdef.type = "craft"
|
||||
|
||||
-- BEGIN Legacy stuff
|
||||
if craftitemdef.inventory_image == nil and craftitemdef.image ~= nil then
|
||||
craftitemdef.inventory_image = craftitemdef.image
|
||||
end
|
||||
-- END Legacy stuff
|
||||
|
||||
minetest.register_item(name, craftitemdef)
|
||||
end
|
||||
|
||||
function minetest.register_tool(name, tooldef)
|
||||
tooldef.type = "tool"
|
||||
tooldef.stack_max = 1
|
||||
|
||||
-- BEGIN Legacy stuff
|
||||
if tooldef.inventory_image == nil and tooldef.image ~= nil then
|
||||
tooldef.inventory_image = tooldef.image
|
||||
end
|
||||
if tooldef.tool_capabilities == nil and
|
||||
(tooldef.full_punch_interval ~= nil or
|
||||
tooldef.basetime ~= nil or
|
||||
tooldef.dt_weight ~= nil or
|
||||
tooldef.dt_crackiness ~= nil or
|
||||
tooldef.dt_crumbliness ~= nil or
|
||||
tooldef.dt_cuttability ~= nil or
|
||||
tooldef.basedurability ~= nil or
|
||||
tooldef.dd_weight ~= nil or
|
||||
tooldef.dd_crackiness ~= nil or
|
||||
tooldef.dd_crumbliness ~= nil or
|
||||
tooldef.dd_cuttability ~= nil) then
|
||||
tooldef.tool_capabilities = {
|
||||
full_punch_interval = tooldef.full_punch_interval,
|
||||
basetime = tooldef.basetime,
|
||||
dt_weight = tooldef.dt_weight,
|
||||
dt_crackiness = tooldef.dt_crackiness,
|
||||
dt_crumbliness = tooldef.dt_crumbliness,
|
||||
dt_cuttability = tooldef.dt_cuttability,
|
||||
basedurability = tooldef.basedurability,
|
||||
dd_weight = tooldef.dd_weight,
|
||||
dd_crackiness = tooldef.dd_crackiness,
|
||||
dd_crumbliness = tooldef.dd_crumbliness,
|
||||
dd_cuttability = tooldef.dd_cuttability,
|
||||
}
|
||||
end
|
||||
-- END Legacy stuff
|
||||
|
||||
minetest.register_item(name, tooldef)
|
||||
end
|
||||
|
||||
function minetest.register_alias(name, convert_to)
|
||||
if forbidden_item_names[name] then
|
||||
error("Unable to register alias: Name is forbidden: " .. name)
|
||||
end
|
||||
if minetest.registered_items[name] ~= nil then
|
||||
minetest.log("WARNING: Not registering alias, item with same name" ..
|
||||
" is already defined: " .. name .. " -> " .. convert_to)
|
||||
else
|
||||
--minetest.log("Registering alias: " .. name .. " -> " .. convert_to)
|
||||
minetest.registered_aliases[name] = convert_to
|
||||
register_alias_raw(name, convert_to)
|
||||
end
|
||||
end
|
||||
|
||||
local register_biome_raw = minetest.register_biome
|
||||
minetest.registered_biomes = {}
|
||||
function minetest.register_biome(biome)
|
||||
minetest.registered_biomes[biome.name] = biome
|
||||
register_biome_raw(biome)
|
||||
end
|
||||
|
||||
function minetest.on_craft(itemstack, player, old_craft_list, craft_inv)
|
||||
for _, func in ipairs(minetest.registered_on_crafts) do
|
||||
itemstack = func(itemstack, player, old_craft_list, craft_inv) or itemstack
|
||||
end
|
||||
return itemstack
|
||||
end
|
||||
|
||||
function minetest.craft_predict(itemstack, player, old_craft_list, craft_inv)
|
||||
for _, func in ipairs(minetest.registered_craft_predicts) do
|
||||
itemstack = func(itemstack, player, old_craft_list, craft_inv) or itemstack
|
||||
end
|
||||
return itemstack
|
||||
end
|
||||
|
||||
-- Alias the forbidden item names to "" so they can't be
|
||||
-- created via itemstrings (e.g. /give)
|
||||
local name
|
||||
for name in pairs(forbidden_item_names) do
|
||||
minetest.registered_aliases[name] = ""
|
||||
register_alias_raw(name, "")
|
||||
end
|
||||
|
||||
|
||||
-- Deprecated:
|
||||
-- Aliases for minetest.register_alias (how ironic...)
|
||||
--minetest.alias_node = minetest.register_alias
|
||||
--minetest.alias_tool = minetest.register_alias
|
||||
--minetest.alias_craftitem = minetest.register_alias
|
||||
|
||||
--
|
||||
-- Built-in node definitions. Also defined in C.
|
||||
--
|
||||
|
||||
minetest.register_item(":unknown", {
|
||||
type = "none",
|
||||
description = "Unknown Item",
|
||||
inventory_image = "unknown_item.png",
|
||||
on_place = minetest.item_place,
|
||||
on_drop = minetest.item_drop,
|
||||
groups = {not_in_creative_inventory=1},
|
||||
diggable = true,
|
||||
})
|
||||
|
||||
minetest.register_node(":air", {
|
||||
description = "Air (you hacker you!)",
|
||||
inventory_image = "unknown_node.png",
|
||||
wield_image = "unknown_node.png",
|
||||
drawtype = "airlike",
|
||||
paramtype = "light",
|
||||
sunlight_propagates = true,
|
||||
walkable = false,
|
||||
pointable = false,
|
||||
diggable = false,
|
||||
buildable_to = true,
|
||||
air_equivalent = true,
|
||||
drop = "",
|
||||
groups = {not_in_creative_inventory=1},
|
||||
})
|
||||
|
||||
minetest.register_node(":ignore", {
|
||||
description = "Ignore (you hacker you!)",
|
||||
inventory_image = "unknown_node.png",
|
||||
wield_image = "unknown_node.png",
|
||||
drawtype = "airlike",
|
||||
paramtype = "none",
|
||||
sunlight_propagates = false,
|
||||
walkable = false,
|
||||
pointable = false,
|
||||
diggable = false,
|
||||
buildable_to = true, -- A way to remove accidentally placed ignores
|
||||
air_equivalent = true,
|
||||
drop = "",
|
||||
groups = {not_in_creative_inventory=1},
|
||||
})
|
||||
|
||||
-- The hand (bare definition)
|
||||
minetest.register_item(":", {
|
||||
type = "none",
|
||||
groups = {not_in_creative_inventory=1},
|
||||
})
|
||||
|
||||
|
||||
function minetest.override_item(name, redefinition)
|
||||
if redefinition.name ~= nil then
|
||||
error("Attempt to redefine name of "..name.." to "..dump(redefinition.name), 2)
|
||||
end
|
||||
if redefinition.type ~= nil then
|
||||
error("Attempt to redefine type of "..name.." to "..dump(redefinition.type), 2)
|
||||
end
|
||||
local item = minetest.registered_items[name]
|
||||
if not item then
|
||||
error("Attempt to override non-existent item "..name, 2)
|
||||
end
|
||||
for k, v in pairs(redefinition) do
|
||||
rawset(item, k, v)
|
||||
end
|
||||
register_item_raw(item)
|
||||
end
|
||||
|
||||
|
||||
function minetest.run_callbacks(callbacks, mode, ...)
|
||||
assert(type(callbacks) == "table")
|
||||
local cb_len = #callbacks
|
||||
if cb_len == 0 then
|
||||
if mode == 2 or mode == 3 then
|
||||
return true
|
||||
elseif mode == 4 or mode == 5 then
|
||||
return false
|
||||
end
|
||||
end
|
||||
local ret = nil
|
||||
for i = 1, cb_len do
|
||||
local cb_ret = callbacks[i](...)
|
||||
|
||||
if mode == 0 and i == 1 then
|
||||
ret = cb_ret
|
||||
elseif mode == 1 and i == cb_len then
|
||||
ret = cb_ret
|
||||
elseif mode == 2 then
|
||||
if not cb_ret or i == 1 then
|
||||
ret = cb_ret
|
||||
end
|
||||
elseif mode == 3 then
|
||||
if cb_ret then
|
||||
return cb_ret
|
||||
end
|
||||
ret = cb_ret
|
||||
elseif mode == 4 then
|
||||
if (cb_ret and not ret) or i == 1 then
|
||||
ret = cb_ret
|
||||
end
|
||||
elseif mode == 5 and cb_ret then
|
||||
return cb_ret
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
--
|
||||
-- Callback registration
|
||||
--
|
||||
|
||||
local function make_registration()
|
||||
local t = {}
|
||||
local registerfunc = function(func) table.insert(t, func) end
|
||||
return t, registerfunc
|
||||
end
|
||||
|
||||
local function make_registration_reverse()
|
||||
local t = {}
|
||||
local registerfunc = function(func) table.insert(t, 1, func) end
|
||||
return t, registerfunc
|
||||
end
|
||||
|
||||
minetest.registered_on_chat_messages, minetest.register_on_chat_message = make_registration()
|
||||
minetest.registered_globalsteps, minetest.register_globalstep = make_registration()
|
||||
minetest.registered_playerevents, minetest.register_playerevent = make_registration()
|
||||
minetest.registered_on_mapgen_inits, minetest.register_on_mapgen_init = make_registration()
|
||||
minetest.registered_on_shutdown, minetest.register_on_shutdown = make_registration()
|
||||
minetest.registered_on_punchnodes, minetest.register_on_punchnode = make_registration()
|
||||
minetest.registered_on_placenodes, minetest.register_on_placenode = make_registration()
|
||||
minetest.registered_on_dignodes, minetest.register_on_dignode = make_registration()
|
||||
minetest.registered_on_generateds, minetest.register_on_generated = make_registration()
|
||||
minetest.registered_on_newplayers, minetest.register_on_newplayer = make_registration()
|
||||
minetest.registered_on_dieplayers, minetest.register_on_dieplayer = make_registration()
|
||||
minetest.registered_on_respawnplayers, minetest.register_on_respawnplayer = make_registration()
|
||||
minetest.registered_on_prejoinplayers, minetest.register_on_prejoinplayer = make_registration()
|
||||
minetest.registered_on_joinplayers, minetest.register_on_joinplayer = make_registration()
|
||||
minetest.registered_on_leaveplayers, minetest.register_on_leaveplayer = make_registration()
|
||||
minetest.registered_on_player_receive_fields, minetest.register_on_player_receive_fields = make_registration_reverse()
|
||||
minetest.registered_on_cheats, minetest.register_on_cheat = make_registration()
|
||||
minetest.registered_on_crafts, minetest.register_on_craft = make_registration()
|
||||
minetest.registered_craft_predicts, minetest.register_craft_predict = make_registration()
|
||||
minetest.registered_on_protection_violation, minetest.register_on_protection_violation = make_registration()
|
||||
|
160
builtin/game/statbars.lua
Normal file
160
builtin/game/statbars.lua
Normal file
|
@ -0,0 +1,160 @@
|
|||
|
||||
local health_bar_definition =
|
||||
{
|
||||
hud_elem_type = "statbar",
|
||||
position = { x=0.5, y=1 },
|
||||
text = "heart.png",
|
||||
number = 20,
|
||||
direction = 0,
|
||||
size = { x=24, y=24 },
|
||||
offset = { x=(-10*24)-25, y=-(48+24+10)},
|
||||
}
|
||||
|
||||
local breath_bar_definition =
|
||||
{
|
||||
hud_elem_type = "statbar",
|
||||
position = { x=0.5, y=1 },
|
||||
text = "bubble.png",
|
||||
number = 20,
|
||||
direction = 0,
|
||||
size = { x=24, y=24 },
|
||||
offset = {x=25,y=-(48+24+10)},
|
||||
}
|
||||
|
||||
local hud_ids = {}
|
||||
|
||||
local function initialize_builtin_statbars(player)
|
||||
|
||||
if not player:is_player() then
|
||||
return
|
||||
end
|
||||
|
||||
local name = player:get_player_name()
|
||||
|
||||
if name == "" then
|
||||
return
|
||||
end
|
||||
|
||||
if (hud_ids[name] == nil) then
|
||||
hud_ids[name] = {}
|
||||
end
|
||||
|
||||
if player:hud_get_flags().healthbar then
|
||||
if hud_ids[name].id_healthbar == nil then
|
||||
health_bar_definition.number = player:get_hp()
|
||||
hud_ids[name].id_healthbar = player:hud_add(health_bar_definition)
|
||||
end
|
||||
else
|
||||
if hud_ids[name].id_healthbar ~= nil then
|
||||
player:hud_remove(hud_ids[name].id_healthbar)
|
||||
hud_ids[name].id_healthbar = nil
|
||||
end
|
||||
end
|
||||
|
||||
if (player:get_breath() < 11) then
|
||||
if player:hud_get_flags().breathbar then
|
||||
if hud_ids[name].id_breathbar == nil then
|
||||
hud_ids[name].id_breathbar = player:hud_add(breath_bar_definition)
|
||||
end
|
||||
else
|
||||
if hud_ids[name].id_breathbar ~= nil then
|
||||
player:hud_remove(hud_ids[name].id_breathbar)
|
||||
hud_ids[name].id_breathbar = nil
|
||||
end
|
||||
end
|
||||
elseif hud_ids[name].id_breathbar ~= nil then
|
||||
player:hud_remove(hud_ids[name].id_breathbar)
|
||||
hud_ids[name].id_breathbar = nil
|
||||
end
|
||||
end
|
||||
|
||||
local function cleanup_builtin_statbars(player)
|
||||
|
||||
if not player:is_player() then
|
||||
return
|
||||
end
|
||||
|
||||
local name = player:get_player_name()
|
||||
|
||||
if name == "" then
|
||||
return
|
||||
end
|
||||
|
||||
hud_ids[name] = nil
|
||||
end
|
||||
|
||||
local function player_event_handler(player,eventname)
|
||||
assert(player:is_player())
|
||||
|
||||
local name = player:get_player_name()
|
||||
|
||||
if name == "" then
|
||||
return
|
||||
end
|
||||
|
||||
if eventname == "health_changed" then
|
||||
initialize_builtin_statbars(player)
|
||||
|
||||
if hud_ids[name].id_healthbar ~= nil then
|
||||
player:hud_change(hud_ids[name].id_healthbar,"number",player:get_hp())
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
if eventname == "breath_changed" then
|
||||
initialize_builtin_statbars(player)
|
||||
|
||||
if hud_ids[name].id_breathbar ~= nil then
|
||||
player:hud_change(hud_ids[name].id_breathbar,"number",player:get_breath()*2)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
if eventname == "hud_changed" then
|
||||
initialize_builtin_statbars(player)
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function minetest.hud_replace_builtin(name, definition)
|
||||
|
||||
if definition == nil or
|
||||
type(definition) ~= "table" or
|
||||
definition.hud_elem_type ~= "statbar" then
|
||||
return false
|
||||
end
|
||||
|
||||
if name == "health" then
|
||||
health_bar_definition = definition
|
||||
|
||||
for name,ids in pairs(hud_ids) do
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if player and hud_ids[name].id_healthbar then
|
||||
player:hud_remove(hud_ids[name].id_healthbar)
|
||||
initialize_builtin_statbars(player)
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
if name == "breath" then
|
||||
breath_bar_definition = definition
|
||||
|
||||
for name,ids in pairs(hud_ids) do
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if player and hud_ids[name].id_breathbar then
|
||||
player:hud_remove(hud_ids[name].id_breathbar)
|
||||
initialize_builtin_statbars(player)
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
minetest.register_on_joinplayer(initialize_builtin_statbars)
|
||||
minetest.register_on_leaveplayer(cleanup_builtin_statbars)
|
||||
minetest.register_playerevent(player_event_handler)
|
33
builtin/game/static_spawn.lua
Normal file
33
builtin/game/static_spawn.lua
Normal file
|
@ -0,0 +1,33 @@
|
|||
-- Minetest: builtin/static_spawn.lua
|
||||
|
||||
local function warn_invalid_static_spawnpoint()
|
||||
if minetest.setting_get("static_spawnpoint") and
|
||||
not minetest.setting_get_pos("static_spawnpoint") then
|
||||
minetest.log('error', "The static_spawnpoint setting is invalid: \""..
|
||||
minetest.setting_get("static_spawnpoint").."\"")
|
||||
end
|
||||
end
|
||||
|
||||
warn_invalid_static_spawnpoint()
|
||||
|
||||
local function put_player_in_spawn(obj)
|
||||
warn_invalid_static_spawnpoint()
|
||||
local static_spawnpoint = minetest.setting_get_pos("static_spawnpoint")
|
||||
if not static_spawnpoint then
|
||||
return false
|
||||
end
|
||||
minetest.log('action', "Moving "..obj:get_player_name()..
|
||||
" to static spawnpoint at "..
|
||||
minetest.pos_to_string(static_spawnpoint))
|
||||
obj:setpos(static_spawnpoint)
|
||||
return true
|
||||
end
|
||||
|
||||
minetest.register_on_newplayer(function(obj)
|
||||
put_player_in_spawn(obj)
|
||||
end)
|
||||
|
||||
minetest.register_on_respawnplayer(function(obj)
|
||||
return put_player_in_spawn(obj)
|
||||
end)
|
||||
|
103
builtin/game/voxelarea.lua
Normal file
103
builtin/game/voxelarea.lua
Normal file
|
@ -0,0 +1,103 @@
|
|||
VoxelArea = {
|
||||
MinEdge = {x=1, y=1, z=1},
|
||||
MaxEdge = {x=0, y=0, z=0},
|
||||
ystride = 0,
|
||||
zstride = 0,
|
||||
}
|
||||
|
||||
function VoxelArea:new(o)
|
||||
o = o or {}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
|
||||
local e = o:getExtent()
|
||||
o.ystride = e.x
|
||||
o.zstride = e.x * e.y
|
||||
|
||||
return o
|
||||
end
|
||||
|
||||
function VoxelArea:getExtent()
|
||||
return {
|
||||
x = self.MaxEdge.x - self.MinEdge.x + 1,
|
||||
y = self.MaxEdge.y - self.MinEdge.y + 1,
|
||||
z = self.MaxEdge.z - self.MinEdge.z + 1,
|
||||
}
|
||||
end
|
||||
|
||||
function VoxelArea:getVolume()
|
||||
local e = self:getExtent()
|
||||
return e.x * e.y * e.z
|
||||
end
|
||||
|
||||
function VoxelArea:index(x, y, z)
|
||||
local i = (z - self.MinEdge.z) * self.zstride +
|
||||
(y - self.MinEdge.y) * self.ystride +
|
||||
(x - self.MinEdge.x) + 1
|
||||
return math.floor(i)
|
||||
end
|
||||
|
||||
function VoxelArea:indexp(p)
|
||||
local i = (p.z - self.MinEdge.z) * self.zstride +
|
||||
(p.y - self.MinEdge.y) * self.ystride +
|
||||
(p.x - self.MinEdge.x) + 1
|
||||
return math.floor(i)
|
||||
end
|
||||
|
||||
function VoxelArea:position(i)
|
||||
local p = {}
|
||||
|
||||
i = i - 1
|
||||
|
||||
p.z = math.floor(i / self.zstride) + self.MinEdge.z
|
||||
i = i % self.zstride
|
||||
|
||||
p.y = math.floor(i / self.ystride) + self.MinEdge.y
|
||||
i = i % self.ystride
|
||||
|
||||
p.x = math.floor(i) + self.MinEdge.x
|
||||
|
||||
return p
|
||||
end
|
||||
|
||||
function VoxelArea:contains(x, y, z)
|
||||
return (x >= self.MinEdge.x) and (x <= self.MaxEdge.x) and
|
||||
(y >= self.MinEdge.y) and (y <= self.MaxEdge.y) and
|
||||
(z >= self.MinEdge.z) and (z <= self.MaxEdge.z)
|
||||
end
|
||||
|
||||
function VoxelArea:containsp(p)
|
||||
return (p.x >= self.MinEdge.x) and (p.x <= self.MaxEdge.x) and
|
||||
(p.y >= self.MinEdge.y) and (p.y <= self.MaxEdge.y) and
|
||||
(p.z >= self.MinEdge.z) and (p.z <= self.MaxEdge.z)
|
||||
end
|
||||
|
||||
function VoxelArea:containsi(i)
|
||||
return (i >= 1) and (i <= self:getVolume())
|
||||
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
|
||||
return function()
|
||||
i = i + 1
|
||||
if i % zstride == zoff then
|
||||
i = i + zstridediff
|
||||
elseif i % ystride == yoff then
|
||||
i = i + ystridediff
|
||||
end
|
||||
if i <= last then
|
||||
return i
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function VoxelArea:iterp(minp, maxp)
|
||||
return self:iter(minp.x, minp.y, minp.z, maxp.x, maxp.y, maxp.z)
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue