Commit fff67d86 authored by Markus Koschany's avatar Markus Koschany

New upstream version 0.4.17+repack

parent d938c80e
...@@ -13,7 +13,7 @@ set(PROJECT_NAME_CAPITALIZED "Minetest") ...@@ -13,7 +13,7 @@ set(PROJECT_NAME_CAPITALIZED "Minetest")
# Also remember to set PROTOCOL_VERSION in network/networkprotocol.h when releasing # Also remember to set PROTOCOL_VERSION in network/networkprotocol.h when releasing
set(VERSION_MAJOR 0) set(VERSION_MAJOR 0)
set(VERSION_MINOR 4) set(VERSION_MINOR 4)
set(VERSION_PATCH 16) set(VERSION_PATCH 17)
set(VERSION_EXTRA "" CACHE STRING "Stuff to append to version string") set(VERSION_EXTRA "" CACHE STRING "Stuff to append to version string")
# Change to false for releases # Change to false for releases
......
...@@ -14,7 +14,7 @@ android { ...@@ -14,7 +14,7 @@ android {
buildToolsVersion "25.0.3" buildToolsVersion "25.0.3"
defaultConfig { defaultConfig {
versionCode 17 versionCode 18
versionName "${System.env.VERSION_STR}.${versionCode}" versionName "${System.env.VERSION_STR}.${versionCode}"
minSdkVersion 9 minSdkVersion 9
targetSdkVersion 9 targetSdkVersion 9
......
...@@ -120,7 +120,12 @@ end ...@@ -120,7 +120,12 @@ end
-- The dumped and level arguments are internal-only. -- The dumped and level arguments are internal-only.
function dump(o, indent, nested, level) function dump(o, indent, nested, level)
if type(o) ~= "table" then local t = type(o)
if not level and t == "userdata" then
-- when userdata (e.g. player) is passed directly, print its metatable:
return "userdata metatable: " .. dump(getmetatable(o))
end
if t ~= "table" then
return basic_dump(o) return basic_dump(o)
end end
-- Contains table -> true/nil of currently nested tables -- Contains table -> true/nil of currently nested tables
...@@ -308,59 +313,25 @@ function core.formspec_escape(text) ...@@ -308,59 +313,25 @@ function core.formspec_escape(text)
end end
function core.wrap_text(text, charlimit) function core.wrap_text(text, max_length, as_table)
local retval = {} local result = {}
local line = {}
local current_idx = 1 if #text <= max_length then
return as_table and {text} or text
local start,stop = string_find(text, " ", current_idx)
local nl_start,nl_stop = string_find(text, "\n", current_idx)
local gotnewline = false
if nl_start ~= nil and (start == nil or nl_start < start) then
start = nl_start
stop = nl_stop
gotnewline = true
end end
local last_line = ""
while start ~= nil do
if string.len(last_line) + (stop-start) > charlimit then
retval[#retval + 1] = last_line
last_line = ""
end
if last_line ~= "" then
last_line = last_line .. " "
end
last_line = last_line .. string_sub(text, current_idx, stop - 1)
if gotnewline then
retval[#retval + 1] = last_line
last_line = ""
gotnewline = false
end
current_idx = stop+1
start,stop = string_find(text, " ", current_idx)
nl_start,nl_stop = string_find(text, "\n", current_idx)
if nl_start ~= nil and (start == nil or nl_start < start) then for word in text:gmatch('%S+') do
start = nl_start local cur_length = #table.concat(line, ' ')
stop = nl_stop if cur_length > 0 and cur_length + #word + 1 >= max_length then
gotnewline = true -- word wouldn't fit on current line, move to next line
table.insert(result, table.concat(line, ' '))
line = {}
end end
table.insert(line, word)
end end
--add last part of text table.insert(result, table.concat(line, ' '))
if string.len(last_line) + (string.len(text) - current_idx) > charlimit then return as_table and result or table.concat(result, '\n')
retval[#retval + 1] = last_line
retval[#retval + 1] = string_sub(text, current_idx)
else
last_line = last_line .. " " .. string_sub(text, current_idx)
retval[#retval + 1] = last_line
end
return retval
end end
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
...@@ -370,7 +341,7 @@ if INIT == "game" then ...@@ -370,7 +341,7 @@ if INIT == "game" then
local dirs2 = {20, 23, 22, 21} local dirs2 = {20, 23, 22, 21}
function core.rotate_and_place(itemstack, placer, pointed_thing, function core.rotate_and_place(itemstack, placer, pointed_thing,
infinitestacks, orient_flags) infinitestacks, orient_flags, prevent_after_place)
orient_flags = orient_flags or {} orient_flags = orient_flags or {}
local unode = core.get_node_or_nil(pointed_thing.under) local unode = core.get_node_or_nil(pointed_thing.under)
...@@ -379,41 +350,20 @@ if INIT == "game" then ...@@ -379,41 +350,20 @@ if INIT == "game" then
end end
local undef = core.registered_nodes[unode.name] local undef = core.registered_nodes[unode.name]
if undef and undef.on_rightclick then if undef and undef.on_rightclick then
undef.on_rightclick(pointed_thing.under, unode, placer, return undef.on_rightclick(pointed_thing.under, unode, placer,
itemstack, pointed_thing) itemstack, pointed_thing)
return
end end
local fdir = core.dir_to_facedir(placer:get_look_dir()) local fdir = placer and core.dir_to_facedir(placer:get_look_dir()) or 0
local wield_name = itemstack:get_name()
local above = pointed_thing.above local above = pointed_thing.above
local under = pointed_thing.under local under = pointed_thing.under
local iswall = (above.y == under.y) local iswall = (above.y == under.y)
local isceiling = not iswall and (above.y < under.y) local isceiling = not iswall and (above.y < under.y)
local anode = core.get_node_or_nil(above)
if not anode then
return
end
local pos = pointed_thing.above
local node = anode
if undef and undef.buildable_to then if undef and undef.buildable_to then
pos = pointed_thing.under
node = unode
iswall = false iswall = false
end end
if core.is_protected(pos, placer:get_player_name()) then
core.record_protection_violation(pos,
placer:get_player_name())
return
end
local ndef = core.registered_nodes[node.name]
if not ndef or not ndef.buildable_to then
return
end
if orient_flags.force_floor then if orient_flags.force_floor then
iswall = false iswall = false
isceiling = false isceiling = false
...@@ -427,31 +377,26 @@ if INIT == "game" then ...@@ -427,31 +377,26 @@ if INIT == "game" then
iswall = not iswall iswall = not iswall
end end
local param2 = fdir
if iswall then if iswall then
core.set_node(pos, {name = wield_name, param2 = dirs1[fdir + 1]
param2 = dirs1[fdir + 1]})
elseif isceiling then elseif isceiling then
if orient_flags.force_facedir then if orient_flags.force_facedir then
core.set_node(pos, {name = wield_name, cparam2 = 20
param2 = 20})
else else
core.set_node(pos, {name = wield_name, param2 = dirs2[fdir + 1]
param2 = dirs2[fdir + 1]})
end end
else -- place right side up else -- place right side up
if orient_flags.force_facedir then if orient_flags.force_facedir then
core.set_node(pos, {name = wield_name, param2 = 0
param2 = 0})
else
core.set_node(pos, {name = wield_name,
param2 = fdir})
end end
end end
if not infinitestacks then local old_itemstack = ItemStack(itemstack)
itemstack:take_item() local new_itemstack, removed = core.item_place_node(
return itemstack itemstack, placer, pointed_thing, param2, prevent_after_place
end )
return infinitestacks and old_itemstack or new_itemstack
end end
...@@ -459,12 +404,18 @@ if INIT == "game" then ...@@ -459,12 +404,18 @@ if INIT == "game" then
--Wrapper for rotate_and_place() to check for sneak and assume Creative mode --Wrapper for rotate_and_place() to check for sneak and assume Creative mode
--implies infinite stacks when performing a 6d rotation. --implies infinite stacks when performing a 6d rotation.
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
local creative_mode_cache = core.settings:get_bool("creative_mode")
local function is_creative(name)
return creative_mode_cache or
core.check_player_privs(name, {creative = true})
end
core.rotate_node = function(itemstack, placer, pointed_thing) core.rotate_node = function(itemstack, placer, pointed_thing)
local name = placer and placer:get_player_name() or ""
local invert_wall = placer and placer:get_player_control().sneak or false
core.rotate_and_place(itemstack, placer, pointed_thing, core.rotate_and_place(itemstack, placer, pointed_thing,
core.settings:get_bool("creative_mode"), is_creative(name),
{invert_wall = placer:get_player_control().sneak}) {invert_wall = invert_wall}, true)
return itemstack return itemstack
end end
end end
...@@ -642,44 +593,26 @@ end ...@@ -642,44 +593,26 @@ end
local ESCAPE_CHAR = string.char(0x1b) local ESCAPE_CHAR = string.char(0x1b)
-- Client-side mods don't have access to settings function core.get_color_escape_sequence(color)
if core.settings and core.settings:get_bool("disable_escape_sequences") then return ESCAPE_CHAR .. "(c@" .. color .. ")"
end
function core.get_color_escape_sequence(color)
return ""
end
function core.get_background_escape_sequence(color)
return ""
end
function core.colorize(color, message)
return message
end
else
function core.get_color_escape_sequence(color)
return ESCAPE_CHAR .. "(c@" .. color .. ")"
end
function core.get_background_escape_sequence(color)
return ESCAPE_CHAR .. "(b@" .. color .. ")"
end
function core.colorize(color, message) function core.get_background_escape_sequence(color)
local lines = tostring(message):split("\n", true) return ESCAPE_CHAR .. "(b@" .. color .. ")"
local color_code = core.get_color_escape_sequence(color) end
for i, line in ipairs(lines) do function core.colorize(color, message)
lines[i] = color_code .. line local lines = tostring(message):split("\n", true)
end local color_code = core.get_color_escape_sequence(color)
return table.concat(lines, "\n") .. core.get_color_escape_sequence("#ffffff") for i, line in ipairs(lines) do
lines[i] = color_code .. line
end end
return table.concat(lines, "\n") .. core.get_color_escape_sequence("#ffffff")
end end
function core.strip_foreground_colors(str) function core.strip_foreground_colors(str)
return (str:gsub(ESCAPE_CHAR .. "%(c@[^)]+%)", "")) return (str:gsub(ESCAPE_CHAR .. "%(c@[^)]+%)", ""))
end end
......
...@@ -67,16 +67,15 @@ local function save_auth_file() ...@@ -67,16 +67,15 @@ local function save_auth_file()
assert(type(stuff.privileges) == "table") assert(type(stuff.privileges) == "table")
assert(stuff.last_login == nil or type(stuff.last_login) == "number") assert(stuff.last_login == nil or type(stuff.last_login) == "number")
end end
local file, errmsg = io.open(core.auth_file_path, 'w+b') local content = {}
if not file then
error(core.auth_file_path.." could not be opened for writing: "..errmsg)
end
for name, stuff in pairs(core.auth_table) do for name, stuff in pairs(core.auth_table) do
local priv_string = core.privs_to_string(stuff.privileges) local priv_string = core.privs_to_string(stuff.privileges)
local parts = {name, stuff.password, priv_string, stuff.last_login or ""} local parts = {name, stuff.password, priv_string, stuff.last_login or ""}
file:write(table.concat(parts, ":").."\n") content[#content + 1] = table.concat(parts, ":")
end
if not core.safe_file_write(core.auth_file_path, table.concat(content, "\n")) then
error(core.auth_file_path.." could not be written to")
end end
io.close(file)
end end
read_auth_file() read_auth_file()
......
...@@ -653,8 +653,8 @@ core.register_chatcommand("pulverize", { ...@@ -653,8 +653,8 @@ core.register_chatcommand("pulverize", {
core.rollback_punch_callbacks = {} core.rollback_punch_callbacks = {}
core.register_on_punchnode(function(pos, node, puncher) core.register_on_punchnode(function(pos, node, puncher)
local name = puncher:get_player_name() local name = puncher and puncher:get_player_name()
if core.rollback_punch_callbacks[name] then if name and core.rollback_punch_callbacks[name] then
core.rollback_punch_callbacks[name](pos, node, puncher) core.rollback_punch_callbacks[name](pos, node, puncher)
core.rollback_punch_callbacks[name] = nil core.rollback_punch_callbacks[name] = nil
end end
...@@ -814,7 +814,7 @@ core.register_chatcommand("shutdown", { ...@@ -814,7 +814,7 @@ core.register_chatcommand("shutdown", {
message = message or "" message = message or ""
if delay ~= "" then if delay ~= "" then
delay = tonumber(param) or 0 delay = tonumber(delay) or 0
else else
delay = 0 delay = 0
core.log("action", name .. " shuts down server") core.log("action", name .. " shuts down server")
......
...@@ -60,8 +60,13 @@ core.register_entity(":__builtin:falling_node", { ...@@ -60,8 +60,13 @@ core.register_entity(":__builtin:falling_node", {
local pos = self.object:getpos() local pos = self.object:getpos()
-- Position of bottom center point -- Position of bottom center point
local bcp = {x = pos.x, y = pos.y - 0.7, z = pos.z} local bcp = {x = pos.x, y = pos.y - 0.7, z = pos.z}
-- Avoid bugs caused by an unloaded node below -- 'bcn' is nil for unloaded nodes
local bcn = core.get_node_or_nil(bcp) local bcn = core.get_node_or_nil(bcp)
-- Delete on contact with ignore at world edges
if bcn and bcn.name == "ignore" then
self.object:remove()
return
end
local bcd = bcn and core.registered_nodes[bcn.name] local bcd = bcn and core.registered_nodes[bcn.name]
if bcn and if bcn and
(not bcd or bcd.walkable or (not bcd or bcd.walkable or
...@@ -93,7 +98,7 @@ core.register_entity(":__builtin:falling_node", { ...@@ -93,7 +98,7 @@ core.register_entity(":__builtin:falling_node", {
core.remove_node(np) core.remove_node(np)
if nd and nd.buildable_to == false then if nd and nd.buildable_to == false then
-- Add dropped items -- Add dropped items
local drops = core.get_node_drops(n2.name, "") local drops = core.get_node_drops(n2, "")
for _, dropped_item in pairs(drops) do for _, dropped_item in pairs(drops) do
core.add_item(np, dropped_item) core.add_item(np, dropped_item)
end end
...@@ -145,9 +150,9 @@ function core.spawn_falling_node(pos) ...@@ -145,9 +150,9 @@ function core.spawn_falling_node(pos)
end end
local function drop_attached_node(p) local function drop_attached_node(p)
local nn = core.get_node(p).name local n = core.get_node(p)
core.remove_node(p) core.remove_node(p)
for _, item in pairs(core.get_node_drops(nn, "")) do for _, item in pairs(core.get_node_drops(n, "")) do
local pos = { local pos = {
x = p.x + math.random()/2 - 0.25, x = p.x + math.random()/2 - 0.25,
y = p.y + math.random()/2 - 0.25, y = p.y + math.random()/2 - 0.25,
......
This diff is collapsed.
...@@ -174,19 +174,18 @@ core.register_entity(":__builtin:item", { ...@@ -174,19 +174,18 @@ core.register_entity(":__builtin:item", {
local p = self.object:getpos() local p = self.object:getpos()
p.y = p.y - 0.5 p.y = p.y - 0.5
local node = core.get_node_or_nil(p) local node = core.get_node_or_nil(p)
local in_unloaded = (node == nil) -- Delete in 'ignore' nodes
if in_unloaded then if node and node.name == "ignore" then
-- Don't infinetly fall into unloaded map self.itemstring = ""
self.object:setvelocity({x = 0, y = 0, z = 0}) self.object:remove()
self.object:setacceleration({x = 0, y = 0, z = 0})
self.physical_state = false
self.object:set_properties({physical = false})
return return
end end
local nn = node.name
-- If node is not registered or node is walkably solid and resting on nodebox -- If node is nil (unloaded area), or node is not registered, or node is
-- walkably solid and item is resting on nodebox
local v = self.object:getvelocity() local v = self.object:getvelocity()
if not core.registered_nodes[nn] or core.registered_nodes[nn].walkable and v.y == 0 then if not node or not core.registered_nodes[node.name] or
core.registered_nodes[node.name].walkable and v.y == 0 then
if self.physical_state then if self.physical_state then
local own_stack = ItemStack(self.object:get_luaentity().itemstring) local own_stack = ItemStack(self.object:get_luaentity().itemstring)
-- Merge with close entities of the same item -- Merge with close entities of the same item
......
...@@ -5,12 +5,11 @@ ...@@ -5,12 +5,11 @@
-- --
function core.check_player_privs(name, ...) function core.check_player_privs(name, ...)
local arg_type = type(name) if core.is_player(name) then
if (arg_type == "userdata" or arg_type == "table") and
name.get_player_name then -- If it quacks like a Player...
name = name:get_player_name() name = name:get_player_name()
elseif arg_type ~= "string" then elseif type(name) ~= "string" then
error("Invalid core.check_player_privs argument type: " .. arg_type, 2) error("core.check_player_privs expects a player or playername as " ..
"argument.", 2)
end end
local requested_privs = {...} local requested_privs = {...}
...@@ -70,6 +69,16 @@ function core.get_connected_players() ...@@ -70,6 +69,16 @@ function core.get_connected_players()
return temp_table return temp_table
end end
function core.is_player(player)
-- a table being a player is also supported because it quacks sufficiently
-- like a player if it has the is_player function
local t = type(player)
return (t == "userdata" or t == "table") and
type(player.is_player) == "function" and player:is_player()
end
function minetest.player_exists(name) function minetest.player_exists(name)
return minetest.get_auth_handler().get_auth(name) ~= nil return minetest.get_auth_handler().get_auth(name) ~= nil
end end
......
...@@ -116,6 +116,8 @@ function core.register_item(name, itemdef) ...@@ -116,6 +116,8 @@ function core.register_item(name, itemdef)
end end
itemdef.name = name itemdef.name = name
local is_overriding = core.registered_items[name]
-- Apply defaults and add to registered_* table -- Apply defaults and add to registered_* table
if itemdef.type == "node" then if itemdef.type == "node" then
-- Use the nodebox as selection box if it's not set manually -- Use the nodebox as selection box if it's not set manually
...@@ -177,7 +179,13 @@ function core.register_item(name, itemdef) ...@@ -177,7 +179,13 @@ function core.register_item(name, itemdef)
--core.log("Registering item: " .. itemdef.name) --core.log("Registering item: " .. itemdef.name)
core.registered_items[itemdef.name] = itemdef core.registered_items[itemdef.name] = itemdef
core.registered_aliases[itemdef.name] = nil core.registered_aliases[itemdef.name] = nil
register_item_raw(itemdef)
-- Used to allow builtin to register ignore to registered_items
if name ~= "ignore" then
register_item_raw(itemdef)
elseif is_overriding then
core.log("warning", "Attempted redefinition of \"ignore\"")
end
end end
function core.unregister_item(name) function core.unregister_item(name)
......
...@@ -21,7 +21,6 @@ if core.print then ...@@ -21,7 +21,6 @@ if core.print then
core.print = nil -- don't pollute our namespace core.print = nil -- don't pollute our namespace
end end
math.randomseed(os.time()) math.randomseed(os.time())
os.setlocale("C", "numeric")
minetest = core minetest = core
-- Load other files -- Load other files
...@@ -47,7 +46,6 @@ elseif INIT == "mainmenu" then ...@@ -47,7 +46,6 @@ elseif INIT == "mainmenu" then
elseif INIT == "async" then elseif INIT == "async" then
dofile(asyncpath .. "init.lua") dofile(asyncpath .. "init.lua")
elseif INIT == "client" then elseif INIT == "client" then
os.setlocale = nil
dofile(clientpath .. "init.lua") dofile(clientpath .. "init.lua")
else else
error(("Unrecognized builtin initialization type %s!"):format(tostring(INIT))) error(("Unrecognized builtin initialization type %s!"):format(tostring(INIT)))
......
...@@ -250,7 +250,7 @@ end ...@@ -250,7 +250,7 @@ end
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
function text2textlist(xpos, ypos, width, height, tl_name, textlen, text, transparency) function text2textlist(xpos, ypos, width, height, tl_name, textlen, text, transparency)
local textlines = core.wrap_text(text, textlen) local textlines = core.wrap_text(text, textlen, true)
local retval = "textlist[" .. xpos .. "," .. ypos .. ";" .. width .. local retval = "textlist[" .. xpos .. "," .. ypos .. ";" .. width ..
"," .. height .. ";" .. tl_name .. ";" "," .. height .. ";" .. tl_name .. ";"
......
...@@ -17,39 +17,36 @@ ...@@ -17,39 +17,36 @@
local function delete_world_formspec(dialogdata) local function delete_world_formspec(dialogdata)
local retval = local retval =
"size[11.5,4.5,true]" .. "size[10,2.5,true]" ..
"label[2,2;" .. "label[0.5,0.5;" ..
fgettext("Delete World \"$1\"?", dialogdata.delete_name) .. "]" .. fgettext("Delete World \"$1\"?", dialogdata.delete_name) .. "]" ..
"button[3.25,3.5;2.5,0.5;world_delete_confirm;" .. fgettext("Delete") .. "]" .. "button[0.5,1.5;2.5,0.5;world_delete_confirm;" .. fgettext("Delete") .. "]" ..
"button[5.75,3.5;2.5,0.5;world_delete_cancel;" .. fgettext("Cancel") .. "]" "button[7.0,1.5;2.5,0.5;world_delete_cancel;" .. fgettext("Cancel") .. "]"
return retval return retval
end end
local function delete_world_buttonhandler(this, fields) local function delete_world_buttonhandler(this, fields)
if fields["world_delete_confirm"] then if fields["world_delete_confirm"] then
if this.data.delete_index > 0 and if this.data.delete_index > 0 and
this.data.delete_index <= #menudata.worldlist:get_raw_list() then this.data.delete_index <= #menudata.worldlist:get_raw_list() then
core.delete_world(this.data.delete_index) core.delete_world(this.data.delete_index)
menudata.worldlist:refresh() menudata.worldlist:refresh()
end end
this:delete() this:delete()
return true return true
end end
if fields["world_delete_cancel"] then if fields["world_delete_cancel"] then
this:delete() this:delete()