--- /dev/null
+engine.log("info", "Initializing Asynchronous environment")
+
+local core = engine or minetest
+
+function core.job_processor(serialized_func, serialized_param)
+ local func = loadstring(serialized_func)
+ local param = core.deserialize(serialized_param)
+ local retval = nil
+
+ if type(func) == "function" then
+ retval = core.serialize(func(param))
+ else
+ core.log("error", "ASYNC WORKER: Unable to deserialize function")
+ end
+
+ return retval or core.serialize(nil)
+end
+
+++ /dev/null
-engine.log("info", "Initializing Asynchronous environment")
-local tbl = engine or minetest
-
-minetest = tbl
-dofile(SCRIPTDIR .. DIR_DELIM .. "serialize.lua")
-dofile(SCRIPTDIR .. DIR_DELIM .. "misc_helpers.lua")
-
-function tbl.job_processor(serialized_func, serialized_param)
- local func = loadstring(serialized_func)
- local param = tbl.deserialize(serialized_param)
- local retval = nil
-
- if type(func) == "function" then
- retval = tbl.serialize(func(param))
- else
- tbl.log("error", "ASYNC WORKER: Unable to deserialize function")
- end
-
- return retval or tbl.serialize(nil)
-end
-
+++ /dev/null
-local tbl = engine or minetest
-
-local SCRIPTDIR = SCRIPTDIR or tbl.get_scriptdir()
-minetest = tbl
-dofile(SCRIPTDIR .. DIR_DELIM .. "serialize.lua")
-
-tbl.async_jobs = {}
-
-local function handle_job(jobid, serialized_retval)
- local retval = tbl.deserialize(serialized_retval)
- assert(type(tbl.async_jobs[jobid]) == "function")
- tbl.async_jobs[jobid](retval)
- tbl.async_jobs[jobid] = nil
-end
-
-if engine ~= nil then
- tbl.async_event_handler = handle_job
-else
- minetest.register_globalstep(function(dtime)
- for i, job in ipairs(tbl.get_finished_jobs()) do
- handle_job(job.jobid, job.retval)
- end
- end)
-end
-
-function tbl.handle_async(func, parameter, callback)
- -- Serialize function
- local serialized_func = string.dump(func)
-
- assert(serialized_func ~= nil)
-
- -- Serialize parameters
- local serialized_param = tbl.serialize(parameter)
-
- if serialized_param == nil then
- return false
- end
-
- local jobid = tbl.do_async_callback(serialized_func, serialized_param)
-
- tbl.async_jobs[jobid] = callback
-
- return true
-end
-
+++ /dev/null
--- 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
-
-
+++ /dev/null
---
--- This file contains built-in stuff in Minetest implemented in Lua.
---
--- It is always loaded and executed after registration of the C API,
--- before loading and running any mods.
---
-
--- Initialize some very basic things
-print = minetest.debug
-math.randomseed(os.time())
-os.setlocale("C", "numeric")
-
--- Load other files
-local modpath = minetest.get_modpath("__builtin")
-dofile(modpath.."/serialize.lua")
-dofile(modpath.."/misc_helpers.lua")
-dofile(modpath.."/item.lua")
-dofile(modpath.."/misc_register.lua")
-dofile(modpath.."/item_entity.lua")
-dofile(modpath.."/deprecated.lua")
-dofile(modpath.."/misc.lua")
-dofile(modpath.."/privileges.lua")
-dofile(modpath.."/auth.lua")
-dofile(modpath.."/chatcommands.lua")
-dofile(modpath.."/static_spawn.lua")
-dofile(modpath.."/detached_inventory.lua")
-dofile(modpath.."/falling.lua")
-dofile(modpath.."/features.lua")
-dofile(modpath.."/voxelarea.lua")
-dofile(modpath.."/vector.lua")
-dofile(modpath.."/forceloading.lua")
-dofile(modpath.."/statbars.lua")
+++ /dev/null
--- 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,
-})
--- /dev/null
+
+local core = engine or minetest
+
+core.async_jobs = {}
+
+local function handle_job(jobid, serialized_retval)
+ local retval = core.deserialize(serialized_retval)
+ assert(type(core.async_jobs[jobid]) == "function")
+ core.async_jobs[jobid](retval)
+ core.async_jobs[jobid] = nil
+end
+
+if engine ~= nil then
+ core.async_event_handler = handle_job
+else
+ minetest.register_globalstep(function(dtime)
+ for i, job in ipairs(core.get_finished_jobs()) do
+ handle_job(job.jobid, job.retval)
+ end
+ end)
+end
+
+function core.handle_async(func, parameter, callback)
+ -- Serialize function
+ local serialized_func = string.dump(func)
+
+ assert(serialized_func ~= nil)
+
+ -- Serialize parameters
+ local serialized_param = core.serialize(parameter)
+
+ if serialized_param == nil then
+ return false
+ end
+
+ local jobid = core.do_async_callback(serialized_func, serialized_param)
+
+ core.async_jobs[jobid] = callback
+
+ return true
+end
+
--- /dev/null
+-- Minetest: builtin/misc_helpers.lua
+
+--------------------------------------------------------------------------------
+function basic_dump2(o)
+ if type(o) == "number" then
+ return tostring(o)
+ elseif type(o) == "string" then
+ return string.format("%q", o)
+ elseif type(o) == "boolean" then
+ return tostring(o)
+ elseif type(o) == "function" then
+ return "<function>"
+ elseif type(o) == "userdata" then
+ return "<userdata>"
+ elseif type(o) == "nil" then
+ return "nil"
+ else
+ error("cannot dump a " .. type(o))
+ return nil
+ end
+end
+
+--------------------------------------------------------------------------------
+function dump2(o, name, dumped)
+ name = name or "_"
+ dumped = dumped or {}
+ io.write(name, " = ")
+ if type(o) == "number" or type(o) == "string" or type(o) == "boolean"
+ or type(o) == "function" or type(o) == "nil"
+ or type(o) == "userdata" then
+ io.write(basic_dump2(o), "\n")
+ elseif type(o) == "table" then
+ if dumped[o] then
+ io.write(dumped[o], "\n")
+ else
+ dumped[o] = name
+ io.write("{}\n") -- new table
+ for k,v in pairs(o) do
+ local fieldname = string.format("%s[%s]", name, basic_dump2(k))
+ dump2(v, fieldname, dumped)
+ end
+ end
+ else
+ error("cannot dump a " .. type(o))
+ return nil
+ end
+end
+
+--------------------------------------------------------------------------------
+function dump(o, dumped)
+ dumped = dumped or {}
+ if type(o) == "number" then
+ return tostring(o)
+ elseif type(o) == "string" then
+ return string.format("%q", o)
+ elseif type(o) == "table" then
+ if dumped[o] then
+ return "<circular reference>"
+ end
+ dumped[o] = true
+ local t = {}
+ for k,v in pairs(o) do
+ t[#t+1] = "[" .. dump(k, dumped) .. "] = " .. dump(v, dumped)
+ end
+ return "{" .. table.concat(t, ", ") .. "}"
+ elseif type(o) == "boolean" then
+ return tostring(o)
+ elseif type(o) == "function" then
+ return "<function>"
+ elseif type(o) == "userdata" then
+ return "<userdata>"
+ elseif type(o) == "nil" then
+ return "nil"
+ else
+ error("cannot dump a " .. type(o))
+ return nil
+ end
+end
+
+--------------------------------------------------------------------------------
+function string:split(sep)
+ local sep, fields = sep or ",", {}
+ local pattern = string.format("([^%s]+)", sep)
+ self:gsub(pattern, function(c) fields[#fields+1] = c end)
+ return fields
+end
+
+--------------------------------------------------------------------------------
+function file_exists(filename)
+ local f = io.open(filename, "r")
+ if f==nil then
+ return false
+ else
+ f:close()
+ return true
+ end
+end
+
+--------------------------------------------------------------------------------
+function string:trim()
+ return (self:gsub("^%s*(.-)%s*$", "%1"))
+end
+
+assert(string.trim("\n \t\tfoo bar\t ") == "foo bar")
+
+--------------------------------------------------------------------------------
+function math.hypot(x, y)
+ local t
+ x = math.abs(x)
+ y = math.abs(y)
+ t = math.min(x, y)
+ x = math.max(x, y)
+ if x == 0 then return 0 end
+ t = t / x
+ return x * math.sqrt(1 + t * t)
+end
+
+--------------------------------------------------------------------------------
+function get_last_folder(text,count)
+ local parts = text:split(DIR_DELIM)
+
+ if count == nil then
+ return parts[#parts]
+ end
+
+ local retval = ""
+ for i=1,count,1 do
+ retval = retval .. parts[#parts - (count-i)] .. DIR_DELIM
+ end
+
+ return retval
+end
+
+--------------------------------------------------------------------------------
+function cleanup_path(temppath)
+
+ local parts = temppath:split("-")
+ temppath = ""
+ for i=1,#parts,1 do
+ if temppath ~= "" then
+ temppath = temppath .. "_"
+ end
+ temppath = temppath .. parts[i]
+ end
+
+ parts = temppath:split(".")
+ temppath = ""
+ for i=1,#parts,1 do
+ if temppath ~= "" then
+ temppath = temppath .. "_"
+ end
+ temppath = temppath .. parts[i]
+ end
+
+ parts = temppath:split("'")
+ temppath = ""
+ for i=1,#parts,1 do
+ if temppath ~= "" then
+ temppath = temppath .. ""
+ end
+ temppath = temppath .. parts[i]
+ end
+
+ parts = temppath:split(" ")
+ temppath = ""
+ for i=1,#parts,1 do
+ if temppath ~= "" then
+ temppath = temppath
+ end
+ temppath = temppath .. parts[i]
+ end
+
+ return temppath
+end
+
+local tbl = engine or minetest
+function tbl.formspec_escape(text)
+ if text ~= nil then
+ text = string.gsub(text,"\\","\\\\")
+ text = string.gsub(text,"%]","\\]")
+ text = string.gsub(text,"%[","\\[")
+ text = string.gsub(text,";","\\;")
+ text = string.gsub(text,",","\\,")
+ end
+ return text
+end
+
+
+function tbl.splittext(text,charlimit)
+ local retval = {}
+
+ local current_idx = 1
+
+ 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
+ local last_line = ""
+ while start ~= nil do
+ if string.len(last_line) + (stop-start) > charlimit then
+ table.insert(retval,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
+ table.insert(retval,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
+ start = nl_start
+ stop = nl_stop
+ gotnewline = true
+ end
+ end
+
+ --add last part of text
+ if string.len(last_line) + (string.len(text) - current_idx) > charlimit then
+ table.insert(retval,last_line)
+ table.insert(retval,string.sub(text,current_idx))
+ else
+ last_line = last_line .. " " .. string.sub(text,current_idx)
+ table.insert(retval,last_line)
+ end
+
+ return retval
+end
+
+--------------------------------------------------------------------------------
+
+if minetest then
+ local dirs1 = {9, 18, 7, 12}
+ local dirs2 = {20, 23, 22, 21}
+
+ function minetest.rotate_and_place(itemstack, placer, pointed_thing,
+ infinitestacks, orient_flags)
+ orient_flags = orient_flags or {}
+
+ local unode = minetest.get_node_or_nil(pointed_thing.under)
+ if not unode then
+ return
+ end
+ local undef = minetest.registered_nodes[unode.name]
+ if undef and undef.on_rightclick then
+ undef.on_rightclick(pointed_thing.under, unode, placer,
+ itemstack, pointed_thing)
+ return
+ end
+ local pitch = placer:get_look_pitch()
+ local fdir = minetest.dir_to_facedir(placer:get_look_dir())
+ local wield_name = itemstack:get_name()
+
+ local above = pointed_thing.above
+ local under = pointed_thing.under
+ local iswall = (above.y == under.y)
+ local isceiling = not iswall and (above.y < under.y)
+ local anode = minetest.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
+ pos = pointed_thing.under
+ node = unode
+ iswall = false
+ end
+
+ if minetest.is_protected(pos, placer:get_player_name()) then
+ minetest.record_protection_violation(pos,
+ placer:get_player_name())
+ return
+ end
+
+ local ndef = minetest.registered_nodes[node.name]
+ if not ndef or not ndef.buildable_to then
+ return
+ end
+
+ if orient_flags.force_floor then
+ iswall = false
+ isceiling = false
+ elseif orient_flags.force_ceiling then
+ iswall = false
+ isceiling = true
+ elseif orient_flags.force_wall then
+ iswall = true
+ isceiling = false
+ elseif orient_flags.invert_wall then
+ iswall = not iswall
+ end
+
+ if iswall then
+ minetest.set_node(pos, {name = wield_name,
+ param2 = dirs1[fdir+1]})
+ elseif isceiling then
+ if orient_flags.force_facedir then
+ minetest.set_node(pos, {name = wield_name,
+ param2 = 20})
+ else
+ minetest.set_node(pos, {name = wield_name,
+ param2 = dirs2[fdir+1]})
+ end
+ else -- place right side up
+ if orient_flags.force_facedir then
+ minetest.set_node(pos, {name = wield_name,
+ param2 = 0})
+ else
+ minetest.set_node(pos, {name = wield_name,
+ param2 = fdir})
+ end
+ end
+
+ if not infinitestacks then
+ itemstack:take_item()
+ return itemstack
+ end
+ end
+
+
+--------------------------------------------------------------------------------
+--Wrapper for rotate_and_place() to check for sneak and assume Creative mode
+--implies infinite stacks when performing a 6d rotation.
+--------------------------------------------------------------------------------
+
+
+ minetest.rotate_node = function(itemstack, placer, pointed_thing)
+ minetest.rotate_and_place(itemstack, placer, pointed_thing,
+ minetest.setting_getbool("creative_mode"),
+ {invert_wall = placer:get_player_control().sneak})
+ return itemstack
+ end
+end
+
+--------------------------------------------------------------------------------
+function tbl.explode_table_event(evt)
+ if evt ~= nil then
+ local parts = evt:split(":")
+ if #parts == 3 then
+ local t = parts[1]:trim()
+ local r = tonumber(parts[2]:trim())
+ local c = tonumber(parts[3]:trim())
+ if type(r) == "number" and type(c) == "number" and t ~= "INV" then
+ return {type=t, row=r, column=c}
+ end
+ end
+ end
+ return {type="INV", row=0, column=0}
+end
+
+--------------------------------------------------------------------------------
+function tbl.explode_textlist_event(evt)
+ if evt ~= nil then
+ local parts = evt:split(":")
+ if #parts == 2 then
+ local t = parts[1]:trim()
+ local r = tonumber(parts[2]:trim())
+ if type(r) == "number" and t ~= "INV" then
+ return {type=t, index=r}
+ end
+ end
+ end
+ return {type="INV", index=0}
+end
+
+--------------------------------------------------------------------------------
+-- mainmenu only functions
+--------------------------------------------------------------------------------
+if engine ~= nil then
+ engine.get_game = function(index)
+ local games = game.get_games()
+
+ if index > 0 and index <= #games then
+ return games[index]
+ end
+
+ return nil
+ end
+
+ function fgettext(text, ...)
+ text = engine.gettext(text)
+ local arg = {n=select('#', ...), ...}
+ if arg.n >= 1 then
+ -- Insert positional parameters ($1, $2, ...)
+ result = ''
+ pos = 1
+ while pos <= text:len() do
+ newpos = text:find('[$]', pos)
+ if newpos == nil then
+ result = result .. text:sub(pos)
+ pos = text:len() + 1
+ else
+ paramindex = tonumber(text:sub(newpos+1, newpos+1))
+ result = result .. text:sub(pos, newpos-1) .. tostring(arg[paramindex])
+ pos = newpos + 2
+ end
+ end
+ text = result
+ end
+ return engine.formspec_escape(text)
+ end
+end
+--------------------------------------------------------------------------------
+-- core only fct
+--------------------------------------------------------------------------------
+if minetest ~= nil then
+ --------------------------------------------------------------------------------
+ function minetest.pos_to_string(pos)
+ return "(" .. pos.x .. "," .. pos.y .. "," .. pos.z .. ")"
+ end
+end
+
--- /dev/null
+-- Minetest: builtin/serialize.lua
+
+-- https://github.com/fab13n/metalua/blob/no-dll/src/lib/serialize.lua
+-- Copyright (c) 2006-2997 Fabien Fleutot <metalua@gmail.com>
+-- License: MIT
+--------------------------------------------------------------------------------
+-- Serialize an object into a source code string. This string, when passed as
+-- an argument to deserialize(), returns an object structurally identical
+-- to the original one. The following are currently supported:
+-- * strings, numbers, booleans, nil
+-- * tables thereof. Tables can have shared part, but can't be recursive yet.
+-- Caveat: metatables and environments aren't saved.
+--------------------------------------------------------------------------------
+
+local no_identity = { number=1, boolean=1, string=1, ['nil']=1 }
+
+function minetest.serialize(x)
+
+ local gensym_max = 0 -- index of the gensym() symbol generator
+ local seen_once = { } -- element->true set of elements seen exactly once in the table
+ local multiple = { } -- element->varname set of elements seen more than once
+ local nested = { } -- transient, set of elements currently being traversed
+ local nest_points = { }
+ local nest_patches = { }
+
+ local function gensym()
+ gensym_max = gensym_max + 1 ; return gensym_max
+ end
+
+ -----------------------------------------------------------------------------
+ -- nest_points are places where a table appears within itself, directly or not.
+ -- for instance, all of these chunks create nest points in table x:
+ -- "x = { }; x[x] = 1", "x = { }; x[1] = x", "x = { }; x[1] = { y = { x } }".
+ -- To handle those, two tables are created by mark_nest_point:
+ -- * nest_points [parent] associates all keys and values in table parent which
+ -- create a nest_point with boolean `true'
+ -- * nest_patches contain a list of { parent, key, value } tuples creating
+ -- a nest point. They're all dumped after all the other table operations
+ -- have been performed.
+ --
+ -- mark_nest_point (p, k, v) fills tables nest_points and nest_patches with
+ -- informations required to remember that key/value (k,v) create a nest point
+ -- in table parent. It also marks `parent' as occuring multiple times, since
+ -- several references to it will be required in order to patch the nest
+ -- points.
+ -----------------------------------------------------------------------------
+ local function mark_nest_point (parent, k, v)
+ local nk, nv = nested[k], nested[v]
+ assert (not nk or seen_once[k] or multiple[k])
+ assert (not nv or seen_once[v] or multiple[v])
+ local mode = (nk and nv and "kv") or (nk and "k") or ("v")
+ local parent_np = nest_points [parent]
+ local pair = { k, v }
+ if not parent_np then parent_np = { }; nest_points [parent] = parent_np end
+ parent_np [k], parent_np [v] = nk, nv
+ table.insert (nest_patches, { parent, k, v })
+ seen_once [parent], multiple [parent] = nil, true
+ end
+
+ -----------------------------------------------------------------------------
+ -- First pass, list the tables and functions which appear more than once in x
+ -----------------------------------------------------------------------------
+ local function mark_multiple_occurences (x)
+ if no_identity [type(x)] then return end
+ if seen_once [x] then seen_once [x], multiple [x] = nil, true
+ elseif multiple [x] then -- pass
+ else seen_once [x] = true end
+
+ if type (x) == 'table' then
+ nested [x] = true
+ for k, v in pairs (x) do
+ if nested[k] or nested[v] then mark_nest_point (x, k, v) else
+ mark_multiple_occurences (k)
+ mark_multiple_occurences (v)
+ end
+ end
+ nested [x] = nil
+ end
+ end
+
+ local dumped = { } -- multiply occuring values already dumped in localdefs
+ local localdefs = { } -- already dumped local definitions as source code lines
+
+ -- mutually recursive functions:
+ local dump_val, dump_or_ref_val
+
+ --------------------------------------------------------------------
+ -- if x occurs multiple times, dump the local var rather than the
+ -- value. If it's the first time it's dumped, also dump the content
+ -- in localdefs.
+ --------------------------------------------------------------------
+ function dump_or_ref_val (x)
+ if nested[x] then return 'false' end -- placeholder for recursive reference
+ if not multiple[x] then return dump_val (x) end
+ local var = dumped [x]
+ if var then return "_[" .. var .. "]" end -- already referenced
+ local val = dump_val(x) -- first occurence, create and register reference
+ var = gensym()
+ table.insert(localdefs, "_["..var.."]="..val)
+ dumped [x] = var
+ return "_[" .. var .. "]"
+ end
+
+ -----------------------------------------------------------------------------
+ -- Second pass, dump the object; subparts occuring multiple times are dumped
+ -- in local variables which can be referenced multiple times;
+ -- care is taken to dump locla vars in asensible order.
+ -----------------------------------------------------------------------------
+ function dump_val(x)
+ local t = type(x)
+ if x==nil then return 'nil'
+ elseif t=="number" then return tostring(x)
+ elseif t=="string" then return string.format("%q", x)
+ elseif t=="boolean" then return x and "true" or "false"
+ elseif t=="function" then
+ return "loadstring("..string.format("%q", string.dump(x))..")"
+ elseif t=="table" then
+ local acc = { }
+ local idx_dumped = { }
+ local np = nest_points [x]
+ for i, v in ipairs(x) do
+ if np and np[v] then
+ table.insert (acc, 'false') -- placeholder
+ else
+ table.insert (acc, dump_or_ref_val(v))
+ end
+ idx_dumped[i] = true
+ end
+ for k, v in pairs(x) do
+ if np and (np[k] or np[v]) then
+ --check_multiple(k); check_multiple(v) -- force dumps in localdefs
+ elseif not idx_dumped[k] then
+ table.insert (acc, "[" .. dump_or_ref_val(k) .. "] = " .. dump_or_ref_val(v))
+ end
+ end
+ return "{ "..table.concat(acc,", ").." }"
+ else
+ error ("Can't serialize data of type "..t)
+ end
+ end
+
+ local function dump_nest_patches()
+ for _, entry in ipairs(nest_patches) do
+ local p, k, v = unpack (entry)
+ assert (multiple[p])
+ local set = dump_or_ref_val (p) .. "[" .. dump_or_ref_val (k) .. "] = " ..
+ dump_or_ref_val (v) .. " -- rec "
+ table.insert (localdefs, set)
+ end
+ end
+
+ mark_multiple_occurences (x)
+ local toplevel = dump_or_ref_val (x)
+ dump_nest_patches()
+
+ if next (localdefs) then
+ return "local _={ }\n" ..
+ table.concat (localdefs, "\n") ..
+ "\nreturn " .. toplevel
+ else
+ return "return " .. toplevel
+ end
+end
+
+-- Deserialization.
+-- http://stackoverflow.com/questions/5958818/loading-serialized-data-into-a-table
+--
+
+local env = {
+ loadstring = loadstring,
+}
+
+local function noop() end
+
+local safe_env = {
+ loadstring = noop,
+}
+
+local function stringtotable(sdata, safe)
+ if sdata:byte(1) == 27 then return nil, "binary bytecode prohibited" end
+ local f, message = assert(loadstring(sdata))
+ if not f then return nil, message end
+ if safe then
+ setfenv(f, safe_env)
+ else
+ setfenv(f, env)
+ end
+ return f()
+end
+
+function minetest.deserialize(sdata, safe)
+ local table = {}
+ local okay, results = pcall(stringtotable, sdata, safe)
+ if okay then
+ return results
+ end
+ minetest.log('error', 'minetest.deserialize(): '.. results)
+ return nil
+end
+
+-- Run some unit tests
+local function unit_test()
+ function unitTest(name, success)
+ if not success then
+ error(name .. ': failed')
+ end
+ end
+
+ unittest_input = {cat={sound="nyan", speed=400}, dog={sound="woof"}}
+ unittest_output = minetest.deserialize(minetest.serialize(unittest_input))
+
+ unitTest("test 1a", unittest_input.cat.sound == unittest_output.cat.sound)
+ unitTest("test 1b", unittest_input.cat.speed == unittest_output.cat.speed)
+ unitTest("test 1c", unittest_input.dog.sound == unittest_output.dog.sound)
+
+ unittest_input = {escapechars="\n\r\t\v\\\"\'", noneuropean="θשׁ٩∂"}
+ unittest_output = minetest.deserialize(minetest.serialize(unittest_input))
+ unitTest("test 3a", unittest_input.escapechars == unittest_output.escapechars)
+ unitTest("test 3b", unittest_input.noneuropean == unittest_output.noneuropean)
+end
+unit_test() -- Run it
+unit_test = nil -- Hide it
+
--- /dev/null
+
+vector = {}
+
+local function assert_vector(v)
+ assert(type(v) == "table" and v.x and v.y and v.z, "Invalid vector")
+end
+
+function vector.new(a, b, c)
+ if type(a) == "table" then
+ assert(a.x and a.y and a.z, "Invalid vector passed to vector.new()")
+ return {x=a.x, y=a.y, z=a.z}
+ elseif a then
+ assert(b and c, "Invalid arguments for vector.new()")
+ return {x=a, y=b, z=c}
+ end
+ return {x=0, y=0, z=0}
+end
+
+function vector.equals(a, b)
+ assert_vector(a)
+ assert_vector(b)
+ return a.x == b.x and
+ a.y == b.y and
+ a.z == b.z
+end
+
+function vector.length(v)
+ assert_vector(v)
+ return math.hypot(v.x, math.hypot(v.y, v.z))
+end
+
+function vector.normalize(v)
+ assert_vector(v)
+ local len = vector.length(v)
+ if len == 0 then
+ return {x=0, y=0, z=0}
+ else
+ return vector.divide(v, len)
+ end
+end
+
+function vector.round(v)
+ assert_vector(v)
+ return {
+ x = math.floor(v.x + 0.5),
+ y = math.floor(v.y + 0.5),
+ z = math.floor(v.z + 0.5)
+ }
+end
+
+function vector.distance(a, b)
+ assert_vector(a)
+ assert_vector(b)
+ local x = a.x - b.x
+ local y = a.y - b.y
+ local z = a.z - b.z
+ return math.hypot(x, math.hypot(y, z))
+end
+
+function vector.direction(pos1, pos2)
+ assert_vector(pos1)
+ assert_vector(pos2)
+ local x_raw = pos2.x - pos1.x
+ local y_raw = pos2.y - pos1.y
+ local z_raw = pos2.z - pos1.z
+ local x_abs = math.abs(x_raw)
+ local y_abs = math.abs(y_raw)
+ local z_abs = math.abs(z_raw)
+ if x_abs >= y_abs and
+ x_abs >= z_abs then
+ y_raw = y_raw * (1 / x_abs)
+ z_raw = z_raw * (1 / x_abs)
+ x_raw = x_raw / x_abs
+ end
+ if y_abs >= x_abs and
+ y_abs >= z_abs then
+ x_raw = x_raw * (1 / y_abs)
+ z_raw = z_raw * (1 / y_abs)
+ y_raw = y_raw / y_abs
+ end
+ if z_abs >= y_abs and
+ z_abs >= x_abs then
+ x_raw = x_raw * (1 / z_abs)
+ y_raw = y_raw * (1 / z_abs)
+ z_raw = z_raw / z_abs
+ end
+ return {x=x_raw, y=y_raw, z=z_raw}
+end
+
+
+function vector.add(a, b)
+ assert_vector(a)
+ if type(b) == "table" then
+ assert_vector(b)
+ return {x = a.x + b.x,
+ y = a.y + b.y,
+ z = a.z + b.z}
+ else
+ return {x = a.x + b,
+ y = a.y + b,
+ z = a.z + b}
+ end
+end
+
+function vector.subtract(a, b)
+ assert_vector(a)
+ if type(b) == "table" then
+ assert_vector(b)
+ return {x = a.x - b.x,
+ y = a.y - b.y,
+ z = a.z - b.z}
+ else
+ return {x = a.x - b,
+ y = a.y - b,
+ z = a.z - b}
+ end
+end
+
+function vector.multiply(a, b)
+ assert_vector(a)
+ if type(b) == "table" then
+ assert_vector(b)
+ return {x = a.x * b.x,
+ y = a.y * b.y,
+ z = a.z * b.z}
+ else
+ return {x = a.x * b,
+ y = a.y * b,
+ z = a.z * b}
+ end
+end
+
+function vector.divide(a, b)
+ assert_vector(a)
+ if type(b) == "table" then
+ assert_vector(b)
+ return {x = a.x / b.x,
+ y = a.y / b.y,
+ z = a.z / b.z}
+ else
+ return {x = a.x / b,
+ y = a.y / b,
+ z = a.z / b}
+ end
+end
+
+++ /dev/null
--- 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
-
+++ /dev/null
--- 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
-
+++ /dev/null
--- 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)
+++ /dev/null
--- 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
+++ /dev/null
---Minetest
---Copyright (C) 2013 sapier
---
---This program is free software; you can redistribute it and/or modify
---it under the terms of the GNU Lesser General Public License as published by
---the Free Software Foundation; either version 2.1 of the License, or
---(at your option) any later version.
---
---This program is distributed in the hope that it will be useful,
---but WITHOUT ANY WARRANTY; without even the implied warranty of
---MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
---GNU Lesser General Public License for more details.
---
---You should have received a copy of the GNU Lesser General Public License along
---with this program; if not, write to the Free Software Foundation, Inc.,
---51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
---------------------------------------------------------------------------------
--- Generic implementation of a filter/sortable list --
--- Usage: --
--- Filterlist needs to be initialized on creation. To achieve this you need to --
--- pass following functions: --
--- raw_fct() (mandatory): --
--- function returning a table containing the elements to be filtered --
--- compare_fct(element1,element2) (mandatory): --
--- function returning true/false if element1 is same element as element2 --
--- uid_match_fct(element1,uid) (optional) --
--- function telling if uid is attached to element1 --
--- filter_fct(element,filtercriteria) (optional) --
--- function returning true/false if filtercriteria met to element --
--- fetch_param (optional) --
--- parameter passed to raw_fct to aquire correct raw data --
--- --
---------------------------------------------------------------------------------
-filterlist = {}
-
---------------------------------------------------------------------------------
-function filterlist.refresh(this)
- this.m_raw_list = this.m_raw_list_fct(this.m_fetch_param)
- filterlist.process(this)
-end
-
---------------------------------------------------------------------------------
-function filterlist.create(raw_fct,compare_fct,uid_match_fct,filter_fct,fetch_param)
-
- assert((raw_fct ~= nil) and (type(raw_fct) == "function"))
- assert((compare_fct ~= nil) and (type(compare_fct) == "function"))
-
- local this = {}
-
- this.m_raw_list_fct = raw_fct
- this.m_compare_fct = compare_fct
- this.m_filter_fct = filter_fct
- this.m_uid_match_fct = uid_match_fct
-
- this.m_filtercriteria = nil
- this.m_fetch_param = fetch_param
-
- this.m_sortmode = "none"
- this.m_sort_list = {}
-
- this.m_processed_list = nil
- this.m_raw_list = this.m_raw_list_fct(this.m_fetch_param)
-
- filterlist.process(this)
-
- return this
-end
-
---------------------------------------------------------------------------------
-function filterlist.add_sort_mechanism(this,name,fct)
- this.m_sort_list[name] = fct
-end
-
---------------------------------------------------------------------------------
-function filterlist.set_filtercriteria(this,criteria)
- if criteria == this.m_filtercriteria and
- type(criteria) ~= "table" then
- return
- end
- this.m_filtercriteria = criteria
- filterlist.process(this)
-end
-
---------------------------------------------------------------------------------
-function filterlist.get_filtercriteria(this)
- return this.m_filtercriteria
-end
-
---------------------------------------------------------------------------------
---supported sort mode "alphabetic|none"
-function filterlist.set_sortmode(this,mode)
- if (mode == this.m_sortmode) then
- return
- end
- this.m_sortmode = mode
- filterlist.process(this)
-end
-
---------------------------------------------------------------------------------
-function filterlist.get_list(this)
- return this.m_processed_list
-end
-
---------------------------------------------------------------------------------
-function filterlist.get_raw_list(this)
- return this.m_raw_list
-end
-
---------------------------------------------------------------------------------
-function filterlist.get_raw_element(this,idx)
- if type(idx) ~= "number" then
- idx = tonumber(idx)
- end
-
- if idx ~= nil and idx > 0 and idx < #this.m_raw_list then
- return this.m_raw_list[idx]
- end
-
- return nil
-end
-
---------------------------------------------------------------------------------
-function filterlist.get_raw_index(this,listindex)
- assert(this.m_processed_list ~= nil)
-
- if listindex ~= nil and listindex > 0 and
- listindex <= #this.m_processed_list then
- local entry = this.m_processed_list[listindex]
-
- for i,v in ipairs(this.m_raw_list) do
-
- if this.m_compare_fct(v,entry) then
- return i
- end
- end
- end
-
- return 0
-end
-
---------------------------------------------------------------------------------
-function filterlist.get_current_index(this,listindex)
- assert(this.m_processed_list ~= nil)
-
- if listindex ~= nil and listindex > 0 and
- listindex <= #this.m_raw_list then
- local entry = this.m_raw_list[listindex]
-
- for i,v in ipairs(this.m_processed_list) do
-
- if this.m_compare_fct(v,entry) then
- return i
- end
- end
- end
-
- return 0
-end
-
---------------------------------------------------------------------------------
-function filterlist.process(this)
- assert(this.m_raw_list ~= nil)
-
- if this.m_sortmode == "none" and
- this.m_filtercriteria == nil then
- this.m_processed_list = this.m_raw_list
- return
- end
-
- this.m_processed_list = {}
-
- for k,v in pairs(this.m_raw_list) do
- if this.m_filtercriteria == nil or
- this.m_filter_fct(v,this.m_filtercriteria) then
- table.insert(this.m_processed_list,v)
- end
- end
-
- if this.m_sortmode == "none" then
- return
- end
-
- if this.m_sort_list[this.m_sortmode] ~= nil and
- type(this.m_sort_list[this.m_sortmode]) == "function" then
-
- this.m_sort_list[this.m_sortmode](this)
- end
-end
-
---------------------------------------------------------------------------------
-function filterlist.size(this)
- if this.m_processed_list == nil then
- return 0
- end
-
- return #this.m_processed_list
-end
-
---------------------------------------------------------------------------------
-function filterlist.uid_exists_raw(this,uid)
- for i,v in ipairs(this.m_raw_list) do
- if this.m_uid_match_fct(v,uid) then
- return true
- end
- end
- return false
-end
-
---------------------------------------------------------------------------------
-function filterlist.raw_index_by_uid(this, uid)
- local elementcount = 0
- local elementidx = 0
- for i,v in ipairs(this.m_raw_list) do
- if this.m_uid_match_fct(v,uid) then
- elementcount = elementcount +1
- elementidx = i
- end
- end
-
-
- -- If there are more elements than one with same name uid can't decide which
- -- one is meant. This shouldn't be possible but just for sure.
- if elementcount > 1 then
- elementidx=0
- end
-
- return elementidx
-end
-
---------------------------------------------------------------------------------
--- COMMON helper functions --
---------------------------------------------------------------------------------
-
---------------------------------------------------------------------------------
-function compare_worlds(world1,world2)
-
- if world1.path ~= world2.path then
- return false
- end
-
- if world1.name ~= world2.name then
- return false
- end
-
- if world1.gameid ~= world2.gameid then
- return false
- end
-
- return true
-end
-
---------------------------------------------------------------------------------
-function sort_worlds_alphabetic(this)
-
- table.sort(this.m_processed_list, function(a, b)
- --fixes issue #857 (crash due to sorting nil in worldlist)
- if a == nil or b == nil then
- if a == nil and b ~= nil then return false end
- if b == nil and a ~= nil then return true end
- return false
- end
- if a.name:lower() == b.name:lower() then
- return a.name < b.name
- end
- return a.name:lower() < b.name:lower()
- end)
-end
-
---------------------------------------------------------------------------------
-function sort_mod_list(this)
-
- table.sort(this.m_processed_list, function(a, b)
- -- Show game mods at bottom
- if a.typ ~= b.typ then
- return b.typ == "game_mod"
- end
- -- If in same or no modpack, sort by name
- if a.modpack == b.modpack then
- if a.name:lower() == b.name:lower() then
- return a.name < b.name
- end
- return a.name:lower() < b.name:lower()
- -- Else compare name to modpack name
- else
- -- Always show modpack pseudo-mod on top of modpack mod list
- if a.name == b.modpack then
- return true
- elseif b.name == a.modpack then
- return false
- end
-
- local name_a = a.modpack or a.name
- local name_b = b.modpack or b.name
- if name_a:lower() == name_b:lower() then
- return name_a < name_b
- end
- return name_a:lower() < name_b:lower()
- end
- end)
-end
+++ /dev/null
--- 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)
--- /dev/null
+-- 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
+
+
--- /dev/null
+-- 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,
+})
--- /dev/null
+-- 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
+
--- /dev/null
+-- 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
+
--- /dev/null
+-- 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)
--- /dev/null
+-- 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
--- /dev/null
+-- 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)
--- /dev/null
+
+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")
+
--- /dev/null
+-- 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,
+}
+
--- /dev/null
+-- 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,
+})
+
--- /dev/null
+-- 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
+
--- /dev/null
+-- 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")
+
--- /dev/null
+-- 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()
+
--- /dev/null
+
+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)
--- /dev/null
+-- 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)
+
--- /dev/null
+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
+++ /dev/null
---Minetest
---Copyright (C) 2013 sapier
---
---This program is free software; you can redistribute it and/or modify
---it under the terms of the GNU Lesser General Public License as published by
---the Free Software Foundation; either version 2.1 of the License, or
---(at your option) any later version.
---
---This program is distributed in the hope that it will be useful,
---but WITHOUT ANY WARRANTY; without even the implied warranty of
---MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
---GNU Lesser General Public License for more details.
---
---You should have received a copy of the GNU Lesser General Public License along
---with this program; if not, write to the Free Software Foundation, Inc.,
---51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-gamemgr = {}
-
---------------------------------------------------------------------------------
-function gamemgr.dialog_new_game()
- local retval =
- "label[2,2;" .. fgettext("Game Name") .. "]"..
- "field[4.5,2.4;6,0.5;te_game_name;;]" ..
- "button[5,4.2;2.6,0.5;new_game_confirm;" .. fgettext("Create") .. "]" ..
- "button[7.5,4.2;2.8,0.5;new_game_cancel;" .. fgettext("Cancel") .. "]"
-
- return retval
-end
-
---------------------------------------------------------------------------------
-function gamemgr.handle_games_buttons(fields)
- if fields["gamelist"] ~= nil then
- local event = engine.explode_textlist_event(fields["gamelist"])
- gamemgr.selected_game = event.index
- end
-
- if fields["btn_game_mgr_edit_game"] ~= nil then
- return {
- is_dialog = true,
- show_buttons = false,
- current_tab = "dialog_edit_game"
- }
- end
-
- if fields["btn_game_mgr_new_game"] ~= nil then
- return {
- is_dialog = true,
- show_buttons = false,
- current_tab = "dialog_new_game"
- }
- end
-
- return nil
-end
-
---------------------------------------------------------------------------------
-function gamemgr.handle_new_game_buttons(fields)
-
- if fields["new_game_confirm"] and
- fields["te_game_name"] ~= nil and
- fields["te_game_name"] ~= "" then
- local gamepath = engine.get_gamepath()
-
- if gamepath ~= nil and
- gamepath ~= "" then
- local gamefolder = cleanup_path(fields["te_game_name"])
-
- --TODO check for already existing first
- engine.create_dir(gamepath .. DIR_DELIM .. gamefolder)
- engine.create_dir(gamepath .. DIR_DELIM .. gamefolder .. DIR_DELIM .. "mods")
- engine.create_dir(gamepath .. DIR_DELIM .. gamefolder .. DIR_DELIM .. "menu")
-
- local gameconf =
- io.open(gamepath .. DIR_DELIM .. gamefolder .. DIR_DELIM .. "game.conf","w")
-
- if gameconf then
- gameconf:write("name = " .. fields["te_game_name"])
- gameconf:close()
- end
- end
- end
-
- return {
- is_dialog = false,
- show_buttons = true,
- current_tab = engine.setting_get("main_menu_tab")
- }
-end
-
---------------------------------------------------------------------------------
-function gamemgr.handle_edit_game_buttons(fields)
- local current_game = gamemgr.get_game(gamemgr.selected_game)
-
- if fields["btn_close_edit_game"] ~= nil or
- current_game == nil then
- return {
- is_dialog = false,
- show_buttons = true,
- current_tab = engine.setting_get("main_menu_tab")
- }
- end
-
- if fields["btn_remove_mod_from_game"] ~= nil then
- gamemgr.delete_mod(current_game,engine.get_textlist_index("mods_current"))
- end
-
- if fields["btn_add_mod_to_game"] ~= nil then
- local modindex = engine.get_textlist_index("mods_available")
-
- local mod = modmgr.get_global_mod(modindex)
- if mod ~= nil then
-
- local sourcepath = mod.path
-
- if not gamemgr.add_mod(current_game,sourcepath) then
- gamedata.errormessage =
- fgettext("Gamemgr: Unable to copy mod \"$1\" to game \"$2\"", mod.name, current_game.id)
- end
- end
- end
-
- return nil
-end
-
---------------------------------------------------------------------------------
-function gamemgr.add_mod(gamespec,sourcepath)
- if gamespec.gamemods_path ~= nil and
- gamespec.gamemods_path ~= "" then
-
- local modname = get_last_folder(sourcepath)
-
- return engine.copy_dir(sourcepath,gamespec.gamemods_path .. DIR_DELIM .. modname);
- end
-
- return false
-end
-
---------------------------------------------------------------------------------
-function gamemgr.delete_mod(gamespec,modindex)
- if gamespec.gamemods_path ~= nil and
- gamespec.gamemods_path ~= "" then
- local game_mods = {}
- get_mods(gamespec.gamemods_path,game_mods)
-
- if modindex > 0 and
- #game_mods >= modindex then
-
- if game_mods[modindex].path:sub(0,gamespec.gamemods_path:len())
- == gamespec.gamemods_path then
- engine.delete_dir(game_mods[modindex].path)
- end
- end
- end
-end
-
---------------------------------------------------------------------------------
-function gamemgr.find_by_gameid(gameid)
- for i=1,#gamemgr.games,1 do
- if gamemgr.games[i].id == gameid then
- return gamemgr.games[i], i
- end
- end
- return nil, nil
-end
-
---------------------------------------------------------------------------------
-function gamemgr.get_game_mods(gamespec, retval)
- if gamespec ~= nil and
- gamespec.gamemods_path ~= nil and
- gamespec.gamemods_path ~= "" then
- get_mods(gamespec.gamemods_path, retval)
- end
-end
-
---------------------------------------------------------------------------------
-function gamemgr.get_game_modlist(gamespec)
- local retval = ""
- local game_mods = {}
- gamemgr.get_game_mods(gamespec, game_mods)
- for i=1,#game_mods,1 do
- if retval ~= "" then
- retval = retval..","
- end
- retval = retval .. game_mods[i].name
- end
- return retval
-end
-
---------------------------------------------------------------------------------
-function gamemgr.gettab(name)
- local retval = ""
-
- if name == "dialog_edit_game" then
- retval = retval .. gamemgr.dialog_edit_game()
- end
-
- if name == "dialog_new_game" then
- retval = retval .. gamemgr.dialog_new_game()
- end
-
- if name == "game_mgr" then
- retval = retval .. gamemgr.tab()
- end
-
- return retval
-end
-
---------------------------------------------------------------------------------
-function gamemgr.tab()
- if gamemgr.selected_game == nil then
- gamemgr.selected_game = 1
- end
-
- local retval =
- "vertlabel[0,-0.25;" .. fgettext("GAMES") .. "]" ..
- "label[1,-0.25;" .. fgettext("Games") .. ":]" ..
- "textlist[1,0.25;4.5,4.4;gamelist;" ..
- gamemgr.gamelist() ..
- ";" .. gamemgr.selected_game .. "]"
-
- local current_game = gamemgr.get_game(gamemgr.selected_game)
-
- if current_game ~= nil then
- if current_game.menuicon_path ~= nil and
- current_game.menuicon_path ~= "" then
- retval = retval ..
- "image[5.8,-0.25;2,2;" ..
- engine.formspec_escape(current_game.menuicon_path) .. "]"
- end
-
- retval = retval ..
- "field[8,-0.25;6,2;;" .. current_game.name .. ";]"..
- "label[6,1.4;" .. fgettext("Mods:") .."]" ..
- "button[9.7,1.5;2,0.2;btn_game_mgr_edit_game;" .. fgettext("edit game") .. "]" ..
- "textlist[6,2;5.5,3.3;game_mgr_modlist;"
- .. gamemgr.get_game_modlist(current_game) ..";0]" ..
- "button[1,4.75;3.2,0.5;btn_game_mgr_new_game;" .. fgettext("new game") .. "]"
- end
- return retval
-end
-
---------------------------------------------------------------------------------
-function gamemgr.dialog_edit_game()
- local current_game = gamemgr.get_game(gamemgr.selected_game)
- if current_game ~= nil then
- local retval =
- "vertlabel[0,-0.25;" .. fgettext("EDIT GAME") .."]" ..
- "label[0,-0.25;" .. current_game.name .. "]" ..
- "button[11.55,-0.2;0.75,0.5;btn_close_edit_game;x]"
-
- if current_game.menuicon_path ~= nil and
- current_game.menuicon_path ~= "" then
- retval = retval ..
- "image[5.25,0;2,2;" ..
- engine.formspec_escape(current_game.menuicon_path) .. "]"
- end
-
- retval = retval ..
- "textlist[0.5,0.5;4.5,4.3;mods_current;"
- .. gamemgr.get_game_modlist(current_game) ..";0]"
-
-
- retval = retval ..
- "textlist[7,0.5;4.5,4.3;mods_available;"
- .. modmgr.render_modlist() .. ";0]"
-
- retval = retval ..
- "button[0.55,4.95;4.7,0.5;btn_remove_mod_from_game;" .. fgettext("Remove selected mod") .."]"
-
- retval = retval ..
- "button[7.05,4.95;4.7,0.5;btn_add_mod_to_game;" .. fgettext("<<-- Add mod") .."]"
-
- return retval
- end
-end
-
---------------------------------------------------------------------------------
-function gamemgr.handle_buttons(tab,fields)
- local retval = nil
-
- if tab == "dialog_edit_game" then
- retval = gamemgr.handle_edit_game_buttons(fields)
- end
-
- if tab == "dialog_new_game" then
- retval = gamemgr.handle_new_game_buttons(fields)
- end
-
- if tab == "game_mgr" then
- retval = gamemgr.handle_games_buttons(fields)
- end
-
- return retval
-end
-
---------------------------------------------------------------------------------
-function gamemgr.get_game(index)
- if index > 0 and index <= #gamemgr.games then
- return gamemgr.games[index]
- end
-
- return nil
-end
-
---------------------------------------------------------------------------------
-function gamemgr.update_gamelist()
- gamemgr.games = engine.get_games()
-end
-
---------------------------------------------------------------------------------
-function gamemgr.gamelist()
- local retval = ""
- if #gamemgr.games > 0 then
- retval = retval .. gamemgr.games[1].id
-
- for i=2,#gamemgr.games,1 do
- retval = retval .. "," .. gamemgr.games[i].name
- end
- end
- return retval
-end
--- /dev/null
+--
+-- This file contains built-in stuff in Minetest implemented in Lua.
+--
+-- It is always loaded and executed after registration of the C API,
+-- before loading and running any mods.
+--
+
+local core = minetest or engine
+minetest = core
+
+-- Initialize some very basic things
+print = core.debug
+math.randomseed(os.time())
+os.setlocale("C", "numeric")
+
+-- Load other files
+local scriptdir = core.get_builtin_path()..DIR_DELIM
+local gamepath = scriptdir.."game"..DIR_DELIM
+local commonpath = scriptdir.."common"..DIR_DELIM
+local asyncpath = scriptdir.."async"..DIR_DELIM
+
+dofile(commonpath.."serialize.lua")
+dofile(commonpath.."misc_helpers.lua")
+
+if INIT == "game" then
+ dofile(gamepath.."init.lua")
+elseif INIT == "mainmenu" then
+ dofile(core.get_mainmenu_path()..DIR_DELIM.."init.lua")
+elseif INIT == "async" then
+ dofile(asyncpath.."init.lua")
+else
+ error(("Unrecognized builtin initialization type %s!"):format(tostring(INIT)))
+end
+
+++ /dev/null
--- 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,
-}
-
+++ /dev/null
--- 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,
-})
-
+++ /dev/null
-print = engine.debug
-math.randomseed(os.time())
-os.setlocale("C", "numeric")
-
-local scriptpath = engine.get_scriptdir()
-
-mt_color_grey = "#AAAAAA"
-mt_color_blue = "#0000DD"
-mt_color_green = "#00DD00"
-mt_color_dark_green = "#003300"
-
---for all other colors ask sfan5 to complete his worK!
-
-dofile(scriptpath .. DIR_DELIM .. "misc_helpers.lua")
-dofile(scriptpath .. DIR_DELIM .. "filterlist.lua")
-dofile(scriptpath .. DIR_DELIM .. "modmgr.lua")
-dofile(scriptpath .. DIR_DELIM .. "modstore.lua")
-dofile(scriptpath .. DIR_DELIM .. "gamemgr.lua")
-dofile(scriptpath .. DIR_DELIM .. "mm_textures.lua")
-dofile(scriptpath .. DIR_DELIM .. "mm_menubar.lua")
-dofile(scriptpath .. DIR_DELIM .. "async_event.lua")
-
-menu = {}
-local tabbuilder = {}
-local worldlist = nil
-
---------------------------------------------------------------------------------
-local function filter_texture_pack_list(list)
- retval = {"None"}
- for _,i in ipairs(list) do
- if i~="base" then
- table.insert(retval, i)
- end
- end
- return retval
-end
-
---------------------------------------------------------------------------------
-function menu.render_favorite(spec,render_details)
- local text = ""
-
- if spec.name ~= nil then
- text = text .. engine.formspec_escape(spec.name:trim())
-
--- if spec.description ~= nil and
--- engine.formspec_escape(spec.description):trim() ~= "" then
--- text = text .. " (" .. engine.formspec_escape(spec.description) .. ")"
--- end
- else
- if spec.address ~= nil then
- text = text .. spec.address:trim()
-
- if spec.port ~= nil then
- text = text .. ":" .. spec.port
- end
- end
- end
-
- if not render_details then
- return text
- end
-
- local details = ""
- if spec.password == true then
- details = details .. "*"
- else
- details = details .. "_"
- end
-
- if spec.creative then
- details = details .. "C"
- else
- details = details .. "_"
- end
-
- if spec.damage then
- details = details .. "D"
- else
- details = details .. "_"
- end
-
- if spec.pvp then
- details = details .. "P"
- else
- details = details .. "_"
- end
- details = details .. " "
-
- local playercount = ""
-
- if spec.clients ~= nil and
- spec.clients_max ~= nil then
- playercount = string.format("%03d",spec.clients) .. "/" ..
- string.format("%03d",spec.clients_max) .. " "
- end
-
- return playercount .. engine.formspec_escape(details) .. text
-end
-
---------------------------------------------------------------------------------
-os.tempfolder = function()
- local filetocheck = os.tmpname()
- os.remove(filetocheck)
-
- local randname = "MTTempModFolder_" .. math.random(0,10000)
- if DIR_DELIM == "\\" then
- local tempfolder = os.getenv("TEMP")
- return tempfolder .. filetocheck
- else
- local backstring = filetocheck:reverse()
- return filetocheck:sub(0,filetocheck:len()-backstring:find(DIR_DELIM)+1) ..randname
- end
-
-end
-
---------------------------------------------------------------------------------
-function text2textlist(xpos,ypos,width,height,tl_name,textlen,text,transparency)
- local textlines = engine.splittext(text,textlen)
-
- local retval = "textlist[" .. xpos .. "," .. ypos .. ";"
- .. width .. "," .. height .. ";"
- .. tl_name .. ";"
-
- for i=1, #textlines, 1 do
- textlines[i] = textlines[i]:gsub("\r","")
- retval = retval .. engine.formspec_escape(textlines[i]) .. ","
- end
-
- retval = retval .. ";0;"
-
- if transparency then
- retval = retval .. "true"
- end
-
- retval = retval .. "]"
-
- return retval
-end
-
---------------------------------------------------------------------------------
-function init_globals()
- --init gamedata
- gamedata.worldindex = 0
-
- worldlist = filterlist.create(
- engine.get_worlds,
- compare_worlds,
- function(element,uid)
- if element.name == uid then
- return true
- end
- return false
- end, --unique id compare fct
- function(element,gameid)
- if element.gameid == gameid then
- return true
- end
- return false
- end --filter fct
- )
-
- filterlist.add_sort_mechanism(worldlist,"alphabetic",sort_worlds_alphabetic)
- filterlist.set_sortmode(worldlist,"alphabetic")
-end
-
---------------------------------------------------------------------------------
-function update_menu()
-
- local formspec
-
- -- handle errors
- if gamedata.errormessage ~= nil then
- formspec = "size[12,5.2,true]" ..
- "textarea[1,2;10,2;;ERROR: " ..
- engine.formspec_escape(gamedata.errormessage) ..
- ";]"..
- "button[4.5,4.2;3,0.5;btn_error_confirm;" .. fgettext("Ok") .. "]"
- else
- formspec = tabbuilder.gettab()
- end
-
- engine.update_formspec(formspec)
-end
-
---------------------------------------------------------------------------------
-function menu.render_world_list()
- local retval = ""
-
- local current_worldlist = filterlist.get_list(worldlist)
-
- for i,v in ipairs(current_worldlist) do
- if retval ~= "" then
- retval = retval ..","
- end
-
- retval = retval .. engine.formspec_escape(v.name) ..
- " \\[" .. engine.formspec_escape(v.gameid) .. "\\]"
- end
-
- return retval
-end
-
---------------------------------------------------------------------------------
-function menu.render_texture_pack_list(list)
- local retval = ""
-
- for i, v in ipairs(list) do
- if retval ~= "" then
- retval = retval ..","
- end
-
- retval = retval .. engine.formspec_escape(v)
- end
-
- return retval
-end
-
---------------------------------------------------------------------------------
-function menu.asyncOnlineFavourites()
- menu.favorites = {}
- engine.handle_async(
- function(param)
- return engine.get_favorites("online")
- end,
- nil,
- function(result)
- menu.favorites = result
- engine.event_handler("Refresh")
- end
- )
-end
-
---------------------------------------------------------------------------------
-function menu.init()
- --init menu data
- gamemgr.update_gamelist()
-
- menu.last_game = tonumber(engine.setting_get("main_menu_last_game_idx"))
-
- if type(menu.last_game) ~= "number" then
- menu.last_game = 1
- end
-
- if engine.setting_getbool("public_serverlist") then
- menu.asyncOnlineFavourites()
- else
- menu.favorites = engine.get_favorites("local")
- end
-
- menu.defaulttexturedir = engine.get_texturepath_share() .. DIR_DELIM .. "base" ..
- DIR_DELIM .. "pack" .. DIR_DELIM
-end
-
---------------------------------------------------------------------------------
-function menu.lastgame()
- if menu.last_game > 0 and menu.last_game <= #gamemgr.games then
- return gamemgr.games[menu.last_game]
- end
-
- if #gamemgr.games >= 1 then
- menu.last_game = 1
- return gamemgr.games[menu.last_game]
- end
-
- --error case!!
- return nil
-end
-
---------------------------------------------------------------------------------
-function menu.update_last_game()
-
- local current_world = filterlist.get_raw_element(worldlist,
- engine.setting_get("mainmenu_last_selected_world")
- )
-
- if current_world == nil then
- return
- end
-
- local gamespec, i = gamemgr.find_by_gameid(current_world.gameid)
- if i ~= nil then
- menu.last_game = i
- engine.setting_set("main_menu_last_game_idx",menu.last_game)
- end
-end
-
---------------------------------------------------------------------------------
-function menu.handle_key_up_down(fields,textlist,settingname)
-
- if fields["key_up"] then
- local oldidx = engine.get_textlist_index(textlist)
-
- if oldidx ~= nil and oldidx > 1 then
- local newidx = oldidx -1
- engine.setting_set(settingname,
- filterlist.get_raw_index(worldlist,newidx))
- end
- end
-
- if fields["key_down"] then
- local oldidx = engine.get_textlist_index(textlist)
-
- if oldidx ~= nil and oldidx < filterlist.size(worldlist) then
- local newidx = oldidx + 1
- engine.setting_set(settingname,
- filterlist.get_raw_index(worldlist,newidx))
- end
- end
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.dialog_create_world()
- local mapgens = {"v6", "v7", "indev", "singlenode", "math"}
-
- local current_seed = engine.setting_get("fixed_map_seed") or ""
- local current_mg = engine.setting_get("mg_name")
-
- local mglist = ""
- local selindex = 1
- local i = 1
- for k,v in pairs(mapgens) do
- if current_mg == v then
- selindex = i
- end
- i = i + 1
- mglist = mglist .. v .. ","
- end
- mglist = mglist:sub(1, -2)
-
- local retval =
- "label[2,0;" .. fgettext("World name") .. "]"..
- "field[4.5,0.4;6,0.5;te_world_name;;]" ..
-
- "label[2,1;" .. fgettext("Seed") .. "]"..
- "field[4.5,1.4;6,0.5;te_seed;;".. current_seed .. "]" ..
-
- "label[2,2;" .. fgettext("Mapgen") .. "]"..
- "dropdown[4.2,2;6.3;dd_mapgen;" .. mglist .. ";" .. selindex .. "]" ..
-
- "label[2,3;" .. fgettext("Game") .. "]"..
- "textlist[4.2,3;5.8,2.3;games;" .. gamemgr.gamelist() ..
- ";" .. menu.last_game .. ";true]" ..
-
- "button[5,5.5;2.6,0.5;world_create_confirm;" .. fgettext("Create") .. "]" ..
- "button[7.5,5.5;2.8,0.5;world_create_cancel;" .. fgettext("Cancel") .. "]"
-
- return retval
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.dialog_delete_world()
- return "label[2,2;" ..
- fgettext("Delete World \"$1\"?", filterlist.get_raw_list(worldlist)[menu.world_to_del].name) .. "]"..
- "button[3.5,4.2;2.6,0.5;world_delete_confirm;" .. fgettext("Yes").. "]" ..
- "button[6,4.2;2.8,0.5;world_delete_cancel;" .. fgettext("No") .. "]"
-end
-
---------------------------------------------------------------------------------
-
-function tabbuilder.gettab()
- local tsize = tabbuilder.tabsizes[tabbuilder.current_tab] or {width=12, height=5.2}
- local retval = "size[" .. tsize.width .. "," .. tsize.height .. ",true]"
-
- if tabbuilder.show_buttons then
- retval = retval .. tabbuilder.tab_header()
- end
-
- local buildfunc = tabbuilder.tabfuncs[tabbuilder.current_tab]
- if buildfunc ~= nil then
- retval = retval .. buildfunc()
- end
-
- retval = retval .. modmgr.gettab(tabbuilder.current_tab)
- retval = retval .. gamemgr.gettab(tabbuilder.current_tab)
- retval = retval .. modstore.gettab(tabbuilder.current_tab)
-
- return retval
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.handle_create_world_buttons(fields)
-
- if fields["world_create_confirm"] or
- fields["key_enter"] then
-
- local worldname = fields["te_world_name"]
- local gameindex = engine.get_textlist_index("games")
-
- if gameindex ~= nil and
- worldname ~= "" then
-
- local message = nil
-
- if not filterlist.uid_exists_raw(worldlist,worldname) then
- engine.setting_set("mg_name",fields["dd_mapgen"])
- message = engine.create_world(worldname,gameindex)
- else
- message = fgettext("A world named \"$1\" already exists", worldname)
- end
-
- engine.setting_set("fixed_map_seed", fields["te_seed"])
-
- if message ~= nil then
- gamedata.errormessage = message
- else
- menu.last_game = gameindex
- engine.setting_set("main_menu_last_game_idx",gameindex)
-
- filterlist.refresh(worldlist)
- engine.setting_set("mainmenu_last_selected_world",
- filterlist.raw_index_by_uid(worldlist,worldname))
- end
- else
- gamedata.errormessage =
- fgettext("No worldname given or no game selected")
- end
- end
-
- if fields["games"] then
- tabbuilder.skipformupdate = true
- return
- end
-
- --close dialog
- tabbuilder.is_dialog = false
- tabbuilder.show_buttons = true
- tabbuilder.current_tab = engine.setting_get("main_menu_tab")
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.handle_delete_world_buttons(fields)
-
- if fields["world_delete_confirm"] then
- if menu.world_to_del > 0 and
- menu.world_to_del <= #filterlist.get_raw_list(worldlist) then
- engine.delete_world(menu.world_to_del)
- menu.world_to_del = 0
- filterlist.refresh(worldlist)
- end
- end
-
- tabbuilder.is_dialog = false
- tabbuilder.show_buttons = true
- tabbuilder.current_tab = engine.setting_get("main_menu_tab")
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.handle_multiplayer_buttons(fields)
-
- if fields["te_name"] ~= nil then
- gamedata.playername = fields["te_name"]
- engine.setting_set("name", fields["te_name"])
- end
-
- if fields["favourites"] ~= nil then
- local event = engine.explode_textlist_event(fields["favourites"])
- if event.type == "DCL" then
- if event.index <= #menu.favorites then
- gamedata.address = menu.favorites[event.index].address
- gamedata.port = menu.favorites[event.index].port
- gamedata.playername = fields["te_name"]
- if fields["te_pwd"] ~= nil then
- gamedata.password = fields["te_pwd"]
- end
- gamedata.selected_world = 0
-
- if menu.favorites ~= nil then
- gamedata.servername = menu.favorites[event.index].name
- gamedata.serverdescription = menu.favorites[event.index].description
- end
-
- if gamedata.address ~= nil and
- gamedata.port ~= nil then
- engine.setting_set("address",gamedata.address)
- engine.setting_set("remote_port",gamedata.port)
- engine.start()
- end
- end
- end
-
- if event.type == "CHG" then
- if event.index <= #menu.favorites then
- local address = menu.favorites[event.index].address
- local port = menu.favorites[event.index].port
-
- if address ~= nil and
- port ~= nil then
- engine.setting_set("address",address)
- engine.setting_set("remote_port",port)
- end
-
- menu.fav_selected = event.index
- end
- end
- return
- end
-
- if fields["key_up"] ~= nil or
- fields["key_down"] ~= nil then
-
- local fav_idx = engine.get_textlist_index("favourites")
-
- if fav_idx ~= nil then
- if fields["key_up"] ~= nil and fav_idx > 1 then
- fav_idx = fav_idx -1
- else if fields["key_down"] and fav_idx < #menu.favorites then
- fav_idx = fav_idx +1
- end end
- end
-
- local address = menu.favorites[fav_idx].address
- local port = menu.favorites[fav_idx].port
-
- if address ~= nil and
- port ~= nil then
- engine.setting_set("address",address)
- engine.setting_set("remote_port",port)
- end
-
- menu.fav_selected = fav_idx
- return
- end
-
- if fields["cb_public_serverlist"] ~= nil then
- engine.setting_set("public_serverlist", fields["cb_public_serverlist"])
-
- if engine.setting_getbool("public_serverlist") then
- menu.asyncOnlineFavourites()
- else
- menu.favorites = engine.get_favorites("local")
- end
- menu.fav_selected = nil
- return
- end
-
- if fields["btn_delete_favorite"] ~= nil then
- local current_favourite = engine.get_textlist_index("favourites")
- if current_favourite == nil then return end
- engine.delete_favorite(current_favourite)
- menu.favorites = engine.get_favorites()
- menu.fav_selected = nil
-
- engine.setting_set("address","")
- engine.setting_set("remote_port","30000")
-
- return
- end
-
- if fields["btn_mp_connect"] ~= nil or
- fields["key_enter"] ~= nil then
-
- gamedata.playername = fields["te_name"]
- gamedata.password = fields["te_pwd"]
- gamedata.address = fields["te_address"]
- gamedata.port = fields["te_port"]
-
- local fav_idx = engine.get_textlist_index("favourites")
-
- if fav_idx ~= nil and fav_idx <= #menu.favorites and
- menu.favorites[fav_idx].address == fields["te_address"] and
- menu.favorites[fav_idx].port == fields["te_port"] then
-
- gamedata.servername = menu.favorites[fav_idx].name
- gamedata.serverdescription = menu.favorites[fav_idx].description
- else
- gamedata.servername = ""
- gamedata.serverdescription = ""
- end
-
- gamedata.selected_world = 0
-
- engine.setting_set("address",fields["te_address"])
- engine.setting_set("remote_port",fields["te_port"])
-
- engine.start()
- return
- end
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.handle_server_buttons(fields)
-
- local world_doubleclick = false
-
- if fields["srv_worlds"] ~= nil then
- local event = engine.explode_textlist_event(fields["srv_worlds"])
-
- if event.type == "DCL" then
- world_doubleclick = true
- end
- if event.type == "CHG" then
- engine.setting_set("mainmenu_last_selected_world",
- filterlist.get_raw_index(worldlist,engine.get_textlist_index("srv_worlds")))
- end
- end
-
- menu.handle_key_up_down(fields,"srv_worlds","mainmenu_last_selected_world")
-
- if fields["cb_creative_mode"] then
- engine.setting_set("creative_mode", fields["cb_creative_mode"])
- end
-
- if fields["cb_enable_damage"] then
- engine.setting_set("enable_damage", fields["cb_enable_damage"])
- end
-
- if fields["cb_server_announce"] then
- engine.setting_set("server_announce", fields["cb_server_announce"])
- end
-
- if fields["start_server"] ~= nil or
- world_doubleclick or
- fields["key_enter"] then
- local selected = engine.get_textlist_index("srv_worlds")
- if selected ~= nil then
- gamedata.playername = fields["te_playername"]
- gamedata.password = fields["te_passwd"]
- gamedata.port = fields["te_serverport"]
- gamedata.address = ""
- gamedata.selected_world = filterlist.get_raw_index(worldlist,selected)
-
- engine.setting_set("port",gamedata.port)
- if fields["te_serveraddr"] ~= nil then
- engine.setting_set("bind_address",fields["te_serveraddr"])
- end
-
- menu.update_last_game(gamedata.selected_world)
- engine.start()
- end
- end
-
- if fields["world_create"] ~= nil then
- tabbuilder.current_tab = "dialog_create_world"
- tabbuilder.is_dialog = true
- tabbuilder.show_buttons = false
- end
-
- if fields["world_delete"] ~= nil then
- local selected = engine.get_textlist_index("srv_worlds")
- if selected ~= nil and
- selected <= filterlist.size(worldlist) then
- local world = filterlist.get_list(worldlist)[selected]
- if world ~= nil and
- world.name ~= nil and
- world.name ~= "" then
- menu.world_to_del = filterlist.get_raw_index(worldlist,selected)
- tabbuilder.current_tab = "dialog_delete_world"
- tabbuilder.is_dialog = true
- tabbuilder.show_buttons = false
- else
- menu.world_to_del = 0
- end
- end
- end
-
- if fields["world_configure"] ~= nil then
- selected = engine.get_textlist_index("srv_worlds")
- if selected ~= nil then
- modmgr.world_config_selected_world = filterlist.get_raw_index(worldlist,selected)
- if modmgr.init_worldconfig() then
- tabbuilder.current_tab = "dialog_configure_world"
- tabbuilder.is_dialog = true
- tabbuilder.show_buttons = false
- end
- end
- end
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.handle_settings_buttons(fields)
- if fields["cb_fancy_trees"] then
- engine.setting_set("new_style_leaves", fields["cb_fancy_trees"])
- end
- if fields["cb_smooth_lighting"] then
- engine.setting_set("smooth_lighting", fields["cb_smooth_lighting"])
- end
- if fields["cb_3d_clouds"] then
- engine.setting_set("enable_3d_clouds", fields["cb_3d_clouds"])
- end
- if fields["cb_opaque_water"] then
- engine.setting_set("opaque_water", fields["cb_opaque_water"])
- end
-
- if fields["cb_mipmapping"] then
- engine.setting_set("mip_map", fields["cb_mipmapping"])
- end
- if fields["cb_anisotrophic"] then
- engine.setting_set("anisotropic_filter", fields["cb_anisotrophic"])
- end
- if fields["cb_bilinear"] then
- engine.setting_set("bilinear_filter", fields["cb_bilinear"])
- end
- if fields["cb_trilinear"] then
- engine.setting_set("trilinear_filter", fields["cb_trilinear"])
- end
-
- if fields["cb_shaders"] then
- if (engine.setting_get("video_driver") == "direct3d8" or engine.setting_get("video_driver") == "direct3d9") then
- engine.setting_set("enable_shaders", "false")
- gamedata.errormessage = fgettext("To enable shaders the OpenGL driver needs to be used.")
- else
- engine.setting_set("enable_shaders", fields["cb_shaders"])
- end
- end
- if fields["cb_pre_ivis"] then
- engine.setting_set("preload_item_visuals", fields["cb_pre_ivis"])
- end
- if fields["cb_particles"] then
- engine.setting_set("enable_particles", fields["cb_particles"])
- end
- if fields["cb_bumpmapping"] then
- engine.setting_set("enable_bumpmapping", fields["cb_bumpmapping"])
- end
- if fields["cb_parallax"] then
- engine.setting_set("enable_parallax_occlusion", fields["cb_parallax"])
- end
- if fields["cb_generate_normalmaps"] then
- engine.setting_set("generate_normalmaps", fields["cb_generate_normalmaps"])
- end
- if fields["cb_waving_water"] then
- engine.setting_set("enable_waving_water", fields["cb_waving_water"])
- end
- if fields["cb_waving_leaves"] then
- engine.setting_set("enable_waving_leaves", fields["cb_waving_leaves"])
- end
- if fields["cb_waving_plants"] then
- engine.setting_set("enable_waving_plants", fields["cb_waving_plants"])
- end
- if fields["btn_change_keys"] ~= nil then
- engine.show_keys_menu()
- end
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.handle_singleplayer_buttons(fields)
-
- local world_doubleclick = false
-
- if fields["sp_worlds"] ~= nil then
- local event = engine.explode_textlist_event(fields["sp_worlds"])
-
- if event.type == "DCL" then
- world_doubleclick = true
- end
-
- if event.type == "CHG" then
- engine.setting_set("mainmenu_last_selected_world",
- filterlist.get_raw_index(worldlist,engine.get_textlist_index("sp_worlds")))
- end
- end
-
- menu.handle_key_up_down(fields,"sp_worlds","mainmenu_last_selected_world")
-
- if fields["cb_creative_mode"] then
- engine.setting_set("creative_mode", fields["cb_creative_mode"])
- end
-
- if fields["cb_enable_damage"] then
- engine.setting_set("enable_damage", fields["cb_enable_damage"])
- end
-
- if fields["play"] ~= nil or
- world_doubleclick or
- fields["key_enter"] then
- local selected = engine.get_textlist_index("sp_worlds")
- if selected ~= nil then
- gamedata.selected_world = filterlist.get_raw_index(worldlist,selected)
- gamedata.singleplayer = true
-
- menu.update_last_game(gamedata.selected_world)
-
- engine.start()
- end
- end
-
- if fields["world_create"] ~= nil then
- tabbuilder.current_tab = "dialog_create_world"
- tabbuilder.is_dialog = true
- tabbuilder.show_buttons = false
- end
-
- if fields["world_delete"] ~= nil then
- local selected = engine.get_textlist_index("sp_worlds")
- if selected ~= nil and
- selected <= filterlist.size(worldlist) then
- local world = filterlist.get_list(worldlist)[selected]
- if world ~= nil and
- world.name ~= nil and
- world.name ~= "" then
- menu.world_to_del = filterlist.get_raw_index(worldlist,selected)
- tabbuilder.current_tab = "dialog_delete_world"
- tabbuilder.is_dialog = true
- tabbuilder.show_buttons = false
- else
- menu.world_to_del = 0
- end
- end
- end
-
- if fields["world_configure"] ~= nil then
- selected = engine.get_textlist_index("sp_worlds")
- if selected ~= nil then
- modmgr.world_config_selected_world = filterlist.get_raw_index(worldlist,selected)
- if modmgr.init_worldconfig() then
- tabbuilder.current_tab = "dialog_configure_world"
- tabbuilder.is_dialog = true
- tabbuilder.show_buttons = false
- end
- end
- end
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.handle_texture_pack_buttons(fields)
- if fields["TPs"] ~= nil then
- local event = engine.explode_textlist_event(fields["TPs"])
- if event.type == "CHG" or event.type == "DCL" then
- local index = engine.get_textlist_index("TPs")
- engine.setting_set("mainmenu_last_selected_TP",
- index)
- local list = filter_texture_pack_list(engine.get_dirlist(engine.get_texturepath(), true))
- local current_index = engine.get_textlist_index("TPs")
- if current_index ~= nil and #list >= current_index then
- local new_path = engine.get_texturepath()..DIR_DELIM..list[current_index]
- if list[current_index] == "None" then new_path = "" end
-
- engine.setting_set("texture_path", new_path)
- end
- end
- end
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.tab_header()
-
- if tabbuilder.last_tab_index == nil then
- tabbuilder.last_tab_index = 1
- end
-
- local toadd = ""
-
- for i=1,#tabbuilder.current_buttons,1 do
-
- if toadd ~= "" then
- toadd = toadd .. ","
- end
-
- toadd = toadd .. tabbuilder.current_buttons[i].caption
- end
- return "tabheader[-0.3,-0.99;main_tab;" .. toadd ..";" .. tabbuilder.last_tab_index .. ";true;false]"
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.handle_tab_buttons(fields)
-
- if fields["main_tab"] then
- local index = tonumber(fields["main_tab"])
- tabbuilder.last_tab_index = index
- tabbuilder.current_tab = tabbuilder.current_buttons[index].name
-
- engine.setting_set("main_menu_tab",tabbuilder.current_tab)
- end
-
- --handle tab changes
- if tabbuilder.current_tab ~= tabbuilder.old_tab then
- if tabbuilder.current_tab ~= "singleplayer" and not tabbuilder.is_dialog then
- menu.update_gametype(true)
- end
- end
-
- if tabbuilder.current_tab == "singleplayer" then
- menu.update_gametype()
- end
-
- tabbuilder.old_tab = tabbuilder.current_tab
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.tab_multiplayer()
-
- local retval =
- "vertlabel[0,-0.25;".. fgettext("CLIENT") .. "]" ..
- "label[1,-0.25;".. fgettext("Favorites:") .. "]"..
- "label[1,4.25;".. fgettext("Address/Port") .. "]"..
- "label[9,2.75;".. fgettext("Name/Password") .. "]" ..
- "field[1.25,5.25;5.5,0.5;te_address;;" ..engine.setting_get("address") .."]" ..
- "field[6.75,5.25;2.25,0.5;te_port;;" ..engine.setting_get("remote_port") .."]" ..
- "checkbox[1,3.6;cb_public_serverlist;".. fgettext("Public Serverlist") .. ";" ..
- dump(engine.setting_getbool("public_serverlist")) .. "]"
-
- if not engine.setting_getbool("public_serverlist") then
- retval = retval ..
- "button[6.45,3.95;2.25,0.5;btn_delete_favorite;".. fgettext("Delete") .. "]"
- end
-
- retval = retval ..
- "button[9,4.95;2.5,0.5;btn_mp_connect;".. fgettext("Connect") .. "]" ..
- "field[9.3,3.75;2.5,0.5;te_name;;" ..engine.setting_get("name") .."]" ..
- "pwdfield[9.3,4.5;2.5,0.5;te_pwd;]" ..
- "textarea[9.3,0.25;2.5,2.75;;"
- if menu.fav_selected ~= nil and
- menu.favorites[menu.fav_selected].description ~= nil then
- retval = retval ..
- engine.formspec_escape(menu.favorites[menu.fav_selected].description,true)
- end
-
- retval = retval ..
- ";]" ..
- "textlist[1,0.35;7.5,3.35;favourites;"
-
- local render_details = engine.setting_getbool("public_serverlist")
-
- if #menu.favorites > 0 then
- retval = retval .. menu.render_favorite(menu.favorites[1],render_details)
-
- for i=2,#menu.favorites,1 do
- retval = retval .. "," .. menu.render_favorite(menu.favorites[i],render_details)
- end
- end
-
- if menu.fav_selected ~= nil then
- retval = retval .. ";" .. menu.fav_selected .. "]"
- else
- retval = retval .. ";0]"
- end
-
- return retval
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.tab_server()
-
- local index = filterlist.get_current_index(worldlist,
- tonumber(engine.setting_get("mainmenu_last_selected_world"))
- )
-
- local retval =
- "button[4,4.15;2.6,0.5;world_delete;".. fgettext("Delete") .. "]" ..
- "button[6.5,4.15;2.8,0.5;world_create;".. fgettext("New") .. "]" ..
- "button[9.2,4.15;2.55,0.5;world_configure;".. fgettext("Configure") .. "]" ..
- "button[8.5,4.9;3.25,0.5;start_server;".. fgettext("Start Game") .. "]" ..
- "label[4,-0.25;".. fgettext("Select World:") .. "]"..
- "vertlabel[0,-0.25;".. fgettext("START SERVER") .. "]" ..
- "checkbox[0.5,0.25;cb_creative_mode;".. fgettext("Creative Mode") .. ";" ..
- dump(engine.setting_getbool("creative_mode")) .. "]"..
- "checkbox[0.5,0.7;cb_enable_damage;".. fgettext("Enable Damage") .. ";" ..
- dump(engine.setting_getbool("enable_damage")) .. "]"..
- "checkbox[0.5,1.15;cb_server_announce;".. fgettext("Public") .. ";" ..
- dump(engine.setting_getbool("server_announce")) .. "]"..
- "field[0.8,3.2;3.5,0.5;te_playername;".. fgettext("Name") .. ";" ..
- engine.setting_get("name") .. "]" ..
- "pwdfield[0.8,4.2;3.5,0.5;te_passwd;".. fgettext("Password") .. "]"
-
- local bind_addr = engine.setting_get("bind_address")
- if bind_addr ~= nil and bind_addr ~= "" then
- retval = retval ..
- "field[0.8,5.2;2.25,0.5;te_serveraddr;".. fgettext("Bind Address") .. ";" ..
- engine.setting_get("bind_address") .."]" ..
- "field[3.05,5.2;1.25,0.5;te_serverport;".. fgettext("Port") .. ";" ..
- engine.setting_get("port") .."]"
- else
- retval = retval ..
- "field[0.8,5.2;3.5,0.5;te_serverport;".. fgettext("Server Port") .. ";" ..
- engine.setting_get("port") .."]"
- end
-
- retval = retval ..
- "textlist[4,0.25;7.5,3.7;srv_worlds;" ..
- menu.render_world_list() ..
- ";" .. index .. "]"
-
- return retval
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.tab_settings()
- tab_string =
- "vertlabel[0,0;" .. fgettext("SETTINGS") .. "]" ..
- "checkbox[1,0;cb_fancy_trees;".. fgettext("Fancy Trees") .. ";"
- .. dump(engine.setting_getbool("new_style_leaves")) .. "]"..
- "checkbox[1,0.5;cb_smooth_lighting;".. fgettext("Smooth Lighting")
- .. ";".. dump(engine.setting_getbool("smooth_lighting")) .. "]"..
- "checkbox[1,1;cb_3d_clouds;".. fgettext("3D Clouds") .. ";"
- .. dump(engine.setting_getbool("enable_3d_clouds")) .. "]"..
- "checkbox[1,1.5;cb_opaque_water;".. fgettext("Opaque Water") .. ";"
- .. dump(engine.setting_getbool("opaque_water")) .. "]"..
- "checkbox[1,2.0;cb_pre_ivis;".. fgettext("Preload item visuals") .. ";"
- .. dump(engine.setting_getbool("preload_item_visuals")) .. "]"..
- "checkbox[1,2.5;cb_particles;".. fgettext("Enable Particles") .. ";"
- .. dump(engine.setting_getbool("enable_particles")) .. "]"..
- "checkbox[4.5,0;cb_mipmapping;".. fgettext("Mip-Mapping") .. ";"
- .. dump(engine.setting_getbool("mip_map")) .. "]"..
- "checkbox[4.5,0.5;cb_anisotrophic;".. fgettext("Anisotropic Filtering") .. ";"
- .. dump(engine.setting_getbool("anisotropic_filter")) .. "]"..
- "checkbox[4.5,1.0;cb_bilinear;".. fgettext("Bi-Linear Filtering") .. ";"
- .. dump(engine.setting_getbool("bilinear_filter")) .. "]"..
- "checkbox[4.5,1.5;cb_trilinear;".. fgettext("Tri-Linear Filtering") .. ";"
- .. dump(engine.setting_getbool("trilinear_filter")) .. "]"..
-
- "checkbox[8,0;cb_shaders;".. fgettext("Shaders") .. ";"
- .. dump(engine.setting_getbool("enable_shaders")) .. "]"..
- "button[1,4.5;2.25,0.5;btn_change_keys;".. fgettext("Change keys") .. "]"
-
- if engine.setting_getbool("enable_shaders") then
- tab_string = tab_string ..
- "checkbox[8,0.5;cb_bumpmapping;".. fgettext("Bumpmapping") .. ";"
- .. dump(engine.setting_getbool("enable_bumpmapping")) .. "]"..
- "checkbox[8,1.0;cb_parallax;".. fgettext("Parallax Occlusion") .. ";"
- .. dump(engine.setting_getbool("enable_parallax_occlusion")) .. "]"..
- "checkbox[8,1.5;cb_generate_normalmaps;".. fgettext("Generate Normalmaps") .. ";"
- .. dump(engine.setting_getbool("generate_normalmaps")) .. "]"..
- "checkbox[8,2.0;cb_waving_water;".. fgettext("Waving Water") .. ";"
- .. dump(engine.setting_getbool("enable_waving_water")) .. "]"..
- "checkbox[8,2.5;cb_waving_leaves;".. fgettext("Waving Leaves") .. ";"
- .. dump(engine.setting_getbool("enable_waving_leaves")) .. "]"..
- "checkbox[8,3.0;cb_waving_plants;".. fgettext("Waving Plants") .. ";"
- .. dump(engine.setting_getbool("enable_waving_plants")) .. "]"
- else
- tab_string = tab_string ..
- "textlist[8.33,0.7;4,1;;#888888" .. fgettext("Bumpmapping") .. ";0;true]" ..
- "textlist[8.33,1.2;4,1;;#888888" .. fgettext("Parallax Occlusion") .. ";0;true]" ..
- "textlist[8.33,1.7;4,1;;#888888" .. fgettext("Generate Normalmaps") .. ";0;true]" ..
- "textlist[8.33,2.2;4,1;;#888888" .. fgettext("Waving Water") .. ";0;true]" ..
- "textlist[8.33,2.7;4,1;;#888888" .. fgettext("Waving Leaves") .. ";0;true]" ..
- "textlist[8.33,3.2;4,1;;#888888" .. fgettext("Waving Plants") .. ";0;true]"
- end
- return tab_string
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.tab_singleplayer()
-
- local index = filterlist.get_current_index(worldlist,
- tonumber(engine.setting_get("mainmenu_last_selected_world"))
- )
-
- return "button[4,4.15;2.6,0.5;world_delete;".. fgettext("Delete") .. "]" ..
- "button[6.5,4.15;2.8,0.5;world_create;".. fgettext("New") .. "]" ..
- "button[9.2,4.15;2.55,0.5;world_configure;".. fgettext("Configure") .. "]" ..
- "button[8.5,4.95;3.25,0.5;play;".. fgettext("Play") .. "]" ..
- "label[4,-0.25;".. fgettext("Select World:") .. "]"..
- "vertlabel[0,-0.25;".. fgettext("SINGLE PLAYER") .. "]" ..
- "checkbox[0.5,0.25;cb_creative_mode;".. fgettext("Creative Mode") .. ";" ..
- dump(engine.setting_getbool("creative_mode")) .. "]"..
- "checkbox[0.5,0.7;cb_enable_damage;".. fgettext("Enable Damage") .. ";" ..
- dump(engine.setting_getbool("enable_damage")) .. "]"..
- "textlist[4,0.25;7.5,3.7;sp_worlds;" ..
- menu.render_world_list() ..
- ";" .. index .. "]" ..
- menubar.formspec
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.tab_texture_packs()
- local retval = "label[4,-0.25;".. fgettext("Select texture pack:") .. "]"..
- "vertlabel[0,-0.25;".. fgettext("TEXTURE PACKS") .. "]" ..
- "textlist[4,0.25;7.5,5.0;TPs;"
-
- local current_texture_path = engine.setting_get("texture_path")
- local list = filter_texture_pack_list(engine.get_dirlist(engine.get_texturepath(), true))
- local index = tonumber(engine.setting_get("mainmenu_last_selected_TP"))
-
- if index == nil then index = 1 end
-
- if current_texture_path == "" then
- retval = retval ..
- menu.render_texture_pack_list(list) ..
- ";" .. index .. "]"
- return retval
- end
-
- local infofile = current_texture_path ..DIR_DELIM.."info.txt"
- local infotext = ""
- local f = io.open(infofile, "r")
- if f==nil then
- infotext = fgettext("No information available")
- else
- infotext = f:read("*all")
- f:close()
- end
-
- local screenfile = current_texture_path..DIR_DELIM.."screenshot.png"
- local no_screenshot = nil
- if not file_exists(screenfile) then
- screenfile = nil
- no_screenshot = menu.defaulttexturedir .. "no_screenshot.png"
- end
-
- return retval ..
- menu.render_texture_pack_list(list) ..
- ";" .. index .. "]" ..
- "image[0.65,0.25;4.0,3.7;"..engine.formspec_escape(screenfile or no_screenshot).."]"..
- "textarea[1.0,3.25;3.7,1.5;;"..engine.formspec_escape(infotext or "")..";]"
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.tab_credits()
- local logofile = menu.defaulttexturedir .. "logo.png"
- return "vertlabel[0,-0.5;CREDITS]" ..
- "label[0.5,3;Minetest " .. engine.get_version() .. "]" ..
- "label[0.5,3.3;http://minetest.net]" ..
- "image[0.5,1;" .. engine.formspec_escape(logofile) .. "]" ..
- "textlist[3.5,-0.25;8.5,5.8;list_credits;" ..
- "#FFFF00" .. fgettext("Core Developers") .."," ..
- "Perttu Ahola (celeron55) <celeron55@gmail.com>,"..
- "Ryan Kwolek (kwolekr) <kwolekr@minetest.net>,"..
- "PilzAdam <pilzadam@minetest.net>," ..
- "Ilya Zhuravlev (xyz) <xyz@minetest.net>,"..
- "Lisa Milne (darkrose) <lisa@ltmnet.com>,"..
- "Maciej Kasatkin (RealBadAngel) <mk@realbadangel.pl>,"..
- "proller <proler@gmail.com>,"..
- "sfan5 <sfan5@live.de>,"..
- "kahrl <kahrl@gmx.net>,"..
- "sapier,"..
- "ShadowNinja <shadowninja@minetest.net>,"..
- "Nathanael Courant (Nore/Novatux) <nore@mesecons.net>,"..
- "BlockMen,"..
- ","..
- "#FFFF00" .. fgettext("Active Contributors") .. "," ..
- "Vanessa Ezekowitz (VanessaE) <vanessaezekowitz@gmail.com>,"..
- "Jurgen Doser (doserj) <jurgen.doser@gmail.com>,"..
- "Jeija <jeija@mesecons.net>,"..
- "MirceaKitsune <mirceakitsune@gmail.com>,"..
- "dannydark <the_skeleton_of_a_child@yahoo.co.uk>,"..
- "0gb.us <0gb.us@0gb.us>,"..
- "," ..
- "#FFFF00" .. fgettext("Previous Contributors") .. "," ..
- "Guiseppe Bilotta (Oblomov) <guiseppe.bilotta@gmail.com>,"..
- "Jonathan Neuschafer <j.neuschaefer@gmx.net>,"..
- "Nils Dagsson Moskopp (erlehmann) <nils@dieweltistgarnichtso.net>,"..
- "Constantin Wenger (SpeedProg) <constantin.wenger@googlemail.com>,"..
- "matttpt <matttpt@gmail.com>,"..
- "JacobF <queatz@gmail.com>,"..
- ";0;true]"
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.init()
- tabbuilder.tabfuncs = {
- singleplayer = tabbuilder.tab_singleplayer,
- multiplayer = tabbuilder.tab_multiplayer,
- server = tabbuilder.tab_server,
- settings = tabbuilder.tab_settings,
- texture_packs = tabbuilder.tab_texture_packs,
- credits = tabbuilder.tab_credits,
- dialog_create_world = tabbuilder.dialog_create_world,
- dialog_delete_world = tabbuilder.dialog_delete_world
- }
-
- tabbuilder.tabsizes = {
- dialog_create_world = {width=12, height=7},
- dialog_delete_world = {width=12, height=5.2}
- }
-
- tabbuilder.current_tab = engine.setting_get("main_menu_tab")
-
- if tabbuilder.current_tab == nil or
- tabbuilder.current_tab == "" then
- tabbuilder.current_tab = "singleplayer"
- engine.setting_set("main_menu_tab",tabbuilder.current_tab)
- end
-
- --initialize tab buttons
- tabbuilder.last_tab = nil
- tabbuilder.show_buttons = true
-
- tabbuilder.current_buttons = {}
- table.insert(tabbuilder.current_buttons,{name="singleplayer", caption=fgettext("Singleplayer")})
- table.insert(tabbuilder.current_buttons,{name="multiplayer", caption=fgettext("Client")})
- table.insert(tabbuilder.current_buttons,{name="server", caption=fgettext("Server")})
- table.insert(tabbuilder.current_buttons,{name="settings", caption=fgettext("Settings")})
- table.insert(tabbuilder.current_buttons,{name="texture_packs", caption=fgettext("Texture Packs")})
-
- if engine.setting_getbool("main_menu_game_mgr") then
- table.insert(tabbuilder.current_buttons,{name="game_mgr", caption=fgettext("Games")})
- end
-
- if engine.setting_getbool("main_menu_mod_mgr") then
- table.insert(tabbuilder.current_buttons,{name="mod_mgr", caption=fgettext("Mods")})
- end
- table.insert(tabbuilder.current_buttons,{name="credits", caption=fgettext("Credits")})
-
-
- for i=1,#tabbuilder.current_buttons,1 do
- if tabbuilder.current_buttons[i].name == tabbuilder.current_tab then
- tabbuilder.last_tab_index = i
- end
- end
-
- if tabbuilder.current_tab ~= "singleplayer" then
- menu.update_gametype(true)
- else
- menu.update_gametype()
- end
-end
-
---------------------------------------------------------------------------------
-function tabbuilder.checkretval(retval)
-
- if retval ~= nil then
- if retval.current_tab ~= nil then
- tabbuilder.current_tab = retval.current_tab
- end
-
- if retval.is_dialog ~= nil then
- tabbuilder.is_dialog = retval.is_dialog
- end
-
- if retval.show_buttons ~= nil then
- tabbuilder.show_buttons = retval.show_buttons
- end
-
- if retval.skipformupdate ~= nil then
- tabbuilder.skipformupdate = retval.skipformupdate
- end
-
- if retval.ignore_menu_quit == true then
- tabbuilder.ignore_menu_quit = true
- else
- tabbuilder.ignore_menu_quit = false
- end
- end
-end
-
---------------------------------------------------------------------------------
---------------------------------------------------------------------------------
--- initialize callbacks
---------------------------------------------------------------------------------
---------------------------------------------------------------------------------
-engine.button_handler = function(fields)
- --print("Buttonhandler: tab: " .. tabbuilder.current_tab .. " fields: " .. dump(fields))
-
- if fields["btn_error_confirm"] then
- gamedata.errormessage = nil
- end
-
- local retval = modmgr.handle_buttons(tabbuilder.current_tab,fields)
- tabbuilder.checkretval(retval)
-
- retval = gamemgr.handle_buttons(tabbuilder.current_tab,fields)
- tabbuilder.checkretval(retval)
-
- retval = modstore.handle_buttons(tabbuilder.current_tab,fields)
- tabbuilder.checkretval(retval)
-
- if tabbuilder.current_tab == "dialog_create_world" then
- tabbuilder.handle_create_world_buttons(fields)
- end
-
- if tabbuilder.current_tab == "dialog_delete_world" then
- tabbuilder.handle_delete_world_buttons(fields)
- end
-
- if tabbuilder.current_tab == "singleplayer" then
- tabbuilder.handle_singleplayer_buttons(fields)
- end
-
- if tabbuilder.current_tab == "texture_packs" then
- tabbuilder.handle_texture_pack_buttons(fields)
- end
-
- if tabbuilder.current_tab == "multiplayer" then
- tabbuilder.handle_multiplayer_buttons(fields)
- end
-
- if tabbuilder.current_tab == "settings" then
- tabbuilder.handle_settings_buttons(fields)
- end
-
- if tabbuilder.current_tab == "server" then
- tabbuilder.handle_server_buttons(fields)
- end
-
- --tab buttons
- tabbuilder.handle_tab_buttons(fields)
-
- --menubar buttons
- menubar.handle_buttons(fields)
-
- if not tabbuilder.skipformupdate then
- --update menu
- update_menu()
- else
- tabbuilder.skipformupdate = false
- end
-end
-
---------------------------------------------------------------------------------
-engine.event_handler = function(event)
- if event == "MenuQuit" then
- if tabbuilder.is_dialog then
- if tabbuilder.ignore_menu_quit then
- return
- end
-
- tabbuilder.is_dialog = false
- tabbuilder.show_buttons = true
- tabbuilder.current_tab = engine.setting_get("main_menu_tab")
- menu.update_gametype()
- update_menu()
- else
- engine.close()
- end
- end
-
- if event == "Refresh" then
- update_menu()
- end
-end
-
---------------------------------------------------------------------------------
-function menu.update_gametype(reset)
- local game = menu.lastgame()
-
- if reset or game == nil then
- mm_texture.reset()
- engine.set_topleft_text("")
- filterlist.set_filtercriteria(worldlist,nil)
- else
- mm_texture.update(tabbuilder.current_tab,game)
- engine.set_topleft_text(game.name)
- filterlist.set_filtercriteria(worldlist,game.id)
- end
-end
-
---------------------------------------------------------------------------------
---------------------------------------------------------------------------------
--- menu startup
---------------------------------------------------------------------------------
---------------------------------------------------------------------------------
-init_globals()
-mm_texture.init()
-menu.init()
-tabbuilder.init()
-menubar.refresh()
-modstore.init()
-
-engine.sound_play("main_menu", true)
-
-update_menu()
--- /dev/null
+--Minetest
+--Copyright (C) 2013 sapier
+--
+--This program is free software; you can redistribute it and/or modify
+--it under the terms of the GNU Lesser General Public License as published by
+--the Free Software Foundation; either version 2.1 of the License, or
+--(at your option) any later version.
+--
+--This program is distributed in the hope that it will be useful,
+--but WITHOUT ANY WARRANTY; without even the implied warranty of
+--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+--GNU Lesser General Public License for more details.
+--
+--You should have received a copy of the GNU Lesser General Public License along
+--with this program; if not, write to the Free Software Foundation, Inc.,
+--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+--------------------------------------------------------------------------------
+-- Generic implementation of a filter/sortable list --
+-- Usage: --
+-- Filterlist needs to be initialized on creation. To achieve this you need to --
+-- pass following functions: --
+-- raw_fct() (mandatory): --
+-- function returning a table containing the elements to be filtered --
+-- compare_fct(element1,element2) (mandatory): --
+-- function returning true/false if element1 is same element as element2 --
+-- uid_match_fct(element1,uid) (optional) --
+-- function telling if uid is attached to element1 --
+-- filter_fct(element,filtercriteria) (optional) --
+-- function returning true/false if filtercriteria met to element --
+-- fetch_param (optional) --
+-- parameter passed to raw_fct to aquire correct raw data --
+-- --
+--------------------------------------------------------------------------------
+filterlist = {}
+
+--------------------------------------------------------------------------------
+function filterlist.refresh(this)
+ this.m_raw_list = this.m_raw_list_fct(this.m_fetch_param)
+ filterlist.process(this)
+end
+
+--------------------------------------------------------------------------------
+function filterlist.create(raw_fct,compare_fct,uid_match_fct,filter_fct,fetch_param)
+
+ assert((raw_fct ~= nil) and (type(raw_fct) == "function"))
+ assert((compare_fct ~= nil) and (type(compare_fct) == "function"))
+
+ local this = {}
+
+ this.m_raw_list_fct = raw_fct
+ this.m_compare_fct = compare_fct
+ this.m_filter_fct = filter_fct
+ this.m_uid_match_fct = uid_match_fct
+
+ this.m_filtercriteria = nil
+ this.m_fetch_param = fetch_param
+
+ this.m_sortmode = "none"
+ this.m_sort_list = {}
+
+ this.m_processed_list = nil
+ this.m_raw_list = this.m_raw_list_fct(this.m_fetch_param)
+
+ filterlist.process(this)
+
+ return this
+end
+
+--------------------------------------------------------------------------------
+function filterlist.add_sort_mechanism(this,name,fct)
+ this.m_sort_list[name] = fct
+end
+
+--------------------------------------------------------------------------------
+function filterlist.set_filtercriteria(this,criteria)
+ if criteria == this.m_filtercriteria and
+ type(criteria) ~= "table" then
+ return
+ end
+ this.m_filtercriteria = criteria
+ filterlist.process(this)
+end
+
+--------------------------------------------------------------------------------
+function filterlist.get_filtercriteria(this)
+ return this.m_filtercriteria
+end
+
+--------------------------------------------------------------------------------
+--supported sort mode "alphabetic|none"
+function filterlist.set_sortmode(this,mode)
+ if (mode == this.m_sortmode) then
+ return
+ end
+ this.m_sortmode = mode
+ filterlist.process(this)
+end
+
+--------------------------------------------------------------------------------
+function filterlist.get_list(this)
+ return this.m_processed_list
+end
+
+--------------------------------------------------------------------------------
+function filterlist.get_raw_list(this)
+ return this.m_raw_list
+end
+
+--------------------------------------------------------------------------------
+function filterlist.get_raw_element(this,idx)
+ if type(idx) ~= "number" then
+ idx = tonumber(idx)
+ end
+
+ if idx ~= nil and idx > 0 and idx < #this.m_raw_list then
+ return this.m_raw_list[idx]
+ end
+
+ return nil
+end
+
+--------------------------------------------------------------------------------
+function filterlist.get_raw_index(this,listindex)
+ assert(this.m_processed_list ~= nil)
+
+ if listindex ~= nil and listindex > 0 and
+ listindex <= #this.m_processed_list then
+ local entry = this.m_processed_list[listindex]
+
+ for i,v in ipairs(this.m_raw_list) do
+
+ if this.m_compare_fct(v,entry) then
+ return i
+ end
+ end
+ end
+
+ return 0
+end
+
+--------------------------------------------------------------------------------
+function filterlist.get_current_index(this,listindex)
+ assert(this.m_processed_list ~= nil)
+
+ if listindex ~= nil and listindex > 0 and
+ listindex <= #this.m_raw_list then
+ local entry = this.m_raw_list[listindex]
+
+ for i,v in ipairs(this.m_processed_list) do
+
+ if this.m_compare_fct(v,entry) then
+ return i
+ end
+ end
+ end
+
+ return 0
+end
+
+--------------------------------------------------------------------------------
+function filterlist.process(this)
+ assert(this.m_raw_list ~= nil)
+
+ if this.m_sortmode == "none" and
+ this.m_filtercriteria == nil then
+ this.m_processed_list = this.m_raw_list
+ return
+ end
+
+ this.m_processed_list = {}
+
+ for k,v in pairs(this.m_raw_list) do
+ if this.m_filtercriteria == nil or
+ this.m_filter_fct(v,this.m_filtercriteria) then
+ table.insert(this.m_processed_list,v)
+ end
+ end
+
+ if this.m_sortmode == "none" then
+ return
+ end
+
+ if this.m_sort_list[this.m_sortmode] ~= nil and
+ type(this.m_sort_list[this.m_sortmode]) == "function" then
+
+ this.m_sort_list[this.m_sortmode](this)
+ end
+end
+
+--------------------------------------------------------------------------------
+function filterlist.size(this)
+ if this.m_processed_list == nil then
+ return 0
+ end
+
+ return #this.m_processed_list
+end
+
+--------------------------------------------------------------------------------
+function filterlist.uid_exists_raw(this,uid)
+ for i,v in ipairs(this.m_raw_list) do
+ if this.m_uid_match_fct(v,uid) then
+ return true
+ end
+ end
+ return false
+end
+
+--------------------------------------------------------------------------------
+function filterlist.raw_index_by_uid(this, uid)
+ local elementcount = 0
+ local elementidx = 0
+ for i,v in ipairs(this.m_raw_list) do
+ if this.m_uid_match_fct(v,uid) then
+ elementcount = elementcount +1
+ elementidx = i
+ end
+ end
+
+
+ -- If there are more elements than one with same name uid can't decide which
+ -- one is meant. This shouldn't be possible but just for sure.
+ if elementcount > 1 then
+ elementidx=0
+ end
+
+ return elementidx
+end
+
+--------------------------------------------------------------------------------
+-- COMMON helper functions --
+--------------------------------------------------------------------------------
+
+--------------------------------------------------------------------------------
+function compare_worlds(world1,world2)
+
+ if world1.path ~= world2.path then
+ return false
+ end
+
+ if world1.name ~= world2.name then
+ return false
+ end
+
+ if world1.gameid ~= world2.gameid then
+ return false
+ end
+
+ return true
+end
+
+--------------------------------------------------------------------------------
+function sort_worlds_alphabetic(this)
+
+ table.sort(this.m_processed_list, function(a, b)
+ --fixes issue #857 (crash due to sorting nil in worldlist)
+ if a == nil or b == nil then
+ if a == nil and b ~= nil then return false end
+ if b == nil and a ~= nil then return true end
+ return false
+ end
+ if a.name:lower() == b.name:lower() then
+ return a.name < b.name
+ end
+ return a.name:lower() < b.name:lower()
+ end)
+end
+
+--------------------------------------------------------------------------------
+function sort_mod_list(this)
+
+ table.sort(this.m_processed_list, function(a, b)
+ -- Show game mods at bottom
+ if a.typ ~= b.typ then
+ return b.typ == "game_mod"
+ end
+ -- If in same or no modpack, sort by name
+ if a.modpack == b.modpack then
+ if a.name:lower() == b.name:lower() then
+ return a.name < b.name
+ end
+ return a.name:lower() < b.name:lower()
+ -- Else compare name to modpack name
+ else
+ -- Always show modpack pseudo-mod on top of modpack mod list
+ if a.name == b.modpack then
+ return true
+ elseif b.name == a.modpack then
+ return false
+ end
+
+ local name_a = a.modpack or a.name
+ local name_b = b.modpack or b.name
+ if name_a:lower() == name_b:lower() then
+ return name_a < name_b
+ end
+ return name_a:lower() < name_b:lower()
+ end
+ end)
+end
--- /dev/null
+--Minetest
+--Copyright (C) 2013 sapier
+--
+--This program is free software; you can redistribute it and/or modify
+--it under the terms of the GNU Lesser General Public License as published by
+--the Free Software Foundation; either version 2.1 of the License, or
+--(at your option) any later version.
+--
+--This program is distributed in the hope that it will be useful,
+--but WITHOUT ANY WARRANTY; without even the implied warranty of
+--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+--GNU Lesser General Public License for more details.
+--
+--You should have received a copy of the GNU Lesser General Public License along
+--with this program; if not, write to the Free Software Foundation, Inc.,
+--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+gamemgr = {}
+
+--------------------------------------------------------------------------------
+function gamemgr.dialog_new_game()
+ local retval =
+ "label[2,2;" .. fgettext("Game Name") .. "]"..
+ "field[4.5,2.4;6,0.5;te_game_name;;]" ..
+ "button[5,4.2;2.6,0.5;new_game_confirm;" .. fgettext("Create") .. "]" ..
+ "button[7.5,4.2;2.8,0.5;new_game_cancel;" .. fgettext("Cancel") .. "]"
+
+ return retval
+end
+
+--------------------------------------------------------------------------------
+function gamemgr.handle_games_buttons(fields)
+ if fields["gamelist"] ~= nil then
+ local event = engine.explode_textlist_event(fields["gamelist"])
+ gamemgr.selected_game = event.index
+ end
+
+ if fields["btn_game_mgr_edit_game"] ~= nil then
+ return {
+ is_dialog = true,
+ show_buttons = false,
+ current_tab = "dialog_edit_game"
+ }
+ end
+
+ if fields["btn_game_mgr_new_game"] ~= nil then
+ return {
+ is_dialog = true,
+ show_buttons = false,
+ current_tab = "dialog_new_game"
+ }
+ end
+
+ return nil
+end
+
+--------------------------------------------------------------------------------
+function gamemgr.handle_new_game_buttons(fields)
+
+ if fields["new_game_confirm"] and
+ fields["te_game_name"] ~= nil and
+ fields["te_game_name"] ~= "" then
+ local gamepath = engine.get_gamepath()
+
+ if gamepath ~= nil and
+ gamepath ~= "" then
+ local gamefolder = cleanup_path(fields["te_game_name"])
+
+ --TODO check for already existing first
+ engine.create_dir(gamepath .. DIR_DELIM .. gamefolder)
+ engine.create_dir(gamepath .. DIR_DELIM .. gamefolder .. DIR_DELIM .. "mods")
+ engine.create_dir(gamepath .. DIR_DELIM .. gamefolder .. DIR_DELIM .. "menu")
+
+ local gameconf =
+ io.open(gamepath .. DIR_DELIM .. gamefolder .. DIR_DELIM .. "game.conf","w")
+
+ if gameconf then
+ gameconf:write("name = " .. fields["te_game_name"])
+ gameconf:close()
+ end
+ end
+ end
+
+ return {
+ is_dialog = false,
+ show_buttons = true,
+ current_tab = engine.setting_get("main_menu_tab")
+ }
+end
+
+--------------------------------------------------------------------------------
+function gamemgr.handle_edit_game_buttons(fields)
+ local current_game = gamemgr.get_game(gamemgr.selected_game)
+
+ if fields["btn_close_edit_game"] ~= nil or
+ current_game == nil then
+ return {
+ is_dialog = false,
+ show_buttons = true,
+ current_tab = engine.setting_get("main_menu_tab")
+ }
+ end
+
+ if fields["btn_remove_mod_from_game"] ~= nil then
+ gamemgr.delete_mod(current_game,engine.get_textlist_index("mods_current"))
+ end
+
+ if fields["btn_add_mod_to_game"] ~= nil then
+ local modindex = engine.get_textlist_index("mods_available")
+
+ local mod = modmgr.get_global_mod(modindex)
+ if mod ~= nil then
+
+ local sourcepath = mod.path
+
+ if not gamemgr.add_mod(current_game,sourcepath) then
+ gamedata.errormessage =
+ fgettext("Gamemgr: Unable to copy mod \"$1\" to game \"$2\"", mod.name, current_game.id)
+ end
+ end
+ end
+
+ return nil
+end
+
+--------------------------------------------------------------------------------
+function gamemgr.add_mod(gamespec,sourcepath)
+ if gamespec.gamemods_path ~= nil and
+ gamespec.gamemods_path ~= "" then
+
+ local modname = get_last_folder(sourcepath)
+
+ return engine.copy_dir(sourcepath,gamespec.gamemods_path .. DIR_DELIM .. modname);
+ end
+
+ return false
+end
+
+--------------------------------------------------------------------------------
+function gamemgr.delete_mod(gamespec,modindex)
+ if gamespec.gamemods_path ~= nil and
+ gamespec.gamemods_path ~= "" then
+ local game_mods = {}
+ get_mods(gamespec.gamemods_path,game_mods)
+
+ if modindex > 0 and
+ #game_mods >= modindex then
+
+ if game_mods[modindex].path:sub(0,gamespec.gamemods_path:len())
+ == gamespec.gamemods_path then
+ engine.delete_dir(game_mods[modindex].path)
+ end
+ end
+ end
+end
+
+--------------------------------------------------------------------------------
+function gamemgr.find_by_gameid(gameid)
+ for i=1,#gamemgr.games,1 do
+ if gamemgr.games[i].id == gameid then
+ return gamemgr.games[i], i
+ end
+ end
+ return nil, nil
+end
+
+--------------------------------------------------------------------------------
+function gamemgr.get_game_mods(gamespec, retval)
+ if gamespec ~= nil and
+ gamespec.gamemods_path ~= nil and
+ gamespec.gamemods_path ~= "" then
+ get_mods(gamespec.gamemods_path, retval)
+ end
+end
+
+--------------------------------------------------------------------------------
+function gamemgr.get_game_modlist(gamespec)
+ local retval = ""
+ local game_mods = {}
+ gamemgr.get_game_mods(gamespec, game_mods)
+ for i=1,#game_mods,1 do
+ if retval ~= "" then
+ retval = retval..","
+ end
+ retval = retval .. game_mods[i].name
+ end
+ return retval
+end
+
+--------------------------------------------------------------------------------
+function gamemgr.gettab(name)
+ local retval = ""
+
+ if name == "dialog_edit_game" then
+ retval = retval .. gamemgr.dialog_edit_game()
+ end
+
+ if name == "dialog_new_game" then
+ retval = retval .. gamemgr.dialog_new_game()
+ end
+
+ if name == "game_mgr" then
+ retval = retval .. gamemgr.tab()
+ end
+
+ return retval
+end
+
+--------------------------------------------------------------------------------
+function gamemgr.tab()
+ if gamemgr.selected_game == nil then
+ gamemgr.selected_game = 1
+ end
+
+ local retval =
+ "vertlabel[0,-0.25;" .. fgettext("GAMES") .. "]" ..
+ "label[1,-0.25;" .. fgettext("Games") .. ":]" ..
+ "textlist[1,0.25;4.5,4.4;gamelist;" ..
+ gamemgr.gamelist() ..
+ ";" .. gamemgr.selected_game .. "]"
+
+ local current_game = gamemgr.get_game(gamemgr.selected_game)
+
+ if current_game ~= nil then
+ if current_game.menuicon_path ~= nil and
+ current_game.menuicon_path ~= "" then
+ retval = retval ..
+ "image[5.8,-0.25;2,2;" ..
+ engine.formspec_escape(current_game.menuicon_path) .. "]"
+ end
+
+ retval = retval ..
+ "field[8,-0.25;6,2;;" .. current_game.name .. ";]"..
+ "label[6,1.4;" .. fgettext("Mods:") .."]" ..
+ "button[9.7,1.5;2,0.2;btn_game_mgr_edit_game;" .. fgettext("edit game") .. "]" ..
+ "textlist[6,2;5.5,3.3;game_mgr_modlist;"
+ .. gamemgr.get_game_modlist(current_game) ..";0]" ..
+ "button[1,4.75;3.2,0.5;btn_game_mgr_new_game;" .. fgettext("new game") .. "]"
+ end
+ return retval
+end
+
+--------------------------------------------------------------------------------
+function gamemgr.dialog_edit_game()
+ local current_game = gamemgr.get_game(gamemgr.selected_game)
+ if current_game ~= nil then
+ local retval =
+ "vertlabel[0,-0.25;" .. fgettext("EDIT GAME") .."]" ..
+ "label[0,-0.25;" .. current_game.name .. "]" ..
+ "button[11.55,-0.2;0.75,0.5;btn_close_edit_game;x]"
+
+ if current_game.menuicon_path ~= nil and
+ current_game.menuicon_path ~= "" then
+ retval = retval ..
+ "image[5.25,0;2,2;" ..
+ engine.formspec_escape(current_game.menuicon_path) .. "]"
+ end
+
+ retval = retval ..
+ "textlist[0.5,0.5;4.5,4.3;mods_current;"
+ .. gamemgr.get_game_modlist(current_game) ..";0]"
+
+
+ retval = retval ..
+ "textlist[7,0.5;4.5,4.3;mods_available;"
+ .. modmgr.render_modlist() .. ";0]"
+
+ retval = retval ..
+ "button[0.55,4.95;4.7,0.5;btn_remove_mod_from_game;" .. fgettext("Remove selected mod") .."]"
+
+ retval = retval ..
+ "button[7.05,4.95;4.7,0.5;btn_add_mod_to_game;" .. fgettext("<<-- Add mod") .."]"
+
+ return retval
+ end
+end
+
+--------------------------------------------------------------------------------
+function gamemgr.handle_buttons(tab,fields)
+ local retval = nil
+
+ if tab == "dialog_edit_game" then
+ retval = gamemgr.handle_edit_game_buttons(fields)
+ end
+
+ if tab == "dialog_new_game" then
+ retval = gamemgr.handle_new_game_buttons(fields)
+ end
+
+ if tab == "game_mgr" then
+ retval = gamemgr.handle_games_buttons(fields)
+ end
+
+ return retval
+end
+
+--------------------------------------------------------------------------------
+function gamemgr.get_game(index)
+ if index > 0 and index <= #gamemgr.games then
+ return gamemgr.games[index]
+ end
+
+ return nil
+end
+
+--------------------------------------------------------------------------------
+function gamemgr.update_gamelist()
+ gamemgr.games = engine.get_games()
+end
+
+--------------------------------------------------------------------------------
+function gamemgr.gamelist()
+ local retval = ""
+ if #gamemgr.games > 0 then
+ retval = retval .. gamemgr.games[1].id
+
+ for i=2,#gamemgr.games,1 do
+ retval = retval .. "," .. gamemgr.games[i].name
+ end
+ end
+ return retval
+end
--- /dev/null
+
+local menupath = engine.get_mainmenu_path()..DIR_DELIM
+local commonpath = engine.get_builtin_path()..DIR_DELIM.."common"..DIR_DELIM
+
+dofile(menupath.."filterlist.lua")
+dofile(menupath.."modmgr.lua")
+dofile(menupath.."modstore.lua")
+dofile(menupath.."gamemgr.lua")
+dofile(menupath.."textures.lua")
+dofile(menupath.."menubar.lua")
+dofile(commonpath.."async_event.lua")
+
+mt_color_grey = "#AAAAAA"
+mt_color_blue = "#0000DD"
+mt_color_green = "#00DD00"
+mt_color_dark_green = "#003300"
+
+--for all other colors ask sfan5 to complete his worK!
+
+menu = {}
+local tabbuilder = {}
+local worldlist = nil
+
+--------------------------------------------------------------------------------
+local function filter_texture_pack_list(list)
+ retval = {"None"}
+ for _,i in ipairs(list) do
+ if i~="base" then
+ table.insert(retval, i)
+ end
+ end
+ return retval
+end
+
+--------------------------------------------------------------------------------
+function menu.render_favorite(spec,render_details)
+ local text = ""
+
+ if spec.name ~= nil then
+ text = text .. engine.formspec_escape(spec.name:trim())
+
+-- if spec.description ~= nil and
+-- engine.formspec_escape(spec.description):trim() ~= "" then
+-- text = text .. " (" .. engine.formspec_escape(spec.description) .. ")"
+-- end
+ else
+ if spec.address ~= nil then
+ text = text .. spec.address:trim()
+
+ if spec.port ~= nil then
+ text = text .. ":" .. spec.port
+ end
+ end
+ end
+
+ if not render_details then
+ return text
+ end
+
+ local details = ""
+ if spec.password == true then
+ details = details .. "*"
+ else
+ details = details .. "_"
+ end
+
+ if spec.creative then
+ details = details .. "C"
+ else
+ details = details .. "_"
+ end
+
+ if spec.damage then
+ details = details .. "D"
+ else
+ details = details .. "_"
+ end
+
+ if spec.pvp then
+ details = details .. "P"
+ else
+ details = details .. "_"
+ end
+ details = details .. " "
+
+ local playercount = ""
+
+ if spec.clients ~= nil and
+ spec.clients_max ~= nil then
+ playercount = string.format("%03d",spec.clients) .. "/" ..
+ string.format("%03d",spec.clients_max) .. " "
+ end
+
+ return playercount .. engine.formspec_escape(details) .. text
+end
+
+--------------------------------------------------------------------------------
+os.tempfolder = function()
+ local filetocheck = os.tmpname()
+ os.remove(filetocheck)
+
+ local randname = "MTTempModFolder_" .. math.random(0,10000)
+ if DIR_DELIM == "\\" then
+ local tempfolder = os.getenv("TEMP")
+ return tempfolder .. filetocheck
+ else
+ local backstring = filetocheck:reverse()
+ return filetocheck:sub(0,filetocheck:len()-backstring:find(DIR_DELIM)+1) ..randname
+ end
+
+end
+
+--------------------------------------------------------------------------------
+function text2textlist(xpos,ypos,width,height,tl_name,textlen,text,transparency)
+ local textlines = engine.splittext(text,textlen)
+
+ local retval = "textlist[" .. xpos .. "," .. ypos .. ";"
+ .. width .. "," .. height .. ";"
+ .. tl_name .. ";"
+
+ for i=1, #textlines, 1 do
+ textlines[i] = textlines[i]:gsub("\r","")
+ retval = retval .. engine.formspec_escape(textlines[i]) .. ","
+ end
+
+ retval = retval .. ";0;"
+
+ if transparency then
+ retval = retval .. "true"
+ end
+
+ retval = retval .. "]"
+
+ return retval
+end
+
+--------------------------------------------------------------------------------
+function init_globals()
+ --init gamedata
+ gamedata.worldindex = 0
+
+ worldlist = filterlist.create(
+ engine.get_worlds,
+ compare_worlds,
+ function(element,uid)
+ if element.name == uid then
+ return true
+ end
+ return false
+ end, --unique id compare fct
+ function(element,gameid)
+ if element.gameid == gameid then
+ return true
+ end
+ return false
+ end --filter fct
+ )
+
+ filterlist.add_sort_mechanism(worldlist,"alphabetic",sort_worlds_alphabetic)
+ filterlist.set_sortmode(worldlist,"alphabetic")
+end
+
+--------------------------------------------------------------------------------
+function update_menu()
+
+ local formspec
+
+ -- handle errors
+ if gamedata.errormessage ~= nil then
+ formspec = "size[12,5.2,true]" ..
+ "textarea[1,2;10,2;;ERROR: " ..
+ engine.formspec_escape(gamedata.errormessage) ..
+ ";]"..
+ "button[4.5,4.2;3,0.5;btn_error_confirm;" .. fgettext("Ok") .. "]"
+ else
+ formspec = tabbuilder.gettab()
+ end
+
+ engine.update_formspec(formspec)
+end
+
+--------------------------------------------------------------------------------
+function menu.render_world_list()
+ local retval = ""
+
+ local current_worldlist = filterlist.get_list(worldlist)
+
+ for i,v in ipairs(current_worldlist) do
+ if retval ~= "" then
+ retval = retval ..","
+ end
+
+ retval = retval .. engine.formspec_escape(v.name) ..
+ " \\[" .. engine.formspec_escape(v.gameid) .. "\\]"
+ end
+
+ return retval
+end
+
+--------------------------------------------------------------------------------
+function menu.render_texture_pack_list(list)
+ local retval = ""
+
+ for i, v in ipairs(list) do
+ if retval ~= "" then
+ retval = retval ..","
+ end
+
+ retval = retval .. engine.formspec_escape(v)
+ end
+
+ return retval
+end
+
+--------------------------------------------------------------------------------
+function menu.asyncOnlineFavourites()
+ menu.favorites = {}
+ engine.handle_async(
+ function(param)
+ return engine.get_favorites("online")
+ end,
+ nil,
+ function(result)
+ menu.favorites = result
+ engine.event_handler("Refresh")
+ end
+ )
+end
+
+--------------------------------------------------------------------------------
+function menu.init()
+ --init menu data
+ gamemgr.update_gamelist()
+
+ menu.last_game = tonumber(engine.setting_get("main_menu_last_game_idx"))
+
+ if type(menu.last_game) ~= "number" then
+ menu.last_game = 1
+ end
+
+ if engine.setting_getbool("public_serverlist") then
+ menu.asyncOnlineFavourites()
+ else
+ menu.favorites = engine.get_favorites("local")
+ end
+
+ menu.defaulttexturedir = engine.get_texturepath_share() .. DIR_DELIM .. "base" ..
+ DIR_DELIM .. "pack" .. DIR_DELIM
+end
+
+--------------------------------------------------------------------------------
+function menu.lastgame()
+ if menu.last_game > 0 and menu.last_game <= #gamemgr.games then
+ return gamemgr.games[menu.last_game]
+ end
+
+ if #gamemgr.games >= 1 then
+ menu.last_game = 1
+ return gamemgr.games[menu.last_game]
+ end
+
+ --error case!!
+ return nil
+end
+
+--------------------------------------------------------------------------------
+function menu.update_last_game()
+
+ local current_world = filterlist.get_raw_element(worldlist,
+ engine.setting_get("mainmenu_last_selected_world")
+ )
+
+ if current_world == nil then
+ return
+ end
+
+ local gamespec, i = gamemgr.find_by_gameid(current_world.gameid)
+ if i ~= nil then
+ menu.last_game = i
+ engine.setting_set("main_menu_last_game_idx",menu.last_game)
+ end
+end
+
+--------------------------------------------------------------------------------
+function menu.handle_key_up_down(fields,textlist,settingname)
+
+ if fields["key_up"] then
+ local oldidx = engine.get_textlist_index(textlist)
+
+ if oldidx ~= nil and oldidx > 1 then
+ local newidx = oldidx -1
+ engine.setting_set(settingname,
+ filterlist.get_raw_index(worldlist,newidx))
+ end
+ end
+
+ if fields["key_down"] then
+ local oldidx = engine.get_textlist_index(textlist)
+
+ if oldidx ~= nil and oldidx < filterlist.size(worldlist) then
+ local newidx = oldidx + 1
+ engine.setting_set(settingname,
+ filterlist.get_raw_index(worldlist,newidx))
+ end
+ end
+end
+
+--------------------------------------------------------------------------------
+function tabbuilder.dialog_create_world()
+ local mapgens = {"v6", "v7", "indev", "singlenode", "math"}
+
+ local current_seed = engine.setting_get("fixed_map_seed") or ""
+ local current_mg = engine.setting_get("mg_name")
+
+ local mglist = ""
+ local selindex = 1
+ local i = 1
+ for k,v in pairs(mapgens) do
+ if current_mg == v then
+ selindex = i
+ end
+ i = i + 1
+ mglist = mglist .. v .. ","
+ end
+ mglist = mglist:sub(1, -2)
+
+ local retval =
+ "label[2,0;" .. fgettext("World name") .. "]"..
+ "field[4.5,0.4;6,0.5;te_world_name;;]" ..
+
+ "label[2,1;" .. fgettext("Seed") .. "]"..
+ "field[4.5,1.4;6,0.5;te_seed;;".. current_seed .. "]" ..
+
+ "label[2,2;" .. fgettext("Mapgen") .. "]"..
+ "dropdown[4.2,2;6.3;dd_mapgen;" .. mglist .. ";" .. selindex .. "]" ..
+
+ "label[2,3;" .. fgettext("Game") .. "]"..
+ "textlist[4.2,3;5.8,2.3;games;" .. gamemgr.gamelist() ..
+ ";" .. menu.last_game .. ";true]" ..
+
+ "button[5,5.5;2.6,0.5;world_create_confirm;" .. fgettext("Create") .. "]" ..
+ "button[7.5,5.5;2.8,0.5;world_create_cancel;" .. fgettext("Cancel") .. "]"
+
+ return retval
+end
+
+--------------------------------------------------------------------------------
+function tabbuilder.dialog_delete_world()
+ return "label[2,2;" ..
+ fgettext("Delete World \"$1\"?", filterlist.get_raw_list(worldlist)[menu.world_to_del].name) .. "]"..
+ "button[3.5,4.2;2.6,0.5;world_delete_confirm;" .. fgettext("Yes").. "]" ..
+ "button[6,4.2;2.8,0.5;world_delete_cancel;" .. fgettext("No") .. "]"
+end
+
+--------------------------------------------------------------------------------
+
+function tabbuilder.gettab()
+ local tsize = tabbuilder.tabsizes[tabbuilder.current_tab] or {width=12, height=5.2}
+ local retval = "size[" .. tsize.width .. "," .. tsize.height .. ",true]"
+
+ if tabbuilder.show_buttons then
+ retval = retval .. tabbuilder.tab_header()
+ end
+
+ local buildfunc = tabbuilder.tabfuncs[tabbuilder.current_tab]
+ if buildfunc ~= nil then
+ retval = retval .. buildfunc()
+ end
+
+ retval = retval .. modmgr.gettab(tabbuilder.current_tab)
+ retval = retval .. gamemgr.gettab(tabbuilder.current_tab)
+ retval = retval .. modstore.gettab(tabbuilder.current_tab)
+
+ return retval
+end
+
+--------------------------------------------------------------------------------
+function tabbuilder.handle_create_world_buttons(fields)
+
+ if fields["world_create_confirm"] or
+ fields["key_enter"] then
+
+ local worldname = fields["te_world_name"]
+ local gameindex = engine.get_textlist_index("games")
+
+ if gameindex ~= nil and
+ worldname ~= "" then
+
+ local message = nil
+
+ if not filterlist.uid_exists_raw(worldlist,worldname) then
+ engine.setting_set("mg_name",fields["dd_mapgen"])
+ message = engine.create_world(worldname,gameindex)
+ else
+ message = fgettext("A world named \"$1\" already exists", worldname)
+ end
+
+ engine.setting_set("fixed_map_seed", fields["te_seed"])
+
+ if message ~= nil then
+ gamedata.errormessage = message
+ else
+ menu.last_game = gameindex
+ engine.setting_set("main_menu_last_game_idx",gameindex)
+
+ filterlist.refresh(worldlist)
+ engine.setting_set("mainmenu_last_selected_world",
+ filterlist.raw_index_by_uid(worldlist,worldname))
+ end
+ else
+ gamedata.errormessage =
+ fgettext("No worldname given or no game selected")
+ end
+ end
+
+ if fields["games"] then
+ tabbuilder.skipformupdate = true
+ return
+ end
+
+ --close dialog
+ tabbuilder.is_dialog = false
+ tabbuilder.show_buttons = true
+ tabbuilder.current_tab = engine.setting_get("main_menu_tab")
+end
+
+--------------------------------------------------------------------------------
+function tabbuilder.handle_delete_world_buttons(fields)
+
+ if fields["world_delete_confirm"] then
+ if menu.world_to_del > 0 and
+ menu.world_to_del <= #filterlist.get_raw_list(worldlist) then
+ engine.delete_world(menu.world_to_del)
+ menu.world_to_del = 0
+ filterlist.refresh(worldlist)
+ end
+ end
+
+ tabbuilder.is_dialog = false
+ tabbuilder.show_buttons = true
+ tabbuilder.current_tab = engine.setting_get("main_menu_tab")
+end
+
+--------------------------------------------------------------------------------
+function tabbuilder.handle_multiplayer_buttons(fields)
+
+ if fields["te_name"] ~= nil then
+ gamedata.playername = fields["te_name"]
+ engine.setting_set("name", fields["te_name"])
+ end
+
+ if fields["favourites"] ~= nil then
+ local event = engine.explode_textlist_event(fields["favourites"])
+ if event.type == "DCL" then
+ if event.index <= #menu.favorites then
+ gamedata.address = menu.favorites[event.index].address
+ gamedata.port = menu.favorites[event.index].port
+ gamedata.playername = fields["te_name"]
+ if fields["te_pwd"] ~= nil then
+ gamedata.password = fields["te_pwd"]
+ end
+ gamedata.selected_world = 0
+
+ if menu.favorites ~= nil then
+ gamedata.servername = menu.favorites[event.index].name
+ gamedata.serverdescription = menu.favorites[event.index].description
+ end
+
+ if gamedata.address ~= nil and
+ gamedata.port ~= nil then
+ engine.setting_set("address",gamedata.address)
+ engine.setting_set("remote_port",gamedata.port)
+ engine.start()
+ end
+ end
+ end
+
+ if event.type == "CHG" then
+ if event.index <= #menu.favorites then
+ local address = menu.favorites[event.index].address
+ local port = menu.favorites[event.index].port
+
+ if address ~= nil and
+ port ~= nil then
+ engine.setting_set("address",address)
+ engine.setting_set("remote_port",port)
+ end
+
+ menu.fav_selected = event.index
+ end
+ end
+ return
+ end
+
+ if fields["key_up"] ~= nil or
+ fields["key_down"] ~= nil then
+
+ local fav_idx = engine.get_textlist_index("favourites")
+
+ if fav_idx ~= nil then
+ if fields["key_up"] ~= nil and fav_idx > 1 then
+ fav_idx = fav_idx -1
+ else if fields["key_down"] and fav_idx < #menu.favorites then
+ fav_idx = fav_idx +1
+ end end
+ end
+
+ local address = menu.favorites[fav_idx].address
+ local port = menu.favorites[fav_idx].port
+
+ if address ~= nil and
+ port ~= nil then
+ engine.setting_set("address",address)
+ engine.setting_set("remote_port",port)
+ end
+
+ menu.fav_selected = fav_idx
+ return
+ end
+
+ if fields["cb_public_serverlist"] ~= nil then
+ engine.setting_set("public_serverlist", fields["cb_public_serverlist"])
+
+ if engine.setting_getbool("public_serverlist") then
+ menu.asyncOnlineFavourites()
+ else
+ menu.favorites = engine.get_favorites("local")
+ end
+ menu.fav_selected = nil
+ return
+ end
+
+ if fields["btn_delete_favorite"] ~= nil then
+ local current_favourite = engine.get_textlist_index("favourites")
+ if current_favourite == nil then return end
+ engine.delete_favorite(current_favourite)
+ menu.favorites = engine.get_favorites()
+ menu.fav_selected = nil
+
+ engine.setting_set("address","")
+ engine.setting_set("remote_port","30000")
+
+ return
+ end
+
+ if fields["btn_mp_connect"] ~= nil or
+ fields["key_enter"] ~= nil then
+
+ gamedata.playername = fields["te_name"]
+ gamedata.password = fields["te_pwd"]
+ gamedata.address = fields["te_address"]
+ gamedata.port = fields["te_port"]
+
+ local fav_idx = engine.get_textlist_index("favourites")
+
+ if fav_idx ~= nil and fav_idx <= #menu.favorites and
+ menu.favorites[fav_idx].address == fields["te_address"] and
+ menu.favorites[fav_idx].port == fields["te_port"] then
+
+ gamedata.servername = menu.favorites[fav_idx].name
+ gamedata.serverdescription = menu.favorites[fav_idx].description
+ else
+ gamedata.servername = ""
+ gamedata.serverdescription = ""
+ end
+
+ gamedata.selected_world = 0
+
+ engine.setting_set("address",fields["te_address"])
+ engine.setting_set("remote_port",fields["te_port"])
+
+ engine.start()
+ return
+ end
+end
+
+--------------------------------------------------------------------------------
+function tabbuilder.handle_server_buttons(fields)
+
+ local world_doubleclick = false
+
+ if fields["srv_worlds"] ~= nil then
+ local event = engine.explode_textlist_event(fields["srv_worlds"])
+
+ if event.type == "DCL" then
+ world_doubleclick = true
+ end
+ if event.type == "CHG" then
+ engine.setting_set("mainmenu_last_selected_world",
+ filterlist.get_raw_index(worldlist,engine.get_textlist_index("srv_worlds")))
+ end
+ end
+
+ menu.handle_key_up_down(fields,"srv_worlds","mainmenu_last_selected_world")
+
+ if fields["cb_creative_mode"] then
+ engine.setting_set("creative_mode", fields["cb_creative_mode"])
+ end
+
+ if fields["cb_enable_damage"] then
+ engine.setting_set("enable_damage", fields["cb_enable_damage"])
+ end
+
+ if fields["cb_server_announce"] then
+ engine.setting_set("server_announce", fields["cb_server_announce"])
+ end
+
+ if fields["start_server"] ~= nil or
+ world_doubleclick or
+ fields["key_enter"] then
+ local selected = engine.get_textlist_index("srv_worlds")
+ if selected ~= nil then
+ gamedata.playername = fields["te_playername"]
+ gamedata.password = fields["te_passwd"]
+ gamedata.port = fields["te_serverport"]
+ gamedata.address = ""
+ gamedata.selected_world = filterlist.get_raw_index(worldlist,selected)
+
+ engine.setting_set("port",gamedata.port)
+ if fields["te_serveraddr"] ~= nil then
+ engine.setting_set("bind_address",fields["te_serveraddr"])
+ end
+
+ menu.update_last_game(gamedata.selected_world)
+ engine.start()
+ end
+ end
+
+ if fields["world_create"] ~= nil then
+ tabbuilder.current_tab = "dialog_create_world"
+ tabbuilder.is_dialog = true
+ tabbuilder.show_buttons = false
+ end
+
+ if fields["world_delete"] ~= nil then
+ local selected = engine.get_textlist_index("srv_worlds")
+ if selected ~= nil and
+ selected <= filterlist.size(worldlist) then
+ local world = filterlist.get_list(worldlist)[selected]
+ if world ~= nil and
+ world.name ~= nil and
+ world.name ~= "" then
+ menu.world_to_del = filterlist.get_raw_index(worldlist,selected)
+ tabbuilder.current_tab = "dialog_delete_world"
+ tabbuilder.is_dialog = true
+ tabbuilder.show_buttons = false
+ else
+ menu.world_to_del = 0
+ end
+ end
+ end
+
+ if fields["world_configure"] ~= nil then
+ selected = engine.get_textlist_index("srv_worlds")
+ if selected ~= nil then
+ modmgr.world_config_selected_world = filterlist.get_raw_index(worldlist,selected)
+ if modmgr.init_worldconfig() then
+ tabbuilder.current_tab = "dialog_configure_world"
+ tabbuilder.is_dialog = true
+ tabbuilder.show_buttons = false
+ end
+ end
+ end
+end
+
+--------------------------------------------------------------------------------
+function tabbuilder.handle_settings_buttons(fields)
+ if fields["cb_fancy_trees"] then
+ engine.setting_set("new_style_leaves", fields["cb_fancy_trees"])
+ end
+ if fields["cb_smooth_lighting"] then
+ engine.setting_set("smooth_lighting", fields["cb_smooth_lighting"])
+ end
+ if fields["cb_3d_clouds"] then
+ engine.setting_set("enable_3d_clouds", fields["cb_3d_clouds"])
+ end
+ if fields["cb_opaque_water"] then
+ engine.setting_set("opaque_water", fields["cb_opaque_water"])
+ end
+
+ if fields["cb_mipmapping"] then
+ engine.setting_set("mip_map", fields["cb_mipmapping"])
+ end
+ if fields["cb_anisotrophic"] then
+ engine.setting_set("anisotropic_filter", fields["cb_anisotrophic"])
+ end
+ if fields["cb_bilinear"] then
+ engine.setting_set("bilinear_filter", fields["cb_bilinear"])
+ end
+ if fields["cb_trilinear"] then
+ engine.setting_set("trilinear_filter", fields["cb_trilinear"])
+ end
+
+ if fields["cb_shaders"] then
+ if (engine.setting_get("video_driver") == "direct3d8" or engine.setting_get("video_driver") == "direct3d9") then
+ engine.setting_set("enable_shaders", "false")
+ gamedata.errormessage = fgettext("To enable shaders the OpenGL driver needs to be used.")
+ else
+ engine.setting_set("enable_shaders", fields["cb_shaders"])
+ end
+ end
+ if fields["cb_pre_ivis"] then
+ engine.setting_set("preload_item_visuals", fields["cb_pre_ivis"])
+ end
+ if fields["cb_particles"] then
+ engine.setting_set("enable_particles", fields["cb_particles"])
+ end
+ if fields["cb_bumpmapping"] then
+ engine.setting_set("enable_bumpmapping", fields["cb_bumpmapping"])
+ end
+ if fields["cb_parallax"] then
+ engine.setting_set("enable_parallax_occlusion", fields["cb_parallax"])
+ end
+ if fields["cb_generate_normalmaps"] then
+ engine.setting_set("generate_normalmaps", fields["cb_generate_normalmaps"])
+ end
+ if fields["cb_waving_water"] then
+ engine.setting_set("enable_waving_water", fields["cb_waving_water"])
+ end
+ if fields["cb_waving_leaves"] then
+ engine.setting_set("enable_waving_leaves", fields["cb_waving_leaves"])
+ end
+ if fields["cb_waving_plants"] then
+ engine.setting_set("enable_waving_plants", fields["cb_waving_plants"])
+ end
+ if fields["btn_change_keys"] ~= nil then
+ engine.show_keys_menu()
+ end
+end
+
+--------------------------------------------------------------------------------
+function tabbuilder.handle_singleplayer_buttons(fields)
+
+ local world_doubleclick = false
+
+ if fields["sp_worlds"] ~= nil then
+ local event = engine.explode_textlist_event(fields["sp_worlds"])
+
+ if event.type == "DCL" then
+ world_doubleclick = true
+ end
+
+ if event.type == "CHG" then
+ engine.setting_set("mainmenu_last_selected_world",
+ filterlist.get_raw_index(worldlist,engine.get_textlist_index("sp_worlds")))
+ end
+ end
+
+ menu.handle_key_up_down(fields,"sp_worlds","mainmenu_last_selected_world")
+
+ if fields["cb_creative_mode"] then
+ engine.setting_set("creative_mode", fields["cb_creative_mode"])
+ end
+
+ if fields["cb_enable_damage"] then
+ engine.setting_set("enable_damage", fields["cb_enable_damage"])
+ end
+
+ if fields["play"] ~= nil or
+ world_doubleclick or
+ fields["key_enter"] then
+ local selected = engine.get_textlist_index("sp_worlds")
+ if selected ~= nil then
+ gamedata.selected_world = filterlist.get_raw_index(worldlist,selected)
+ gamedata.singleplayer = true
+
+ menu.update_last_game(gamedata.selected_world)
+
+ engine.start()
+ end
+ end
+
+ if fields["world_create"] ~= nil then
+ tabbuilder.current_tab = "dialog_create_world"
+ tabbuilder.is_dialog = true
+ tabbuilder.show_buttons = false
+ end
+
+ if fields["world_delete"] ~= nil then
+ local selected = engine.get_textlist_index("sp_worlds")
+ if selected ~= nil and
+ selected <= filterlist.size(worldlist) then
+ local world = filterlist.get_list(worldlist)[selected]
+ if world ~= nil and
+ world.name ~= nil and
+ world.name ~= "" then
+ menu.world_to_del = filterlist.get_raw_index(worldlist,selected)
+ tabbuilder.current_tab = "dialog_delete_world"
+ tabbuilder.is_dialog = true
+ tabbuilder.show_buttons = false
+ else
+ menu.world_to_del = 0
+ end
+ end
+ end
+
+ if fields["world_configure"] ~= nil then
+ selected = engine.get_textlist_index("sp_worlds")
+ if selected ~= nil then
+ modmgr.world_config_selected_world = filterlist.get_raw_index(worldlist,selected)
+ if modmgr.init_worldconfig() then
+ tabbuilder.current_tab = "dialog_configure_world"
+ tabbuilder.is_dialog = true
+ tabbuilder.show_buttons = false
+ end
+ end
+ end
+end
+
+--------------------------------------------------------------------------------
+function tabbuilder.handle_texture_pack_buttons(fields)
+ if fields["TPs"] ~= nil then
+ local event = engine.explode_textlist_event(fields["TPs"])
+ if event.type == "CHG" or event.type == "DCL" then
+ local index = engine.get_textlist_index("TPs")
+ engine.setting_set("mainmenu_last_selected_TP",
+ index)
+ local list = filter_texture_pack_list(engine.get_dirlist(engine.get_texturepath(), true))
+ local current_index = engine.get_textlist_index("TPs")
+ if current_index ~= nil and #list >= current_index then
+ local new_path = engine.get_texturepath()..DIR_DELIM..list[current_index]
+ if list[current_index] == "None" then new_path = "" end
+
+ engine.setting_set("texture_path", new_path)
+ end
+ end
+ end
+end
+
+--------------------------------------------------------------------------------
+function tabbuilder.tab_header()
+
+ if tabbuilder.last_tab_index == nil then
+ tabbuilder.last_tab_index = 1
+ end
+
+ local toadd = ""
+
+ for i=1,#tabbuilder.current_buttons,1 do
+
+ if toadd ~= "" then
+ toadd = toadd .. ","
+ end
+
+ toadd = toadd .. tabbuilder.current_buttons[i].caption
+ end
+ return "tabheader[-0.3,-0.99;main_tab;" .. toadd ..";" .. tabbuilder.last_tab_index .. ";true;false]"
+end
+
+--------------------------------------------------------------------------------
+function tabbuilder.handle_tab_buttons(fields)
+
+ if fields["main_tab"] then
+ local index = tonumber(fields["main_tab"])
+ tabbuilder.last_tab_index = index
+ tabbuilder.current_tab = tabbuilder.current_buttons[index].name
+
+ engine.setting_set("main_menu_tab",tabbuilder.current_tab)
+ end
+
+ --handle tab changes
+ if tabbuilder.current_tab ~= tabbuilder.old_tab then
+ if tabbuilder.current_tab ~= "singleplayer" and not tabbuilder.is_dialog then
+ menu.update_gametype(true)
+ end
+ end
+
+ if tabbuilder.current_tab == "singleplayer" then
+ menu.update_gametype()
+ end
+
+ tabbuilder.old_tab = tabbuilder.current_tab
+end
+
+--------------------------------------------------------------------------------
+function tabbuilder.tab_multiplayer()
+
+ local retval =
+ "vertlabel[0,-0.25;".. fgettext("CLIENT") .. "]" ..
+ "label[1,-0.25;".. fgettext("Favorites:") .. "]"..
+ "label[1,4.25;".. fgettext("Address/Port") .. "]"..
+ "label[9,2.75;".. fgettext("Name/Password") .. "]" ..
+ "field[1.25,5.25;5.5,0.5;te_address;;" ..engine.setting_get("address") .."]" ..
+ "field[6.75,5.25;2.25,0.5;te_port;;" ..engine.setting_get("remote_port") .."]" ..
+ "checkbox[1,3.6;cb_public_serverlist;".. fgettext("Public Serverlist") .. ";" ..
+ dump(engine.setting_getbool("public_serverlist")) .. "]"
+
+ if not engine.setting_getbool("public_serverlist") then
+ retval = retval ..
+ "button[6.45,3.95;2.25,0.5;btn_delete_favorite;".. fgettext("Delete") .. "]"
+ end
+
+ retval = retval ..
+ "button[9,4.95;2.5,0.5;btn_mp_connect;".. fgettext("Connect") .. "]" ..
+ "field[9.3,3.75;2.5,0.5;te_name;;" ..engine.setting_get("name") .."]" ..
+ "pwdfield[9.3,4.5;2.5,0.5;te_pwd;]" ..
+ "textarea[9.3,0.25;2.5,2.75;;"
+ if menu.fav_selected ~= nil and
+ menu.favorites[menu.fav_selected].description ~= nil then
+ retval = retval ..
+ engine.formspec_escape(menu.favorites[menu.fav_selected].description,true)
+ end
+
+ retval = retval ..
+ ";]" ..
+ "textlist[1,0.35;7.5,3.35;favourites;"
+
+ local render_details = engine.setting_getbool("public_serverlist")
+
+ if #menu.favorites > 0 then
+ retval = retval .. menu.render_favorite(menu.favorites[1],render_details)
+
+ for i=2,#menu.favorites,1 do
+ retval = retval .. "," .. menu.render_favorite(menu.favorites[i],render_details)
+ end
+ end
+
+ if menu.fav_selected ~= nil then
+ retval = retval .. ";" .. menu.fav_selected .. "]"
+ else
+ retval = retval .. ";0]"
+ end
+
+ return retval
+end
+
+--------------------------------------------------------------------------------
+function tabbuilder.tab_server()
+
+ local index = filterlist.get_current_index(worldlist,
+ tonumber(engine.setting_get("mainmenu_last_selected_world"))
+ )
+
+ local retval =
+ "button[4,4.15;2.6,0.5;world_delete;".. fgettext("Delete") .. "]" ..
+ "button[6.5,4.15;2.8,0.5;world_create;".. fgettext("New") .. "]" ..
+ "button[9.2,4.15;2.55,0.5;world_configure;".. fgettext("Configure") .. "]" ..
+ "button[8.5,4.9;3.25,0.5;start_server;".. fgettext("Start Game") .. "]" ..
+ "label[4,-0.25;".. fgettext("Select World:") .. "]"..
+ "vertlabel[0,-0.25;".. fgettext("START SERVER") .. "]" ..
+ "checkbox[0.5,0.25;cb_creative_mode;".. fgettext("Creative Mode") .. ";" ..
+ dump(engine.setting_getbool("creative_mode")) .. "]"..
+ "checkbox[0.5,0.7;cb_enable_damage;".. fgettext("Enable Damage") .. ";" ..
+ dump(engine.setting_getbool("enable_damage")) .. "]"..
+ "checkbox[0.5,1.15;cb_server_announce;".. fgettext("Public") .. ";" ..
+ dump(engine.setting_getbool("server_announce")) .. "]"..
+ "field[0.8,3.2;3.5,0.5;te_playername;".. fgettext("Name") .. ";" ..
+ engine.setting_get("name") .. "]" ..
+ "pwdfield[0.8,4.2;3.5,0.5;te_passwd;".. fgettext("Password") .. "]"
+
+ local bind_addr = engine.setting_get("bind_address")
+ if bind_addr ~= nil and bind_addr ~= "" then
+ retval = retval ..
+ "field[0.8,5.2;2.25,0.5;te_serveraddr;".. fgettext("Bind Address") .. ";" ..
+ engine.setting_get("bind_address") .."]" ..
+ "field[3.05,5.2;1.25,0.5;te_serverport;".. fgettext("Port") .. ";" ..
+ engine.setting_get("port") .."]"
+ else
+ retval = retval ..
+ "field[0.8,5.2;3.5,0.5;te_serverport;".. fgettext("Server Port") .. ";" ..
+ engine.setting_get("port") .."]"
+ end
+
+ retval = retval ..
+ "textlist[4,0.25;7.5,3.7;srv_worlds;" ..
+ menu.render_world_list() ..
+ ";" .. index .. "]"
+
+ return retval
+end
+
+--------------------------------------------------------------------------------
+function tabbuilder.tab_settings()
+ tab_string =
+ "vertlabel[0,0;" .. fgettext("SETTINGS") .. "]" ..
+ "checkbox[1,0;cb_fancy_trees;".. fgettext("Fancy Trees") .. ";"
+ .. dump(engine.setting_getbool("new_style_leaves")) .. "]"..
+ "checkbox[1,0.5;cb_smooth_lighting;".. fgettext("Smooth Lighting")
+ .. ";".. dump(engine.setting_getbool("smooth_lighting")) .. "]"..
+ "checkbox[1,1;cb_3d_clouds;".. fgettext("3D Clouds") .. ";"
+ .. dump(engine.setting_getbool("enable_3d_clouds")) .. "]"..
+ "checkbox[1,1.5;cb_opaque_water;".. fgettext("Opaque Water") .. ";"
+ .. dump(engine.setting_getbool("opaque_water")) .. "]"..
+ "checkbox[1,2.0;cb_pre_ivis;".. fgettext("Preload item visuals") .. ";"
+ .. dump(engine.setting_getbool("preload_item_visuals")) .. "]"..
+ "checkbox[1,2.5;cb_particles;".. fgettext("Enable Particles") .. ";"
+ .. dump(engine.setting_getbool("enable_particles")) .. "]"..
+ "checkbox[4.5,0;cb_mipmapping;".. fgettext("Mip-Mapping") .. ";"
+ .. dump(engine.setting_getbool("mip_map")) .. "]"..
+ "checkbox[4.5,0.5;cb_anisotrophic;".. fgettext("Anisotropic Filtering") .. ";"
+ .. dump(engine.setting_getbool("anisotropic_filter")) .. "]"..
+ "checkbox[4.5,1.0;cb_bilinear;".. fgettext("Bi-Linear Filtering") .. ";"
+ .. dump(engine.setting_getbool("bilinear_filter")) .. "]"..
+ "checkbox[4.5,1.5;cb_trilinear;".. fgettext("Tri-Linear Filtering") .. ";"
+ .. dump(engine.setting_getbool("trilinear_filter")) .. "]"..
+
+ "checkbox[8,0;cb_shaders;".. fgettext("Shaders") .. ";"
+ .. dump(engine.setting_getbool("enable_shaders")) .. "]"..
+ "button[1,4.5;2.25,0.5;btn_change_keys;".. fgettext("Change keys") .. "]"
+
+ if engine.setting_getbool("enable_shaders") then
+ tab_string = tab_string ..
+ "checkbox[8,0.5;cb_bumpmapping;".. fgettext("Bumpmapping") .. ";"
+ .. dump(engine.setting_getbool("enable_bumpmapping")) .. "]"..
+ "checkbox[8,1.0;cb_parallax;".. fgettext("Parallax Occlusion") .. ";"
+ .. dump(engine.setting_getbool("enable_parallax_occlusion")) .. "]"..
+ "checkbox[8,1.5;cb_generate_normalmaps;".. fgettext("Generate Normalmaps") .. ";"
+ .. dump(engine.setting_getbool("generate_normalmaps")) .. "]"..
+ "checkbox[8,2.0;cb_waving_water;".. fgettext("Waving Water") .. ";"
+ .. dump(engine.setting_getbool("enable_waving_water")) .. "]"..
+ "checkbox[8,2.5;cb_waving_leaves;".. fgettext("Waving Leaves") .. ";"
+ .. dump(engine.setting_getbool("enable_waving_leaves")) .. "]"..
+ "checkbox[8,3.0;cb_waving_plants;".. fgettext("Waving Plants") .. ";"
+ .. dump(engine.setting_getbool("enable_waving_plants")) .. "]"
+ else
+ tab_string = tab_string ..
+ "textlist[8.33,0.7;4,1;;#888888" .. fgettext("Bumpmapping") .. ";0;true]" ..
+ "textlist[8.33,1.2;4,1;;#888888" .. fgettext("Parallax Occlusion") .. ";0;true]" ..
+ "textlist[8.33,1.7;4,1;;#888888" .. fgettext("Generate Normalmaps") .. ";0;true]" ..
+ "textlist[8.33,2.2;4,1;;#888888" .. fgettext("Waving Water") .. ";0;true]" ..
+ "textlist[8.33,2.7;4,1;;#888888" .. fgettext("Waving Leaves") .. ";0;true]" ..
+ "textlist[8.33,3.2;4,1;;#888888" .. fgettext("Waving Plants") .. ";0;true]"
+ end
+ return tab_string
+end
+
+--------------------------------------------------------------------------------
+function tabbuilder.tab_singleplayer()
+
+ local index = filterlist.get_current_index(worldlist,
+ tonumber(engine.setting_get("mainmenu_last_selected_world"))
+ )
+
+ return "button[4,4.15;2.6,0.5;world_delete;".. fgettext("Delete") .. "]" ..
+ "button[6.5,4.15;2.8,0.5;world_create;".. fgettext("New") .. "]" ..
+ "button[9.2,4.15;2.55,0.5;world_configure;".. fgettext("Configure") .. "]" ..
+ "button[8.5,4.95;3.25,0.5;play;".. fgettext("Play") .. "]" ..
+ "label[4,-0.25;".. fgettext("Select World:") .. "]"..
+ "vertlabel[0,-0.25;".. fgettext("SINGLE PLAYER") .. "]" ..
+ "checkbox[0.5,0.25;cb_creative_mode;".. fgettext("Creative Mode") .. ";" ..
+ dump(engine.setting_getbool("creative_mode")) .. "]"..
+ "checkbox[0.5,0.7;cb_enable_damage;".. fgettext("Enable Damage") .. ";" ..
+ dump(engine.setting_getbool("enable_damage")) .. "]"..
+ "textlist[4,0.25;7.5,3.7;sp_worlds;" ..
+ menu.render_world_list() ..
+ ";" .. index .. "]" ..
+ menubar.formspec
+end
+
+--------------------------------------------------------------------------------
+function tabbuilder.tab_texture_packs()
+ local retval = "label[4,-0.25;".. fgettext("Select texture pack:") .. "]"..
+ "vertlabel[0,-0.25;".. fgettext("TEXTURE PACKS") .. "]" ..
+ "textlist[4,0.25;7.5,5.0;TPs;"
+
+ local current_texture_path = engine.setting_get("texture_path")
+ local list = filter_texture_pack_list(engine.get_dirlist(engine.get_texturepath(), true))
+ local index = tonumber(engine.setting_get("mainmenu_last_selected_TP"))
+
+ if index == nil then index = 1 end
+
+ if current_texture_path == "" then
+ retval = retval ..
+ menu.render_texture_pack_list(list) ..
+ ";" .. index .. "]"
+ return retval
+ end
+
+ local infofile = current_texture_path ..DIR_DELIM.."info.txt"
+ local infotext = ""
+ local f = io.open(infofile, "r")
+ if f==nil then
+ infotext = fgettext("No information available")
+ else
+ infotext = f:read("*all")
+ f:close()
+ end
+
+ local screenfile = current_texture_path..DIR_DELIM.."screenshot.png"
+ local no_screenshot = nil
+ if not file_exists(screenfile) then
+ screenfile = nil
+ no_screenshot = menu.defaulttexturedir .. "no_screenshot.png"
+ end
+
+ return retval ..
+ menu.render_texture_pack_list(list) ..
+ ";" .. index .. "]" ..
+ "image[0.65,0.25;4.0,3.7;"..engine.formspec_escape(screenfile or no_screenshot).."]"..
+ "textarea[1.0,3.25;3.7,1.5;;"..engine.formspec_escape(infotext or "")..";]"
+end
+
+--------------------------------------------------------------------------------
+function tabbuilder.tab_credits()
+ local logofile = menu.defaulttexturedir .. "logo.png"
+ return "vertlabel[0,-0.5;CREDITS]" ..
+ "label[0.5,3;Minetest " .. engine.get_version() .. "]" ..
+ "label[0.5,3.3;http://minetest.net]" ..
+ "image[0.5,1;" .. engine.formspec_escape(logofile) .. "]" ..
+ "textlist[3.5,-0.25;8.5,5.8;list_credits;" ..
+ "#FFFF00" .. fgettext("Core Developers") .."," ..
+ "Perttu Ahola (celeron55) <celeron55@gmail.com>,"..
+ "Ryan Kwolek (kwolekr) <kwolekr@minetest.net>,"..
+ "PilzAdam <pilzadam@minetest.net>," ..
+ "Ilya Zhuravlev (xyz) <xyz@minetest.net>,"..
+ "Lisa Milne (darkrose) <lisa@ltmnet.com>,"..
+ "Maciej Kasatkin (RealBadAngel) <mk@realbadangel.pl>,"..
+ "proller <proler@gmail.com>,"..
+ "sfan5 <sfan5@live.de>,"..
+ "kahrl <kahrl@gmx.net>,"..
+ "sapier,"..
+ "ShadowNinja <shadowninja@minetest.net>,"..
+ "Nathanael Courant (Nore/Novatux) <nore@mesecons.net>,"..
+ "BlockMen,"..
+ ","..
+ "#FFFF00" .. fgettext("Active Contributors") .. "," ..
+ "Vanessa Ezekowitz (VanessaE) <vanessaezekowitz@gmail.com>,"..
+ "Jurgen Doser (doserj) <jurgen.doser@gmail.com>,"..
+ "Jeija <jeija@mesecons.net>,"..
+ "MirceaKitsune <mirceakitsune@gmail.com>,"..
+ "dannydark <the_skeleton_of_a_child@yahoo.co.uk>,"..
+ "0gb.us <0gb.us@0gb.us>,"..
+ "," ..
+ "#FFFF00" .. fgettext("Previous Contributors") .. "," ..
+ "Guiseppe Bilotta (Oblomov) <guiseppe.bilotta@gmail.com>,"..
+ "Jonathan Neuschafer <j.neuschaefer@gmx.net>,"..
+ "Nils Dagsson Moskopp (erlehmann) <nils@dieweltistgarnichtso.net>,"..
+ "Constantin Wenger (SpeedProg) <constantin.wenger@googlemail.com>,"..
+ "matttpt <matttpt@gmail.com>,"..
+ "JacobF <queatz@gmail.com>,"..
+ ";0;true]"
+end
+
+--------------------------------------------------------------------------------
+function tabbuilder.init()
+ tabbuilder.tabfuncs = {
+ singleplayer = tabbuilder.tab_singleplayer,
+ multiplayer = tabbuilder.tab_multiplayer,
+ server = tabbuilder.tab_server,
+ settings = tabbuilder.tab_settings,
+ texture_packs = tabbuilder.tab_texture_packs,
+ credits = tabbuilder.tab_credits,
+ dialog_create_world = tabbuilder.dialog_create_world,
+ dialog_delete_world = tabbuilder.dialog_delete_world
+ }
+
+ tabbuilder.tabsizes = {
+ dialog_create_world = {width=12, height=7},
+ dialog_delete_world = {width=12, height=5.2}
+ }
+
+ tabbuilder.current_tab = engine.setting_get("main_menu_tab")
+
+ if tabbuilder.current_tab == nil or
+ tabbuilder.current_tab == "" then
+ tabbuilder.current_tab = "singleplayer"
+ engine.setting_set("main_menu_tab",tabbuilder.current_tab)
+ end
+
+ --initialize tab buttons
+ tabbuilder.last_tab = nil
+ tabbuilder.show_buttons = true
+
+ tabbuilder.current_buttons = {}
+ table.insert(tabbuilder.current_buttons,{name="singleplayer", caption=fgettext("Singleplayer")})
+ table.insert(tabbuilder.current_buttons,{name="multiplayer", caption=fgettext("Client")})
+ table.insert(tabbuilder.current_buttons,{name="server", caption=fgettext("Server")})
+ table.insert(tabbuilder.current_buttons,{name="settings", caption=fgettext("Settings")})
+ table.insert(tabbuilder.current_buttons,{name="texture_packs", caption=fgettext("Texture Packs")})
+
+ if engine.setting_getbool("main_menu_game_mgr") then
+ table.insert(tabbuilder.current_buttons,{name="game_mgr", caption=fgettext("Games")})
+ end
+
+ if engine.setting_getbool("main_menu_mod_mgr") then
+ table.insert(tabbuilder.current_buttons,{name="mod_mgr", caption=fgettext("Mods")})
+ end
+ table.insert(tabbuilder.current_buttons,{name="credits", caption=fgettext("Credits")})
+
+
+ for i=1,#tabbuilder.current_buttons,1 do
+ if tabbuilder.current_buttons[i].name == tabbuilder.current_tab then
+ tabbuilder.last_tab_index = i
+ end
+ end
+
+ if tabbuilder.current_tab ~= "singleplayer" then
+ menu.update_gametype(true)
+ else
+ menu.update_gametype()
+ end
+end
+
+--------------------------------------------------------------------------------
+function tabbuilder.checkretval(retval)
+
+ if retval ~= nil then
+ if retval.current_tab ~= nil then
+ tabbuilder.current_tab = retval.current_tab
+ end
+
+ if retval.is_dialog ~= nil then
+ tabbuilder.is_dialog = retval.is_dialog
+ end
+
+ if retval.show_buttons ~= nil then
+ tabbuilder.show_buttons = retval.show_buttons
+ end
+
+ if retval.skipformupdate ~= nil then
+ tabbuilder.skipformupdate = retval.skipformupdate
+ end
+
+ if retval.ignore_menu_quit == true then
+ tabbuilder.ignore_menu_quit = true
+ else
+ tabbuilder.ignore_menu_quit = false
+ end
+ end
+end
+
+--------------------------------------------------------------------------------
+--------------------------------------------------------------------------------
+-- initialize callbacks
+--------------------------------------------------------------------------------
+--------------------------------------------------------------------------------
+engine.button_handler = function(fields)
+ --print("Buttonhandler: tab: " .. tabbuilder.current_tab .. " fields: " .. dump(fields))
+
+ if fields["btn_error_confirm"] then
+ gamedata.errormessage = nil
+ end
+
+ local retval = modmgr.handle_buttons(tabbuilder.current_tab,fields)
+ tabbuilder.checkretval(retval)
+
+ retval = gamemgr.handle_buttons(tabbuilder.current_tab,fields)
+ tabbuilder.checkretval(retval)
+
+ retval = modstore.handle_buttons(tabbuilder.current_tab,fields)
+ tabbuilder.checkretval(retval)
+
+ if tabbuilder.current_tab == "dialog_create_world" then
+ tabbuilder.handle_create_world_buttons(fields)
+ end
+
+ if tabbuilder.current_tab == "dialog_delete_world" then
+ tabbuilder.handle_delete_world_buttons(fields)
+ end
+
+ if tabbuilder.current_tab == "singleplayer" then
+ tabbuilder.handle_singleplayer_buttons(fields)
+ end
+
+ if tabbuilder.current_tab == "texture_packs" then
+ tabbuilder.handle_texture_pack_buttons(fields)
+ end
+
+ if tabbuilder.current_tab == "multiplayer" then
+ tabbuilder.handle_multiplayer_buttons(fields)
+ end
+
+ if tabbuilder.current_tab == "settings" then
+ tabbuilder.handle_settings_buttons(fields)
+ end
+
+ if tabbuilder.current_tab == "server" then
+ tabbuilder.handle_server_buttons(fields)
+ end
+
+ --tab buttons
+ tabbuilder.handle_tab_buttons(fields)
+
+ --menubar buttons
+ menubar.handle_buttons(fields)
+
+ if not tabbuilder.skipformupdate then
+ --update menu
+ update_menu()
+ else
+ tabbuilder.skipformupdate = false
+ end
+end
+
+--------------------------------------------------------------------------------
+engine.event_handler = function(event)
+ if event == "MenuQuit" then
+ if tabbuilder.is_dialog then
+ if tabbuilder.ignore_menu_quit then
+ return
+ end
+
+ tabbuilder.is_dialog = false
+ tabbuilder.show_buttons = true
+ tabbuilder.current_tab = engine.setting_get("main_menu_tab")
+ menu.update_gametype()
+ update_menu()
+ else
+ engine.close()
+ end
+ end
+
+ if event == "Refresh" then
+ update_menu()
+ end
+end
+
+--------------------------------------------------------------------------------
+function menu.update_gametype(reset)
+ local game = menu.lastgame()
+
+ if reset or game == nil then
+ mm_texture.reset()
+ engine.set_topleft_text("")
+ filterlist.set_filtercriteria(worldlist,nil)
+ else
+ mm_texture.update(tabbuilder.current_tab,game)
+ engine.set_topleft_text(game.name)
+ filterlist.set_filtercriteria(worldlist,game.id)
+ end
+end
+
+--------------------------------------------------------------------------------
+--------------------------------------------------------------------------------
+-- menu startup
+--------------------------------------------------------------------------------
+--------------------------------------------------------------------------------
+init_globals()
+mm_texture.init()
+menu.init()
+tabbuilder.init()
+menubar.refresh()
+modstore.init()
+
+engine.sound_play("main_menu", true)
+
+update_menu()
--- /dev/null
+--Minetest
+--Copyright (C) 2013 sapier
+--
+--This program is free software; you can redistribute it and/or modify
+--it under the terms of the GNU Lesser General Public License as published by
+--the Free Software Foundation; either version 2.1 of the License, or
+--(at your option) any later version.
+--
+--This program is distributed in the hope that it will be useful,
+--but WITHOUT ANY WARRANTY; without even the implied warranty of
+--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+--GNU Lesser General Public License for more details.
+--
+--You should have received a copy of the GNU Lesser General Public License along
+--with this program; if not, write to the Free Software Foundation, Inc.,
+--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+menubar = {}
+
+--------------------------------------------------------------------------------
+function menubar.handle_buttons(fields)
+ for i=1,#menubar.buttons,1 do
+ if fields[menubar.buttons[i].btn_name] ~= nil then
+ menu.last_game = menubar.buttons[i].index
+ engine.setting_set("main_menu_last_game_idx",menu.last_game)
+ menu.update_gametype()
+ end
+ end
+end
+
+--------------------------------------------------------------------------------
+function menubar.refresh()
+
+ menubar.formspec = "box[-0.3,5.625;12.4,1.2;#000000]" ..
+ "box[-0.3,5.6;12.4,0.05;#FFFFFF]"
+ menubar.buttons = {}
+
+ local button_base = -0.08
+
+ local maxbuttons = #gamemgr.games
+
+ if maxbuttons > 11 then
+ maxbuttons = 11
+ end
+
+ for i=1,maxbuttons,1 do
+
+ local btn_name = "menubar_btn_" .. gamemgr.games[i].id
+ local buttonpos = button_base + (i-1) * 1.1
+ if gamemgr.games[i].menuicon_path ~= nil and
+ gamemgr.games[i].menuicon_path ~= "" then
+
+ menubar.formspec = menubar.formspec ..
+ "image_button[" .. buttonpos .. ",5.72;1.165,1.175;" ..
+ engine.formspec_escape(gamemgr.games[i].menuicon_path) .. ";" ..
+ btn_name .. ";;true;false]"
+ else
+
+ local part1 = gamemgr.games[i].id:sub(1,5)
+ local part2 = gamemgr.games[i].id:sub(6,10)
+ local part3 = gamemgr.games[i].id:sub(11)
+
+ local text = part1 .. "\n" .. part2
+ if part3 ~= nil and
+ part3 ~= "" then
+ text = text .. "\n" .. part3
+ end
+ menubar.formspec = menubar.formspec ..
+ "image_button[" .. buttonpos .. ",5.72;1.165,1.175;;" ..btn_name ..
+ ";" .. text .. ";true;true]"
+ end
+
+ local toadd = {
+ btn_name = btn_name,
+ index = i,
+ }
+
+ table.insert(menubar.buttons,toadd)
+ end
+end
--- /dev/null
+--Minetest
+--Copyright (C) 2013 sapier
+--
+--This program is free software; you can redistribute it and/or modify
+--it under the terms of the GNU Lesser General Public License as published by
+--the Free Software Foundation; either version 2.1 of the License, or
+--(at your option) any later version.
+--
+--This program is distributed in the hope that it will be useful,
+--but WITHOUT ANY WARRANTY; without even the implied warranty of
+--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+--GNU Lesser General Public License for more details.
+--
+--You should have received a copy of the GNU Lesser General Public License along
+--with this program; if not, write to the Free Software Foundation, Inc.,
+--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+--------------------------------------------------------------------------------
+function get_mods(path,retval,modpack)
+
+ local mods = engine.get_dirlist(path,true)
+ for i=1,#mods,1 do
+ local toadd = {}
+ local modpackfile = nil
+
+ toadd.name = mods[i]
+ toadd.path = path .. DIR_DELIM .. mods[i] .. DIR_DELIM
+ if modpack ~= nil and
+ modpack ~= "" then
+ toadd.modpack = modpack
+ else
+ local filename = path .. DIR_DELIM .. mods[i] .. DIR_DELIM .. "modpack.txt"
+ local error = nil
+ modpackfile,error = io.open(filename,"r")
+ end
+
+ if modpackfile ~= nil then
+ modpackfile:close()
+ toadd.is_modpack = true
+ table.insert(retval,toadd)
+ get_mods(path .. DIR_DELIM .. mods[i],retval,mods[i])
+ else
+ table.insert(retval,toadd)
+ end
+ end
+end
+
+--modmanager implementation
+modmgr = {}
+
+--------------------------------------------------------------------------------
+function modmgr.extract(modfile)
+ if modfile.type == "zip" then
+ local tempfolder = os.tempfolder()
+
+ if tempfolder ~= nil and
+ tempfolder ~= "" then
+ engine.create_dir(tempfolder)
+ if engine.extract_zip(modfile.name,tempfolder) then
+ return tempfolder
+ end
+ end
+ end
+ return nil
+end
+
+-------------------------------------------------------------------------------
+function modmgr.getbasefolder(temppath)
+
+ if temppath == nil then
+ return {
+ type = "invalid",
+ path = ""
+ }
+ end
+
+ local testfile = io.open(temppath .. DIR_DELIM .. "init.lua","r")
+ if testfile ~= nil then
+ testfile:close()
+ return {
+ type="mod",
+ path=temppath
+ }
+ end
+
+ testfile = io.open(temppath .. DIR_DELIM .. "modpack.txt","r")
+ if testfile ~= nil then
+ testfile:close()
+ return {
+ type="modpack",
+ path=temppath
+ }
+ end
+
+ local subdirs = engine.get_dirlist(temppath,true)
+
+ --only single mod or modpack allowed
+ if #subdirs ~= 1 then
+ return {
+ type = "invalid",
+ path = ""
+ }
+ end
+
+ testfile =
+ io.open(temppath .. DIR_DELIM .. subdirs[1] ..DIR_DELIM .."init.lua","r")
+ if testfile ~= nil then
+ testfile:close()
+ return {
+ type="mod",
+ path= temppath .. DIR_DELIM .. subdirs[1]
+ }
+ end
+
+ testfile =
+ io.open(temppath .. DIR_DELIM .. subdirs[1] ..DIR_DELIM .."modpack.txt","r")
+ if testfile ~= nil then
+ testfile:close()
+ return {
+ type="modpack",
+ path=temppath .. DIR_DELIM .. subdirs[1]
+ }
+ end
+
+ return {
+ type = "invalid",
+ path = ""
+ }
+end
+
+--------------------------------------------------------------------------------
+function modmgr.isValidModname(modpath)
+ if modpath:find("-") ~= nil then
+ return false
+ end
+
+ return true
+end
+
+--------------------------------------------------------------------------------
+function modmgr.parse_register_line(line)
+ local pos1 = line:find("\"")
+ local pos2 = nil
+ if pos1 ~= nil then
+ pos2 = line:find("\"",pos1+1)
+ end
+
+ if pos1 ~= nil and pos2 ~= nil then
+ local item = line:sub(pos1+1,pos2-1)
+
+ if item ~= nil and
+ item ~= "" then
+ local pos3 = item:find(":")
+
+ if pos3 ~= nil then
+ local retval = item:sub(1,pos3-1)
+ if retval ~= nil and
+ retval ~= "" then
+ return retval
+ end
+ end
+ end
+ end
+ return nil
+end
+
+--------------------------------------------------------------------------------
+function modmgr.parse_dofile_line(modpath,line)
+ local pos1 = line:find("\"")
+ local pos2 = nil
+ if pos1 ~= nil then
+ pos2 = line:find("\"",pos1+1)
+ end
+
+ if pos1 ~= nil and pos2 ~= nil then
+ local filename = line:sub(pos1+1,pos2-1)
+
+ if filename ~= nil and
+ filename ~= "" and
+ filename:find(".lua") then
+ return modmgr.identify_modname(modpath,filename)
+ end
+ end
+ return nil
+end
+
+--------------------------------------------------------------------------------
+function modmgr.identify_modname(modpath,filename)
+ local testfile = io.open(modpath .. DIR_DELIM .. filename,"r")
+ if testfile ~= nil then
+ local line = testfile:read()
+
+ while line~= nil do
+ local modname = nil
+
+ if line:find("minetest.register_tool") then
+ modname = modmgr.parse_register_line(line)
+ end
+
+ if line:find("minetest.register_craftitem") then
+ modname = modmgr.parse_register_line(line)
+ end
+
+
+ if line:find("minetest.register_node") then
+ modname = modmgr.parse_register_line(line)
+ end
+
+ if line:find("dofile") then
+ modname = modmgr.parse_dofile_line(modpath,line)
+ end
+
+ if modname ~= nil then
+ testfile:close()
+ return modname
+ end
+
+ line = testfile:read()
+ end
+ testfile:close()
+ end
+
+ return nil
+end
+
+--------------------------------------------------------------------------------
+function modmgr.tab()
+
+ if modmgr.global_mods == nil then
+ modmgr.refresh_globals()
+ end
+
+ if modmgr.selected_mod == nil then
+ modmgr.selected_mod = 1
+ end
+
+ local retval =
+ "vertlabel[0,-0.25;".. fgettext("MODS") .. "]" ..
+ "label[0.8,-0.25;".. fgettext("Installed Mods:") .. "]" ..
+ "textlist[0.75,0.25;4.5,4;modlist;" ..
+ modmgr.render_modlist(modmgr.global_mods) ..
+ ";" .. modmgr.selected_mod .. "]"
+
+ retval = retval ..
+ "label[0.8,4.2;" .. fgettext("Add mod:") .. "]" ..
+-- TODO Disabled due to upcoming release 0.4.8 and irrlicht messing up localization
+-- "button[0.75,4.85;1.8,0.5;btn_mod_mgr_install_local;".. fgettext("Local install") .. "]" ..
+ "button[2.45,4.85;3.05,0.5;btn_mod_mgr_download;".. fgettext("Online mod repository") .. "]"
+
+ local selected_mod = nil
+
+ if filterlist.size(modmgr.global_mods) >= modmgr.selected_mod then
+ selected_mod = filterlist.get_list(modmgr.global_mods)[modmgr.selected_mod]
+ end
+
+ if selected_mod ~= nil then
+ local modscreenshot = nil
+
+ --check for screenshot beeing available
+ local screenshotfilename = selected_mod.path .. DIR_DELIM .. "screenshot.png"
+ local error = nil
+ screenshotfile,error = io.open(screenshotfilename,"r")
+ if error == nil then
+ screenshotfile:close()
+ modscreenshot = screenshotfilename
+ end
+
+ if modscreenshot == nil then
+ modscreenshot = modstore.basetexturedir .. "no_screenshot.png"
+ end
+
+ retval = retval
+ .. "image[5.5,0;3,2;" .. engine.formspec_escape(modscreenshot) .. "]"
+ .. "label[8.25,0.6;" .. selected_mod.name .. "]"
+
+ local descriptionlines = nil
+ error = nil
+ local descriptionfilename = selected_mod.path .. "description.txt"
+ descriptionfile,error = io.open(descriptionfilename,"r")
+ if error == nil then
+ descriptiontext = descriptionfile:read("*all")
+
+ descriptionlines = engine.splittext(descriptiontext,42)
+ descriptionfile:close()
+ else
+ descriptionlines = {}
+ table.insert(descriptionlines,fgettext("No mod description available"))
+ end
+
+ retval = retval ..
+ "label[5.5,1.7;".. fgettext("Mod information:") .. "]" ..
+ "textlist[5.5,2.2;6.2,2.4;description;"
+
+ for i=1,#descriptionlines,1 do
+ retval = retval .. engine.formspec_escape(descriptionlines[i]) .. ","
+ end
+
+
+ if selected_mod.is_modpack then
+ retval = retval .. ";0]" ..
+ "button[10,4.85;2,0.5;btn_mod_mgr_rename_modpack;" ..
+ fgettext("Rename") .. "]"
+ retval = retval .. "button[5.5,4.85;4.5,0.5;btn_mod_mgr_delete_mod;"
+ .. fgettext("Uninstall selected modpack") .. "]"
+ else
+ --show dependencies
+
+ retval = retval .. ",Depends:,"
+
+ toadd = modmgr.get_dependencies(selected_mod.path)
+
+ retval = retval .. toadd .. ";0]"
+
+ retval = retval .. "button[5.5,4.85;4.5,0.5;btn_mod_mgr_delete_mod;"
+ .. fgettext("Uninstall selected mod") .. "]"
+ end
+ end
+ return retval
+end
+
+--------------------------------------------------------------------------------
+function modmgr.dialog_rename_modpack()
+
+ local mod = filterlist.get_list(modmgr.global_mods)[modmgr.selected_mod]
+
+ local retval =
+ "label[1.75,1;".. fgettext("Rename Modpack:") .. "]"..
+ "field[4.5,1.4;6,0.5;te_modpack_name;;" ..
+ mod.name ..
+ "]" ..
+ "button[5,4.2;2.6,0.5;dlg_rename_modpack_confirm;"..
+ fgettext("Accept") .. "]" ..
+ "button[7.5,4.2;2.8,0.5;dlg_rename_modpack_cancel;"..
+ fgettext("Cancel") .. "]"
+
+ return retval
+end
+
+--------------------------------------------------------------------------------
+function modmgr.precheck()
+
+ if modmgr.world_config_selected_world == nil then
+ modmgr.world_config_selected_world = 1
+ end
+
+ if modmgr.world_config_selected_mod == nil then
+ modmgr.world_config_selected_mod = 1
+ end
+
+ if modmgr.hide_gamemods == nil then
+ modmgr.hide_gamemods = true
+ end
+
+ if modmgr.hide_modpackcontents == nil then
+ modmgr.hide_modpackcontents = true
+ end
+end
+
+--------------------------------------------------------------------------------
+function modmgr.render_modlist(render_list)
+ local retval = ""
+
+ if render_list == nil then
+ if modmgr.global_mods == nil then
+ modmgr.refresh_globals()
+ end
+ render_list = modmgr.global_mods
+ end
+
+ local list = filterlist.get_list(render_list)
+ local last_modpack = nil
+
+ for i,v in ipairs(list) do
+ if retval ~= "" then
+ retval = retval ..","
+ end
+
+ local color = ""
+
+ if v.is_modpack then
+ local rawlist = filterlist.get_raw_list(render_list)
+
+ local all_enabled = true
+ for j=1,#rawlist,1 do
+ if rawlist[j].modpack == list[i].name and
+ rawlist[j].enabled ~= true then
+ all_enabled = false
+ break
+ end
+ end
+
+ if all_enabled == false then
+ color = mt_color_grey
+ else
+ color = mt_color_dark_green
+ end
+ end
+
+ if v.typ == "game_mod" then
+ color = mt_color_blue
+ else
+ if v.enabled then
+ color = mt_color_green
+ end
+ end
+
+ retval = retval .. color
+ if v.modpack ~= nil then
+ retval = retval .. " "
+ end
+ retval = retval .. v.name
+ end
+
+ return retval
+end
+
+--------------------------------------------------------------------------------
+function modmgr.dialog_configure_world()
+ modmgr.precheck()
+
+ local worldspec = engine.get_worlds()[modmgr.world_config_selected_world]
+ local mod = filterlist.get_list(modmgr.modlist)[modmgr.world_config_selected_mod]
+
+ local retval =
+ "size[11,6.5,true]" ..
+ "label[0.5,-0.25;" .. fgettext("World:") .. "]" ..
+ "label[1.75,-0.25;" .. worldspec.name .. "]"
+
+ if modmgr.hide_gamemods then
+ retval = retval .. "checkbox[0,5.75;cb_hide_gamemods;" .. fgettext("Hide Game") .. ";true]"
+ else
+ retval = retval .. "checkbox[0,5.75;cb_hide_gamemods;" .. fgettext("Hide Game") .. ";false]"
+ end
+
+ if modmgr.hide_modpackcontents then
+ retval = retval .. "checkbox[2,5.75;cb_hide_mpcontent;" .. fgettext("Hide mp content") .. ";true]"
+ else
+ retval = retval .. "checkbox[2,5.75;cb_hide_mpcontent;" .. fgettext("Hide mp content") .. ";false]"
+ end
+
+ if mod == nil then
+ mod = {name=""}
+ end
+ retval = retval ..
+ "label[0,0.45;" .. fgettext("Mod:") .. "]" ..
+ "label[0.75,0.45;" .. mod.name .. "]" ..
+ "label[0,1;" .. fgettext("Depends:") .. "]" ..
+ "textlist[0,1.5;5,4.25;world_config_depends;" ..
+ modmgr.get_dependencies(mod.path) .. ";0]" ..
+ "button[9.25,6.35;2,0.5;btn_config_world_save;" .. fgettext("Save") .. "]" ..
+ "button[7.4,6.35;2,0.5;btn_config_world_cancel;" .. fgettext("Cancel") .. "]"
+
+ if mod ~= nil and mod.name ~= "" and mod.typ ~= "game_mod" then
+ if mod.is_modpack then
+ local rawlist = filterlist.get_raw_list(modmgr.modlist)
+
+ local all_enabled = true
+ for j=1,#rawlist,1 do
+ if rawlist[j].modpack == mod.name and
+ rawlist[j].enabled ~= true then
+ all_enabled = false
+ break
+ end
+ end
+
+ if all_enabled == false then
+ retval = retval .. "button[5.5,-0.125;2,0.5;btn_mp_enable;" .. fgettext("Enable MP") .. "]"
+ else
+ retval = retval .. "button[5.5,-0.125;2,0.5;btn_mp_disable;" .. fgettext("Disable MP") .. "]"
+ end
+ else
+ if mod.enabled then
+ retval = retval .. "checkbox[5.5,-0.375;cb_mod_enable;" .. fgettext("enabled") .. ";true]"
+ else
+ retval = retval .. "checkbox[5.5,-0.375;cb_mod_enable;" .. fgettext("enabled") .. ";false]"
+ end
+ end
+ end
+
+ retval = retval ..
+ "button[8.5,-0.125;2.5,0.5;btn_all_mods;" .. fgettext("Enable all") .. "]" ..
+ "textlist[5.5,0.5;5.5,5.75;world_config_modlist;"
+
+ retval = retval .. modmgr.render_modlist(modmgr.modlist)
+
+ retval = retval .. ";" .. modmgr.world_config_selected_mod .."]"
+
+ return retval
+end
+
+--------------------------------------------------------------------------------
+function modmgr.handle_buttons(tab,fields)
+
+ local retval = nil
+
+ if tab == "mod_mgr" then
+ retval = modmgr.handle_modmgr_buttons(fields)
+ end
+
+ if tab == "dialog_rename_modpack" then
+ retval = modmgr.handle_rename_modpack_buttons(fields)
+ end
+
+ if tab == "dialog_delete_mod" then
+ retval = modmgr.handle_delete_mod_buttons(fields)
+ end
+
+ if tab == "dialog_configure_world" then
+ retval = modmgr.handle_configure_world_buttons(fields)
+ end
+
+ return retval
+end
+
+--------------------------------------------------------------------------------
+function modmgr.get_dependencies(modfolder)
+ local toadd = ""
+ if modfolder ~= nil then
+ local filename = modfolder ..
+ DIR_DELIM .. "depends.txt"
+
+ local dependencyfile = io.open(filename,"r")
+
+ if dependencyfile then
+ local dependency = dependencyfile:read("*l")
+ while dependency do
+ if toadd ~= "" then
+ toadd = toadd .. ","
+ end
+ toadd = toadd .. dependency
+ dependency = dependencyfile:read()
+ end
+ dependencyfile:close()
+ end
+ end
+
+ return toadd
+end
+
+
+--------------------------------------------------------------------------------
+function modmgr.get_worldconfig(worldpath)
+ local filename = worldpath ..
+ DIR_DELIM .. "world.mt"
+
+ local worldfile = Settings(filename)
+
+ local worldconfig = {}
+ worldconfig.global_mods = {}
+ worldconfig.game_mods = {}
+
+ for key,value in pairs(worldfile:to_table()) do
+ if key == "gameid" then
+ worldconfig.id = value
+ else
+ worldconfig.global_mods[key] = engine.is_yes(value)
+ end
+ end
+
+ --read gamemods
+ local gamespec = gamemgr.find_by_gameid(worldconfig.id)
+ gamemgr.get_game_mods(gamespec, worldconfig.game_mods)
+
+ return worldconfig
+end
+--------------------------------------------------------------------------------
+function modmgr.handle_modmgr_buttons(fields)
+ local retval = {
+ tab = nil,
+ is_dialog = nil,
+ show_buttons = nil,
+ }
+
+ if fields["modlist"] ~= nil then
+ local event = engine.explode_textlist_event(fields["modlist"])
+ modmgr.selected_mod = event.index
+ end
+
+ if fields["btn_mod_mgr_install_local"] ~= nil then
+ engine.show_file_open_dialog("mod_mgt_open_dlg",fgettext("Select Mod File:"))
+ end
+
+ if fields["btn_mod_mgr_download"] ~= nil then
+ modstore.update_modlist()
+ retval.current_tab = "dialog_modstore_unsorted"
+ retval.is_dialog = true
+ retval.show_buttons = false
+ return retval
+ end
+
+ if fields["btn_mod_mgr_rename_modpack"] ~= nil then
+ retval.current_tab = "dialog_rename_modpack"
+ retval.is_dialog = true
+ retval.show_buttons = false
+ return retval
+ end
+
+ if fields["btn_mod_mgr_delete_mod"] ~= nil then
+ retval.current_tab = "dialog_delete_mod"
+ retval.is_dialog = true
+ retval.show_buttons = false
+ return retval
+ end
+
+ if fields["mod_mgt_open_dlg_accepted"] ~= nil and
+ fields["mod_mgt_open_dlg_accepted"] ~= "" then
+ modmgr.installmod(fields["mod_mgt_open_dlg_accepted"],nil)
+ end
+
+ return nil;
+end
+
+--------------------------------------------------------------------------------
+function modmgr.installmod(modfilename,basename)
+ local modfile = modmgr.identify_filetype(modfilename)
+ local modpath = modmgr.extract(modfile)
+
+ if modpath == nil then
+ gamedata.errormessage = fgettext("Install Mod: file: \"$1\"", modfile.name) ..
+ fgettext("\nInstall Mod: unsupported filetype \"$1\" or broken archive", modfile.type)
+ return
+ end
+
+
+ local basefolder = modmgr.getbasefolder(modpath)
+
+ if basefolder.type == "modpack" then
+ local clean_path = nil
+
+ if basename ~= nil then
+ clean_path = "mp_" .. basename
+ end
+
+ if clean_path == nil then
+ clean_path = get_last_folder(cleanup_path(basefolder.path))
+ end
+
+ if clean_path ~= nil then
+ local targetpath = engine.get_modpath() .. DIR_DELIM .. clean_path
+ if not engine.copy_dir(basefolder.path,targetpath) then
+ gamedata.errormessage = fgettext("Failed to install $1 to $2", basename, targetpath)
+ end
+ else
+ gamedata.errormessage = fgettext("Install Mod: unable to find suitable foldername for modpack $1", modfilename)
+ end
+ end
+
+ if basefolder.type == "mod" then
+ local targetfolder = basename
+
+ if targetfolder == nil then
+ targetfolder = modmgr.identify_modname(basefolder.path,"init.lua")
+ end
+
+ --if heuristic failed try to use current foldername
+ if targetfolder == nil then
+ targetfolder = get_last_folder(basefolder.path)
+ end
+
+ if targetfolder ~= nil and modmgr.isValidModname(targetfolder) then
+ local targetpath = engine.get_modpath() .. DIR_DELIM .. targetfolder
+ engine.copy_dir(basefolder.path,targetpath)
+ else
+ gamedata.errormessage = fgettext("Install Mod: unable to find real modname for: $1", modfilename)
+ end
+ end
+
+ engine.delete_dir(modpath)
+
+ modmgr.refresh_globals()
+
+end
+
+--------------------------------------------------------------------------------
+function modmgr.handle_rename_modpack_buttons(fields)
+
+ if fields["dlg_rename_modpack_confirm"] ~= nil then
+ local mod = filterlist.get_list(modmgr.global_mods)[modmgr.selected_mod]
+ local oldpath = engine.get_modpath() .. DIR_DELIM .. mod.name
+ local targetpath = engine.get_modpath() .. DIR_DELIM .. fields["te_modpack_name"]
+ engine.copy_dir(oldpath,targetpath,false)
+ modmgr.refresh_globals()
+ modmgr.selected_mod = filterlist.get_current_index(modmgr.global_mods,
+ filterlist.raw_index_by_uid(modmgr.global_mods, fields["te_modpack_name"]))
+ end
+
+ return {
+ is_dialog = false,
+ show_buttons = true,
+ current_tab = engine.setting_get("main_menu_tab")
+ }
+end
+--------------------------------------------------------------------------------
+function modmgr.handle_configure_world_buttons(fields)
+ if fields["world_config_modlist"] ~= nil then
+ local event = engine.explode_textlist_event(fields["world_config_modlist"])
+ modmgr.world_config_selected_mod = event.index
+
+ if event.type == "DCL" then
+ modmgr.world_config_enable_mod(nil)
+ end
+ end
+
+ if fields["key_enter"] ~= nil then
+ modmgr.world_config_enable_mod(nil)
+ end
+
+ if fields["cb_mod_enable"] ~= nil then
+ local toset = engine.is_yes(fields["cb_mod_enable"])
+ modmgr.world_config_enable_mod(toset)
+ end
+
+ if fields["btn_mp_enable"] ~= nil or
+ fields["btn_mp_disable"] then
+ local toset = (fields["btn_mp_enable"] ~= nil)
+ modmgr.world_config_enable_mod(toset)
+ end
+
+ if fields["cb_hide_gamemods"] ~= nil then
+ local current = filterlist.get_filtercriteria(modmgr.modlist)
+
+ if current == nil then
+ current = {}
+ end
+
+ if engine.is_yes(fields["cb_hide_gamemods"]) then
+ current.hide_game = true
+ modmgr.hide_gamemods = true
+ else
+ current.hide_game = false
+ modmgr.hide_gamemods = false
+ end
+
+ filterlist.set_filtercriteria(modmgr.modlist,current)
+ end
+
+ if fields["cb_hide_mpcontent"] ~= nil then
+ local current = filterlist.get_filtercriteria(modmgr.modlist)
+
+ if current == nil then
+ current = {}
+ end
+
+ if engine.is_yes(fields["cb_hide_mpcontent"]) then
+ current.hide_modpackcontents = true
+ modmgr.hide_modpackcontents = true
+ else
+ current.hide_modpackcontents = false
+ modmgr.hide_modpackcontents = false
+ end
+
+ filterlist.set_filtercriteria(modmgr.modlist,current)
+ end
+
+ if fields["btn_config_world_save"] then
+ local worldspec = engine.get_worlds()[modmgr.world_config_selected_world]
+
+ local filename = worldspec.path ..
+ DIR_DELIM .. "world.mt"
+
+ local worldfile = Settings(filename)
+ local mods = worldfile:to_table()
+
+ local rawlist = filterlist.get_raw_list(modmgr.modlist)
+
+ local i,mod
+ for i,mod in ipairs(rawlist) do
+ if not mod.is_modpack and
+ mod.typ ~= "game_mod" then
+ if mod.enabled then
+ worldfile:set("load_mod_"..mod.name, "true")
+ else
+ worldfile:set("load_mod_"..mod.name, "false")
+ end
+ mods["load_mod_"..mod.name] = nil
+ end
+ end
+
+ -- Remove mods that are not present anymore
+ for key,value in pairs(mods) do
+ if key:sub(1,9) == "load_mod_" then
+ worldfile:remove(key)
+ end
+ end
+
+ if not worldfile:write() then
+ engine.log("error", "Failed to write world config file")
+ end
+
+ modmgr.modlist = nil
+ modmgr.worldconfig = nil
+
+ return {
+ is_dialog = false,
+ show_buttons = true,
+ current_tab = engine.setting_get("main_menu_tab")
+ }
+ end
+
+ if fields["btn_config_world_cancel"] then
+
+ modmgr.worldconfig = nil
+
+ return {
+ is_dialog = false,
+ show_buttons = true,
+ current_tab = engine.setting_get("main_menu_tab")
+ }
+ end
+
+ if fields["btn_all_mods"] then
+ local list = filterlist.get_raw_list(modmgr.modlist)
+
+ for i=1,#list,1 do
+ if list[i].typ ~= "game_mod" and
+ not list[i].is_modpack then
+ list[i].enabled = true
+ end
+ end
+ end
+
+
+
+ return nil
+end
+--------------------------------------------------------------------------------
+function modmgr.world_config_enable_mod(toset)
+ local mod = filterlist.get_list(modmgr.modlist)
+ [engine.get_textlist_index("world_config_modlist")]
+
+ if mod.typ == "game_mod" then
+ -- game mods can't be enabled or disabled
+ elseif not mod.is_modpack then
+ if toset == nil then
+ mod.enabled = not mod.enabled
+ else
+ mod.enabled = toset
+ end
+ else
+ local list = filterlist.get_raw_list(modmgr.modlist)
+ for i=1,#list,1 do
+ if list[i].modpack == mod.name then
+ if toset == nil then
+ toset = not list[i].enabled
+ end
+ list[i].enabled = toset
+ end
+ end
+ end
+end
+--------------------------------------------------------------------------------
+function modmgr.handle_delete_mod_buttons(fields)
+ local mod = filterlist.get_list(modmgr.global_mods)[modmgr.selected_mod]
+
+ if fields["dlg_delete_mod_confirm"] ~= nil then
+
+ if mod.path ~= nil and
+ mod.path ~= "" and
+ mod.path ~= engine.get_modpath() then
+ if not engine.delete_dir(mod.path) then
+ gamedata.errormessage = fgettext("Modmgr: failed to delete \"$1\"", mod.path)
+ end
+ modmgr.refresh_globals()
+ else
+ gamedata.errormessage = fgettext("Modmgr: invalid modpath \"$1\"", mod.path)
+ end
+ end
+
+ return {
+ is_dialog = false,
+ show_buttons = true,
+ current_tab = engine.setting_get("main_menu_tab")
+ }
+end
+
+--------------------------------------------------------------------------------
+function modmgr.dialog_delete_mod()
+
+ local mod = filterlist.get_list(modmgr.global_mods)[modmgr.selected_mod]
+
+ local retval =
+ "field[1.75,1;10,3;;" .. fgettext("Are you sure you want to delete \"$1\"?", mod.name) .. ";]"..
+ "button[4,4.2;1,0.5;dlg_delete_mod_confirm;" .. fgettext("Yes") .. "]" ..
+ "button[6.5,4.2;3,0.5;dlg_delete_mod_cancel;" .. fgettext("No of course not!") .. "]"
+
+ return retval
+end
+
+--------------------------------------------------------------------------------
+function modmgr.preparemodlist(data)
+ local retval = {}
+
+ local global_mods = {}
+ local game_mods = {}
+
+ --read global mods
+ local modpath = engine.get_modpath()
+
+ if modpath ~= nil and
+ modpath ~= "" then
+ get_mods(modpath,global_mods)
+ end
+
+ for i=1,#global_mods,1 do
+ global_mods[i].typ = "global_mod"
+ table.insert(retval,global_mods[i])
+ end
+
+ --read game mods
+ local gamespec = gamemgr.find_by_gameid(data.gameid)
+ gamemgr.get_game_mods(gamespec, game_mods)
+
+ for i=1,#game_mods,1 do
+ game_mods[i].typ = "game_mod"
+ table.insert(retval,game_mods[i])
+ end
+
+ if data.worldpath == nil then
+ return retval
+ end
+
+ --read world mod configuration
+ local filename = data.worldpath ..
+ DIR_DELIM .. "world.mt"
+
+ local worldfile = Settings(filename)
+
+ for key,value in pairs(worldfile:to_table()) do
+ if key:sub(1, 9) == "load_mod_" then
+ key = key:sub(10)
+ local element = nil
+ for i=1,#retval,1 do
+ if retval[i].name == key then
+ element = retval[i]
+ break
+ end
+ end
+ if element ~= nil then
+ element.enabled = engine.is_yes(value)
+ else
+ engine.log("info", "Mod: " .. key .. " " .. dump(value) .. " but not found")
+ end
+ end
+ end
+
+ return retval
+end
+
+--------------------------------------------------------------------------------
+function modmgr.init_worldconfig()
+ modmgr.precheck()
+ local worldspec = engine.get_worlds()[modmgr.world_config_selected_world]
+
+ if worldspec ~= nil then
+ --read worldconfig
+ modmgr.worldconfig = modmgr.get_worldconfig(worldspec.path)
+
+ if modmgr.worldconfig.id == nil or
+ modmgr.worldconfig.id == "" then
+ modmgr.worldconfig = nil
+ return false
+ end
+
+ modmgr.modlist = filterlist.create(
+ modmgr.preparemodlist, --refresh
+ modmgr.comparemod, --compare
+ function(element,uid) --uid match
+ if element.name == uid then
+ return true
+ end
+ end,
+ function(element,criteria)
+ if criteria.hide_game and
+ element.typ == "game_mod" then
+ return false
+ end
+
+ if criteria.hide_modpackcontents and
+ element.modpack ~= nil then
+ return false
+ end
+ return true
+ end, --filter
+ { worldpath= worldspec.path,
+ gameid = worldspec.gameid }
+ )
+
+ filterlist.set_filtercriteria(modmgr.modlist, {
+ hide_game=modmgr.hide_gamemods,
+ hide_modpackcontents= modmgr.hide_modpackcontents
+ })
+ filterlist.add_sort_mechanism(modmgr.modlist, "alphabetic", sort_mod_list)
+ filterlist.set_sortmode(modmgr.modlist, "alphabetic")
+
+ return true
+ end
+
+ return false
+end
+
+--------------------------------------------------------------------------------
+function modmgr.comparemod(elem1,elem2)
+ if elem1 == nil or elem2 == nil then
+ return false
+ end
+ if elem1.name ~= elem2.name then
+ return false
+ end
+ if elem1.is_modpack ~= elem2.is_modpack then
+ return false
+ end
+ if elem1.typ ~= elem2.typ then
+ return false
+ end
+ if elem1.modpack ~= elem2.modpack then
+ return false
+ end
+
+ if elem1.path ~= elem2.path then
+ return false
+ end
+
+ return true
+end
+
+--------------------------------------------------------------------------------
+function modmgr.gettab(name)
+ local retval = ""
+
+ if name == "mod_mgr" then
+ retval = retval .. modmgr.tab()
+ end
+
+ if name == "dialog_rename_modpack" then
+ retval = retval .. modmgr.dialog_rename_modpack()
+ end
+
+ if name == "dialog_delete_mod" then
+ retval = retval .. modmgr.dialog_delete_mod()
+ end
+
+ if name == "dialog_configure_world" then
+ retval = retval .. modmgr.dialog_configure_world()
+ end
+
+ return retval
+end
+
+--------------------------------------------------------------------------------
+function modmgr.mod_exists(basename)
+
+ if modmgr.global_mods == nil then
+ modmgr.refresh_globals()
+ end
+
+ if filterlist.raw_index_by_uid(modmgr.global_mods,basename) > 0 then
+ return true
+ end
+
+ return false
+end
+
+--------------------------------------------------------------------------------
+function modmgr.get_global_mod(idx)
+
+ if modmgr.global_mods == nil then
+ return nil
+ end
+
+ if idx == nil or idx < 1 or idx > filterlist.size(modmgr.global_mods) then
+ return nil
+ end
+
+ return filterlist.get_list(modmgr.global_mods)[idx]
+end
+
+--------------------------------------------------------------------------------
+function modmgr.refresh_globals()
+ modmgr.global_mods = filterlist.create(
+ modmgr.preparemodlist, --refresh
+ modmgr.comparemod, --compare
+ function(element,uid) --uid match
+ if element.name == uid then
+ return true
+ end
+ end,
+ nil, --filter
+ {}
+ )
+ filterlist.add_sort_mechanism(modmgr.global_mods, "alphabetic", sort_mod_list)
+ filterlist.set_sortmode(modmgr.global_mods, "alphabetic")
+end
+
+--------------------------------------------------------------------------------
+function modmgr.identify_filetype(name)
+
+ if name:sub(-3):lower() == "zip" then
+ return {
+ name = name,
+ type = "zip"
+ }
+ end
+
+ if name:sub(-6):lower() == "tar.gz" or
+ name:sub(-3):lower() == "tgz"then
+ return {
+ name = name,
+ type = "tgz"
+ }
+ end
+
+ if name:sub(-6):lower() == "tar.bz2" then
+ return {
+ name = name,
+ type = "tbz"
+ }
+ end
+
+ if name:sub(-2):lower() == "7z" then
+ return {
+ name = name,
+ type = "7z"
+ }
+ end
+
+ return {
+ name = name,
+ type = "ukn"
+ }
+end
--- /dev/null
+--Minetest
+--Copyright (C) 2013 sapier
+--
+--This program is free software; you can redistribute it and/or modify
+--it under the terms of the GNU Lesser General Public License as published by
+--the Free Software Foundation; either version 2.1 of the License, or
+--(at your option) any later version.
+--
+--This program is distributed in the hope that it will be useful,
+--but WITHOUT ANY WARRANTY; without even the implied warranty of
+--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+--GNU Lesser General Public License for more details.
+--
+--You should have received a copy of the GNU Lesser General Public License along
+--with this program; if not, write to the Free Software Foundation, Inc.,
+--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+--------------------------------------------------------------------------------
+
+--modstore implementation
+modstore = {}
+
+--------------------------------------------------------------------------------
+-- @function [parent=#modstore] init
+function modstore.init()
+ modstore.tabnames = {}
+
+ table.insert(modstore.tabnames,"dialog_modstore_unsorted")
+ table.insert(modstore.tabnames,"dialog_modstore_search")
+
+ modstore.modsperpage = 5
+
+ modstore.basetexturedir = engine.get_texturepath() .. DIR_DELIM .. "base" ..
+ DIR_DELIM .. "pack" .. DIR_DELIM
+
+ modstore.lastmodtitle = ""
+ modstore.last_search = ""
+
+ modstore.searchlist = filterlist.create(
+ function()
+ if modstore.modlist_unsorted ~= nil and
+ modstore.modlist_unsorted.data ~= nil then
+ return modstore.modlist_unsorted.data
+ end
+ return {}
+ end,
+ function(element,modid)
+ if element.id == modid then
+ return true
+ end
+ return false
+ end, --compare fct
+ nil, --uid match fct
+ function(element,substring)
+ if substring == nil or
+ substring == "" then
+ return false
+ end
+ substring = substring:upper()
+
+ if element.title ~= nil and
+ element.title:upper():find(substring) ~= nil then
+ return true
+ end
+
+ if element.details ~= nil and
+ element.details.author ~= nil and
+ element.details.author:upper():find(substring) ~= nil then
+ return true
+ end
+
+ if element.details ~= nil and
+ element.details.description ~= nil and
+ element.details.description:upper():find(substring) ~= nil then
+ return true
+ end
+ return false
+ end --filter fct
+ )
+
+ modstore.current_list = nil
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#modstore] nametoindex
+function modstore.nametoindex(name)
+
+ for i=1,#modstore.tabnames,1 do
+ if modstore.tabnames[i] == name then
+ return i
+ end
+ end
+
+ return 1
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#modstore] getsuccessfuldialog
+function modstore.getsuccessfuldialog()
+ local retval = ""
+ retval = retval .. "size[6,2,true]"
+ if modstore.lastmodentry ~= nil then
+ retval = retval .. "label[0,0.25;" .. fgettext("Successfully installed:") .. "]"
+ retval = retval .. "label[3,0.25;" .. modstore.lastmodentry.moddetails.title .. "]"
+
+
+ retval = retval .. "label[0,0.75;" .. fgettext("Shortname:") .. "]"
+ retval = retval .. "label[3,0.75;" .. engine.formspec_escape(modstore.lastmodentry.moddetails.basename) .. "]"
+
+ end
+ retval = retval .. "button[2.5,1.5;1,0.5;btn_confirm_mod_successfull;" .. fgettext("ok") .. "]"
+
+
+ return retval
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#modstore] gettab
+function modstore.gettab(tabname)
+ local retval = ""
+
+ local is_modstore_tab = false
+
+ if tabname == "dialog_modstore_unsorted" then
+ modstore.modsperpage = 5
+ retval = modstore.getmodlist(modstore.modlist_unsorted)
+ is_modstore_tab = true
+ end
+
+ if tabname == "dialog_modstore_search" then
+ retval = modstore.getsearchpage()
+ is_modstore_tab = true
+ end
+
+ if is_modstore_tab then
+ return modstore.tabheader(tabname) .. retval
+ end
+
+ if tabname == "modstore_mod_installed" then
+ return modstore.getsuccessfuldialog()
+ end
+
+ if tabname == "modstore_downloading" then
+ return "size[6,2]label[0.25,0.75;" .. fgettext("Downloading") ..
+ " " .. modstore.lastmodtitle .. " " ..
+ fgettext("please wait...") .. "]"
+ end
+
+ return ""
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#modstore] tabheader
+function modstore.tabheader(tabname)
+ local retval = "size[12,10.25,true]"
+ retval = retval .. "tabheader[-0.3,-0.99;modstore_tab;" ..
+ "Unsorted,Search;" ..
+ modstore.nametoindex(tabname) .. ";true;false]" ..
+ "button[4,9.9;4,0.5;btn_modstore_close;" ..
+ fgettext("Close modstore") .. "]"
+
+ return retval
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#modstore] handle_buttons
+function modstore.handle_buttons(current_tab,fields)
+
+ if fields["modstore_tab"] then
+ local index = tonumber(fields["modstore_tab"])
+
+ if index > 0 and
+ index <= #modstore.tabnames then
+ if modstore.tabnames[index] == "dialog_modstore_search" then
+ filterlist.set_filtercriteria(modstore.searchlist,modstore.last_search)
+ filterlist.refresh(modstore.searchlist)
+ modstore.modsperpage = 4
+ modstore.currentlist = {
+ page = 0,
+ pagecount =
+ math.ceil(filterlist.size(modstore.searchlist) / modstore.modsperpage),
+ data = filterlist.get_list(modstore.searchlist),
+ }
+ end
+
+ return {
+ current_tab = modstore.tabnames[index],
+ is_dialog = true,
+ show_buttons = false
+ }
+ end
+
+ end
+
+ if fields["btn_modstore_page_up"] then
+ if modstore.current_list ~= nil and modstore.current_list.page > 0 then
+ modstore.current_list.page = modstore.current_list.page - 1
+ end
+ end
+
+ if fields["btn_modstore_page_down"] then
+ if modstore.current_list ~= nil and
+ modstore.current_list.page <modstore.current_list.pagecount-1 then
+ modstore.current_list.page = modstore.current_list.page +1
+ end
+ end
+
+ if fields["btn_hidden_close_download"] ~= nil then
+ if fields["btn_hidden_close_download"].successfull then
+ modstore.lastmodentry = fields["btn_hidden_close_download"]
+ return {
+ current_tab = "modstore_mod_installed",
+ is_dialog = true,
+ show_buttons = false
+ }
+ else
+ modstore.lastmodtitle = ""
+ return {
+ current_tab = modstore.tabnames[1],
+ is_dialog = true,
+ show_buttons = false
+ }
+ end
+ end
+
+ if fields["btn_confirm_mod_successfull"] then
+ modstore.lastmodentry = nil
+ modstore.lastmodtitle = ""
+ return {
+ current_tab = modstore.tabnames[1],
+ is_dialog = true,
+ show_buttons = false
+ }
+ end
+
+ if fields["btn_modstore_search"] or
+ (fields["key_enter"] and fields["te_modstore_search"] ~= nil) then
+ modstore.last_search = fields["te_modstore_search"]
+ filterlist.set_filtercriteria(modstore.searchlist,fields["te_modstore_search"])
+ filterlist.refresh(modstore.searchlist)
+ modstore.currentlist = {
+ page = 0,
+ pagecount = math.ceil(filterlist.size(modstore.searchlist) / modstore.modsperpage),
+ data = filterlist.get_list(modstore.searchlist),
+ }
+ end
+
+
+ if fields["btn_modstore_close"] then
+ return {
+ is_dialog = false,
+ show_buttons = true,
+ current_tab = engine.setting_get("main_menu_tab")
+ }
+ end
+
+ for key,value in pairs(fields) do
+ local foundat = key:find("btn_install_mod_")
+ if ( foundat == 1) then
+ local modid = tonumber(key:sub(17))
+ for i=1,#modstore.modlist_unsorted.data,1 do
+ if modstore.modlist_unsorted.data[i].id == modid then
+ local moddetails = modstore.modlist_unsorted.data[i].details
+
+ if modstore.lastmodtitle ~= "" then
+ modstore.lastmodtitle = modstore.lastmodtitle .. ", "
+ end
+
+ modstore.lastmodtitle = modstore.lastmodtitle .. moddetails.title
+
+ engine.handle_async(
+ function(param)
+
+ local fullurl = engine.setting_get("modstore_download_url") ..
+ param.moddetails.download_url
+
+ if param.version ~= nil then
+ local found = false
+ for i=1,#param.moddetails.versions, 1 do
+ if param.moddetails.versions[i].date:sub(1,10) == param.version then
+ fullurl = engine.setting_get("modstore_download_url") ..
+ param.moddetails.versions[i].download_url
+ found = true
+ end
+ end
+
+ if not found then
+ return {
+ moddetails = param.moddetails,
+ successfull = false
+ }
+ end
+ end
+
+ if engine.download_file(fullurl,param.filename) then
+ return {
+ texturename = param.texturename,
+ moddetails = param.moddetails,
+ filename = param.filename,
+ successfull = true
+ }
+ else
+ return {
+ moddetails = param.moddetails,
+ successfull = false
+ }
+ end
+ end,
+ {
+ moddetails = moddetails,
+ version = fields["dd_version" .. modid],
+ filename = os.tempfolder() .. "_MODNAME_" .. moddetails.basename .. ".zip",
+ texturename = modstore.modlist_unsorted.data[i].texturename
+ },
+ function(result)
+ if result.successfull then
+ modmgr.installmod(result.filename,result.moddetails.basename)
+ os.remove(result.filename)
+ else
+ gamedata.errormessage = "Failed to download " .. result.moddetails.title
+ end
+
+ if gamedata.errormessage == nil then
+ engine.button_handler({btn_hidden_close_download=result})
+ else
+ engine.button_handler({btn_hidden_close_download={successfull=false}})
+ end
+ end
+ )
+
+ return {
+ current_tab = "modstore_downloading",
+ is_dialog = true,
+ show_buttons = false,
+ ignore_menu_quit = true
+ }
+ end
+ end
+ break
+ end
+ end
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#modstore] update_modlist
+function modstore.update_modlist()
+ modstore.modlist_unsorted = {}
+ modstore.modlist_unsorted.data = {}
+ modstore.modlist_unsorted.pagecount = 1
+ modstore.modlist_unsorted.page = 0
+
+ engine.handle_async(
+ function(param)
+ return engine.get_modstore_list()
+ end,
+ nil,
+ function(result)
+ if result ~= nil then
+ modstore.modlist_unsorted = {}
+ modstore.modlist_unsorted.data = result
+
+ if modstore.modlist_unsorted.data ~= nil then
+ modstore.modlist_unsorted.pagecount =
+ math.ceil((#modstore.modlist_unsorted.data / modstore.modsperpage))
+ else
+ modstore.modlist_unsorted.data = {}
+ modstore.modlist_unsorted.pagecount = 1
+ end
+ modstore.modlist_unsorted.page = 0
+ modstore.fetchdetails()
+ engine.event_handler("Refresh")
+ end
+ end
+ )
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#modstore] fetchdetails
+function modstore.fetchdetails()
+
+ for i=1,#modstore.modlist_unsorted.data,1 do
+ engine.handle_async(
+ function(param)
+ param.details = engine.get_modstore_details(tostring(param.modid))
+ return param
+ end,
+ {
+ modid=modstore.modlist_unsorted.data[i].id,
+ listindex=i
+ },
+ function(result)
+ if result ~= nil and
+ modstore.modlist_unsorted ~= nil
+ and modstore.modlist_unsorted.data ~= nil and
+ modstore.modlist_unsorted.data[result.listindex] ~= nil and
+ modstore.modlist_unsorted.data[result.listindex].id ~= nil then
+
+ modstore.modlist_unsorted.data[result.listindex].details = result.details
+ engine.event_handler("Refresh")
+ end
+ end
+ )
+ end
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#modstore] getscreenshot
+function modstore.getscreenshot(ypos,listentry)
+
+ if listentry.details ~= nil and
+ (listentry.details.screenshot_url == nil or
+ listentry.details.screenshot_url == "") then
+
+ if listentry.texturename == nil then
+ listentry.texturename = modstore.basetexturedir .. "no_screenshot.png"
+ end
+
+ return "image[0,".. ypos .. ";3,2;" ..
+ engine.formspec_escape(listentry.texturename) .. "]"
+ end
+
+ if listentry.details ~= nil and
+ listentry.texturename == nil then
+ --make sure we don't download multiple times
+ listentry.texturename = "in progress"
+
+ --prepare url and filename
+ local fullurl = engine.setting_get("modstore_download_url") ..
+ listentry.details.screenshot_url
+ local filename = os.tempfolder() .. "_MID_" .. listentry.id
+
+ --trigger download
+ engine.handle_async(
+ --first param is downloadfct
+ function(param)
+ param.successfull = engine.download_file(param.fullurl,param.filename)
+ return param
+ end,
+ --second parameter is data passed to async job
+ {
+ fullurl = fullurl,
+ filename = filename,
+ modid = listentry.id
+ },
+ --integrate result to raw list
+ function(result)
+ if result.successfull then
+ local found = false
+ for i=1,#modstore.modlist_unsorted.data,1 do
+ if modstore.modlist_unsorted.data[i].id == result.modid then
+ found = true
+ modstore.modlist_unsorted.data[i].texturename = result.filename
+ break
+ end
+ end
+ if found then
+ engine.event_handler("Refresh")
+ else
+ engine.log("error","got screenshot but didn't find matching mod: " .. result.modid)
+ end
+ end
+ end
+ )
+ end
+
+ if listentry.texturename ~= nil and
+ listentry.texturename ~= "in progress" then
+ return "image[0,".. ypos .. ";3,2;" ..
+ engine.formspec_escape(listentry.texturename) .. "]"
+ end
+
+ return ""
+end
+
+--------------------------------------------------------------------------------
+--@function [parent=#modstore] getshortmodinfo
+function modstore.getshortmodinfo(ypos,listentry,details)
+ local retval = ""
+
+ retval = retval .. "box[0," .. ypos .. ";11.4,1.75;#FFFFFF]"
+
+ --screenshot
+ retval = retval .. modstore.getscreenshot(ypos,listentry)
+
+ --title + author
+ retval = retval .."label[2.75," .. ypos .. ";" ..
+ engine.formspec_escape(details.title) .. " (" .. details.author .. ")]"
+
+ --description
+ local descriptiony = ypos + 0.5
+ retval = retval .. "textarea[3," .. descriptiony .. ";6.5,1.55;;" ..
+ engine.formspec_escape(details.description) .. ";]"
+
+ --rating
+ local ratingy = ypos
+ retval = retval .."label[7," .. ratingy .. ";" ..
+ fgettext("Rating") .. ":]"
+ retval = retval .. "label[8.7," .. ratingy .. ";" .. details.rating .."]"
+
+ --versions (IMPORTANT has to be defined AFTER rating)
+ if details.versions ~= nil and
+ #details.versions > 1 then
+ local versiony = ypos + 0.05
+ retval = retval .. "dropdown[9.1," .. versiony .. ";2.48,0.25;dd_version" .. details.id .. ";"
+ local versions = ""
+ for i=1,#details.versions , 1 do
+ if versions ~= "" then
+ versions = versions .. ","
+ end
+
+ versions = versions .. details.versions[i].date:sub(1,10)
+ end
+ retval = retval .. versions .. ";1]"
+ end
+
+ if details.basename then
+ --install button
+ local buttony = ypos + 1.2
+ retval = retval .."button[9.1," .. buttony .. ";2.5,0.5;btn_install_mod_" .. details.id .. ";"
+
+ if modmgr.mod_exists(details.basename) then
+ retval = retval .. fgettext("re-Install") .."]"
+ else
+ retval = retval .. fgettext("Install") .."]"
+ end
+ end
+
+ return retval
+end
+
+--------------------------------------------------------------------------------
+--@function [parent=#modstore] getmodlist
+function modstore.getmodlist(list,yoffset)
+
+ modstore.current_list = list
+
+ if #list.data == 0 then
+ return ""
+ end
+
+ if yoffset == nil then
+ yoffset = 0
+ end
+
+ local scrollbar = ""
+ scrollbar = scrollbar .. "label[0.1,9.5;"
+ .. fgettext("Page $1 of $2", list.page+1, list.pagecount) .. "]"
+ scrollbar = scrollbar .. "box[11.6," .. (yoffset + 0.35) .. ";0.28,"
+ .. (8.6 - yoffset) .. ";#000000]"
+ local scrollbarpos = (yoffset + 0.75) +
+ ((7.7 -yoffset)/(list.pagecount-1)) * list.page
+ scrollbar = scrollbar .. "box[11.6," ..scrollbarpos .. ";0.28,0.5;#32CD32]"
+ scrollbar = scrollbar .. "button[11.6," .. (yoffset + (0.3))
+ .. ";0.5,0.5;btn_modstore_page_up;^]"
+ scrollbar = scrollbar .. "button[11.6," .. 9.0
+ .. ";0.5,0.5;btn_modstore_page_down;v]"
+
+ local retval = ""
+
+ local endmod = (list.page * modstore.modsperpage) + modstore.modsperpage
+
+ if (endmod > #list.data) then
+ endmod = #list.data
+ end
+
+ for i=(list.page * modstore.modsperpage) +1, endmod, 1 do
+ --getmoddetails
+ local details = list.data[i].details
+
+ if details == nil then
+ details = {}
+ details.title = list.data[i].title
+ details.author = ""
+ details.rating = -1
+ details.description = ""
+ end
+
+ if details ~= nil then
+ local screenshot_ypos =
+ yoffset +(i-1 - (list.page * modstore.modsperpage))*1.9 +0.2
+
+ retval = retval .. modstore.getshortmodinfo(screenshot_ypos,
+ list.data[i],
+ details)
+ end
+ end
+
+ return retval .. scrollbar
+end
+
+--------------------------------------------------------------------------------
+--@function [parent=#modstore] getsearchpage
+function modstore.getsearchpage()
+ local retval = ""
+ local search = ""
+
+ if modstore.last_search ~= nil then
+ search = modstore.last_search
+ end
+
+ retval = retval ..
+ "button[9.5,0.2;2.5,0.5;btn_modstore_search;".. fgettext("Search") .. "]" ..
+ "field[0.5,0.5;9,0.5;te_modstore_search;;" .. search .. "]"
+
+
+ --show 4 mods only
+ modstore.modsperpage = 4
+ retval = retval ..
+ modstore.getmodlist(
+ modstore.currentlist,
+ 1.75)
+
+ return retval;
+end
+
--- /dev/null
+--Minetest
+--Copyright (C) 2013 sapier
+--
+--This program is free software; you can redistribute it and/or modify
+--it under the terms of the GNU Lesser General Public License as published by
+--the Free Software Foundation; either version 2.1 of the License, or
+--(at your option) any later version.
+--
+--This program is distributed in the hope that it will be useful,
+--but WITHOUT ANY WARRANTY; without even the implied warranty of
+--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+--GNU Lesser General Public License for more details.
+--
+--You should have received a copy of the GNU Lesser General Public License along
+--with this program; if not, write to the Free Software Foundation, Inc.,
+--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+
+mm_texture = {}
+
+--------------------------------------------------------------------------------
+function mm_texture.init()
+ mm_texture.defaulttexturedir = engine.get_texturepath() .. DIR_DELIM .. "base" ..
+ DIR_DELIM .. "pack" .. DIR_DELIM
+ mm_texture.basetexturedir = mm_texture.defaulttexturedir
+
+ mm_texture.texturepack = engine.setting_get("texture_path")
+
+ mm_texture.gameid = nil
+end
+
+--------------------------------------------------------------------------------
+function mm_texture.update(tab,gamedetails)
+ if tab ~= "singleplayer" then
+ mm_texture.reset()
+ return
+ end
+
+ if gamedetails == nil then
+ return
+ end
+
+ mm_texture.update_game(gamedetails)
+end
+
+--------------------------------------------------------------------------------
+function mm_texture.reset()
+ mm_texture.gameid = nil
+ local have_bg = false
+ local have_overlay = mm_texture.set_generic("overlay")
+
+ if not have_overlay then
+ have_bg = mm_texture.set_generic("background")
+ end
+
+ mm_texture.clear("header")
+ mm_texture.clear("footer")
+ engine.set_clouds(false)
+
+ mm_texture.set_generic("footer")
+ mm_texture.set_generic("header")
+
+ if not have_bg and
+ engine.setting_getbool("enable_clouds") then
+ engine.set_clouds(true)
+ end
+end
+
+--------------------------------------------------------------------------------
+function mm_texture.update_game(gamedetails)
+ if mm_texture.gameid == gamedetails.id then
+ return
+ end
+
+ local have_bg = false
+ local have_overlay = mm_texture.set_game("overlay",gamedetails)
+
+ if not have_overlay then
+ have_bg = mm_texture.set_game("background",gamedetails)
+ end
+
+ mm_texture.clear("header")
+ mm_texture.clear("footer")
+ engine.set_clouds(false)
+
+ if not have_bg and
+ engine.setting_getbool("enable_clouds") then
+ engine.set_clouds(true)
+ end
+
+ mm_texture.set_game("footer",gamedetails)
+ mm_texture.set_game("header",gamedetails)
+
+ mm_texture.gameid = gamedetails.id
+end
+
+--------------------------------------------------------------------------------
+function mm_texture.clear(identifier)
+ engine.set_background(identifier,"")
+end
+
+--------------------------------------------------------------------------------
+function mm_texture.set_generic(identifier)
+ --try texture pack first
+ if mm_texture.texturepack ~= nil then
+ local path = mm_texture.texturepack .. DIR_DELIM .."menu_" ..
+ identifier .. ".png"
+ if engine.set_background(identifier,path) then
+ return true
+ end
+ end
+
+ if mm_texture.defaulttexturedir ~= nil then
+ local path = mm_texture.defaulttexturedir .. DIR_DELIM .."menu_" ..
+ identifier .. ".png"
+ if engine.set_background(identifier,path) then
+ return true
+ end
+ end
+
+ return false
+end
+
+--------------------------------------------------------------------------------
+function mm_texture.set_game(identifier,gamedetails)
+
+ if gamedetails == nil then
+ return false
+ end
+
+ if mm_texture.texturepack ~= nil then
+ local path = mm_texture.texturepack .. DIR_DELIM ..
+ gamedetails.id .. "_menu_" .. identifier .. ".png"
+ if engine.set_background(identifier,path) then
+ return true
+ end
+ end
+
+ local path = gamedetails.path .. DIR_DELIM .."menu" ..
+ DIR_DELIM .. identifier .. ".png"
+ if engine.set_background(identifier,path) then
+ return true
+ end
+
+ return false
+end
+++ /dev/null
--- 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
-
+++ /dev/null
--- Minetest: builtin/misc_helpers.lua
-
---------------------------------------------------------------------------------
-function basic_dump2(o)
- if type(o) == "number" then
- return tostring(o)
- elseif type(o) == "string" then
- return string.format("%q", o)
- elseif type(o) == "boolean" then
- return tostring(o)
- elseif type(o) == "function" then
- return "<function>"
- elseif type(o) == "userdata" then
- return "<userdata>"
- elseif type(o) == "nil" then
- return "nil"
- else
- error("cannot dump a " .. type(o))
- return nil
- end
-end
-
---------------------------------------------------------------------------------
-function dump2(o, name, dumped)
- name = name or "_"
- dumped = dumped or {}
- io.write(name, " = ")
- if type(o) == "number" or type(o) == "string" or type(o) == "boolean"
- or type(o) == "function" or type(o) == "nil"
- or type(o) == "userdata" then
- io.write(basic_dump2(o), "\n")
- elseif type(o) == "table" then
- if dumped[o] then
- io.write(dumped[o], "\n")
- else
- dumped[o] = name
- io.write("{}\n") -- new table
- for k,v in pairs(o) do
- local fieldname = string.format("%s[%s]", name, basic_dump2(k))
- dump2(v, fieldname, dumped)
- end
- end
- else
- error("cannot dump a " .. type(o))
- return nil
- end
-end
-
---------------------------------------------------------------------------------
-function dump(o, dumped)
- dumped = dumped or {}
- if type(o) == "number" then
- return tostring(o)
- elseif type(o) == "string" then
- return string.format("%q", o)
- elseif type(o) == "table" then
- if dumped[o] then
- return "<circular reference>"
- end
- dumped[o] = true
- local t = {}
- for k,v in pairs(o) do
- t[#t+1] = "[" .. dump(k, dumped) .. "] = " .. dump(v, dumped)
- end
- return "{" .. table.concat(t, ", ") .. "}"
- elseif type(o) == "boolean" then
- return tostring(o)
- elseif type(o) == "function" then
- return "<function>"
- elseif type(o) == "userdata" then
- return "<userdata>"
- elseif type(o) == "nil" then
- return "nil"
- else
- error("cannot dump a " .. type(o))
- return nil
- end
-end
-
---------------------------------------------------------------------------------
-function string:split(sep)
- local sep, fields = sep or ",", {}
- local pattern = string.format("([^%s]+)", sep)
- self:gsub(pattern, function(c) fields[#fields+1] = c end)
- return fields
-end
-
---------------------------------------------------------------------------------
-function file_exists(filename)
- local f = io.open(filename, "r")
- if f==nil then
- return false
- else
- f:close()
- return true
- end
-end
-
---------------------------------------------------------------------------------
-function string:trim()
- return (self:gsub("^%s*(.-)%s*$", "%1"))
-end
-
-assert(string.trim("\n \t\tfoo bar\t ") == "foo bar")
-
---------------------------------------------------------------------------------
-function math.hypot(x, y)
- local t
- x = math.abs(x)
- y = math.abs(y)
- t = math.min(x, y)
- x = math.max(x, y)
- if x == 0 then return 0 end
- t = t / x
- return x * math.sqrt(1 + t * t)
-end
-
---------------------------------------------------------------------------------
-function get_last_folder(text,count)
- local parts = text:split(DIR_DELIM)
-
- if count == nil then
- return parts[#parts]
- end
-
- local retval = ""
- for i=1,count,1 do
- retval = retval .. parts[#parts - (count-i)] .. DIR_DELIM
- end
-
- return retval
-end
-
---------------------------------------------------------------------------------
-function cleanup_path(temppath)
-
- local parts = temppath:split("-")
- temppath = ""
- for i=1,#parts,1 do
- if temppath ~= "" then
- temppath = temppath .. "_"
- end
- temppath = temppath .. parts[i]
- end
-
- parts = temppath:split(".")
- temppath = ""
- for i=1,#parts,1 do
- if temppath ~= "" then
- temppath = temppath .. "_"
- end
- temppath = temppath .. parts[i]
- end
-
- parts = temppath:split("'")
- temppath = ""
- for i=1,#parts,1 do
- if temppath ~= "" then
- temppath = temppath .. ""
- end
- temppath = temppath .. parts[i]
- end
-
- parts = temppath:split(" ")
- temppath = ""
- for i=1,#parts,1 do
- if temppath ~= "" then
- temppath = temppath
- end
- temppath = temppath .. parts[i]
- end
-
- return temppath
-end
-
-local tbl = engine or minetest
-function tbl.formspec_escape(text)
- if text ~= nil then
- text = string.gsub(text,"\\","\\\\")
- text = string.gsub(text,"%]","\\]")
- text = string.gsub(text,"%[","\\[")
- text = string.gsub(text,";","\\;")
- text = string.gsub(text,",","\\,")
- end
- return text
-end
-
-
-function tbl.splittext(text,charlimit)
- local retval = {}
-
- local current_idx = 1
-
- 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
- local last_line = ""
- while start ~= nil do
- if string.len(last_line) + (stop-start) > charlimit then
- table.insert(retval,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
- table.insert(retval,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
- start = nl_start
- stop = nl_stop
- gotnewline = true
- end
- end
-
- --add last part of text
- if string.len(last_line) + (string.len(text) - current_idx) > charlimit then
- table.insert(retval,last_line)
- table.insert(retval,string.sub(text,current_idx))
- else
- last_line = last_line .. " " .. string.sub(text,current_idx)
- table.insert(retval,last_line)
- end
-
- return retval
-end
-
---------------------------------------------------------------------------------
-
-if minetest then
- local dirs1 = {9, 18, 7, 12}
- local dirs2 = {20, 23, 22, 21}
-
- function minetest.rotate_and_place(itemstack, placer, pointed_thing,
- infinitestacks, orient_flags)
- orient_flags = orient_flags or {}
-
- local unode = minetest.get_node_or_nil(pointed_thing.under)
- if not unode then
- return
- end
- local undef = minetest.registered_nodes[unode.name]
- if undef and undef.on_rightclick then
- undef.on_rightclick(pointed_thing.under, unode, placer,
- itemstack, pointed_thing)
- return
- end
- local pitch = placer:get_look_pitch()
- local fdir = minetest.dir_to_facedir(placer:get_look_dir())
- local wield_name = itemstack:get_name()
-
- local above = pointed_thing.above
- local under = pointed_thing.under
- local iswall = (above.y == under.y)
- local isceiling = not iswall and (above.y < under.y)
- local anode = minetest.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
- pos = pointed_thing.under
- node = unode
- iswall = false
- end
-
- if minetest.is_protected(pos, placer:get_player_name()) then
- minetest.record_protection_violation(pos,
- placer:get_player_name())
- return
- end
-
- local ndef = minetest.registered_nodes[node.name]
- if not ndef or not ndef.buildable_to then
- return
- end
-
- if orient_flags.force_floor then
- iswall = false
- isceiling = false
- elseif orient_flags.force_ceiling then
- iswall = false
- isceiling = true
- elseif orient_flags.force_wall then
- iswall = true
- isceiling = false
- elseif orient_flags.invert_wall then
- iswall = not iswall
- end
-
- if iswall then
- minetest.set_node(pos, {name = wield_name,
- param2 = dirs1[fdir+1]})
- elseif isceiling then
- if orient_flags.force_facedir then
- minetest.set_node(pos, {name = wield_name,
- param2 = 20})
- else
- minetest.set_node(pos, {name = wield_name,
- param2 = dirs2[fdir+1]})
- end
- else -- place right side up
- if orient_flags.force_facedir then
- minetest.set_node(pos, {name = wield_name,
- param2 = 0})
- else
- minetest.set_node(pos, {name = wield_name,
- param2 = fdir})
- end
- end
-
- if not infinitestacks then
- itemstack:take_item()
- return itemstack
- end
- end
-
-
---------------------------------------------------------------------------------
---Wrapper for rotate_and_place() to check for sneak and assume Creative mode
---implies infinite stacks when performing a 6d rotation.
---------------------------------------------------------------------------------
-
-
- minetest.rotate_node = function(itemstack, placer, pointed_thing)
- minetest.rotate_and_place(itemstack, placer, pointed_thing,
- minetest.setting_getbool("creative_mode"),
- {invert_wall = placer:get_player_control().sneak})
- return itemstack
- end
-end
-
---------------------------------------------------------------------------------
-function tbl.explode_table_event(evt)
- if evt ~= nil then
- local parts = evt:split(":")
- if #parts == 3 then
- local t = parts[1]:trim()
- local r = tonumber(parts[2]:trim())
- local c = tonumber(parts[3]:trim())
- if type(r) == "number" and type(c) == "number" and t ~= "INV" then
- return {type=t, row=r, column=c}
- end
- end
- end
- return {type="INV", row=0, column=0}
-end
-
---------------------------------------------------------------------------------
-function tbl.explode_textlist_event(evt)
- if evt ~= nil then
- local parts = evt:split(":")
- if #parts == 2 then
- local t = parts[1]:trim()
- local r = tonumber(parts[2]:trim())
- if type(r) == "number" and t ~= "INV" then
- return {type=t, index=r}
- end
- end
- end
- return {type="INV", index=0}
-end
-
---------------------------------------------------------------------------------
--- mainmenu only functions
---------------------------------------------------------------------------------
-if engine ~= nil then
- engine.get_game = function(index)
- local games = game.get_games()
-
- if index > 0 and index <= #games then
- return games[index]
- end
-
- return nil
- end
-
- function fgettext(text, ...)
- text = engine.gettext(text)
- local arg = {n=select('#', ...), ...}
- if arg.n >= 1 then
- -- Insert positional parameters ($1, $2, ...)
- result = ''
- pos = 1
- while pos <= text:len() do
- newpos = text:find('[$]', pos)
- if newpos == nil then
- result = result .. text:sub(pos)
- pos = text:len() + 1
- else
- paramindex = tonumber(text:sub(newpos+1, newpos+1))
- result = result .. text:sub(pos, newpos-1) .. tostring(arg[paramindex])
- pos = newpos + 2
- end
- end
- text = result
- end
- return engine.formspec_escape(text)
- end
-end
---------------------------------------------------------------------------------
--- core only fct
---------------------------------------------------------------------------------
-if minetest ~= nil then
- --------------------------------------------------------------------------------
- function minetest.pos_to_string(pos)
- return "(" .. pos.x .. "," .. pos.y .. "," .. pos.z .. ")"
- end
-end
-
+++ /dev/null
--- 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()
-
+++ /dev/null
---Minetest
---Copyright (C) 2013 sapier
---
---This program is free software; you can redistribute it and/or modify
---it under the terms of the GNU Lesser General Public License as published by
---the Free Software Foundation; either version 2.1 of the License, or
---(at your option) any later version.
---
---This program is distributed in the hope that it will be useful,
---but WITHOUT ANY WARRANTY; without even the implied warranty of
---MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
---GNU Lesser General Public License for more details.
---
---You should have received a copy of the GNU Lesser General Public License along
---with this program; if not, write to the Free Software Foundation, Inc.,
---51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-menubar = {}
-
---------------------------------------------------------------------------------
-function menubar.handle_buttons(fields)
- for i=1,#menubar.buttons,1 do
- if fields[menubar.buttons[i].btn_name] ~= nil then
- menu.last_game = menubar.buttons[i].index
- engine.setting_set("main_menu_last_game_idx",menu.last_game)
- menu.update_gametype()
- end
- end
-end
-
---------------------------------------------------------------------------------
-function menubar.refresh()
-
- menubar.formspec = "box[-0.3,5.625;12.4,1.2;#000000]" ..
- "box[-0.3,5.6;12.4,0.05;#FFFFFF]"
- menubar.buttons = {}
-
- local button_base = -0.08
-
- local maxbuttons = #gamemgr.games
-
- if maxbuttons > 11 then
- maxbuttons = 11
- end
-
- for i=1,maxbuttons,1 do
-
- local btn_name = "menubar_btn_" .. gamemgr.games[i].id
- local buttonpos = button_base + (i-1) * 1.1
- if gamemgr.games[i].menuicon_path ~= nil and
- gamemgr.games[i].menuicon_path ~= "" then
-
- menubar.formspec = menubar.formspec ..
- "image_button[" .. buttonpos .. ",5.72;1.165,1.175;" ..
- engine.formspec_escape(gamemgr.games[i].menuicon_path) .. ";" ..
- btn_name .. ";;true;false]"
- else
-
- local part1 = gamemgr.games[i].id:sub(1,5)
- local part2 = gamemgr.games[i].id:sub(6,10)
- local part3 = gamemgr.games[i].id:sub(11)
-
- local text = part1 .. "\n" .. part2
- if part3 ~= nil and
- part3 ~= "" then
- text = text .. "\n" .. part3
- end
- menubar.formspec = menubar.formspec ..
- "image_button[" .. buttonpos .. ",5.72;1.165,1.175;;" ..btn_name ..
- ";" .. text .. ";true;true]"
- end
-
- local toadd = {
- btn_name = btn_name,
- index = i,
- }
-
- table.insert(menubar.buttons,toadd)
- end
-end
+++ /dev/null
---Minetest
---Copyright (C) 2013 sapier
---
---This program is free software; you can redistribute it and/or modify
---it under the terms of the GNU Lesser General Public License as published by
---the Free Software Foundation; either version 2.1 of the License, or
---(at your option) any later version.
---
---This program is distributed in the hope that it will be useful,
---but WITHOUT ANY WARRANTY; without even the implied warranty of
---MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
---GNU Lesser General Public License for more details.
---
---You should have received a copy of the GNU Lesser General Public License along
---with this program; if not, write to the Free Software Foundation, Inc.,
---51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-
-mm_texture = {}
-
---------------------------------------------------------------------------------
-function mm_texture.init()
- mm_texture.defaulttexturedir = engine.get_texturepath() .. DIR_DELIM .. "base" ..
- DIR_DELIM .. "pack" .. DIR_DELIM
- mm_texture.basetexturedir = mm_texture.defaulttexturedir
-
- mm_texture.texturepack = engine.setting_get("texture_path")
-
- mm_texture.gameid = nil
-end
-
---------------------------------------------------------------------------------
-function mm_texture.update(tab,gamedetails)
- if tab ~= "singleplayer" then
- mm_texture.reset()
- return
- end
-
- if gamedetails == nil then
- return
- end
-
- mm_texture.update_game(gamedetails)
-end
-
---------------------------------------------------------------------------------
-function mm_texture.reset()
- mm_texture.gameid = nil
- local have_bg = false
- local have_overlay = mm_texture.set_generic("overlay")
-
- if not have_overlay then
- have_bg = mm_texture.set_generic("background")
- end
-
- mm_texture.clear("header")
- mm_texture.clear("footer")
- engine.set_clouds(false)
-
- mm_texture.set_generic("footer")
- mm_texture.set_generic("header")
-
- if not have_bg and
- engine.setting_getbool("enable_clouds") then
- engine.set_clouds(true)
- end
-end
-
---------------------------------------------------------------------------------
-function mm_texture.update_game(gamedetails)
- if mm_texture.gameid == gamedetails.id then
- return
- end
-
- local have_bg = false
- local have_overlay = mm_texture.set_game("overlay",gamedetails)
-
- if not have_overlay then
- have_bg = mm_texture.set_game("background",gamedetails)
- end
-
- mm_texture.clear("header")
- mm_texture.clear("footer")
- engine.set_clouds(false)
-
- if not have_bg and
- engine.setting_getbool("enable_clouds") then
- engine.set_clouds(true)
- end
-
- mm_texture.set_game("footer",gamedetails)
- mm_texture.set_game("header",gamedetails)
-
- mm_texture.gameid = gamedetails.id
-end
-
---------------------------------------------------------------------------------
-function mm_texture.clear(identifier)
- engine.set_background(identifier,"")
-end
-
---------------------------------------------------------------------------------
-function mm_texture.set_generic(identifier)
- --try texture pack first
- if mm_texture.texturepack ~= nil then
- local path = mm_texture.texturepack .. DIR_DELIM .."menu_" ..
- identifier .. ".png"
- if engine.set_background(identifier,path) then
- return true
- end
- end
-
- if mm_texture.defaulttexturedir ~= nil then
- local path = mm_texture.defaulttexturedir .. DIR_DELIM .."menu_" ..
- identifier .. ".png"
- if engine.set_background(identifier,path) then
- return true
- end
- end
-
- return false
-end
-
---------------------------------------------------------------------------------
-function mm_texture.set_game(identifier,gamedetails)
-
- if gamedetails == nil then
- return false
- end
-
- if mm_texture.texturepack ~= nil then
- local path = mm_texture.texturepack .. DIR_DELIM ..
- gamedetails.id .. "_menu_" .. identifier .. ".png"
- if engine.set_background(identifier,path) then
- return true
- end
- end
-
- local path = gamedetails.path .. DIR_DELIM .."menu" ..
- DIR_DELIM .. identifier .. ".png"
- if engine.set_background(identifier,path) then
- return true
- end
-
- return false
-end
+++ /dev/null
---Minetest
---Copyright (C) 2013 sapier
---
---This program is free software; you can redistribute it and/or modify
---it under the terms of the GNU Lesser General Public License as published by
---the Free Software Foundation; either version 2.1 of the License, or
---(at your option) any later version.
---
---This program is distributed in the hope that it will be useful,
---but WITHOUT ANY WARRANTY; without even the implied warranty of
---MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
---GNU Lesser General Public License for more details.
---
---You should have received a copy of the GNU Lesser General Public License along
---with this program; if not, write to the Free Software Foundation, Inc.,
---51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
---------------------------------------------------------------------------------
-function get_mods(path,retval,modpack)
-
- local mods = engine.get_dirlist(path,true)
- for i=1,#mods,1 do
- local toadd = {}
- local modpackfile = nil
-
- toadd.name = mods[i]
- toadd.path = path .. DIR_DELIM .. mods[i] .. DIR_DELIM
- if modpack ~= nil and
- modpack ~= "" then
- toadd.modpack = modpack
- else
- local filename = path .. DIR_DELIM .. mods[i] .. DIR_DELIM .. "modpack.txt"
- local error = nil
- modpackfile,error = io.open(filename,"r")
- end
-
- if modpackfile ~= nil then
- modpackfile:close()
- toadd.is_modpack = true
- table.insert(retval,toadd)
- get_mods(path .. DIR_DELIM .. mods[i],retval,mods[i])
- else
- table.insert(retval,toadd)
- end
- end
-end
-
---modmanager implementation
-modmgr = {}
-
---------------------------------------------------------------------------------
-function modmgr.extract(modfile)
- if modfile.type == "zip" then
- local tempfolder = os.tempfolder()
-
- if tempfolder ~= nil and
- tempfolder ~= "" then
- engine.create_dir(tempfolder)
- if engine.extract_zip(modfile.name,tempfolder) then
- return tempfolder
- end
- end
- end
- return nil
-end
-
--------------------------------------------------------------------------------
-function modmgr.getbasefolder(temppath)
-
- if temppath == nil then
- return {
- type = "invalid",
- path = ""
- }
- end
-
- local testfile = io.open(temppath .. DIR_DELIM .. "init.lua","r")
- if testfile ~= nil then
- testfile:close()
- return {
- type="mod",
- path=temppath
- }
- end
-
- testfile = io.open(temppath .. DIR_DELIM .. "modpack.txt","r")
- if testfile ~= nil then
- testfile:close()
- return {
- type="modpack",
- path=temppath
- }
- end
-
- local subdirs = engine.get_dirlist(temppath,true)
-
- --only single mod or modpack allowed
- if #subdirs ~= 1 then
- return {
- type = "invalid",
- path = ""
- }
- end
-
- testfile =
- io.open(temppath .. DIR_DELIM .. subdirs[1] ..DIR_DELIM .."init.lua","r")
- if testfile ~= nil then
- testfile:close()
- return {
- type="mod",
- path= temppath .. DIR_DELIM .. subdirs[1]
- }
- end
-
- testfile =
- io.open(temppath .. DIR_DELIM .. subdirs[1] ..DIR_DELIM .."modpack.txt","r")
- if testfile ~= nil then
- testfile:close()
- return {
- type="modpack",
- path=temppath .. DIR_DELIM .. subdirs[1]
- }
- end
-
- return {
- type = "invalid",
- path = ""
- }
-end
-
---------------------------------------------------------------------------------
-function modmgr.isValidModname(modpath)
- if modpath:find("-") ~= nil then
- return false
- end
-
- return true
-end
-
---------------------------------------------------------------------------------
-function modmgr.parse_register_line(line)
- local pos1 = line:find("\"")
- local pos2 = nil
- if pos1 ~= nil then
- pos2 = line:find("\"",pos1+1)
- end
-
- if pos1 ~= nil and pos2 ~= nil then
- local item = line:sub(pos1+1,pos2-1)
-
- if item ~= nil and
- item ~= "" then
- local pos3 = item:find(":")
-
- if pos3 ~= nil then
- local retval = item:sub(1,pos3-1)
- if retval ~= nil and
- retval ~= "" then
- return retval
- end
- end
- end
- end
- return nil
-end
-
---------------------------------------------------------------------------------
-function modmgr.parse_dofile_line(modpath,line)
- local pos1 = line:find("\"")
- local pos2 = nil
- if pos1 ~= nil then
- pos2 = line:find("\"",pos1+1)
- end
-
- if pos1 ~= nil and pos2 ~= nil then
- local filename = line:sub(pos1+1,pos2-1)
-
- if filename ~= nil and
- filename ~= "" and
- filename:find(".lua") then
- return modmgr.identify_modname(modpath,filename)
- end
- end
- return nil
-end
-
---------------------------------------------------------------------------------
-function modmgr.identify_modname(modpath,filename)
- local testfile = io.open(modpath .. DIR_DELIM .. filename,"r")
- if testfile ~= nil then
- local line = testfile:read()
-
- while line~= nil do
- local modname = nil
-
- if line:find("minetest.register_tool") then
- modname = modmgr.parse_register_line(line)
- end
-
- if line:find("minetest.register_craftitem") then
- modname = modmgr.parse_register_line(line)
- end
-
-
- if line:find("minetest.register_node") then
- modname = modmgr.parse_register_line(line)
- end
-
- if line:find("dofile") then
- modname = modmgr.parse_dofile_line(modpath,line)
- end
-
- if modname ~= nil then
- testfile:close()
- return modname
- end
-
- line = testfile:read()
- end
- testfile:close()
- end
-
- return nil
-end
-
---------------------------------------------------------------------------------
-function modmgr.tab()
-
- if modmgr.global_mods == nil then
- modmgr.refresh_globals()
- end
-
- if modmgr.selected_mod == nil then
- modmgr.selected_mod = 1
- end
-
- local retval =
- "vertlabel[0,-0.25;".. fgettext("MODS") .. "]" ..
- "label[0.8,-0.25;".. fgettext("Installed Mods:") .. "]" ..
- "textlist[0.75,0.25;4.5,4;modlist;" ..
- modmgr.render_modlist(modmgr.global_mods) ..
- ";" .. modmgr.selected_mod .. "]"
-
- retval = retval ..
- "label[0.8,4.2;" .. fgettext("Add mod:") .. "]" ..
--- TODO Disabled due to upcoming release 0.4.8 and irrlicht messing up localization
--- "button[0.75,4.85;1.8,0.5;btn_mod_mgr_install_local;".. fgettext("Local install") .. "]" ..
- "button[2.45,4.85;3.05,0.5;btn_mod_mgr_download;".. fgettext("Online mod repository") .. "]"
-
- local selected_mod = nil
-
- if filterlist.size(modmgr.global_mods) >= modmgr.selected_mod then
- selected_mod = filterlist.get_list(modmgr.global_mods)[modmgr.selected_mod]
- end
-
- if selected_mod ~= nil then
- local modscreenshot = nil
-
- --check for screenshot beeing available
- local screenshotfilename = selected_mod.path .. DIR_DELIM .. "screenshot.png"
- local error = nil
- screenshotfile,error = io.open(screenshotfilename,"r")
- if error == nil then
- screenshotfile:close()
- modscreenshot = screenshotfilename
- end
-
- if modscreenshot == nil then
- modscreenshot = modstore.basetexturedir .. "no_screenshot.png"
- end
-
- retval = retval
- .. "image[5.5,0;3,2;" .. engine.formspec_escape(modscreenshot) .. "]"
- .. "label[8.25,0.6;" .. selected_mod.name .. "]"
-
- local descriptionlines = nil
- error = nil
- local descriptionfilename = selected_mod.path .. "description.txt"
- descriptionfile,error = io.open(descriptionfilename,"r")
- if error == nil then
- descriptiontext = descriptionfile:read("*all")
-
- descriptionlines = engine.splittext(descriptiontext,42)
- descriptionfile:close()
- else
- descriptionlines = {}
- table.insert(descriptionlines,fgettext("No mod description available"))
- end
-
- retval = retval ..
- "label[5.5,1.7;".. fgettext("Mod information:") .. "]" ..
- "textlist[5.5,2.2;6.2,2.4;description;"
-
- for i=1,#descriptionlines,1 do
- retval = retval .. engine.formspec_escape(descriptionlines[i]) .. ","
- end
-
-
- if selected_mod.is_modpack then
- retval = retval .. ";0]" ..
- "button[10,4.85;2,0.5;btn_mod_mgr_rename_modpack;" ..
- fgettext("Rename") .. "]"
- retval = retval .. "button[5.5,4.85;4.5,0.5;btn_mod_mgr_delete_mod;"
- .. fgettext("Uninstall selected modpack") .. "]"
- else
- --show dependencies
-
- retval = retval .. ",Depends:,"
-
- toadd = modmgr.get_dependencies(selected_mod.path)
-
- retval = retval .. toadd .. ";0]"
-
- retval = retval .. "button[5.5,4.85;4.5,0.5;btn_mod_mgr_delete_mod;"
- .. fgettext("Uninstall selected mod") .. "]"
- end
- end
- return retval
-end
-
---------------------------------------------------------------------------------
-function modmgr.dialog_rename_modpack()
-
- local mod = filterlist.get_list(modmgr.global_mods)[modmgr.selected_mod]
-
- local retval =
- "label[1.75,1;".. fgettext("Rename Modpack:") .. "]"..
- "field[4.5,1.4;6,0.5;te_modpack_name;;" ..
- mod.name ..
- "]" ..
- "button[5,4.2;2.6,0.5;dlg_rename_modpack_confirm;"..
- fgettext("Accept") .. "]" ..
- "button[7.5,4.2;2.8,0.5;dlg_rename_modpack_cancel;"..
- fgettext("Cancel") .. "]"
-
- return retval
-end
-
---------------------------------------------------------------------------------
-function modmgr.precheck()
-
- if modmgr.world_config_selected_world == nil then
- modmgr.world_config_selected_world = 1
- end
-
- if modmgr.world_config_selected_mod == nil then
- modmgr.world_config_selected_mod = 1
- end
-
- if modmgr.hide_gamemods == nil then
- modmgr.hide_gamemods = true
- end
-
- if modmgr.hide_modpackcontents == nil then
- modmgr.hide_modpackcontents = true
- end
-end
-
---------------------------------------------------------------------------------
-function modmgr.render_modlist(render_list)
- local retval = ""
-
- if render_list == nil then
- if modmgr.global_mods == nil then
- modmgr.refresh_globals()
- end
- render_list = modmgr.global_mods
- end
-
- local list = filterlist.get_list(render_list)
- local last_modpack = nil
-
- for i,v in ipairs(list) do
- if retval ~= "" then
- retval = retval ..","
- end
-
- local color = ""
-
- if v.is_modpack then
- local rawlist = filterlist.get_raw_list(render_list)
-
- local all_enabled = true
- for j=1,#rawlist,1 do
- if rawlist[j].modpack == list[i].name and
- rawlist[j].enabled ~= true then
- all_enabled = false
- break
- end
- end
-
- if all_enabled == false then
- color = mt_color_grey
- else
- color = mt_color_dark_green
- end
- end
-
- if v.typ == "game_mod" then
- color = mt_color_blue
- else
- if v.enabled then
- color = mt_color_green
- end
- end
-
- retval = retval .. color
- if v.modpack ~= nil then
- retval = retval .. " "
- end
- retval = retval .. v.name
- end
-
- return retval
-end
-
---------------------------------------------------------------------------------
-function modmgr.dialog_configure_world()
- modmgr.precheck()
-
- local worldspec = engine.get_worlds()[modmgr.world_config_selected_world]
- local mod = filterlist.get_list(modmgr.modlist)[modmgr.world_config_selected_mod]
-
- local retval =
- "size[11,6.5,true]" ..
- "label[0.5,-0.25;" .. fgettext("World:") .. "]" ..
- "label[1.75,-0.25;" .. worldspec.name .. "]"
-
- if modmgr.hide_gamemods then
- retval = retval .. "checkbox[0,5.75;cb_hide_gamemods;" .. fgettext("Hide Game") .. ";true]"
- else
- retval = retval .. "checkbox[0,5.75;cb_hide_gamemods;" .. fgettext("Hide Game") .. ";false]"
- end
-
- if modmgr.hide_modpackcontents then
- retval = retval .. "checkbox[2,5.75;cb_hide_mpcontent;" .. fgettext("Hide mp content") .. ";true]"
- else
- retval = retval .. "checkbox[2,5.75;cb_hide_mpcontent;" .. fgettext("Hide mp content") .. ";false]"
- end
-
- if mod == nil then
- mod = {name=""}
- end
- retval = retval ..
- "label[0,0.45;" .. fgettext("Mod:") .. "]" ..
- "label[0.75,0.45;" .. mod.name .. "]" ..
- "label[0,1;" .. fgettext("Depends:") .. "]" ..
- "textlist[0,1.5;5,4.25;world_config_depends;" ..
- modmgr.get_dependencies(mod.path) .. ";0]" ..
- "button[9.25,6.35;2,0.5;btn_config_world_save;" .. fgettext("Save") .. "]" ..
- "button[7.4,6.35;2,0.5;btn_config_world_cancel;" .. fgettext("Cancel") .. "]"
-
- if mod ~= nil and mod.name ~= "" and mod.typ ~= "game_mod" then
- if mod.is_modpack then
- local rawlist = filterlist.get_raw_list(modmgr.modlist)
-
- local all_enabled = true
- for j=1,#rawlist,1 do
- if rawlist[j].modpack == mod.name and
- rawlist[j].enabled ~= true then
- all_enabled = false
- break
- end
- end
-
- if all_enabled == false then
- retval = retval .. "button[5.5,-0.125;2,0.5;btn_mp_enable;" .. fgettext("Enable MP") .. "]"
- else
- retval = retval .. "button[5.5,-0.125;2,0.5;btn_mp_disable;" .. fgettext("Disable MP") .. "]"
- end
- else
- if mod.enabled then
- retval = retval .. "checkbox[5.5,-0.375;cb_mod_enable;" .. fgettext("enabled") .. ";true]"
- else
- retval = retval .. "checkbox[5.5,-0.375;cb_mod_enable;" .. fgettext("enabled") .. ";false]"
- end
- end
- end
-
- retval = retval ..
- "button[8.5,-0.125;2.5,0.5;btn_all_mods;" .. fgettext("Enable all") .. "]" ..
- "textlist[5.5,0.5;5.5,5.75;world_config_modlist;"
-
- retval = retval .. modmgr.render_modlist(modmgr.modlist)
-
- retval = retval .. ";" .. modmgr.world_config_selected_mod .."]"
-
- return retval
-end
-
---------------------------------------------------------------------------------
-function modmgr.handle_buttons(tab,fields)
-
- local retval = nil
-
- if tab == "mod_mgr" then
- retval = modmgr.handle_modmgr_buttons(fields)
- end
-
- if tab == "dialog_rename_modpack" then
- retval = modmgr.handle_rename_modpack_buttons(fields)
- end
-
- if tab == "dialog_delete_mod" then
- retval = modmgr.handle_delete_mod_buttons(fields)
- end
-
- if tab == "dialog_configure_world" then
- retval = modmgr.handle_configure_world_buttons(fields)
- end
-
- return retval
-end
-
---------------------------------------------------------------------------------
-function modmgr.get_dependencies(modfolder)
- local toadd = ""
- if modfolder ~= nil then
- local filename = modfolder ..
- DIR_DELIM .. "depends.txt"
-
- local dependencyfile = io.open(filename,"r")
-
- if dependencyfile then
- local dependency = dependencyfile:read("*l")
- while dependency do
- if toadd ~= "" then
- toadd = toadd .. ","
- end
- toadd = toadd .. dependency
- dependency = dependencyfile:read()
- end
- dependencyfile:close()
- end
- end
-
- return toadd
-end
-
-
---------------------------------------------------------------------------------
-function modmgr.get_worldconfig(worldpath)
- local filename = worldpath ..
- DIR_DELIM .. "world.mt"
-
- local worldfile = Settings(filename)
-
- local worldconfig = {}
- worldconfig.global_mods = {}
- worldconfig.game_mods = {}
-
- for key,value in pairs(worldfile:to_table()) do
- if key == "gameid" then
- worldconfig.id = value
- else
- worldconfig.global_mods[key] = engine.is_yes(value)
- end
- end
-
- --read gamemods
- local gamespec = gamemgr.find_by_gameid(worldconfig.id)
- gamemgr.get_game_mods(gamespec, worldconfig.game_mods)
-
- return worldconfig
-end
---------------------------------------------------------------------------------
-function modmgr.handle_modmgr_buttons(fields)
- local retval = {
- tab = nil,
- is_dialog = nil,
- show_buttons = nil,
- }
-
- if fields["modlist"] ~= nil then
- local event = engine.explode_textlist_event(fields["modlist"])
- modmgr.selected_mod = event.index
- end
-
- if fields["btn_mod_mgr_install_local"] ~= nil then
- engine.show_file_open_dialog("mod_mgt_open_dlg",fgettext("Select Mod File:"))
- end
-
- if fields["btn_mod_mgr_download"] ~= nil then
- modstore.update_modlist()
- retval.current_tab = "dialog_modstore_unsorted"
- retval.is_dialog = true
- retval.show_buttons = false
- return retval
- end
-
- if fields["btn_mod_mgr_rename_modpack"] ~= nil then
- retval.current_tab = "dialog_rename_modpack"
- retval.is_dialog = true
- retval.show_buttons = false
- return retval
- end
-
- if fields["btn_mod_mgr_delete_mod"] ~= nil then
- retval.current_tab = "dialog_delete_mod"
- retval.is_dialog = true
- retval.show_buttons = false
- return retval
- end
-
- if fields["mod_mgt_open_dlg_accepted"] ~= nil and
- fields["mod_mgt_open_dlg_accepted"] ~= "" then
- modmgr.installmod(fields["mod_mgt_open_dlg_accepted"],nil)
- end
-
- return nil;
-end
-
---------------------------------------------------------------------------------
-function modmgr.installmod(modfilename,basename)
- local modfile = modmgr.identify_filetype(modfilename)
- local modpath = modmgr.extract(modfile)
-
- if modpath == nil then
- gamedata.errormessage = fgettext("Install Mod: file: \"$1\"", modfile.name) ..
- fgettext("\nInstall Mod: unsupported filetype \"$1\" or broken archive", modfile.type)
- return
- end
-
-
- local basefolder = modmgr.getbasefolder(modpath)
-
- if basefolder.type == "modpack" then
- local clean_path = nil
-
- if basename ~= nil then
- clean_path = "mp_" .. basename
- end
-
- if clean_path == nil then
- clean_path = get_last_folder(cleanup_path(basefolder.path))
- end
-
- if clean_path ~= nil then
- local targetpath = engine.get_modpath() .. DIR_DELIM .. clean_path
- if not engine.copy_dir(basefolder.path,targetpath) then
- gamedata.errormessage = fgettext("Failed to install $1 to $2", basename, targetpath)
- end
- else
- gamedata.errormessage = fgettext("Install Mod: unable to find suitable foldername for modpack $1", modfilename)
- end
- end
-
- if basefolder.type == "mod" then
- local targetfolder = basename
-
- if targetfolder == nil then
- targetfolder = modmgr.identify_modname(basefolder.path,"init.lua")
- end
-
- --if heuristic failed try to use current foldername
- if targetfolder == nil then
- targetfolder = get_last_folder(basefolder.path)
- end
-
- if targetfolder ~= nil and modmgr.isValidModname(targetfolder) then
- local targetpath = engine.get_modpath() .. DIR_DELIM .. targetfolder
- engine.copy_dir(basefolder.path,targetpath)
- else
- gamedata.errormessage = fgettext("Install Mod: unable to find real modname for: $1", modfilename)
- end
- end
-
- engine.delete_dir(modpath)
-
- modmgr.refresh_globals()
-
-end
-
---------------------------------------------------------------------------------
-function modmgr.handle_rename_modpack_buttons(fields)
-
- if fields["dlg_rename_modpack_confirm"] ~= nil then
- local mod = filterlist.get_list(modmgr.global_mods)[modmgr.selected_mod]
- local oldpath = engine.get_modpath() .. DIR_DELIM .. mod.name
- local targetpath = engine.get_modpath() .. DIR_DELIM .. fields["te_modpack_name"]
- engine.copy_dir(oldpath,targetpath,false)
- modmgr.refresh_globals()
- modmgr.selected_mod = filterlist.get_current_index(modmgr.global_mods,
- filterlist.raw_index_by_uid(modmgr.global_mods, fields["te_modpack_name"]))
- end
-
- return {
- is_dialog = false,
- show_buttons = true,
- current_tab = engine.setting_get("main_menu_tab")
- }
-end
---------------------------------------------------------------------------------
-function modmgr.handle_configure_world_buttons(fields)
- if fields["world_config_modlist"] ~= nil then
- local event = engine.explode_textlist_event(fields["world_config_modlist"])
- modmgr.world_config_selected_mod = event.index
-
- if event.type == "DCL" then
- modmgr.world_config_enable_mod(nil)
- end
- end
-
- if fields["key_enter"] ~= nil then
- modmgr.world_config_enable_mod(nil)
- end
-
- if fields["cb_mod_enable"] ~= nil then
- local toset = engine.is_yes(fields["cb_mod_enable"])
- modmgr.world_config_enable_mod(toset)
- end
-
- if fields["btn_mp_enable"] ~= nil or
- fields["btn_mp_disable"] then
- local toset = (fields["btn_mp_enable"] ~= nil)
- modmgr.world_config_enable_mod(toset)
- end
-
- if fields["cb_hide_gamemods"] ~= nil then
- local current = filterlist.get_filtercriteria(modmgr.modlist)
-
- if current == nil then
- current = {}
- end
-
- if engine.is_yes(fields["cb_hide_gamemods"]) then
- current.hide_game = true
- modmgr.hide_gamemods = true
- else
- current.hide_game = false
- modmgr.hide_gamemods = false
- end
-
- filterlist.set_filtercriteria(modmgr.modlist,current)
- end
-
- if fields["cb_hide_mpcontent"] ~= nil then
- local current = filterlist.get_filtercriteria(modmgr.modlist)
-
- if current == nil then
- current = {}
- end
-
- if engine.is_yes(fields["cb_hide_mpcontent"]) then
- current.hide_modpackcontents = true
- modmgr.hide_modpackcontents = true
- else
- current.hide_modpackcontents = false
- modmgr.hide_modpackcontents = false
- end
-
- filterlist.set_filtercriteria(modmgr.modlist,current)
- end
-
- if fields["btn_config_world_save"] then
- local worldspec = engine.get_worlds()[modmgr.world_config_selected_world]
-
- local filename = worldspec.path ..
- DIR_DELIM .. "world.mt"
-
- local worldfile = Settings(filename)
- local mods = worldfile:to_table()
-
- local rawlist = filterlist.get_raw_list(modmgr.modlist)
-
- local i,mod
- for i,mod in ipairs(rawlist) do
- if not mod.is_modpack and
- mod.typ ~= "game_mod" then
- if mod.enabled then
- worldfile:set("load_mod_"..mod.name, "true")
- else
- worldfile:set("load_mod_"..mod.name, "false")
- end
- mods["load_mod_"..mod.name] = nil
- end
- end
-
- -- Remove mods that are not present anymore
- for key,value in pairs(mods) do
- if key:sub(1,9) == "load_mod_" then
- worldfile:remove(key)
- end
- end
-
- if not worldfile:write() then
- engine.log("error", "Failed to write world config file")
- end
-
- modmgr.modlist = nil
- modmgr.worldconfig = nil
-
- return {
- is_dialog = false,
- show_buttons = true,
- current_tab = engine.setting_get("main_menu_tab")
- }
- end
-
- if fields["btn_config_world_cancel"] then
-
- modmgr.worldconfig = nil
-
- return {
- is_dialog = false,
- show_buttons = true,
- current_tab = engine.setting_get("main_menu_tab")
- }
- end
-
- if fields["btn_all_mods"] then
- local list = filterlist.get_raw_list(modmgr.modlist)
-
- for i=1,#list,1 do
- if list[i].typ ~= "game_mod" and
- not list[i].is_modpack then
- list[i].enabled = true
- end
- end
- end
-
-
-
- return nil
-end
---------------------------------------------------------------------------------
-function modmgr.world_config_enable_mod(toset)
- local mod = filterlist.get_list(modmgr.modlist)
- [engine.get_textlist_index("world_config_modlist")]
-
- if mod.typ == "game_mod" then
- -- game mods can't be enabled or disabled
- elseif not mod.is_modpack then
- if toset == nil then
- mod.enabled = not mod.enabled
- else
- mod.enabled = toset
- end
- else
- local list = filterlist.get_raw_list(modmgr.modlist)
- for i=1,#list,1 do
- if list[i].modpack == mod.name then
- if toset == nil then
- toset = not list[i].enabled
- end
- list[i].enabled = toset
- end
- end
- end
-end
---------------------------------------------------------------------------------
-function modmgr.handle_delete_mod_buttons(fields)
- local mod = filterlist.get_list(modmgr.global_mods)[modmgr.selected_mod]
-
- if fields["dlg_delete_mod_confirm"] ~= nil then
-
- if mod.path ~= nil and
- mod.path ~= "" and
- mod.path ~= engine.get_modpath() then
- if not engine.delete_dir(mod.path) then
- gamedata.errormessage = fgettext("Modmgr: failed to delete \"$1\"", mod.path)
- end
- modmgr.refresh_globals()
- else
- gamedata.errormessage = fgettext("Modmgr: invalid modpath \"$1\"", mod.path)
- end
- end
-
- return {
- is_dialog = false,
- show_buttons = true,
- current_tab = engine.setting_get("main_menu_tab")
- }
-end
-
---------------------------------------------------------------------------------
-function modmgr.dialog_delete_mod()
-
- local mod = filterlist.get_list(modmgr.global_mods)[modmgr.selected_mod]
-
- local retval =
- "field[1.75,1;10,3;;" .. fgettext("Are you sure you want to delete \"$1\"?", mod.name) .. ";]"..
- "button[4,4.2;1,0.5;dlg_delete_mod_confirm;" .. fgettext("Yes") .. "]" ..
- "button[6.5,4.2;3,0.5;dlg_delete_mod_cancel;" .. fgettext("No of course not!") .. "]"
-
- return retval
-end
-
---------------------------------------------------------------------------------
-function modmgr.preparemodlist(data)
- local retval = {}
-
- local global_mods = {}
- local game_mods = {}
-
- --read global mods
- local modpath = engine.get_modpath()
-
- if modpath ~= nil and
- modpath ~= "" then
- get_mods(modpath,global_mods)
- end
-
- for i=1,#global_mods,1 do
- global_mods[i].typ = "global_mod"
- table.insert(retval,global_mods[i])
- end
-
- --read game mods
- local gamespec = gamemgr.find_by_gameid(data.gameid)
- gamemgr.get_game_mods(gamespec, game_mods)
-
- for i=1,#game_mods,1 do
- game_mods[i].typ = "game_mod"
- table.insert(retval,game_mods[i])
- end
-
- if data.worldpath == nil then
- return retval
- end
-
- --read world mod configuration
- local filename = data.worldpath ..
- DIR_DELIM .. "world.mt"
-
- local worldfile = Settings(filename)
-
- for key,value in pairs(worldfile:to_table()) do
- if key:sub(1, 9) == "load_mod_" then
- key = key:sub(10)
- local element = nil
- for i=1,#retval,1 do
- if retval[i].name == key then
- element = retval[i]
- break
- end
- end
- if element ~= nil then
- element.enabled = engine.is_yes(value)
- else
- engine.log("info", "Mod: " .. key .. " " .. dump(value) .. " but not found")
- end
- end
- end
-
- return retval
-end
-
---------------------------------------------------------------------------------
-function modmgr.init_worldconfig()
- modmgr.precheck()
- local worldspec = engine.get_worlds()[modmgr.world_config_selected_world]
-
- if worldspec ~= nil then
- --read worldconfig
- modmgr.worldconfig = modmgr.get_worldconfig(worldspec.path)
-
- if modmgr.worldconfig.id == nil or
- modmgr.worldconfig.id == "" then
- modmgr.worldconfig = nil
- return false
- end
-
- modmgr.modlist = filterlist.create(
- modmgr.preparemodlist, --refresh
- modmgr.comparemod, --compare
- function(element,uid) --uid match
- if element.name == uid then
- return true
- end
- end,
- function(element,criteria)
- if criteria.hide_game and
- element.typ == "game_mod" then
- return false
- end
-
- if criteria.hide_modpackcontents and
- element.modpack ~= nil then
- return false
- end
- return true
- end, --filter
- { worldpath= worldspec.path,
- gameid = worldspec.gameid }
- )
-
- filterlist.set_filtercriteria(modmgr.modlist, {
- hide_game=modmgr.hide_gamemods,
- hide_modpackcontents= modmgr.hide_modpackcontents
- })
- filterlist.add_sort_mechanism(modmgr.modlist, "alphabetic", sort_mod_list)
- filterlist.set_sortmode(modmgr.modlist, "alphabetic")
-
- return true
- end
-
- return false
-end
-
---------------------------------------------------------------------------------
-function modmgr.comparemod(elem1,elem2)
- if elem1 == nil or elem2 == nil then
- return false
- end
- if elem1.name ~= elem2.name then
- return false
- end
- if elem1.is_modpack ~= elem2.is_modpack then
- return false
- end
- if elem1.typ ~= elem2.typ then
- return false
- end
- if elem1.modpack ~= elem2.modpack then
- return false
- end
-
- if elem1.path ~= elem2.path then
- return false
- end
-
- return true
-end
-
---------------------------------------------------------------------------------
-function modmgr.gettab(name)
- local retval = ""
-
- if name == "mod_mgr" then
- retval = retval .. modmgr.tab()
- end
-
- if name == "dialog_rename_modpack" then
- retval = retval .. modmgr.dialog_rename_modpack()
- end
-
- if name == "dialog_delete_mod" then
- retval = retval .. modmgr.dialog_delete_mod()
- end
-
- if name == "dialog_configure_world" then
- retval = retval .. modmgr.dialog_configure_world()
- end
-
- return retval
-end
-
---------------------------------------------------------------------------------
-function modmgr.mod_exists(basename)
-
- if modmgr.global_mods == nil then
- modmgr.refresh_globals()
- end
-
- if filterlist.raw_index_by_uid(modmgr.global_mods,basename) > 0 then
- return true
- end
-
- return false
-end
-
---------------------------------------------------------------------------------
-function modmgr.get_global_mod(idx)
-
- if modmgr.global_mods == nil then
- return nil
- end
-
- if idx == nil or idx < 1 or idx > filterlist.size(modmgr.global_mods) then
- return nil
- end
-
- return filterlist.get_list(modmgr.global_mods)[idx]
-end
-
---------------------------------------------------------------------------------
-function modmgr.refresh_globals()
- modmgr.global_mods = filterlist.create(
- modmgr.preparemodlist, --refresh
- modmgr.comparemod, --compare
- function(element,uid) --uid match
- if element.name == uid then
- return true
- end
- end,
- nil, --filter
- {}
- )
- filterlist.add_sort_mechanism(modmgr.global_mods, "alphabetic", sort_mod_list)
- filterlist.set_sortmode(modmgr.global_mods, "alphabetic")
-end
-
---------------------------------------------------------------------------------
-function modmgr.identify_filetype(name)
-
- if name:sub(-3):lower() == "zip" then
- return {
- name = name,
- type = "zip"
- }
- end
-
- if name:sub(-6):lower() == "tar.gz" or
- name:sub(-3):lower() == "tgz"then
- return {
- name = name,
- type = "tgz"
- }
- end
-
- if name:sub(-6):lower() == "tar.bz2" then
- return {
- name = name,
- type = "tbz"
- }
- end
-
- if name:sub(-2):lower() == "7z" then
- return {
- name = name,
- type = "7z"
- }
- end
-
- return {
- name = name,
- type = "ukn"
- }
-end
+++ /dev/null
---Minetest
---Copyright (C) 2013 sapier
---
---This program is free software; you can redistribute it and/or modify
---it under the terms of the GNU Lesser General Public License as published by
---the Free Software Foundation; either version 2.1 of the License, or
---(at your option) any later version.
---
---This program is distributed in the hope that it will be useful,
---but WITHOUT ANY WARRANTY; without even the implied warranty of
---MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
---GNU Lesser General Public License for more details.
---
---You should have received a copy of the GNU Lesser General Public License along
---with this program; if not, write to the Free Software Foundation, Inc.,
---51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
---------------------------------------------------------------------------------
-
---modstore implementation
-modstore = {}
-
---------------------------------------------------------------------------------
--- @function [parent=#modstore] init
-function modstore.init()
- modstore.tabnames = {}
-
- table.insert(modstore.tabnames,"dialog_modstore_unsorted")
- table.insert(modstore.tabnames,"dialog_modstore_search")
-
- modstore.modsperpage = 5
-
- modstore.basetexturedir = engine.get_texturepath() .. DIR_DELIM .. "base" ..
- DIR_DELIM .. "pack" .. DIR_DELIM
-
- modstore.lastmodtitle = ""
- modstore.last_search = ""
-
- modstore.searchlist = filterlist.create(
- function()
- if modstore.modlist_unsorted ~= nil and
- modstore.modlist_unsorted.data ~= nil then
- return modstore.modlist_unsorted.data
- end
- return {}
- end,
- function(element,modid)
- if element.id == modid then
- return true
- end
- return false
- end, --compare fct
- nil, --uid match fct
- function(element,substring)
- if substring == nil or
- substring == "" then
- return false
- end
- substring = substring:upper()
-
- if element.title ~= nil and
- element.title:upper():find(substring) ~= nil then
- return true
- end
-
- if element.details ~= nil and
- element.details.author ~= nil and
- element.details.author:upper():find(substring) ~= nil then
- return true
- end
-
- if element.details ~= nil and
- element.details.description ~= nil and
- element.details.description:upper():find(substring) ~= nil then
- return true
- end
- return false
- end --filter fct
- )
-
- modstore.current_list = nil
-end
-
---------------------------------------------------------------------------------
--- @function [parent=#modstore] nametoindex
-function modstore.nametoindex(name)
-
- for i=1,#modstore.tabnames,1 do
- if modstore.tabnames[i] == name then
- return i
- end
- end
-
- return 1
-end
-
---------------------------------------------------------------------------------
--- @function [parent=#modstore] getsuccessfuldialog
-function modstore.getsuccessfuldialog()
- local retval = ""
- retval = retval .. "size[6,2,true]"
- if modstore.lastmodentry ~= nil then
- retval = retval .. "label[0,0.25;" .. fgettext("Successfully installed:") .. "]"
- retval = retval .. "label[3,0.25;" .. modstore.lastmodentry.moddetails.title .. "]"
-
-
- retval = retval .. "label[0,0.75;" .. fgettext("Shortname:") .. "]"
- retval = retval .. "label[3,0.75;" .. engine.formspec_escape(modstore.lastmodentry.moddetails.basename) .. "]"
-
- end
- retval = retval .. "button[2.5,1.5;1,0.5;btn_confirm_mod_successfull;" .. fgettext("ok") .. "]"
-
-
- return retval
-end
-
---------------------------------------------------------------------------------
--- @function [parent=#modstore] gettab
-function modstore.gettab(tabname)
- local retval = ""
-
- local is_modstore_tab = false
-
- if tabname == "dialog_modstore_unsorted" then
- modstore.modsperpage = 5
- retval = modstore.getmodlist(modstore.modlist_unsorted)
- is_modstore_tab = true
- end
-
- if tabname == "dialog_modstore_search" then
- retval = modstore.getsearchpage()
- is_modstore_tab = true
- end
-
- if is_modstore_tab then
- return modstore.tabheader(tabname) .. retval
- end
-
- if tabname == "modstore_mod_installed" then
- return modstore.getsuccessfuldialog()
- end
-
- if tabname == "modstore_downloading" then
- return "size[6,2]label[0.25,0.75;" .. fgettext("Downloading") ..
- " " .. modstore.lastmodtitle .. " " ..
- fgettext("please wait...") .. "]"
- end
-
- return ""
-end
-
---------------------------------------------------------------------------------
--- @function [parent=#modstore] tabheader
-function modstore.tabheader(tabname)
- local retval = "size[12,10.25,true]"
- retval = retval .. "tabheader[-0.3,-0.99;modstore_tab;" ..
- "Unsorted,Search;" ..
- modstore.nametoindex(tabname) .. ";true;false]" ..
- "button[4,9.9;4,0.5;btn_modstore_close;" ..
- fgettext("Close modstore") .. "]"
-
- return retval
-end
-
---------------------------------------------------------------------------------
--- @function [parent=#modstore] handle_buttons
-function modstore.handle_buttons(current_tab,fields)
-
- if fields["modstore_tab"] then
- local index = tonumber(fields["modstore_tab"])
-
- if index > 0 and
- index <= #modstore.tabnames then
- if modstore.tabnames[index] == "dialog_modstore_search" then
- filterlist.set_filtercriteria(modstore.searchlist,modstore.last_search)
- filterlist.refresh(modstore.searchlist)
- modstore.modsperpage = 4
- modstore.currentlist = {
- page = 0,
- pagecount =
- math.ceil(filterlist.size(modstore.searchlist) / modstore.modsperpage),
- data = filterlist.get_list(modstore.searchlist),
- }
- end
-
- return {
- current_tab = modstore.tabnames[index],
- is_dialog = true,
- show_buttons = false
- }
- end
-
- end
-
- if fields["btn_modstore_page_up"] then
- if modstore.current_list ~= nil and modstore.current_list.page > 0 then
- modstore.current_list.page = modstore.current_list.page - 1
- end
- end
-
- if fields["btn_modstore_page_down"] then
- if modstore.current_list ~= nil and
- modstore.current_list.page <modstore.current_list.pagecount-1 then
- modstore.current_list.page = modstore.current_list.page +1
- end
- end
-
- if fields["btn_hidden_close_download"] ~= nil then
- if fields["btn_hidden_close_download"].successfull then
- modstore.lastmodentry = fields["btn_hidden_close_download"]
- return {
- current_tab = "modstore_mod_installed",
- is_dialog = true,
- show_buttons = false
- }
- else
- modstore.lastmodtitle = ""
- return {
- current_tab = modstore.tabnames[1],
- is_dialog = true,
- show_buttons = false
- }
- end
- end
-
- if fields["btn_confirm_mod_successfull"] then
- modstore.lastmodentry = nil
- modstore.lastmodtitle = ""
- return {
- current_tab = modstore.tabnames[1],
- is_dialog = true,
- show_buttons = false
- }
- end
-
- if fields["btn_modstore_search"] or
- (fields["key_enter"] and fields["te_modstore_search"] ~= nil) then
- modstore.last_search = fields["te_modstore_search"]
- filterlist.set_filtercriteria(modstore.searchlist,fields["te_modstore_search"])
- filterlist.refresh(modstore.searchlist)
- modstore.currentlist = {
- page = 0,
- pagecount = math.ceil(filterlist.size(modstore.searchlist) / modstore.modsperpage),
- data = filterlist.get_list(modstore.searchlist),
- }
- end
-
-
- if fields["btn_modstore_close"] then
- return {
- is_dialog = false,
- show_buttons = true,
- current_tab = engine.setting_get("main_menu_tab")
- }
- end
-
- for key,value in pairs(fields) do
- local foundat = key:find("btn_install_mod_")
- if ( foundat == 1) then
- local modid = tonumber(key:sub(17))
- for i=1,#modstore.modlist_unsorted.data,1 do
- if modstore.modlist_unsorted.data[i].id == modid then
- local moddetails = modstore.modlist_unsorted.data[i].details
-
- if modstore.lastmodtitle ~= "" then
- modstore.lastmodtitle = modstore.lastmodtitle .. ", "
- end
-
- modstore.lastmodtitle = modstore.lastmodtitle .. moddetails.title
-
- engine.handle_async(
- function(param)
-
- local fullurl = engine.setting_get("modstore_download_url") ..
- param.moddetails.download_url
-
- if param.version ~= nil then
- local found = false
- for i=1,#param.moddetails.versions, 1 do
- if param.moddetails.versions[i].date:sub(1,10) == param.version then
- fullurl = engine.setting_get("modstore_download_url") ..
- param.moddetails.versions[i].download_url
- found = true
- end
- end
-
- if not found then
- return {
- moddetails = param.moddetails,
- successfull = false
- }
- end
- end
-
- if engine.download_file(fullurl,param.filename) then
- return {
- texturename = param.texturename,
- moddetails = param.moddetails,
- filename = param.filename,
- successfull = true
- }
- else
- return {
- moddetails = param.moddetails,
- successfull = false
- }
- end
- end,
- {
- moddetails = moddetails,
- version = fields["dd_version" .. modid],
- filename = os.tempfolder() .. "_MODNAME_" .. moddetails.basename .. ".zip",
- texturename = modstore.modlist_unsorted.data[i].texturename
- },
- function(result)
- if result.successfull then
- modmgr.installmod(result.filename,result.moddetails.basename)
- os.remove(result.filename)
- else
- gamedata.errormessage = "Failed to download " .. result.moddetails.title
- end
-
- if gamedata.errormessage == nil then
- engine.button_handler({btn_hidden_close_download=result})
- else
- engine.button_handler({btn_hidden_close_download={successfull=false}})
- end
- end
- )
-
- return {
- current_tab = "modstore_downloading",
- is_dialog = true,
- show_buttons = false,
- ignore_menu_quit = true
- }
- end
- end
- break
- end
- end
-end
-
---------------------------------------------------------------------------------
--- @function [parent=#modstore] update_modlist
-function modstore.update_modlist()
- modstore.modlist_unsorted = {}
- modstore.modlist_unsorted.data = {}
- modstore.modlist_unsorted.pagecount = 1
- modstore.modlist_unsorted.page = 0
-
- engine.handle_async(
- function(param)
- return engine.get_modstore_list()
- end,
- nil,
- function(result)
- if result ~= nil then
- modstore.modlist_unsorted = {}
- modstore.modlist_unsorted.data = result
-
- if modstore.modlist_unsorted.data ~= nil then
- modstore.modlist_unsorted.pagecount =
- math.ceil((#modstore.modlist_unsorted.data / modstore.modsperpage))
- else
- modstore.modlist_unsorted.data = {}
- modstore.modlist_unsorted.pagecount = 1
- end
- modstore.modlist_unsorted.page = 0
- modstore.fetchdetails()
- engine.event_handler("Refresh")
- end
- end
- )
-end
-
---------------------------------------------------------------------------------
--- @function [parent=#modstore] fetchdetails
-function modstore.fetchdetails()
-
- for i=1,#modstore.modlist_unsorted.data,1 do
- engine.handle_async(
- function(param)
- param.details = engine.get_modstore_details(tostring(param.modid))
- return param
- end,
- {
- modid=modstore.modlist_unsorted.data[i].id,
- listindex=i
- },
- function(result)
- if result ~= nil and
- modstore.modlist_unsorted ~= nil
- and modstore.modlist_unsorted.data ~= nil and
- modstore.modlist_unsorted.data[result.listindex] ~= nil and
- modstore.modlist_unsorted.data[result.listindex].id ~= nil then
-
- modstore.modlist_unsorted.data[result.listindex].details = result.details
- engine.event_handler("Refresh")
- end
- end
- )
- end
-end
-
---------------------------------------------------------------------------------
--- @function [parent=#modstore] getscreenshot
-function modstore.getscreenshot(ypos,listentry)
-
- if listentry.details ~= nil and
- (listentry.details.screenshot_url == nil or
- listentry.details.screenshot_url == "") then
-
- if listentry.texturename == nil then
- listentry.texturename = modstore.basetexturedir .. "no_screenshot.png"
- end
-
- return "image[0,".. ypos .. ";3,2;" ..
- engine.formspec_escape(listentry.texturename) .. "]"
- end
-
- if listentry.details ~= nil and
- listentry.texturename == nil then
- --make sure we don't download multiple times
- listentry.texturename = "in progress"
-
- --prepare url and filename
- local fullurl = engine.setting_get("modstore_download_url") ..
- listentry.details.screenshot_url
- local filename = os.tempfolder() .. "_MID_" .. listentry.id
-
- --trigger download
- engine.handle_async(
- --first param is downloadfct
- function(param)
- param.successfull = engine.download_file(param.fullurl,param.filename)
- return param
- end,
- --second parameter is data passed to async job
- {
- fullurl = fullurl,
- filename = filename,
- modid = listentry.id
- },
- --integrate result to raw list
- function(result)
- if result.successfull then
- local found = false
- for i=1,#modstore.modlist_unsorted.data,1 do
- if modstore.modlist_unsorted.data[i].id == result.modid then
- found = true
- modstore.modlist_unsorted.data[i].texturename = result.filename
- break
- end
- end
- if found then
- engine.event_handler("Refresh")
- else
- engine.log("error","got screenshot but didn't find matching mod: " .. result.modid)
- end
- end
- end
- )
- end
-
- if listentry.texturename ~= nil and
- listentry.texturename ~= "in progress" then
- return "image[0,".. ypos .. ";3,2;" ..
- engine.formspec_escape(listentry.texturename) .. "]"
- end
-
- return ""
-end
-
---------------------------------------------------------------------------------
---@function [parent=#modstore] getshortmodinfo
-function modstore.getshortmodinfo(ypos,listentry,details)
- local retval = ""
-
- retval = retval .. "box[0," .. ypos .. ";11.4,1.75;#FFFFFF]"
-
- --screenshot
- retval = retval .. modstore.getscreenshot(ypos,listentry)
-
- --title + author
- retval = retval .."label[2.75," .. ypos .. ";" ..
- engine.formspec_escape(details.title) .. " (" .. details.author .. ")]"
-
- --description
- local descriptiony = ypos + 0.5
- retval = retval .. "textarea[3," .. descriptiony .. ";6.5,1.55;;" ..
- engine.formspec_escape(details.description) .. ";]"
-
- --rating
- local ratingy = ypos
- retval = retval .."label[7," .. ratingy .. ";" ..
- fgettext("Rating") .. ":]"
- retval = retval .. "label[8.7," .. ratingy .. ";" .. details.rating .."]"
-
- --versions (IMPORTANT has to be defined AFTER rating)
- if details.versions ~= nil and
- #details.versions > 1 then
- local versiony = ypos + 0.05
- retval = retval .. "dropdown[9.1," .. versiony .. ";2.48,0.25;dd_version" .. details.id .. ";"
- local versions = ""
- for i=1,#details.versions , 1 do
- if versions ~= "" then
- versions = versions .. ","
- end
-
- versions = versions .. details.versions[i].date:sub(1,10)
- end
- retval = retval .. versions .. ";1]"
- end
-
- if details.basename then
- --install button
- local buttony = ypos + 1.2
- retval = retval .."button[9.1," .. buttony .. ";2.5,0.5;btn_install_mod_" .. details.id .. ";"
-
- if modmgr.mod_exists(details.basename) then
- retval = retval .. fgettext("re-Install") .."]"
- else
- retval = retval .. fgettext("Install") .."]"
- end
- end
-
- return retval
-end
-
---------------------------------------------------------------------------------
---@function [parent=#modstore] getmodlist
-function modstore.getmodlist(list,yoffset)
-
- modstore.current_list = list
-
- if #list.data == 0 then
- return ""
- end
-
- if yoffset == nil then
- yoffset = 0
- end
-
- local scrollbar = ""
- scrollbar = scrollbar .. "label[0.1,9.5;"
- .. fgettext("Page $1 of $2", list.page+1, list.pagecount) .. "]"
- scrollbar = scrollbar .. "box[11.6," .. (yoffset + 0.35) .. ";0.28,"
- .. (8.6 - yoffset) .. ";#000000]"
- local scrollbarpos = (yoffset + 0.75) +
- ((7.7 -yoffset)/(list.pagecount-1)) * list.page
- scrollbar = scrollbar .. "box[11.6," ..scrollbarpos .. ";0.28,0.5;#32CD32]"
- scrollbar = scrollbar .. "button[11.6," .. (yoffset + (0.3))
- .. ";0.5,0.5;btn_modstore_page_up;^]"
- scrollbar = scrollbar .. "button[11.6," .. 9.0
- .. ";0.5,0.5;btn_modstore_page_down;v]"
-
- local retval = ""
-
- local endmod = (list.page * modstore.modsperpage) + modstore.modsperpage
-
- if (endmod > #list.data) then
- endmod = #list.data
- end
-
- for i=(list.page * modstore.modsperpage) +1, endmod, 1 do
- --getmoddetails
- local details = list.data[i].details
-
- if details == nil then
- details = {}
- details.title = list.data[i].title
- details.author = ""
- details.rating = -1
- details.description = ""
- end
-
- if details ~= nil then
- local screenshot_ypos =
- yoffset +(i-1 - (list.page * modstore.modsperpage))*1.9 +0.2
-
- retval = retval .. modstore.getshortmodinfo(screenshot_ypos,
- list.data[i],
- details)
- end
- end
-
- return retval .. scrollbar
-end
-
---------------------------------------------------------------------------------
---@function [parent=#modstore] getsearchpage
-function modstore.getsearchpage()
- local retval = ""
- local search = ""
-
- if modstore.last_search ~= nil then
- search = modstore.last_search
- end
-
- retval = retval ..
- "button[9.5,0.2;2.5,0.5;btn_modstore_search;".. fgettext("Search") .. "]" ..
- "field[0.5,0.5;9,0.5;te_modstore_search;;" .. search .. "]"
-
-
- --show 4 mods only
- modstore.modsperpage = 4
- retval = retval ..
- modstore.getmodlist(
- modstore.currentlist,
- 1.75)
-
- return retval;
-end
-
+++ /dev/null
--- 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")
-
+++ /dev/null
--- Minetest: builtin/serialize.lua
-
--- https://github.com/fab13n/metalua/blob/no-dll/src/lib/serialize.lua
--- Copyright (c) 2006-2997 Fabien Fleutot <metalua@gmail.com>
--- License: MIT
---------------------------------------------------------------------------------
--- Serialize an object into a source code string. This string, when passed as
--- an argument to deserialize(), returns an object structurally identical
--- to the original one. The following are currently supported:
--- * strings, numbers, booleans, nil
--- * tables thereof. Tables can have shared part, but can't be recursive yet.
--- Caveat: metatables and environments aren't saved.
---------------------------------------------------------------------------------
-
-local no_identity = { number=1, boolean=1, string=1, ['nil']=1 }
-
-function minetest.serialize(x)
-
- local gensym_max = 0 -- index of the gensym() symbol generator
- local seen_once = { } -- element->true set of elements seen exactly once in the table
- local multiple = { } -- element->varname set of elements seen more than once
- local nested = { } -- transient, set of elements currently being traversed
- local nest_points = { }
- local nest_patches = { }
-
- local function gensym()
- gensym_max = gensym_max + 1 ; return gensym_max
- end
-
- -----------------------------------------------------------------------------
- -- nest_points are places where a table appears within itself, directly or not.
- -- for instance, all of these chunks create nest points in table x:
- -- "x = { }; x[x] = 1", "x = { }; x[1] = x", "x = { }; x[1] = { y = { x } }".
- -- To handle those, two tables are created by mark_nest_point:
- -- * nest_points [parent] associates all keys and values in table parent which
- -- create a nest_point with boolean `true'
- -- * nest_patches contain a list of { parent, key, value } tuples creating
- -- a nest point. They're all dumped after all the other table operations
- -- have been performed.
- --
- -- mark_nest_point (p, k, v) fills tables nest_points and nest_patches with
- -- informations required to remember that key/value (k,v) create a nest point
- -- in table parent. It also marks `parent' as occuring multiple times, since
- -- several references to it will be required in order to patch the nest
- -- points.
- -----------------------------------------------------------------------------
- local function mark_nest_point (parent, k, v)
- local nk, nv = nested[k], nested[v]
- assert (not nk or seen_once[k] or multiple[k])
- assert (not nv or seen_once[v] or multiple[v])
- local mode = (nk and nv and "kv") or (nk and "k") or ("v")
- local parent_np = nest_points [parent]
- local pair = { k, v }
- if not parent_np then parent_np = { }; nest_points [parent] = parent_np end
- parent_np [k], parent_np [v] = nk, nv
- table.insert (nest_patches, { parent, k, v })
- seen_once [parent], multiple [parent] = nil, true
- end
-
- -----------------------------------------------------------------------------
- -- First pass, list the tables and functions which appear more than once in x
- -----------------------------------------------------------------------------
- local function mark_multiple_occurences (x)
- if no_identity [type(x)] then return end
- if seen_once [x] then seen_once [x], multiple [x] = nil, true
- elseif multiple [x] then -- pass
- else seen_once [x] = true end
-
- if type (x) == 'table' then
- nested [x] = true
- for k, v in pairs (x) do
- if nested[k] or nested[v] then mark_nest_point (x, k, v) else
- mark_multiple_occurences (k)
- mark_multiple_occurences (v)
- end
- end
- nested [x] = nil
- end
- end
-
- local dumped = { } -- multiply occuring values already dumped in localdefs
- local localdefs = { } -- already dumped local definitions as source code lines
-
- -- mutually recursive functions:
- local dump_val, dump_or_ref_val
-
- --------------------------------------------------------------------
- -- if x occurs multiple times, dump the local var rather than the
- -- value. If it's the first time it's dumped, also dump the content
- -- in localdefs.
- --------------------------------------------------------------------
- function dump_or_ref_val (x)
- if nested[x] then return 'false' end -- placeholder for recursive reference
- if not multiple[x] then return dump_val (x) end
- local var = dumped [x]
- if var then return "_[" .. var .. "]" end -- already referenced
- local val = dump_val(x) -- first occurence, create and register reference
- var = gensym()
- table.insert(localdefs, "_["..var.."]="..val)
- dumped [x] = var
- return "_[" .. var .. "]"
- end
-
- -----------------------------------------------------------------------------
- -- Second pass, dump the object; subparts occuring multiple times are dumped
- -- in local variables which can be referenced multiple times;
- -- care is taken to dump locla vars in asensible order.
- -----------------------------------------------------------------------------
- function dump_val(x)
- local t = type(x)
- if x==nil then return 'nil'
- elseif t=="number" then return tostring(x)
- elseif t=="string" then return string.format("%q", x)
- elseif t=="boolean" then return x and "true" or "false"
- elseif t=="function" then
- return "loadstring("..string.format("%q", string.dump(x))..")"
- elseif t=="table" then
- local acc = { }
- local idx_dumped = { }
- local np = nest_points [x]
- for i, v in ipairs(x) do
- if np and np[v] then
- table.insert (acc, 'false') -- placeholder
- else
- table.insert (acc, dump_or_ref_val(v))
- end
- idx_dumped[i] = true
- end
- for k, v in pairs(x) do
- if np and (np[k] or np[v]) then
- --check_multiple(k); check_multiple(v) -- force dumps in localdefs
- elseif not idx_dumped[k] then
- table.insert (acc, "[" .. dump_or_ref_val(k) .. "] = " .. dump_or_ref_val(v))
- end
- end
- return "{ "..table.concat(acc,", ").." }"
- else
- error ("Can't serialize data of type "..t)
- end
- end
-
- local function dump_nest_patches()
- for _, entry in ipairs(nest_patches) do
- local p, k, v = unpack (entry)
- assert (multiple[p])
- local set = dump_or_ref_val (p) .. "[" .. dump_or_ref_val (k) .. "] = " ..
- dump_or_ref_val (v) .. " -- rec "
- table.insert (localdefs, set)
- end
- end
-
- mark_multiple_occurences (x)
- local toplevel = dump_or_ref_val (x)
- dump_nest_patches()
-
- if next (localdefs) then
- return "local _={ }\n" ..
- table.concat (localdefs, "\n") ..
- "\nreturn " .. toplevel
- else
- return "return " .. toplevel
- end
-end
-
--- Deserialization.
--- http://stackoverflow.com/questions/5958818/loading-serialized-data-into-a-table
---
-
-local env = {
- loadstring = loadstring,
-}
-
-local function noop() end
-
-local safe_env = {
- loadstring = noop,
-}
-
-local function stringtotable(sdata, safe)
- if sdata:byte(1) == 27 then return nil, "binary bytecode prohibited" end
- local f, message = assert(loadstring(sdata))
- if not f then return nil, message end
- if safe then
- setfenv(f, safe_env)
- else
- setfenv(f, env)
- end
- return f()
-end
-
-function minetest.deserialize(sdata, safe)
- local table = {}
- local okay, results = pcall(stringtotable, sdata, safe)
- if okay then
- return results
- end
- minetest.log('error', 'minetest.deserialize(): '.. results)
- return nil
-end
-
--- Run some unit tests
-local function unit_test()
- function unitTest(name, success)
- if not success then
- error(name .. ': failed')
- end
- end
-
- unittest_input = {cat={sound="nyan", speed=400}, dog={sound="woof"}}
- unittest_output = minetest.deserialize(minetest.serialize(unittest_input))
-
- unitTest("test 1a", unittest_input.cat.sound == unittest_output.cat.sound)
- unitTest("test 1b", unittest_input.cat.speed == unittest_output.cat.speed)
- unitTest("test 1c", unittest_input.dog.sound == unittest_output.dog.sound)
-
- unittest_input = {escapechars="\n\r\t\v\\\"\'", noneuropean="θשׁ٩∂"}
- unittest_output = minetest.deserialize(minetest.serialize(unittest_input))
- unitTest("test 3a", unittest_input.escapechars == unittest_output.escapechars)
- unitTest("test 3b", unittest_input.noneuropean == unittest_output.noneuropean)
-end
-unit_test() -- Run it
-unit_test = nil -- Hide it
-
+++ /dev/null
-
-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)
+++ /dev/null
--- 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)
-
+++ /dev/null
-
-vector = {}
-
-local function assert_vector(v)
- assert(type(v) == "table" and v.x and v.y and v.z, "Invalid vector")
-end
-
-function vector.new(a, b, c)
- if type(a) == "table" then
- assert(a.x and a.y and a.z, "Invalid vector passed to vector.new()")
- return {x=a.x, y=a.y, z=a.z}
- elseif a then
- assert(b and c, "Invalid arguments for vector.new()")
- return {x=a, y=b, z=c}
- end
- return {x=0, y=0, z=0}
-end
-
-function vector.equals(a, b)
- assert_vector(a)
- assert_vector(b)
- return a.x == b.x and
- a.y == b.y and
- a.z == b.z
-end
-
-function vector.length(v)
- assert_vector(v)
- return math.hypot(v.x, math.hypot(v.y, v.z))
-end
-
-function vector.normalize(v)
- assert_vector(v)
- local len = vector.length(v)
- if len == 0 then
- return {x=0, y=0, z=0}
- else
- return vector.divide(v, len)
- end
-end
-
-function vector.round(v)
- assert_vector(v)
- return {
- x = math.floor(v.x + 0.5),
- y = math.floor(v.y + 0.5),
- z = math.floor(v.z + 0.5)
- }
-end
-
-function vector.distance(a, b)
- assert_vector(a)
- assert_vector(b)
- local x = a.x - b.x
- local y = a.y - b.y
- local z = a.z - b.z
- return math.hypot(x, math.hypot(y, z))
-end
-
-function vector.direction(pos1, pos2)
- assert_vector(pos1)
- assert_vector(pos2)
- local x_raw = pos2.x - pos1.x
- local y_raw = pos2.y - pos1.y
- local z_raw = pos2.z - pos1.z
- local x_abs = math.abs(x_raw)
- local y_abs = math.abs(y_raw)
- local z_abs = math.abs(z_raw)
- if x_abs >= y_abs and
- x_abs >= z_abs then
- y_raw = y_raw * (1 / x_abs)
- z_raw = z_raw * (1 / x_abs)
- x_raw = x_raw / x_abs
- end
- if y_abs >= x_abs and
- y_abs >= z_abs then
- x_raw = x_raw * (1 / y_abs)
- z_raw = z_raw * (1 / y_abs)
- y_raw = y_raw / y_abs
- end
- if z_abs >= y_abs and
- z_abs >= x_abs then
- x_raw = x_raw * (1 / z_abs)
- y_raw = y_raw * (1 / z_abs)
- z_raw = z_raw / z_abs
- end
- return {x=x_raw, y=y_raw, z=z_raw}
-end
-
-
-function vector.add(a, b)
- assert_vector(a)
- if type(b) == "table" then
- assert_vector(b)
- return {x = a.x + b.x,
- y = a.y + b.y,
- z = a.z + b.z}
- else
- return {x = a.x + b,
- y = a.y + b,
- z = a.z + b}
- end
-end
-
-function vector.subtract(a, b)
- assert_vector(a)
- if type(b) == "table" then
- assert_vector(b)
- return {x = a.x - b.x,
- y = a.y - b.y,
- z = a.z - b.z}
- else
- return {x = a.x - b,
- y = a.y - b,
- z = a.z - b}
- end
-end
-
-function vector.multiply(a, b)
- assert_vector(a)
- if type(b) == "table" then
- assert_vector(b)
- return {x = a.x * b.x,
- y = a.y * b.y,
- z = a.z * b.z}
- else
- return {x = a.x * b,
- y = a.y * b,
- z = a.z * b}
- end
-end
-
-function vector.divide(a, b)
- assert_vector(a)
- if type(b) == "table" then
- assert_vector(b)
- return {x = a.x / b.x,
- y = a.y / b.y,
- z = a.z / b.z}
- else
- return {x = a.x / b,
- y = a.y / b,
- z = a.z / b}
- end
-end
-
+++ /dev/null
-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
settings->setDefault("enable_ipv6", "true");
settings->setDefault("ipv6_server", "false");
- settings->setDefault("main_menu_script","");
- settings->setDefault("main_menu_mod_mgr","1");
- settings->setDefault("main_menu_game_mgr","0");
+ settings->setDefault("main_menu_path", "");
+ settings->setDefault("main_menu_mod_mgr", "1");
+ settings->setDefault("main_menu_game_mgr", "0");
settings->setDefault("modstore_download_url", "https://forum.minetest.net/media/");
settings->setDefault("modstore_listmods_url", "https://forum.minetest.net/mmdb/mods/");
settings->setDefault("modstore_details_url", "https://forum.minetest.net/mmdb/mod/*/");
m_formspecgui = new FormspecFormSource("");
/* Create menu */
- m_menu =
- new GUIFormSpecMenu( m_device,
- m_parent,
- -1,
- m_menumanager,
- 0 /* &client */,
- 0 /* gamedef */,
- m_texture_source,
- m_formspecgui,
- m_buttonhandler,
- NULL);
+ m_menu = new GUIFormSpecMenu(m_device,
+ m_parent,
+ -1,
+ m_menumanager,
+ NULL /* &client */,
+ NULL /* gamedef */,
+ m_texture_source,
+ m_formspecgui,
+ m_buttonhandler,
+ NULL);
m_menu->allowClose(false);
m_menu->lockSize(true,v2u32(800,600));
/******************************************************************************/
bool GUIEngine::loadMainMenuScript()
{
- // Try custom menu script (main_menu_script)
+ // Try custom menu script (main_menu_path)
- std::string menuscript = g_settings->get("main_menu_script");
- if(menuscript != "") {
- m_scriptdir = fs::RemoveLastPathComponent(menuscript);
-
- if(m_script->loadMod(menuscript, "__custommenu")) {
- // custom menu script loaded
- return true;
- }
- else {
- infostream
- << "GUIEngine: execution of custom menu: \""
- << menuscript << "\" failed!"
- << std::endl
- << "\tfalling back to builtin menu"
- << std::endl;
- }
+ m_scriptdir = g_settings->get("main_menu_path");
+ if (m_scriptdir.empty()) {
+ m_scriptdir = porting::path_share + DIR_DELIM "builtin" + DIR_DELIM "mainmenu";
}
- // Try builtin menu script (main_menu_script)
-
- std::string builtin_menuscript =
- porting::path_share + DIR_DELIM + "builtin"
- + DIR_DELIM + "mainmenu.lua";
-
- m_scriptdir = fs::RemoveRelativePathComponents(
- fs::RemoveLastPathComponent(builtin_menuscript));
-
- if(m_script->loadMod(builtin_menuscript, "__builtinmenu")) {
- // builtin menu script loaded
+ std::string script = porting::path_share + DIR_DELIM "builtin" + DIR_DELIM "init.lua";
+ if (m_script->loadScript(script)) {
+ // Menu script loaded
return true;
- }
- else {
- errorstream
- << "GUIEngine: unable to load builtin menu"
- << std::endl;
+ } else {
+ infostream
+ << "GUIEngine: execution of menu script in: \""
+ << m_scriptdir << "\" failed!" << std::endl;
}
return false;
#include "lualib.h"
}
+#include "server.h"
#include "s_async.h"
#include "log.h"
#include "filesys.h"
lua_pushstring(L, DIR_DELIM);
lua_setglobal(L, "DIR_DELIM");
- lua_pushstring(L,
- (porting::path_share + DIR_DELIM + "builtin").c_str());
- lua_setglobal(L, "SCRIPTDIR");
+ // Push builtin initialization type
+ lua_pushstring(L, "async");
+ lua_setglobal(L, "INIT");
jobDispatcher->prepareEnvironment(L, top);
}
porting::setThreadName((std::string("AsyncWorkTh_") + number).c_str());
- std::string asyncscript = porting::path_share + DIR_DELIM + "builtin"
- + DIR_DELIM + "async_env.lua";
+ lua_State *L = getStack();
- if (!loadScript(asyncscript)) {
+ std::string script = getServer()->getBuiltinLuaPath() + DIR_DELIM + "init.lua";
+ if (!loadScript(script)) {
errorstream
<< "AsyncWorkderThread execution of async base environment failed!"
<< std::endl;
abort();
}
- lua_State *L = getStack();
// Main loop
while (!StopRequested()) {
// Wait for job
lua_pop(m_luastack, 1);
#endif
- m_server = 0;
- m_environment = 0;
- m_guiengine = 0;
+ m_server = NULL;
+ m_environment = NULL;
+ m_guiengine = NULL;
}
ScriptApiBase::~ScriptApiBase()
{
ModNameStorer modnamestorer(getStack(), modname);
- if(!string_allowed(modname, MODNAME_ALLOWED_CHARS)){
+ if (!string_allowed(modname, MODNAME_ALLOWED_CHARS)) {
errorstream<<"Error loading mod \""<<modname
<<"\": modname does not follow naming conventions: "
<<"Only chararacters [a-z0-9_] are allowed."<<std::endl;
return false;
}
- bool success = false;
-
- try{
- success = loadScript(scriptpath);
- }
- catch(LuaError &e){
- errorstream<<"Error loading mod \""<<modname
- <<"\": "<<e.what()<<std::endl;
- }
-
- return success;
+ return loadScript(scriptpath);
}
bool ScriptApiBase::loadScript(const std::string &scriptpath)
}
/******************************************************************************/
-int ModApiMainMenu::l_get_scriptdir(lua_State *L)
+int ModApiMainMenu::l_get_mainmenu_path(lua_State *L)
{
GUIEngine* engine = getGuiEngine(L);
assert(engine != 0);
API_FCT(delete_dir);
API_FCT(copy_dir);
API_FCT(extract_zip);
- API_FCT(get_scriptdir);
+ API_FCT(get_mainmenu_path);
API_FCT(show_file_open_dialog);
API_FCT(get_version);
API_FCT(download_file);
//filesystem
- static int l_get_scriptdir(lua_State *L);
+ static int l_get_mainmenu_path(lua_State *L);
static int l_get_modpath(lua_State *L);
{
NO_MAP_LOCK_REQUIRED;
std::string modname = luaL_checkstring(L, 1);
- // Do it
- if(modname == "__builtin"){
- std::string path = getServer(L)->getBuiltinLuaPath();
- lua_pushstring(L, path.c_str());
- return 1;
- }
const ModSpec *mod = getServer(L)->getModSpec(modname);
- if(!mod){
+ if (!mod) {
lua_pushnil(L);
return 1;
}
#include "common/c_content.h"
#include "cpp_api/s_async.h"
#include "debug.h"
+#include "porting.h"
#include "log.h"
#include "tool.h"
#include "settings.h"
return 1;
}
+int ModApiUtil::l_get_builtin_path(lua_State *L)
+{
+ std::string path = porting::path_share + DIR_DELIM + "builtin";
+ lua_pushstring(L, path.c_str());
+ return 1;
+}
+
+
void ModApiUtil::Initialize(lua_State *L, int top)
{
API_FCT(debug);
API_FCT(get_password_hash);
API_FCT(is_yes);
+
+ API_FCT(get_builtin_path);
}
void ModApiUtil::InitializeAsync(AsyncEngine& engine)
ASYNC_API_FCT(write_json);
ASYNC_API_FCT(is_yes);
+
+ ASYNC_API_FCT(get_builtin_path);
}
+
// is_yes(arg)
static int l_is_yes(lua_State *L);
+ // get_scriptdir()
+ static int l_get_builtin_path(lua_State *L);
+
public:
static void Initialize(lua_State *L, int top);
*/
#include "scripting_game.h"
+#include "server.h"
+#include "filesys.h"
#include "log.h"
#include "cpp_api/s_internal.h"
#include "lua_api/l_base.h"
SCRIPTAPI_PRECHECKHEADER
+ lua_pushstring(L, DIR_DELIM);
+ lua_setglobal(L, "DIR_DELIM");
+
// Create the main minetest table
lua_newtable(L);
lua_setglobal(L, "minetest");
InitializeModApi(L, top);
lua_pop(L, 1);
+ // Push builtin initialization type
+ lua_pushstring(L, "game");
+ lua_setglobal(L, "INIT");
+
infostream << "SCRIPTAPI: Initialized game modules" << std::endl;
}
*/
#include "scripting_mainmenu.h"
+#include "mods.h"
+#include "porting.h"
#include "log.h"
#include "filesys.h"
#include "cpp_api/s_internal.h"
initializeModApi(L, top);
lua_pop(L, 1);
+ // Push builtin initialization type
+ lua_pushstring(L, "mainmenu");
+ lua_setglobal(L, "INIT");
+
infostream << "SCRIPTAPI: Initialized main menu modules" << std::endl;
}
errorstream << std::endl;
}
- // Path to builtin.lua
- std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
-
// Lock environment
JMutexAutoLock envlock(m_env_mutex);
m_script = new GameScripting(this);
+ std::string scriptpath = getBuiltinLuaPath() + DIR_DELIM "init.lua";
- // Load and run builtin.lua
- infostream<<"Server: Loading builtin.lua [\""
- <<builtinpath<<"\"]"<<std::endl;
- bool success = m_script->loadMod(builtinpath, "__builtin");
- if(!success){
- errorstream<<"Server: Failed to load and run "
- <<builtinpath<<std::endl;
- throw ModError("Failed to load and run "+builtinpath);
+ if (!m_script->loadScript(scriptpath)) {
+ throw ModError("Failed to load and run " + scriptpath);
}
+
+
// Print 'em
infostream<<"Server: Loading mods: ";
for(std::vector<ModSpec>::iterator i = m_mods.begin();