]> git.lizzy.rs Git - dragonfireclient.git/commitdiff
Merge branch 'master' of https://github.com/minetest/minetest
authorElias Fleckenstein <eliasfleckenstein@web.de>
Thu, 2 Jun 2022 18:54:02 +0000 (20:54 +0200)
committerElias Fleckenstein <eliasfleckenstein@web.de>
Thu, 2 Jun 2022 18:54:02 +0000 (20:54 +0200)
206 files changed:
.gitignore
.luacheckrc
CMakeLists.txt
LICENSE.txt
README.md
builtin/async/game.lua
builtin/client/chatcommands.lua
builtin/client/cheats.lua [new file with mode: 0644]
builtin/client/death_formspec.lua
builtin/client/init.lua
builtin/client/register.lua
builtin/client/util.lua [new file with mode: 0644]
builtin/common/chatcommands.lua
builtin/common/misc_helpers.lua
builtin/common/voxelarea.lua [new file with mode: 0644]
builtin/game/init.lua
builtin/game/voxelarea.lua [deleted file]
builtin/init.lua
builtin/mainmenu/dlg_contentstore.lua
builtin/mainmenu/dlg_settings_advanced.lua
builtin/mainmenu/init.lua
builtin/mainmenu/pkgmgr.lua
builtin/mainmenu/tab_about.lua
builtin/mainmenu/tab_content.lua
builtin/settingtypes.txt
clientmods/mods_here.txt [new file with mode: 0644]
clientmods/preview/example.lua [deleted file]
clientmods/preview/examples/first.lua [deleted file]
clientmods/preview/init.lua [deleted file]
clientmods/preview/mod.conf [deleted file]
doc/client_lua_api.txt
doc/lua_api.txt
doc/protocol.md [new file with mode: 0644]
doc/protocol.txt [deleted file]
games/devtest/mods/basetools/.sounds/default_grass_footstep.1.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_break_glass.1.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_break_glass.2.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_break_glass.3.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_chest_close.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_chest_open.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_cool_lava.1.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_cool_lava.2.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_cool_lava.3.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_dig_choppy.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_dig_cracky.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_dig_crumbly.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_dig_dig_immediate.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_dig_metal.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_dig_oddly_breakable_by_hand.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_dig_snappy.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_dirt_footstep.1.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_dirt_footstep.2.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_dug_metal.1.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_dug_metal.2.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_dug_node.1.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_dug_node.2.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_glass_footstep.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_grass_footstep.2.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_grass_footstep.3.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_gravel_footstep.1.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_gravel_footstep.2.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_gravel_footstep.3.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_gravel_footstep.4.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_hard_footstep.1.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_hard_footstep.2.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_hard_footstep.3.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_item_smoke.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_metal_footstep.1.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_metal_footstep.2.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_metal_footstep.3.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_place_node.1.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_place_node.2.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_place_node.3.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_place_node_hard.1.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_place_node_hard.2.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_place_node_metal.1.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_place_node_metal.2.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_sand_footstep.1.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_sand_footstep.2.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_snow_footstep.1.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_snow_footstep.2.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_snow_footstep.3.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_snow_footstep.4.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_snow_footstep.5.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_tool_breaks.1.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_tool_breaks.2.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_tool_breaks.3.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_water_footstep.1.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_water_footstep.2.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_water_footstep.3.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_water_footstep.4.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_wood_footstep.1.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/default_wood_footstep.2.ogg [new file with mode: 0644]
games/devtest/mods/basetools/sounds/player_damage.ogg [new file with mode: 0644]
games/devtest/mods/player_api/README.txt [new file with mode: 0644]
games/devtest/mods/player_api/api.lua [new file with mode: 0644]
games/devtest/mods/player_api/init.lua [new file with mode: 0644]
games/devtest/mods/player_api/license.txt [new file with mode: 0644]
games/devtest/mods/player_api/mod.conf [new file with mode: 0644]
games/devtest/mods/player_api/models/character.b3d [new file with mode: 0644]
games/devtest/mods/player_api/models/character.blend [new file with mode: 0644]
games/devtest/mods/player_api/models/character.png [new file with mode: 0644]
games/devtest/mods/player_api/textures/player.png [new file with mode: 0644]
games/devtest/mods/player_api/textures/player_back.png [new file with mode: 0644]
latex/doxygen.sty [new file with mode: 0644]
latex/md_README.tex [new file with mode: 0644]
latex/refman.log [new file with mode: 0644]
latex/refman.tex [new file with mode: 0644]
misc/Info.plist
misc/dragonfire-icon-24x24.png [new file with mode: 0644]
misc/dragonfire-icon.icns [new file with mode: 0644]
misc/dragonfire-icon.ico [new file with mode: 0644]
misc/dragonfire-icon.ico.png [new file with mode: 0644]
misc/dragonfire-xorg-icon-128.png [new file with mode: 0644]
misc/dragonfire.svg [new file with mode: 0644]
misc/minetest-icon-24x24.png [deleted file]
misc/minetest-icon.icns [deleted file]
misc/minetest-icon.ico [deleted file]
misc/minetest-xorg-icon-128.png [deleted file]
misc/minetest.svg [deleted file]
misc/net.minetest.minetest.desktop [changed mode: 0644->0755]
misc/winresource.rc
src/activeobjectmgr.h
src/client/camera.cpp
src/client/camera.h
src/client/client.cpp
src/client/client.h
src/client/clientenvironment.cpp
src/client/clientenvironment.h
src/client/clientmap.cpp
src/client/clientobject.h
src/client/content_cao.cpp
src/client/content_cao.h
src/client/game.cpp
src/client/game.h
src/client/gameui.cpp
src/client/gameui.h
src/client/hud.cpp
src/client/inputhandler.cpp
src/client/inputhandler.h
src/client/keys.h
src/client/localplayer.cpp
src/client/localplayer.h
src/client/mapblock_mesh.cpp
src/client/mapblock_mesh.h
src/client/mesh_generator_thread.h
src/client/minimap.cpp
src/client/render/core.cpp
src/client/render/core.h
src/client/renderingengine.cpp
src/collision.cpp
src/collision.h
src/defaultsettings.cpp
src/environment.cpp
src/gamedef.h
src/gui/CMakeLists.txt
src/gui/cheatMenu.cpp [new file with mode: 0644]
src/gui/cheatMenu.h [new file with mode: 0644]
src/gui/guiInventoryList.cpp
src/gui/guiInventoryList.h
src/gui/guiKeyChangeMenu.cpp
src/main.cpp
src/map.cpp
src/map.h
src/network/clientpackethandler.cpp
src/nodedef.cpp
src/player.cpp
src/player.h
src/raycast.cpp
src/raycast.h
src/script/common/c_content.cpp
src/script/common/c_content.h
src/script/cpp_api/CMakeLists.txt
src/script/cpp_api/s_base.cpp
src/script/cpp_api/s_base.h
src/script/cpp_api/s_cheats.cpp [new file with mode: 0644]
src/script/cpp_api/s_cheats.h [new file with mode: 0644]
src/script/cpp_api/s_client.cpp
src/script/cpp_api/s_client.h
src/script/cpp_api/s_security.cpp
src/script/lua_api/CMakeLists.txt
src/script/lua_api/l_base.cpp
src/script/lua_api/l_base.h
src/script/lua_api/l_client.cpp
src/script/lua_api/l_client.h
src/script/lua_api/l_clientobject.cpp [new file with mode: 0644]
src/script/lua_api/l_clientobject.h [new file with mode: 0644]
src/script/lua_api/l_env.cpp
src/script/lua_api/l_env.h
src/script/lua_api/l_inventoryaction.cpp [new file with mode: 0644]
src/script/lua_api/l_inventoryaction.h [new file with mode: 0644]
src/script/lua_api/l_item.cpp
src/script/lua_api/l_localplayer.cpp
src/script/lua_api/l_localplayer.h
src/script/lua_api/l_mainmenu.cpp
src/script/lua_api/l_server.cpp
src/script/lua_api/l_util.cpp
src/script/scripting_client.cpp
src/script/scripting_client.h
src/server/serverinventorymgr.h
src/serverenvironment.cpp
src/unittest/test.cpp
textures/base/pack/logo.png
textures/base/pack/menu_bg.png
util/buildbot/buildwin32.sh
util/buildbot/buildwin64.sh

index bb5e0a0cdb150d712ddc777a68dca9674d9a93cf..8a963d3c9b09fe7278db06ffe695bde676a60b86 100644 (file)
@@ -52,9 +52,9 @@ build/.cmake/
 !/mods/minetest/mods_here.txt
 /worlds
 /world/
-/clientmods/*
-!/clientmods/preview/
 /client/mod_storage/
+/clientmods/*
+!/clientmods/mods_here.txt
 
 ## Configuration/log files
 minetest.conf
index a922bdea9af7950a7777b8125dc98c1099e3157a..ca321d9537350f74b93427d282c538c9e58c7a7f 100644 (file)
@@ -19,7 +19,7 @@ read_globals = {
        "Settings",
 
        string = {fields = {"split", "trim"}},
-       table  = {fields = {"copy", "getn", "indexof", "insert_all"}},
+       table  = {fields = {"copy", "getn", "indexof", "insert_all", "combine"}},
        math   = {fields = {"hypot", "round"}},
 }
 
index 09e3dcccd1f1481a1b54fd9c7e67adb36f1c3d96..fe1cb47eb38751d491da02983c198f5ecad45fc1 100644 (file)
@@ -9,7 +9,7 @@ endif()
 
 # This can be read from ${PROJECT_NAME} after project() is called
 project(minetest)
-set(PROJECT_NAME_CAPITALIZED "Minetest")
+set(PROJECT_NAME_CAPITALIZED "Dragonfire")
 
 set(CMAKE_CXX_STANDARD 14)
 set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
@@ -20,10 +20,10 @@ set(CLANG_MINIMUM_VERSION "3.5")
 set(VERSION_MAJOR 5)
 set(VERSION_MINOR 6)
 set(VERSION_PATCH 0)
-set(VERSION_EXTRA "" CACHE STRING "Stuff to append to version string")
+set(VERSION_EXTRA "dragonfire" CACHE STRING "Stuff to append to version string")
 
 # Change to false for releases
-set(DEVELOPMENT_BUILD TRUE)
+set(DEVELOPMENT_BUILD FALSE)
 
 set(VERSION_STRING "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")
 if(VERSION_EXTRA)
@@ -247,14 +247,14 @@ if(UNIX AND NOT APPLE)
        install(FILES "doc/minetest.6" "doc/minetestserver.6" DESTINATION "${MANDIR}/man6")
        install(FILES "misc/net.minetest.minetest.desktop" DESTINATION "${XDG_APPS_DIR}")
        install(FILES "misc/net.minetest.minetest.appdata.xml" DESTINATION "${APPDATADIR}")
-       install(FILES "misc/minetest.svg" DESTINATION "${ICONDIR}/hicolor/scalable/apps")
-       install(FILES "misc/minetest-xorg-icon-128.png"
+       install(FILES "misc/dragonfire.svg" DESTINATION "${ICONDIR}/hicolor/scalable/apps")
+       install(FILES "misc/dragonfire-xorg-icon-128.png"
                DESTINATION "${ICONDIR}/hicolor/128x128/apps"
-               RENAME "minetest.png")
+               RENAME "dragonfire.png")
 endif()
 
 if(APPLE)
-       install(FILES "misc/minetest-icon.icns" DESTINATION "${SHAREDIR}")
+       install(FILES "misc/dragonfire-icon.icns" DESTINATION "${SHAREDIR}")
        install(FILES "misc/Info.plist" DESTINATION "${BUNDLE_PATH}/Contents")
 endif()
 
@@ -343,7 +343,7 @@ if(WIN32)
                set(CPACK_CREATE_DESKTOP_LINKS ${PROJECT_NAME})
                set(CPACK_PACKAGING_INSTALL_PREFIX "/${PROJECT_NAME_CAPITALIZED}")
 
-               set(CPACK_WIX_PRODUCT_ICON "${CMAKE_CURRENT_SOURCE_DIR}/misc/minetest-icon.ico")
+               set(CPACK_WIX_PRODUCT_ICON "${CMAKE_CURRENT_SOURCE_DIR}/misc/dragonfire-icon.ico")
                # Supported languages can be found at
                # http://wixtoolset.org/documentation/manual/v3/wixui/wixui_localization.html
                #set(CPACK_WIX_CULTURES "ar-SA,bg-BG,ca-ES,hr-HR,cs-CZ,da-DK,nl-NL,en-US,et-EE,fi-FI,fr-FR,de-DE")
index 6eae833d5e6199a6a7c24d2137beb0e547c7399d..41d58901e397a09472e8ef97449542c112bd4133 100644 (file)
@@ -36,10 +36,10 @@ rubenwardy, paramat:
   textures/base/pack/start_icon.png
   textures/base/pack/end_icon.png
 
-erlehmann:
-  misc/minetest-icon-24x24.png
-  misc/minetest-icon.ico
-  misc/minetest.svg
+EliasFleckenstein03:
+  misc/dragonfire-icon-24x24.png
+  misc/dragonfire-icon.ico
+  misc/dragonfire.svg
   textures/base/pack/logo.png
 
 JRottm:
index 8d0e68e0cd7fa2fb297609db662dc98eaff9da7f..4fef8f0c04bd3000f106a10ba2e273647625c48c 100644 (file)
--- a/README.md
+++ b/README.md
@@ -12,7 +12,7 @@ and contributors (see source file comments and the version control log)
 
 In case you downloaded the source code
 --------------------------------------
-If you downloaded the Minetest Engine source code in which this file is
+If you downloaded the Dragonfire Client source code in which this file is
 contained, you probably want to download the [Minetest Game](https://github.com/minetest/minetest_game/)
 project too. See its README.txt for more information.
 
@@ -172,8 +172,8 @@ For Fedora users:
 
 Download source (this is the URL to the latest of source repository, which might not work at all times) using Git:
 
-    git clone --depth 1 https://github.com/minetest/minetest.git
-    cd minetest
+    git clone --depth 1 https://github.com/dragonfireclient/dragonfireclient
+    cd dragonfireclient
 
 Download minetest_game (otherwise only the "Development Test" game is available) using Git:
 
index 8cb9720b66d113aaac82cd4fd96e5ee520665fb0..e3119d8cb0cdbe725579fb173dcb3843d39f0fef 100644 (file)
@@ -13,12 +13,13 @@ end
 
 -- Import a bunch of individual files from builtin/game/
 local gamepath = core.get_builtin_path() .. "game" .. DIR_DELIM
+local commonpath = core.get_builtin_path() .. "common" .. DIR_DELIM
 
 dofile(gamepath .. "constants.lua")
 dofile(gamepath .. "item_s.lua")
 dofile(gamepath .. "misc_s.lua")
 dofile(gamepath .. "features.lua")
-dofile(gamepath .. "voxelarea.lua")
+dofile(commonpath .. "voxelarea.lua")
 
 -- Transfer of globals
 do
index a563a66276f745f6868bcb1a23464e9dbdb67fe3..37308efd9c1a49573462b92a99201aed5c030599 100644 (file)
@@ -41,34 +41,144 @@ core.register_on_sending_chat_message(function(message)
        return true
 end)
 
-core.register_chatcommand("list_players", {
-       description = core.gettext("List online players"),
+function core.run_server_chatcommand(cmd, param)
+       core.send_chat_message("/" .. cmd .. " " .. param)
+end
+
+core.register_chatcommand("say", {
+       description = "Send raw text",
+       func = function(text)
+               core.send_chat_message(text)
+               return true
+       end,
+})
+
+core.register_chatcommand("teleport", {
+       params = "<X>,<Y>,<Z>",
+       description = "Teleport to coordinates.",
        func = function(param)
-               local player_names = core.get_player_names()
-               if not player_names then
-                       return false, core.gettext("This command is disabled by server.")
+               local success, pos = core.parse_pos(param)
+               if success then
+                       core.localplayer:set_pos(pos)
+                       return true, "Teleporting to " .. core.pos_to_string(pos)
                end
+               return false, pos
+       end,
+})
 
-               local players = table.concat(player_names, ", ")
-               return true, core.gettext("Online players: ") .. players
+core.register_chatcommand("wielded", {
+       description = "Print itemstring of wieleded item",
+       func = function()
+               return true, core.localplayer:get_wielded_item():to_string()
        end
 })
 
 core.register_chatcommand("disconnect", {
-       description = core.gettext("Exit to main menu"),
+       description = "Exit to main menu",
        func = function(param)
                core.disconnect()
        end,
 })
 
-core.register_chatcommand("clear_chat_queue", {
-       description = core.gettext("Clear the out chat queue"),
+core.register_chatcommand("players", {
+       description = "List online players",
        func = function(param)
-               core.clear_out_chat_queue()
-               return true, core.gettext("The out chat queue is now empty.")
+               return true, "Online players: " .. table.concat(core.get_player_names(), ", ")
+       end
+})
+
+core.register_chatcommand("kill", {
+       description = "Kill yourself",
+       func = function()
+               core.send_damage(10000)
        end,
 })
 
-function core.run_server_chatcommand(cmd, param)
-       core.send_chat_message("/" .. cmd .. " " .. param)
-end
+core.register_chatcommand("set", {
+       params = "([-n] <name> <value>) | <name>",
+       description = "Set or read client configuration setting",
+       func = function(param)
+               local arg, setname, setvalue = string.match(param, "(-[n]) ([^ ]+) (.+)")
+               if arg and arg == "-n" and setname and setvalue then
+                       core.settings:set(setname, setvalue)
+                       return true, setname .. " = " .. setvalue
+               end
+
+               setname, setvalue = string.match(param, "([^ ]+) (.+)")
+               if setname and setvalue then
+                       if not core.settings:get(setname) then
+                               return false, "Failed. Use '.set -n <name> <value>' to create a new setting."
+                       end
+                       core.settings:set(setname, setvalue)
+                       return true, setname .. " = " .. setvalue
+               end
+
+               setname = string.match(param, "([^ ]+)")
+               if setname then
+                       setvalue = core.settings:get(setname)
+                       if not setvalue then
+                               setvalue = "<not set>"
+                       end
+                       return true, setname .. " = " .. setvalue
+               end
+
+               return false, "Invalid parameters (see .help set)."
+       end,
+})
+
+core.register_chatcommand("place", {
+       params = "<X>,<Y>,<Z>",
+       description = "Place wielded item",
+       func = function(param)
+               local success, pos = core.parse_relative_pos(param)
+               if success then
+                       core.place_node(pos)
+                       return true, "Node placed at " .. core.pos_to_string(pos)
+               end
+               return false, pos
+       end,
+})
+
+core.register_chatcommand("dig", {
+       params = "<X>,<Y>,<Z>",
+       description = "Dig node",
+       func = function(param)
+               local success, pos = core.parse_relative_pos(param)
+               if success then
+                       core.dig_node(pos)
+                       return true, "Node at " .. core.pos_to_string(pos) .. " dug"
+               end
+               return false, pos
+       end,
+})
+
+core.register_chatcommand("setyaw", {
+       params = "<yaw>",
+       description = "Set your yaw",
+       func = function(param)
+               local yaw = tonumber(param)
+               if yaw then
+                       core.localplayer:set_yaw(yaw)
+                       return true
+               else
+                       return false, "Invalid usage (See .help setyaw)"
+               end
+       end
+})
+
+core.register_chatcommand("setpitch", {
+       params = "<pitch>",
+       description = "Set your pitch",
+       func = function(param)
+               local pitch = tonumber(param)
+               if pitch then
+                       core.localplayer:set_pitch(pitch)
+                       return true
+               else
+                       return false, "Invalid usage (See .help setpitch)"
+               end
+       end
+})
+
+core.register_list_command("xray", "Configure X-Ray", "xray_nodes")
+core.register_list_command("search", "Configure NodeESP", "node_esp_nodes")
diff --git a/builtin/client/cheats.lua b/builtin/client/cheats.lua
new file mode 100644 (file)
index 0000000..b712d0f
--- /dev/null
@@ -0,0 +1,59 @@
+core.cheats = {
+       ["Combat"] = {
+               ["AntiKnockback"] = "antiknockback",
+               ["AttachmentFloat"] = "float_above_parent",
+       },
+       ["Movement"] = {
+               ["Freecam"] = "freecam",
+               ["AutoForward"] = "continuous_forward",
+               ["PitchMove"] = "pitch_move",
+               ["AutoJump"] = "autojump",
+               ["Jesus"] = "jesus",
+               ["NoSlow"] = "no_slow",
+               ["JetPack"] = "jetpack",
+               ["AntiSlip"] = "antislip",
+               ["AirJump"] = "airjump",
+               ["Spider"] = "spider",
+       },
+       ["Render"] = {
+               ["Xray"] = "xray",
+               ["Fullbright"] = "fullbright",
+               ["HUDBypass"] = "hud_flags_bypass",
+               ["NoHurtCam"] = "no_hurt_cam",
+               ["BrightNight"] = "no_night",
+               ["Coords"] = "coords",
+               ["CheatHUD"] = "cheat_hud",
+               ["EntityESP"] = "enable_entity_esp",
+               ["EntityTracers"] = "enable_entity_tracers",
+               ["PlayerESP"] = "enable_player_esp",
+               ["PlayerTracers"] = "enable_player_tracers",
+               ["NodeESP"] = "enable_node_esp",
+               ["NodeTracers"] = "enable_node_tracers",
+       },
+       ["Interact"] = {
+               ["FastDig"] = "fastdig",
+               ["FastPlace"] = "fastplace",
+               ["AutoDig"] = "autodig",
+               ["AutoPlace"] = "autoplace",
+               ["InstantBreak"] = "instant_break",
+               ["FastHit"] = "spamclick",
+               ["AutoHit"] = "autohit",
+       },
+       ["Exploit"] = {
+               ["EntitySpeed"] = "entity_speed",
+       },
+       ["Player"] = {
+               ["NoFallDamage"] = "prevent_natural_damage",
+               ["NoForceRotate"] = "no_force_rotate",
+               ["Reach"] = "reach",
+               ["PointLiquids"] = "point_liquids",
+               ["PrivBypass"] = "priv_bypass",
+               ["AutoRespawn"] = "autorespawn",
+               ["ThroughWalls"] = "dont_point_nodes",
+       },
+}
+
+function core.register_cheat(cheatname, category, func)
+       core.cheats[category] = core.cheats[category] or {}
+       core.cheats[category][cheatname] = func
+end
index c25c799ab7fd3f48d79df208c3718986cf49fde5..ff484b32f6312e62796ebc61ee0364ee2044dc3b 100644 (file)
@@ -1,15 +1,38 @@
--- CSM death formspec. Only used when clientside modding is enabled, otherwise
--- handled by the engine.
+local death_formspec = ""
+       .. "size[11,5.5]"
+       .. "bgcolor[#320000b4;true]"
+       .. "label[4.85,1.35;" .. fgettext("You died") .. "]"
+       .. "button_exit[2,3;3,0.5;btn_respawn;" .. fgettext("Respawn") .. "]"
+       .. "button_exit[6,3;3,0.5;btn_ghost_mode;" .. "Ghost Mode" .. "]"
+       .. "set_focus[btn_respawn;true]"
 
 core.register_on_death(function()
-       local formspec = "size[11,5.5]bgcolor[#320000b4;true]" ..
-               "label[4.85,1.35;" .. fgettext("You died") ..
-               "]button_exit[4,3;3,0.5;btn_respawn;".. fgettext("Respawn") .."]"
-       core.show_formspec("bultin:death", formspec)
+       core.display_chat_message("You died at " .. core.pos_to_string(vector.round(core.localplayer:get_pos())) .. ".")
+       if core.settings:get_bool("autorespawn") then
+               core.send_respawn()
+       else
+               core.show_formspec("bultin:death", death_formspec)
+       end
 end)
 
 core.register_on_formspec_input(function(formname, fields)
        if formname == "bultin:death" then
-               core.send_respawn()
+               if fields.btn_ghost_mode then
+                       core.display_chat_message("You are in ghost mode. Use .respawn to Respawn.")
+               else
+                       core.send_respawn()
+               end
        end
 end)
+
+core.register_chatcommand("respawn", {
+       description = "Respawn when in ghost mode",
+       func = function()
+               if core.localplayer:get_hp() == 0 then
+                       core.send_respawn()
+                       core.display_chat_message("Respawned.")
+               else
+                       core.display_chat_message("You are not in ghost mode.")
+               end
+       end
+})
index 589fe8f246fbec43b2701cf009144ec25d6c1151..d750375b8e7ef8893516c1d87ccc808bdce09b74 100644 (file)
@@ -6,5 +6,10 @@ local commonpath = scriptpath.."common"..DIR_DELIM
 dofile(clientpath .. "register.lua")
 dofile(commonpath .. "after.lua")
 dofile(commonpath .. "chatcommands.lua")
+dofile(commonpath .. "vector.lua")
+dofile(commonpath .. "voxelarea.lua")
+dofile(clientpath .. "util.lua")
 dofile(clientpath .. "chatcommands.lua")
 dofile(clientpath .. "death_formspec.lua")
+dofile(clientpath .. "cheats.lua")
+
index 61db4a30b7cd564d19cd98f3f19bcd8ebca001d7..637a22556cd0a293484bbeb37c03fdec6a221c30 100644 (file)
@@ -46,6 +46,26 @@ function core.run_callbacks(callbacks, mode, ...)
        return ret
 end
 
+function core.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 itemdef = core.get_item_def(name)
+       if not itemdef then
+               error("Attempt to override non-existent item "..name, 2)
+       end
+       local nodedef = core.get_node_def(name)
+       table.combine(itemdef, nodedef)
+
+       for k, v in pairs(redefinition) do
+               rawset(itemdef, k, v)
+       end
+       core.register_item_raw(itemdef)
+end
+
 --
 -- Callback registration
 --
@@ -81,3 +101,13 @@ core.registered_on_item_use, core.register_on_item_use = make_registration()
 core.registered_on_modchannel_message, core.register_on_modchannel_message = make_registration()
 core.registered_on_modchannel_signal, core.register_on_modchannel_signal = make_registration()
 core.registered_on_inventory_open, core.register_on_inventory_open = make_registration()
+core.registered_on_recieve_physics_override, core.register_on_recieve_physics_override = make_registration()
+core.registered_on_play_sound, core.register_on_play_sound = make_registration()
+core.registered_on_spawn_particle, core.register_on_spawn_particle = make_registration()
+core.registered_on_object_properties_change, core.register_on_object_properties_change = make_registration()
+core.registered_on_object_hp_change, core.register_on_object_hp_change = make_registration()
+core.registered_on_object_add, core.register_on_object_add = make_registration()
+
+core.registered_nodes = {}
+core.registered_items = {}
+core.object_refs = {}
diff --git a/builtin/client/util.lua b/builtin/client/util.lua
new file mode 100644 (file)
index 0000000..440f99e
--- /dev/null
@@ -0,0 +1,80 @@
+function core.parse_pos(param)
+       local p = {}
+       local playerpos = core.localplayer:get_pos()
+       p.x, p.y, p.z = string.match(param, "^([~|%d.-]+)[, ] *([~|%d.-]+)[, ] *([~|%d.-]+)$")
+       for k, v in pairs(p) do
+               if p[k] == "~" then
+                       p[k] = playerpos[k]
+               else
+                       p[k] = tonumber(v)
+               end
+       end
+       if p.x and p.y and p.z then
+               return true, vector.round(p)
+       end
+       return false, "Invalid position (" .. param .. ")"
+end
+
+function core.parse_relative_pos(param)
+       local success, pos = core.parse_pos(param:gsub("~", "0"))
+       if success then pos = vector.round(vector.add(core.localplayer:get_pos(), pos)) end
+       return success, pos
+end
+
+function core.find_item(item, mini, maxi)
+       for index, stack in ipairs(core.get_inventory("current_player").main) do
+               if (not mini or index >= mini) and (not maxi or index <= maxi) and stack:get_name() == item then
+                       return index
+               end
+       end
+end
+
+function core.switch_to_item(item)
+       local i = core.find_item(item)
+       if i then
+               core.localplayer:set_wield_index(i)
+               return true
+       else
+               return false
+       end
+end
+
+function core.get_pointed_thing()
+       local pos = core.camera:get_pos()
+       local pos2 = vector.add(pos, vector.multiply(core.camera:get_look_dir(), 7))
+       local player = core.localplayer
+       if not player then return end
+       local item = player:get_wielded_item()
+       if not item then return end
+       local def = core.get_item_def(item:get_name())
+       local ray = core.raycast(pos, pos2, true, core.settings:get_bool("point_liquids") or def and def.liquids_pointable)
+       return ray and ray:next()
+end
+
+function core.close_formspec(formname)
+       return core.show_formspec(formname, "")
+end
+
+function core.get_nearby_objects(radius)
+       return core.get_objects_inside_radius(core.localplayer:get_pos(), radius)
+end
+
+-- HTTP callback interface
+
+function core.http_add_fetch(httpenv)
+       httpenv.fetch = function(req, callback)
+               local handle = httpenv.fetch_async(req)
+
+               local function update_http_status()
+                       local res = httpenv.fetch_async_get(handle)
+                       if res.completed then
+                               callback(res)
+                       else
+                               core.after(0, update_http_status)
+                       end
+               end
+               core.after(0, update_http_status)
+       end
+
+       return httpenv
+end
index 7c3da0601c44546f5b82d84379506920183af7d5..817f1f526186d2657ba9084731d12adf844ec8d5 100644 (file)
@@ -69,6 +69,51 @@ function core.override_chatcommand(name, redefinition)
        core.registered_chatcommands[name] = chatcommand
 end
 
+if INIT == "client" then
+       function core.register_list_command(command, desc, setting)
+               local def = {}
+               def.description = desc
+               def.params = "del <item> | add <item> | list"
+               function def.func(param)
+                       local list = (minetest.settings:get(setting) or ""):split(",")
+                       if param == "list" then
+                               return true, table.concat(list, ", ")
+                       else
+                               local sparam = param:split(" ")
+                               local cmd = sparam[1]
+                               local item = sparam[2]
+                               if cmd == "del" then
+                                       if not item then
+                                               return false, "Missing item."
+                                       end
+                                       local i = table.indexof(list, item)
+                                       if i == -1 then
+                                               return false, item .. " is not on the list."
+                                       else
+                                               table.remove(list, i)
+                                               core.settings:set(setting, table.concat(list, ","))
+                                               return true, "Removed " .. item .. " from the list."
+                                       end
+                               elseif cmd == "add" then
+                                       if not item then
+                                               return false, "Missing item."
+                                       end
+                                       local i = table.indexof(list, item)
+                                       if i ~= -1 then
+                                               return false, item .. " is already on the list."
+                                       else
+                                               table.insert(list, item)
+                                               core.settings:set(setting, table.concat(list, ","))
+                                               return true, "Added " .. item .. " to the list."
+                                       end
+                               end
+                       end
+                       return false, "Invalid usage. (See .help " .. command .. ")"
+               end
+               core.register_chatcommand(command, def)
+       end
+end
+
 local function format_help_line(cmd, def)
        local cmd_marker = INIT == "client" and "." or "/"
        local msg = core.colorize("#00ffff", cmd_marker .. cmd)
index d2356b50572cedd04e6923ec3b796ea67acba9cf..f8a905c7bbf6d819e9009022fa9bcb4d2c687245 100644 (file)
@@ -516,6 +516,17 @@ function table.shuffle(t, from, to, random)
 end
 
 
+function table.combine(t, other)
+       other = other or {}
+       for k, v in pairs(other) do
+               if type(v) == "table" and type(t[k]) == "table" then
+                       table.combine(t[k], v)
+               else
+                       t[k] = v
+               end
+       end
+end
+
 --------------------------------------------------------------------------------
 -- mainmenu only functions
 --------------------------------------------------------------------------------
@@ -583,6 +594,66 @@ function core.colorize(color, message)
        return table.concat(lines, "\n") .. core.get_color_escape_sequence("#ffffff")
 end
 
+local function rgb_to_hex(rgb)
+       local hexadecimal = "#"
+
+       for key, value in pairs(rgb) do
+               local hex = ""
+
+               while(value > 0)do
+                       local index = math.fmod(value, 16) + 1
+                       value = math.floor(value / 16)
+                       hex = string.sub("0123456789ABCDEF", index, index) .. hex
+               end
+
+               if(string.len(hex) == 0)then
+                       hex = "00"
+               elseif(string.len(hex) == 1)then
+                       hex = "0" .. hex
+               end
+
+               hexadecimal = hexadecimal .. hex
+       end
+
+       return hexadecimal
+end
+
+local function color_from_hue(hue)
+       local h = hue / 60
+       local c = 255
+       local x = (1 - math.abs(h % 2 - 1)) * 255
+
+       local i = math.floor(h)
+       if i == 0 then
+               return rgb_to_hex({c, x, 0})
+       elseif i == 1 then
+               return rgb_to_hex({x, c, 0})
+       elseif i == 2 then
+               return rgb_to_hex({0, c, x})
+       elseif i == 3 then
+               return rgb_to_hex({0, x, c})
+       elseif i == 4 then
+               return rgb_to_hex({x, 0, c})
+       else
+               return rgb_to_hex({c, 0, x})
+       end
+end
+
+function core.rainbow(input)
+       local step = 360 / input:len()
+       local hue = 0
+       local output = ""
+       for i = 1, input:len() do
+               local char = input:sub(i, i)
+               if char:match("%s") then
+                       output = output .. char
+               else
+                       output = output  .. core.get_color_escape_sequence(color_from_hue(hue)) .. char
+               end
+               hue = hue + step
+       end
+       return output
+end
 
 function core.strip_foreground_colors(str)
        return (str:gsub(ESCAPE_CHAR .. "%(c@[^)]+%)", ""))
@@ -636,6 +707,19 @@ function core.get_translator(textdomain)
        return function(str, ...) return core.translate(textdomain or "", str, ...) end
 end
 
+function core.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
+               end
+               -- The position where a node would be dug
+               return pointed_thing.under
+       elseif pointed_thing.type == "object" then
+               return pointed_thing.ref and pointed_thing.ref:get_pos()
+       end
+end
+
 --------------------------------------------------------------------------------
 -- Returns the exact coordinate of a pointed surface
 --------------------------------------------------------------------------------
@@ -768,3 +852,12 @@ function core.parse_coordinates(x, y, z, relative_to)
        local rz = core.parse_relative_number(z, relative_to.z)
        return rx and ry and rz and { x = rx, y = ry, z = rz }
 end
+
+function core.inventorycube(img1, img2, img3)
+       img2 = img2 or img1
+       img3 = img3 or img1
+       return "[inventorycube"
+                       .. "{" .. img1:gsub("%^", "&")
+                       .. "{" .. img2:gsub("%^", "&")
+                       .. "{" .. img3:gsub("%^", "&")
+end
diff --git a/builtin/common/voxelarea.lua b/builtin/common/voxelarea.lua
new file mode 100644 (file)
index 0000000..64436bf
--- /dev/null
@@ -0,0 +1,132 @@
+VoxelArea = {
+       MinEdge = vector.new(1, 1, 1),
+       MaxEdge = vector.new(0, 0, 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()
+       local MaxEdge, MinEdge = self.MaxEdge, self.MinEdge
+       return vector.new(
+               MaxEdge.x - MinEdge.x + 1,
+               MaxEdge.y - MinEdge.y + 1,
+               MaxEdge.z - 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 MinEdge = self.MinEdge
+       local i = (z - MinEdge.z) * self.zstride +
+                         (y - MinEdge.y) * self.ystride +
+                         (x - MinEdge.x) + 1
+       return math.floor(i)
+end
+
+function VoxelArea:indexp(p)
+       local MinEdge = self.MinEdge
+       local i = (p.z - MinEdge.z) * self.zstride +
+                         (p.y - MinEdge.y) * self.ystride +
+                         (p.x - MinEdge.x) + 1
+       return math.floor(i)
+end
+
+function VoxelArea:position(i)
+       local p = {}
+       local MinEdge = self.MinEdge
+
+       i = i - 1
+
+       p.z = math.floor(i / self.zstride) + MinEdge.z
+       i = i % self.zstride
+
+       p.y = math.floor(i / self.ystride) + MinEdge.y
+       i = i % self.ystride
+
+       p.x = math.floor(i) + MinEdge.x
+
+       return p
+end
+
+function VoxelArea:contains(x, y, z)
+       local MaxEdge, MinEdge = self.MaxEdge, self.MinEdge
+       return (x >= MinEdge.x) and (x <= MaxEdge.x) and
+                  (y >= MinEdge.y) and (y <= MaxEdge.y) and
+                  (z >= MinEdge.z) and (z <= MaxEdge.z)
+end
+
+function VoxelArea:containsp(p)
+       local MaxEdge, MinEdge = self.MaxEdge, self.MinEdge
+       return (p.x >= MinEdge.x) and (p.x <= MaxEdge.x) and
+                  (p.y >= MinEdge.y) and (p.y <= MaxEdge.y) and
+                  (p.z >= MinEdge.z) and (p.z <= 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 xrange = maxx - minx + 1
+       local nextaction = i + 1 + xrange
+
+       local y = 0
+       local yrange = maxy - miny + 1
+       local yreqstride = self.ystride - xrange
+
+       local z = 0
+       local zrange = maxz - minz + 1
+       local multistride = self.zstride - ((yrange - 1) * self.ystride + xrange)
+
+       return function()
+               -- continue i until it needs to jump
+               i = i + 1
+               if i ~= nextaction then
+                       return i
+               end
+
+               -- continue y until maxy is exceeded
+               y = y + 1
+               if y ~= yrange then
+                       -- set i to index(minx, miny + y, minz + z) - 1
+                       i = i + yreqstride
+                       nextaction = i + xrange
+                       return i
+               end
+
+               -- continue z until maxz is exceeded
+               z = z + 1
+               if z == zrange then
+                       -- cuboid finished, return nil
+                       return
+               end
+
+               -- set i to index(minx, miny, minz + z) - 1
+               i = i + multistride
+
+               y = 0
+               nextaction = i + xrange
+               return i
+       end
+end
+
+function VoxelArea:iterp(minp, maxp)
+       return self:iter(minp.x, minp.y, minp.z, maxp.x, maxp.y, maxp.z)
+end
index 68d6a10f8d164585fa65e7ed6942f7645f57c332..b9ab97b58251078a3f97523866db2204f8727baa 100644 (file)
@@ -17,6 +17,7 @@ if core.settings:get_bool("profiler.load") then
 end
 
 dofile(commonpath .. "after.lua")
+dofile(commonpath .. "voxelarea.lua")
 dofile(gamepath .. "item_entity.lua")
 dofile(gamepath .. "deprecated.lua")
 dofile(gamepath .. "misc_s.lua")
@@ -30,7 +31,6 @@ dofile(gamepath .. "static_spawn.lua")
 dofile(gamepath .. "detached_inventory.lua")
 assert(loadfile(gamepath .. "falling.lua"))(builtin_shared)
 dofile(gamepath .. "features.lua")
-dofile(gamepath .. "voxelarea.lua")
 dofile(gamepath .. "forceloading.lua")
 dofile(gamepath .. "statbars.lua")
 dofile(gamepath .. "knockback.lua")
diff --git a/builtin/game/voxelarea.lua b/builtin/game/voxelarea.lua
deleted file mode 100644 (file)
index 64436bf..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-VoxelArea = {
-       MinEdge = vector.new(1, 1, 1),
-       MaxEdge = vector.new(0, 0, 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()
-       local MaxEdge, MinEdge = self.MaxEdge, self.MinEdge
-       return vector.new(
-               MaxEdge.x - MinEdge.x + 1,
-               MaxEdge.y - MinEdge.y + 1,
-               MaxEdge.z - 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 MinEdge = self.MinEdge
-       local i = (z - MinEdge.z) * self.zstride +
-                         (y - MinEdge.y) * self.ystride +
-                         (x - MinEdge.x) + 1
-       return math.floor(i)
-end
-
-function VoxelArea:indexp(p)
-       local MinEdge = self.MinEdge
-       local i = (p.z - MinEdge.z) * self.zstride +
-                         (p.y - MinEdge.y) * self.ystride +
-                         (p.x - MinEdge.x) + 1
-       return math.floor(i)
-end
-
-function VoxelArea:position(i)
-       local p = {}
-       local MinEdge = self.MinEdge
-
-       i = i - 1
-
-       p.z = math.floor(i / self.zstride) + MinEdge.z
-       i = i % self.zstride
-
-       p.y = math.floor(i / self.ystride) + MinEdge.y
-       i = i % self.ystride
-
-       p.x = math.floor(i) + MinEdge.x
-
-       return p
-end
-
-function VoxelArea:contains(x, y, z)
-       local MaxEdge, MinEdge = self.MaxEdge, self.MinEdge
-       return (x >= MinEdge.x) and (x <= MaxEdge.x) and
-                  (y >= MinEdge.y) and (y <= MaxEdge.y) and
-                  (z >= MinEdge.z) and (z <= MaxEdge.z)
-end
-
-function VoxelArea:containsp(p)
-       local MaxEdge, MinEdge = self.MaxEdge, self.MinEdge
-       return (p.x >= MinEdge.x) and (p.x <= MaxEdge.x) and
-                  (p.y >= MinEdge.y) and (p.y <= MaxEdge.y) and
-                  (p.z >= MinEdge.z) and (p.z <= 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 xrange = maxx - minx + 1
-       local nextaction = i + 1 + xrange
-
-       local y = 0
-       local yrange = maxy - miny + 1
-       local yreqstride = self.ystride - xrange
-
-       local z = 0
-       local zrange = maxz - minz + 1
-       local multistride = self.zstride - ((yrange - 1) * self.ystride + xrange)
-
-       return function()
-               -- continue i until it needs to jump
-               i = i + 1
-               if i ~= nextaction then
-                       return i
-               end
-
-               -- continue y until maxy is exceeded
-               y = y + 1
-               if y ~= yrange then
-                       -- set i to index(minx, miny + y, minz + z) - 1
-                       i = i + yreqstride
-                       nextaction = i + xrange
-                       return i
-               end
-
-               -- continue z until maxz is exceeded
-               z = z + 1
-               if z == zrange then
-                       -- cuboid finished, return nil
-                       return
-               end
-
-               -- set i to index(minx, miny, minz + z) - 1
-               i = i + multistride
-
-               y = 0
-               nextaction = i + xrange
-               return i
-       end
-end
-
-function VoxelArea:iterp(minp, maxp)
-       return self:iter(minp.x, minp.y, minp.z, maxp.x, maxp.y, maxp.z)
-end
index 8691360169379bc82ede6e9892a41442fea6a3b8..fd176e942dcb3b3e77f849b6c5c68ca16491738e 100644 (file)
@@ -37,7 +37,6 @@ dofile(commonpath .. "misc_helpers.lua")
 
 if INIT == "game" then
        dofile(gamepath .. "init.lua")
-       assert(not core.get_http_api)
 elseif INIT == "mainmenu" then
        local mm_script = core.settings:get("main_menu_script")
        local custom_loaded = false
index 16ab1c3a7720c0299feae9045aa6c6af3de3b1f8..924c66400829469b3bbe71d9b234775e4e70ce34 100644 (file)
@@ -42,8 +42,8 @@ local num_per_page = 5
 local filter_type = 1
 local filter_types_titles = {
        fgettext("All packages"),
-       fgettext("Games"),
-       fgettext("Mods"),
+--     fgettext("Games"),
+       fgettext("Clientmods"),
        fgettext("Texture packs"),
 }
 
@@ -52,7 +52,7 @@ local download_queue = {}
 
 local filter_types_type = {
        nil,
-       "game",
+--     "game",
        "mod",
        "txp",
 }
@@ -630,7 +630,7 @@ end
 function store.update_paths()
        local mod_hash = {}
        pkgmgr.refresh_globals()
-       for _, mod in pairs(pkgmgr.global_mods:get_list()) do
+       for _, mod in pairs(pkgmgr.clientmods:get_list()) do
                if mod.author and mod.release > 0 then
                        local id = mod.author:lower() .. "/" .. mod.name
                        mod_hash[store.aliases[id] or id] = mod
index 320db7e40cb28eae5a5fe8416b3903343cc80a7f..d6f485cf73d29c2176b1c16a51bf8b2e94e9b2d4 100644 (file)
@@ -405,6 +405,36 @@ local function parse_config_file(read_all, parse_mods)
                                file:close()
                        end
                end
+
+               -- Parse clientmods
+               local clientmods_category_initialized = false
+               local clientmods = {}
+               get_mods(core.get_clientmodpath(), "clientmods", clientmods)
+               for _, clientmod in ipairs(clientmods) do
+                       local path = clientmod.path .. DIR_DELIM .. FILENAME
+                       local file = io.open(path, "r")
+                       if file then
+                               if not clientmods_category_initialized then
+                                       fgettext_ne("Clientmods") -- not used, but needed for xgettext
+                                       table.insert(settings, {
+                                               name = "Clientmods",
+                                               level = 0,
+                                               type = "category",
+                                       })
+                                       clientmods_category_initialized = true
+                               end
+
+                               table.insert(settings, {
+                                       name = clientmod.name,
+                                       level = 1,
+                                       type = "category",
+                               })
+
+                               parse_single_file(file, path, read_all, settings, 2, false)
+
+                               file:close()
+                       end
+               end
        end
 
        return settings
index 8e716c2ebceeb555983b196c2c9752badd64291b..94345467734943b5f10134224ea317d3b81817f0 100644 (file)
@@ -124,3 +124,4 @@ local function init_globals()
 end
 
 init_globals()
+
index b2f3243c4800cef98d4b226f404a08c1c44fc31f..c482cac9993fda5cecb0579b8ce9455ad9731362 100644 (file)
@@ -604,7 +604,7 @@ function pkgmgr.install_dir(type, path, basename, targetpath)
                                clean_path = get_last_folder(cleanup_path(basefolder.path))
                        end
                        if clean_path then
-                               targetpath = core.get_modpath() .. DIR_DELIM .. clean_path
+                               targetpath = core.get_clientmodpath() .. DIR_DELIM .. clean_path
                        else
                                return nil,
                                        fgettext("Install Mod: Unable to find suitable folder name for modpack $1",
@@ -630,7 +630,7 @@ function pkgmgr.install_dir(type, path, basename, targetpath)
                        end
 
                        if targetfolder ~= nil and pkgmgr.isValidModname(targetfolder) then
-                               targetpath = core.get_modpath() .. DIR_DELIM .. targetfolder
+                               targetpath = core.get_clientmodpath() .. DIR_DELIM .. targetfolder
                        else
                                return nil, fgettext("Install Mod: Unable to find real mod name for: $1", path)
                        end
@@ -666,6 +666,53 @@ function pkgmgr.install_dir(type, path, basename, targetpath)
 end
 
 --------------------------------------------------------------------------------
+function pkgmgr.prepareclientmodlist(data)
+       local retval = {}
+
+       local clientmods = {}
+
+       --read clientmods
+       local modpath = core.get_clientmodpath()
+
+       if modpath ~= nil and modpath ~= "" then
+               get_mods(modpath, "clientmods", clientmods)
+       end
+
+       for i=1,#clientmods,1 do
+               clientmods[i].type = "mod"
+               clientmods[i].loc = "global"
+               clientmods[i].is_clientside = true
+               retval[#retval + 1] = clientmods[i]
+       end
+
+       --read mods configuration
+       local filename = modpath ..
+                               DIR_DELIM .. "mods.conf"
+
+       local conffile = Settings(filename)
+
+       for key,value in pairs(conffile: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 and
+                                       not retval[i].is_modpack then
+                                       element = retval[i]
+                                       break
+                               end
+                       end
+                       if element ~= nil then
+                               element.enabled = value ~= "false" and value ~= "nil" and value
+                       else
+                               core.log("info", "Clientmod: " .. key .. " " .. dump(value) .. " but not found")
+                       end
+               end
+       end
+
+       return retval
+end
+
 function pkgmgr.preparemodlist(data)
        local retval = {}
 
@@ -822,6 +869,10 @@ function pkgmgr.refresh_globals()
                        pkgmgr.comparemod, is_equal, nil, {})
        pkgmgr.global_mods:add_sort_mechanism("alphabetic", sort_mod_list)
        pkgmgr.global_mods:set_sortmode("alphabetic")
+       pkgmgr.clientmods = filterlist.create(pkgmgr.prepareclientmodlist,
+                       pkgmgr.comparemod, is_equal, nil, {})
+       pkgmgr.clientmods:add_sort_mechanism("alphabetic", sort_mod_list)
+       pkgmgr.clientmods:set_sortmode("alphabetic")
 end
 
 --------------------------------------------------------------------------------
index ba258fd2d0486672aa95abd4d933287dc5d9de91..3336786ba4ea9e56d4cafbf29a4eda18d632da28 100644 (file)
 --51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
 --------------------------------------------------------------------------------
+local dragonfire_team = {
+       "Elias Fleckenstein [Main Developer]",
+       "cora [Core Developer]",
+       "emilia [Core Developer]",
+       "oneplustwo [Developer]",
+       "joshia_wi [Developer]",
+       "Code-Sploit [Developer]",
+       "DerZombiiie [User Support]",
+       "Rtx [User Support]",
+}
 
 local core_developers = {
        "Perttu Ahola (celeron55) <celeron55@gmail.com>",
@@ -113,6 +123,8 @@ return {
                        "tablecolumns[color;text]" ..
                        "tableoptions[background=#00000000;highlight=#00000000;border=false]" ..
                        "table[3.5,-0.25;8.5,6.05;list_credits;" ..
+                       "#FFFF00," .. fgettext("Dragonfire Team") .. ",," ..
+                       buildCreditList(dragonfire_team) .. ",,," ..
                        "#FFFF00," .. fgettext("Core Developers") .. ",," ..
                        buildCreditList(core_developers) .. ",,," ..
                        "#FFFF00," .. fgettext("Active Contributors") .. ",," ..
index 5e14d1902efcc506bed6ea9d3ad6638012f76102..a366d4ab4a11e3907c928ebab755903408e384cf 100644 (file)
 local packages_raw
 local packages
 
+local function modname_valid(name)
+       return not name:find("[^a-z0-9_]")
+end
+
 --------------------------------------------------------------------------------
 local function get_formspec(tabview, name, tabdata)
        if pkgmgr.global_mods == nil then
@@ -33,6 +37,7 @@ local function get_formspec(tabview, name, tabdata)
                table.insert_all(packages_raw, pkgmgr.games)
                table.insert_all(packages_raw, pkgmgr.get_texture_packs())
                table.insert_all(packages_raw, pkgmgr.global_mods:get_list())
+               table.insert_all(packages_raw, pkgmgr.clientmods:get_list())
 
                local function get_data()
                        return packages_raw
@@ -45,6 +50,38 @@ local function get_formspec(tabview, name, tabdata)
 
                packages = filterlist.create(get_data, pkgmgr.compare_package,
                                is_equal, nil, {})
+
+               local filename = core.get_clientmodpath() .. DIR_DELIM .. "mods.conf"
+
+               local conffile = Settings(filename)
+               local mods = conffile:to_table()
+
+               for i = 1, #packages_raw do
+                       local mod = packages_raw[i]
+                       if mod.is_clientside and not mod.is_modpack then
+                               if modname_valid(mod.name) then
+                                       conffile:set("load_mod_" .. mod.name,
+                                               mod.enabled and "true" or "false")
+                               elseif mod.enabled then
+                                       gamedata.errormessage = fgettext_ne("Failed to enable clientmo" ..
+                                               "d \"$1\" as it contains disallowed characters. " ..
+                                               "Only characters [a-z0-9_] are allowed.",
+                                               mod.name)
+                               end
+                               mods["load_mod_" .. mod.name] = nil
+                       end
+               end
+
+               -- Remove mods that are not present anymore
+               for key in pairs(mods) do
+                       if key:sub(1, 9) == "load_mod_" then
+                               conffile:remove(key)
+                       end
+               end
+
+               if not conffile:write() then
+                       core.log("error", "Failed to write clientmod config file")
+               end
        end
 
        if tabdata.selected_pkg == nil then
@@ -104,9 +141,21 @@ local function get_formspec(tabview, name, tabdata)
 
                if selected_pkg.type == "mod" then
                        if selected_pkg.is_modpack then
-                               retval = retval ..
-                                       "button[8.65,4.65;3.25,1;btn_mod_mgr_rename_modpack;" ..
-                                       fgettext("Rename") .. "]"
+                               if selected_pkg.is_clientside then
+                                       if pkgmgr.is_modpack_entirely_enabled({list = packages}, selected_pkg.name) then
+                                               retval = retval ..
+                                                       "button[8.65,4.65;3.25,1;btn_mod_mgr_mp_disable;" ..
+                                                       fgettext("Disable modpack") .. "]"
+                                       else
+                                               retval = retval ..
+                                                       "button[8.65,4.65;3.25,1;btn_mod_mgr_mp_enable;" ..
+                                                       fgettext("Enable modpack") .. "]"
+                                       end
+                               else
+                                       retval = retval ..
+                                               "button[8.65,4.65;3.25,1;btn_mod_mgr_rename_modpack;" ..
+                                               fgettext("Rename") .. "]"
+                               end
                        else
                                --show dependencies
                                desc = desc .. "\n\n"
@@ -127,6 +176,17 @@ local function get_formspec(tabview, name, tabdata)
                                                        "\n" .. toadd_soft
                                        end
                                end
+                               if selected_pkg.is_clientside then
+                                       if selected_pkg.enabled then
+                                               retval = retval ..
+                                                       "button[8.65,4.65;3.25,1;btn_mod_mgr_disable_mod;" ..
+                                                       fgettext("Disable") .. "]"
+                                       else
+                                               retval = retval ..
+                                                       "button[8.65,4.65;3.25,1;btn_mod_mgr_enable_mod;" ..
+                                                       fgettext("Enable") .. "]"
+                                       end
+                               end
                        end
 
                else
@@ -156,7 +216,7 @@ local function get_formspec(tabview, name, tabdata)
 end
 
 --------------------------------------------------------------------------------
-local function handle_doubleclick(pkg)
+local function handle_doubleclick(pkg, pkg_name)
        if pkg.type == "txp" then
                if core.settings:get("texture_path") == pkg.path then
                        core.settings:set("texture_path", "")
@@ -167,6 +227,9 @@ local function handle_doubleclick(pkg)
 
                mm_game_theme.init()
                mm_game_theme.reset()
+       elseif pkg.is_clientside then
+               pkgmgr.enable_mod({data = {list = packages, selected_mod = pkg_name}})
+               packages = nil
        end
 end
 
@@ -176,11 +239,27 @@ local function handle_buttons(tabview, fields, tabname, tabdata)
                local event = core.explode_table_event(fields["pkglist"])
                tabdata.selected_pkg = event.row
                if event.type == "DCL" then
-                       handle_doubleclick(packages:get_list()[tabdata.selected_pkg])
+                       handle_doubleclick(packages:get_list()[tabdata.selected_pkg], tabdata.selected_pkg)
                end
                return true
        end
 
+       if fields.btn_mod_mgr_mp_enable ~= nil or
+                       fields.btn_mod_mgr_mp_disable ~= nil then
+               pkgmgr.enable_mod({data = {list = packages, selected_mod = tabdata.selected_pkg}},
+                       fields.btn_mod_mgr_mp_enable ~= nil)
+               packages = nil
+               return true
+       end
+
+       if fields.btn_mod_mgr_enable_mod ~= nil or
+                       fields.btn_mod_mgr_disable_mod ~= nil then
+               pkgmgr.enable_mod({data = {list = packages, selected_mod = tabdata.selected_pkg}},
+                       fields.btn_mod_mgr_enable_mod ~= nil)
+               packages = nil
+               return true
+       end
+
        if fields["btn_contentdb"] ~= nil then
                local dlg = create_store_dlg()
                dlg:set_parent(tabview)
index 3f6f6c9fc32731fbaddbc79e302a508c1a21d2a0..a6a2b9c7763ecd4224326117fde3866df801ad08 100644 (file)
@@ -197,6 +197,10 @@ keymap_place (Place key) key KEY_RBUTTON
 #    See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
 keymap_inventory (Inventory key) key KEY_KEY_I
 
+#    Key for opening the special inventory.
+#    See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_special_inventory (Special inventory key) key KEY_KEY_O
+
 #    Key for moving fast in fast mode.
 #    See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
 keymap_aux1 (Aux1 key) key KEY_KEY_E
@@ -277,6 +281,14 @@ keymap_drop (Drop item key) key KEY_KEY_Q
 #    See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
 keymap_zoom (View zoom key) key KEY_KEY_Z
 
+#    Key for toggling Killaura.
+#    See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_toggle_killaura (Killaura key) key KEY_KEY_X
+
+#    Key for toggling Freecam.
+#    See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
+keymap_toggle_freecam (Freecam key) key KEY_KEY_G
+
 #    Key for selecting the first hotbar slot.
 #    See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
 keymap_slot1 (Hotbar slot 1 key) key KEY_KEY_1
@@ -2275,3 +2287,114 @@ contentdb_flag_blacklist (ContentDB Flag Blacklist) string nonfree, desktop_defa
 #    Maximum number of concurrent downloads. Downloads exceeding this limit will be queued.
 #    This should be lower than curl_parallel_limit.
 contentdb_max_concurrent_downloads (ContentDB Max Concurrent Downloads) int 3
+
+[Cheat Menu]
+
+#   Font to use for cheat menu
+cheat_menu_font (MenuFont) enum FM_Mono FM_Standard,FM_Mono,FM_Fallback,FM_MaxMode,FM_Unspecified
+
+#   (RGB value)
+cheat_menu_bg_color (Cell background color) v3f 255, 145, 88
+
+cheat_menu_bg_color_alpha (Cell background color alpha) int 192
+
+#   (RGB value)
+cheat_menu_active_bg_color (Active cell background color) v3f 255, 87, 53
+
+cheat_menu_active_bg_color_alpha (Active cell background color alpha) int 192
+
+#   (RGB value)
+cheat_menu_font_color (Font color) v3f 0, 0, 0
+
+cheat_menu_font_color_alpha (Font color alpha) int 255 
+
+#   (RGB value)
+cheat_menu_selected_font_color (Selected font color) v3f 255, 252, 88
+
+cheat_menu_selected_font_color_alpha (Selected font color alpha) int 255
+
+cheat_menu_head_height (Head height) int 50
+
+cheat_menu_entry_height (Entry height) int 40
+
+cheat_menu_entry_width (Entry width) int 200
+
+[Cheats]
+
+fullbright (Fullbright) bool false
+
+xray (XRay) bool false
+
+xray_nodes (XRay Nodes) string default:stone,mcl_core:stone
+
+priv_bypass (PrivBypass) bool true
+
+fastdig (FastDig) bool false
+
+fastplace (FastPlace) bool false
+
+autodig (AutoDig) bool false
+
+autoplace (AutoPlace) bool false
+
+prevent_natural_damage (NoFallDamage) bool true
+
+freecam (Freecam) bool false
+
+no_hurt_cam (NoHurtCam) bool false
+
+hud_flags_bypass (HUDBypass) bool true
+
+antiknockback (AntiKnockback) bool false
+
+entity_speed (EntitySpeed) bool false
+
+jesus (Jesus) bool false
+
+instant_break (InstantBreak) bool false
+
+no_night (BrightNight) bool false
+
+coords (Coords) bool false
+
+point_liquids (PointLiquids) bool false
+
+spamclick (FastHit) bool false
+
+no_force_rotate (NoForceRotate) bool false
+
+no_slow (NoSlow) bool false
+
+cheat_hud (CheatHUD) bool true
+
+node_esp_nodes (NodeESP Nodes) string
+
+jetpack (JetPack) bool false
+
+autohit (AutoHit) bool false
+
+antislip (AntiSlip) bool false
+
+enable_entity_tracers (EntityTracers) bool false
+
+enable_entity_esp (EntityESP) bool false
+
+enable_player_tracers (PlayerTracers) bool false
+
+enable_player_esp (PlayerESP) bool false
+
+enable_node_esp (NodeESP) bool false
+
+enable_node_tracers (NodeTracers) bool false
+
+entity_esp_color (EntityESP Color) v3f 255, 255, 255
+
+player_esp_color (PlayerESP Color) v3f 0, 255, 0
+
+tool_range (Additional Tool Range) int 2
+
+reach (Reach) bool false
+
+airjump (AirJump) bool false
+
+spider (Spider) bool false
diff --git a/clientmods/mods_here.txt b/clientmods/mods_here.txt
new file mode 100644 (file)
index 0000000..ea2175f
--- /dev/null
@@ -0,0 +1,4 @@
+You can install Minetest or Dragonfire clientmods by copying (and extracting) them into this folder.
+To enable them write
+  load_mod_<modname> = true
+in mods.conf in this directory.
diff --git a/clientmods/preview/example.lua b/clientmods/preview/example.lua
deleted file mode 100644 (file)
index 2f42eef..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-print("Loaded example file!, loading more examples")
-dofile(core.get_modpath(core.get_current_modname()) .. "/examples/first.lua")
diff --git a/clientmods/preview/examples/first.lua b/clientmods/preview/examples/first.lua
deleted file mode 100644 (file)
index c24f461..0000000
+++ /dev/null
@@ -1 +0,0 @@
-print("loaded first.lua example file")
diff --git a/clientmods/preview/init.lua b/clientmods/preview/init.lua
deleted file mode 100644 (file)
index 977ed0e..0000000
+++ /dev/null
@@ -1,203 +0,0 @@
-local modname = assert(core.get_current_modname())
-local modstorage = core.get_mod_storage()
-local mod_channel
-
-dofile(core.get_modpath(modname) .. "example.lua")
-
-core.register_on_shutdown(function()
-       print("[PREVIEW] shutdown client")
-end)
-local id = nil
-
-do
-       local server_info = core.get_server_info()
-       print("Server version: " .. server_info.protocol_version)
-       print("Server ip: " .. server_info.ip)
-       print("Server address: " .. server_info.address)
-       print("Server port: " .. server_info.port)
-
-       print("CSM restrictions: " .. dump(core.get_csm_restrictions()))
-
-       local l1, l2 = core.get_language()
-       print("Configured language: " .. l1 .. " / " .. l2)
-end
-
-mod_channel = core.mod_channel_join("experimental_preview")
-
-core.after(4, function()
-       if mod_channel:is_writeable() then
-               mod_channel:send_all("preview talk to experimental")
-       end
-end)
-
-core.after(1, function()
-       print("armor: " .. dump(core.localplayer:get_armor_groups()))
-       id = core.localplayer:hud_add({
-                       hud_elem_type = "text",
-                       name = "example",
-                       number = 0xff0000,
-                       position = {x=0, y=1},
-                       offset = {x=8, y=-8},
-                       text = "You are using the preview mod",
-                       scale = {x=200, y=60},
-                       alignment = {x=1, y=-1},
-       })
-end)
-
-core.register_on_modchannel_message(function(channel, sender, message)
-       print("[PREVIEW][modchannels] Received message `" .. message .. "` on channel `"
-                       .. channel .. "` from sender `" .. sender .. "`")
-       core.after(1, function()
-               mod_channel:send_all("CSM preview received " .. message)
-       end)
-end)
-
-core.register_on_modchannel_signal(function(channel, signal)
-       print("[PREVIEW][modchannels] Received signal id `" .. signal .. "` on channel `"
-                       .. channel)
-end)
-
-core.register_on_inventory_open(function(inventory)
-       print("INVENTORY OPEN")
-       print(dump(inventory))
-       return false
-end)
-
-core.register_on_placenode(function(pointed_thing, node)
-       print("The local player place a node!")
-       print("pointed_thing :" .. dump(pointed_thing))
-       print("node placed :" .. dump(node))
-       return false
-end)
-
-core.register_on_item_use(function(itemstack, pointed_thing)
-       print("The local player used an item!")
-       print("pointed_thing :" .. dump(pointed_thing))
-       print("item = " .. itemstack:get_name())
-
-       if not itemstack:is_empty() then
-               return false
-       end
-
-       local pos = core.camera:get_pos()
-       local pos2 = vector.add(pos, vector.multiply(core.camera:get_look_dir(), 100))
-
-       local rc = core.raycast(pos, pos2)
-       local i = rc:next()
-       print("[PREVIEW] raycast next: " .. dump(i))
-       if i then
-               print("[PREVIEW] line of sight: " .. (core.line_of_sight(pos, i.above) and "yes" or "no"))
-
-               local n1 = core.find_nodes_in_area(pos, i.under, {"default:stone"})
-               local n2 = core.find_nodes_in_area_under_air(pos, i.under, {"default:stone"})
-               print(("[PREVIEW] found %s nodes, %s nodes under air"):format(
-                               n1 and #n1 or "?", n2 and #n2 or "?"))
-       end
-
-       return false
-end)
-
--- This is an example function to ensure it's working properly, should be removed before merge
-core.register_on_receiving_chat_message(function(message)
-       print("[PREVIEW] Received message " .. message)
-       return false
-end)
-
--- This is an example function to ensure it's working properly, should be removed before merge
-core.register_on_sending_chat_message(function(message)
-       print("[PREVIEW] Sending message " .. message)
-       return false
-end)
-
-core.register_on_chatcommand(function(command, params)
-       print("[PREVIEW] caught command '"..command.."'. Parameters: '"..params.."'")
-end)
-
--- This is an example function to ensure it's working properly, should be removed before merge
-core.register_on_hp_modification(function(hp)
-       print("[PREVIEW] HP modified " .. hp)
-end)
-
--- This is an example function to ensure it's working properly, should be removed before merge
-core.register_on_damage_taken(function(hp)
-       print("[PREVIEW] Damage taken " .. hp)
-end)
-
--- This is an example function to ensure it's working properly, should be removed before merge
-core.register_chatcommand("dump", {
-       func = function(param)
-               return true, dump(_G)
-       end,
-})
-
-local function preview_minimap()
-       local minimap = core.ui.minimap
-       if not minimap then
-               print("[PREVIEW] Minimap is disabled. Skipping.")
-               return
-       end
-       minimap:set_mode(4)
-       minimap:show()
-       minimap:set_pos({x=5, y=50, z=5})
-       minimap:set_shape(math.random(0, 1))
-
-       print("[PREVIEW] Minimap: mode => " .. dump(minimap:get_mode()) ..
-                       " position => " .. dump(minimap:get_pos()) ..
-                       " angle => " .. dump(minimap:get_angle()))
-end
-
-core.after(2, function()
-       print("[PREVIEW] loaded " .. modname .. " mod")
-       modstorage:set_string("current_mod", modname)
-       assert(modstorage:get_string("current_mod") == modname)
-       preview_minimap()
-end)
-
-core.after(5, function()
-       if core.ui.minimap then
-               core.ui.minimap:show()
-       end
-
-       print("[PREVIEW] Time of day " .. core.get_timeofday())
-
-       print("[PREVIEW] Node level: " .. core.get_node_level({x=0, y=20, z=0}) ..
-               " max level " .. core.get_node_max_level({x=0, y=20, z=0}))
-
-       print("[PREVIEW] Find node near: " .. dump(core.find_node_near({x=0, y=20, z=0}, 10,
-               {"group:tree", "default:dirt", "default:stone"})))
-end)
-
-core.register_on_dignode(function(pos, node)
-       print("The local player dug a node!")
-       print("pos:" .. dump(pos))
-       print("node:" .. dump(node))
-       return false
-end)
-
-core.register_on_punchnode(function(pos, node)
-       print("The local player punched a node!")
-       local itemstack = core.localplayer:get_wielded_item()
-       print(dump(itemstack:to_table()))
-       print("pos:" .. dump(pos))
-       print("node:" .. dump(node))
-       local meta = core.get_meta(pos)
-       print("punched meta: " .. (meta and dump(meta:to_table()) or "(missing)"))
-       return false
-end)
-
-core.register_chatcommand("privs", {
-       func = function(param)
-               return true, core.privs_to_string(minetest.get_privilege_list())
-       end,
-})
-
-core.register_chatcommand("text", {
-       func = function(param)
-               return core.localplayer:hud_change(id, "text", param)
-       end,
-})
-
-
-core.register_on_mods_loaded(function()
-       core.log("Yeah preview mod is loaded with other CSM mods.")
-end)
diff --git a/clientmods/preview/mod.conf b/clientmods/preview/mod.conf
deleted file mode 100644 (file)
index 23a5c3e..0000000
+++ /dev/null
@@ -1 +0,0 @@
-name = preview
index d08cd9b5efeae6f84a52343e950ddc00286a1c6f..75e40945ff18517cf0f818e9de69ebb92eea7487 100644 (file)
@@ -86,9 +86,16 @@ Mod directory structure
     clientmods
     ├── modname
     │   ├── mod.conf
+    |   ├── settingtypes.txt
     │   ├── init.lua
     └── another
 
+### `settingtypes.txt`
+
+The format is documented in `builtin/settingtypes.txt`.
+It is parsed by the main menu settings dialogue to list mod-specific
+settings in the "Clientmods" category.
+
 ### modname
 
 The location of this directory.
@@ -212,7 +219,7 @@ For helper functions see "Vector helpers".
 ### pointed_thing
 * `{type="nothing"}`
 * `{type="node", under=pos, above=pos}`
-* `{type="object", id=ObjectID}`
+* `{type="object", ref=ClientObjectRef}`
 
 Flag Specifier Format
 ---------------------
@@ -671,6 +678,14 @@ Minetest namespace reference
 ### Global callback registration functions
 Call these functions only at load time!
 
+* `minetest.get_send_speed(speed)`
+       * This function is called every time the player's speed is sent to server
+       * The `speed` argument is the actual speed of the player
+       * If you define it, you can return a modified `speed`. This speed will be
+               sent to server instead.
+* `minetest.open_enderchest()`
+    * This function is called if the client uses the Keybind for it (by default "O")
+    * You can override it
 * `minetest.register_globalstep(function(dtime))`
     * Called every client environment step, usually interval of 0.1s
 * `minetest.register_on_mods_loaded(function())`
@@ -690,6 +705,13 @@ Call these functions only at load time!
     * Adds definition to minetest.registered_chatcommands
 * `minetest.unregister_chatcommand(name)`
     * Unregisters a chatcommands registered with register_chatcommand.
+* `minetest.register_list_command(command, desc, setting)`
+    * Registers a chatcommand `command` to manage a list that takes the args `del | add | list <param>`
+    * The list is stored comma-seperated in `setting`
+    * `desc` is the description
+    * `add` adds something to the list
+    * `del` del removes something from the list
+    * `list` lists all items on the list
 * `minetest.register_on_chatcommand(function(command, params))`
     * Called always when a chatcommand is triggered, before `minetest.registered_chatcommands`
       is checked to see if that the command exists, but after the input is parsed.
@@ -738,6 +760,32 @@ Call these functions only at load time!
     * Called when the local player open inventory
     * Newest functions are called first
     * If any function returns true, inventory doesn't open
+* `minetest.register_on_recieve_physics_override(function(override))`
+    * Called when recieving physics_override from server
+    * Newest functions are called first
+    * If any function returns true, the physics override does not change
+* `minetest.register_on_play_sound(function(SimpleSoundSpec))`
+    * Called when recieving a play sound command from server
+    * Newest functions are called first
+    * If any function returns true, the sound does not play
+* `minetest.register_on_spawn_partice(function(particle definition))`
+    * Called when recieving a spawn particle command from server
+    * Newest functions are called first
+    * If any function returns true, the particle does not spawn
+* `minetest.register_on_object_add(function(obj))`
+       * Called every time an object is added
+* `minetest.register_on_object_properties_change(function(obj))`
+    * Called every time the properties of an object are changed server-side
+    * May modify the object's properties without the fear of infinite recursion
+* `minetest.register_on_object_hp_change(function(obj))`
+    * Called every time the hp of an object are changes server-side
+
+### Setting-related
+* `minetest.settings`: Settings object containing all of the settings from the
+  main config file (`minetest.conf`).
+* `minetest.setting_get_pos(name)`: Loads a setting from the main settings and
+  parses it as a position (in the format `(1,2,3)`). Returns a position or nil.
+
 ### Sounds
 * `minetest.sound_play(spec, parameters)`: returns a handle
     * `spec` is a `SimpleSoundSpec`
@@ -761,6 +809,20 @@ Call these functions only at load time!
     * Returns the time of day: `0` for midnight, `0.5` for midday
 
 ### Map
+* `minetest.interact(action, pointed_thing)`
+    * Sends an interaction to the server
+    * `pointed_thing` is a pointed_thing
+    * `action` is one of
+        * "start_digging": Use to punch nodes / objects
+        * "stop_digging": Use to abort digging a "start_digging" command
+        * "digging_completed": Use to finish a "start_digging" command or dig a node instantly
+        * "place": Use to rightclick nodes and objects
+        * "use": Use to leftclick an item in air (pointed_thing.type is usually "nothing")
+        * "activate": Same as "use", but rightclick
+* `minetest.place_node(pos)`
+    * Places the wielded node/item of the player at pos.
+* `minetest.dig_node(pos)`
+    * Instantly digs the node at pos. This may fuck up with anticheat.
 * `minetest.get_node_or_nil(pos)`
     * Returns the node at the given position as table in the format
       `{name="node_name", param1=0, param2=0}`, returns `nil`
@@ -777,6 +839,26 @@ Call these functions only at load time!
     * `nodenames`: e.g. `{"ignore", "group:tree"}` or `"default:dirt"`
     * `search_center` is an optional boolean (default: `false`)
       If true `pos` is also checked for the nodes
+* `minetest.find_nodes_near(pos, radius, nodenames, [search_center])`: returns a
+  list of positions.
+    * `radius`: using a maximum metric
+    * `nodenames`: e.g. `{"ignore", "group:tree"}` or `"default:dirt"`
+    * `search_center` is an optional boolean (default: `false`)
+      If true `pos` is also checked for the nodes
+* `minetest.find_nodes_near_under_air(pos, radius, nodenames, [search_center])`: returns a
+  list of positions.
+    * `radius`: using a maximum metric
+    * `nodenames`: e.g. `{"ignore", "group:tree"}` or `"default:dirt"`
+    * `search_center` is an optional boolean (default: `false`)
+      If true `pos` is also checked for the nodes
+    * Return value: Table with all node positions with a node air above
+* `minetest.find_nodes_near_under_air_except(pos, radius, nodenames, [search_center])`: returns a
+  list of positions.
+    * `radius`: using a maximum metric
+    * `nodenames`: e.g. `{"ignore", "group:tree"}` or `"default:dirt"`, specifies the nodes to be ignored
+    * `search_center` is an optional boolean (default: `false`)
+      If true `pos` is also checked for the nodes
+    * Return value: Table with all node positions with a node air above
 * `minetest.find_nodes_in_area(pos1, pos2, nodenames, [grouped])`
     * `pos1` and `pos2` are the min and max positions of the area to search.
     * `nodenames`: e.g. `{"ignore", "group:tree"}` or `"default:dirt"`
@@ -804,7 +886,33 @@ Call these functions only at load time!
     * `pos2`: end of the ray
     * `objects`: if false, only nodes will be returned. Default is `true`.
     * `liquids`: if false, liquid nodes won't be returned. Default is `false`.
-
+* `minetest.get_pointed_thing()` returns `PointedThing`
+    * Returns the thing currently pointed by player
+* `minetest.get_pointed_thing_position(pointed_thing, above)`
+    * Returns the position of a `pointed_thing` or `nil` if the `pointed_thing`
+      does not refer to a node or entity.
+    * If the optional `above` parameter is true and the `pointed_thing` refers
+      to a node, then it will return the `above` position of the `pointed_thing`.
+* `minetest.find_path(pos1,pos2,searchdistance,max_jump,max_drop,algorithm)`
+    * returns table containing path that can be walked on
+    * returns a table of 3D points representing a path from `pos1` to `pos2` or
+      `nil` on failure.
+    * Reasons for failure:
+        * No path exists at all
+        * No path exists within `searchdistance` (see below)
+        * Start or end pos is buried in land
+    * `pos1`: start position
+    * `pos2`: end position
+    * `searchdistance`: maximum distance from the search positions to search in.
+      In detail: Path must be completely inside a cuboid. The minimum
+      `searchdistance` of 1 will confine search between `pos1` and `pos2`.
+      Larger values will increase the size of this cuboid in all directions
+    * `max_jump`: maximum height difference to consider walkable
+    * `max_drop`: maximum height difference to consider droppable
+    * `algorithm`: One of `"A*_noprefetch"` (default), `"A*"`, `"Dijkstra"`.
+      Difference between `"A*"` and `"A*_noprefetch"` is that
+      `"A*"` will pre-calculate the cost-data, the other will calculate it
+      on-the-fly
 * `minetest.find_nodes_with_meta(pos1, pos2)`
     * Get a table of positions of nodes that have metadata within a region
       {pos1, pos2}.
@@ -816,12 +924,16 @@ Call these functions only at load time!
     * get max available level for leveled node
 
 ### Player
+* `minetest.send_damage(hp)`
+    * Sends fall damage to server
 * `minetest.send_chat_message(message)`
     * Act as if `message` was typed by the player into the terminal.
 * `minetest.run_server_chatcommand(cmd, param)`
     * Alias for `minetest.send_chat_message("/" .. cmd .. " " .. param)`
 * `minetest.clear_out_chat_queue()`
     * Clears the out chat queue
+* `minetest.drop_selected_item()`
+    * Drops the selected item
 * `minetest.localplayer`
     * Reference to the LocalPlayer object. See [`LocalPlayer`](#localplayer) class reference for methods.
 
@@ -833,8 +945,15 @@ Call these functions only at load time!
     * Convert between two privilege representations
 
 ### Client Environment
+* `minetest.object_refs`
+    * Map of object references, indexed by active object id
 * `minetest.get_player_names()`
     * Returns list of player names on server (nil if CSM_RF_READ_PLAYERINFO is enabled by server)
+* `minetest.get_objects_inside_radius(pos, radius)`: returns a list of
+  ClientObjectRefs.
+    * `radius`: using an euclidean metric
+* `minetest.get_nearby_objects(radius)`
+    * alias for minetest.get_objects_inside_radius(minetest.localplayer:get_pos(), radius)
 * `minetest.disconnect()`
     * Disconnect from the server and exit to main menu.
     * Returns `false` if the client is already disconnecting otherwise returns `true`.
@@ -843,6 +962,81 @@ Call these functions only at load time!
 * `minetest.send_respawn()`
     * Sends a respawn request to the server.
 
+### HTTP Requests
+
+* `minetest.request_http_api()`:
+    * returns `HTTPApiTable` containing http functions if the calling mod has
+      been granted access by being listed in the `secure.http_mods` or
+      `secure.trusted_mods` setting, otherwise returns `nil`.
+    * The returned table contains the functions `fetch`, `fetch_async` and
+      `fetch_async_get` described below.
+    * Only works at init time and must be called from the mod's main scope
+      (not from a function).
+    * Function only exists if minetest server was built with cURL support.
+    * **DO NOT ALLOW ANY OTHER MODS TO ACCESS THE RETURNED TABLE, STORE IT IN
+      A LOCAL VARIABLE!**
+* `HTTPApiTable.fetch(HTTPRequest req, callback)`
+    * Performs given request asynchronously and calls callback upon completion
+    * callback: `function(HTTPRequestResult res)`
+    * Use this HTTP function if you are unsure, the others are for advanced use
+* `HTTPApiTable.fetch_async(HTTPRequest req)`: returns handle
+    * Performs given request asynchronously and returns handle for
+      `HTTPApiTable.fetch_async_get`
+* `HTTPApiTable.fetch_async_get(handle)`: returns HTTPRequestResult
+    * Return response data for given asynchronous HTTP request
+
+### `HTTPRequest` definition
+
+Used by `HTTPApiTable.fetch` and `HTTPApiTable.fetch_async`.
+
+    {
+        url = "http://example.org",
+
+        timeout = 10,
+        -- Timeout for connection in seconds. Default is 3 seconds.
+
+        post_data = "Raw POST request data string" OR {field1 = "data1", field2 = "data2"},
+        -- Optional, if specified a POST request with post_data is performed.
+        -- Accepts both a string and a table. If a table is specified, encodes
+        -- table as x-www-form-urlencoded key-value pairs.
+        -- If post_data is not specified, a GET request is performed instead.
+
+        user_agent = "ExampleUserAgent",
+        -- Optional, if specified replaces the default minetest user agent with
+        -- given string
+
+        extra_headers = { "Accept-Language: en-us", "Accept-Charset: utf-8" },
+        -- Optional, if specified adds additional headers to the HTTP request.
+        -- You must make sure that the header strings follow HTTP specification
+        -- ("Key: Value").
+
+        multipart = boolean
+        -- Optional, if true performs a multipart HTTP request.
+        -- Default is false.
+    }
+
+### `HTTPRequestResult` definition
+
+Passed to `HTTPApiTable.fetch` callback. Returned by
+`HTTPApiTable.fetch_async_get`.
+
+    {
+        completed = true,
+        -- If true, the request has finished (either succeeded, failed or timed
+        -- out)
+
+        succeeded = true,
+        -- If true, the request was successful
+
+        timeout = false,
+        -- If true, the request timed out
+
+        code = 200,
+        -- HTTP status code
+
+        data = "response"
+    }
+
 ### Storage API
 * `minetest.get_mod_storage()`:
     * returns reference to mod private `StorageRef`
@@ -866,7 +1060,27 @@ Call these functions only at load time!
 * `minetest.delete_particlespawner(id)`
     * Delete `ParticleSpawner` with `id` (return value from `minetest.add_particlespawner`)
 
-### Misc.
+### Misc
+* `minetest.set_keypress(key, value)`
+    * Act as if a key was pressed (value = true) / released (value = false)
+    * The key must be an keymap_* setting
+    * e.g. minetest.set_keypress("jump", true) will cause te player to jump until minetest.set_keypress("jump", false) is called or the player presses & releases the space bar himself
+* `minetest.get_inventory(location)`
+    * Returns the inventory at location
+* `minetest.find_item(item)`
+    * finds and an item in the inventory
+    * returns index on success or nil if item is not found
+* `minetest.switch_to_item(item)`
+    * `item` is an Itemstring
+    * searches to item in inventory, sets the wield index to it if found
+    * returns true on success, false if item was not found
+* `minetest.register_cheat(name, category, setting | function)`
+    * Register an entry for the cheat menu
+    * If the Category is nonexistant, it will be created
+    * If the 3rd argument is a string it will be interpreted as a setting and toggled
+        when the player selects the entry in the cheat menu
+    * If the 3rd argument is a function it will be called
+        when the player selects the entry in the cheat menu
 * `minetest.parse_json(string[, nullvalue])`: returns something
     * Convert a string containing JSON data into the Lua equivalent
     * `nullvalue`: returned in place of the JSON null; defaults to `nil`
@@ -926,6 +1140,16 @@ Call these functions only at load time!
     * returns the exact position on the surface of a pointed node
 * `minetest.global_exists(name)`
     * Checks if a global variable has been set, without triggering a warning.
+* `minetest.make_screenshot()`
+    * Triggers the MT makeScreenshot functionality
+* `minetest.request_insecure_environment()`: returns an environment containing
+  insecure functions if the calling mod has been listed as trusted in the
+  `secure.trusted_mods` setting or security is disabled, otherwise returns
+  `nil`.
+    * Only works at init time and must be called from the mod's main scope
+      (ie: the init.lua of the mod, not from another Lua file or within a function).
+    * **DO NOT ALLOW ANY OTHER MODS TO ACCESS THE RETURNED ENVIRONMENT, STORE
+      IT IN A LOCAL VARIABLE!**
 
 ### UI
 * `minetest.ui.minimap`
@@ -935,6 +1159,14 @@ Call these functions only at load time!
     * Reference to the camera object. See [`Camera`](#camera) class reference for methods.
 * `minetest.show_formspec(formname, formspec)` : returns true on success
        * Shows a formspec to the player
+* `minetest.close_formspec(formname)`
+    * `formname`: has to exactly match the one given in `show_formspec`, or the
+      formspec will not close.
+    * calling `show_formspec(formname, "")` is equal to this
+      expression.
+    * to close a formspec regardless of the formname, call
+      `minetest.close_formspec("")`.
+      **USE THIS ONLY WHEN ABSOLUTELY NECESSARY!**
 * `minetest.display_chat_message(message)` returns true on success
        * Shows a chat message to the current player.
 
@@ -1013,14 +1245,28 @@ Methods:
 
 * `get_pos()`
     * returns current player current position
+* `set_pos(pos)`
+    * sets the position (anticheat may not like this)
+* `get_yaw()`
+    * returns the yaw (degrees)
+* `set_yaw(yaw)`
+    * sets the yaw (degrees)
+* `get_pitch()`
+    * returns the pitch (degrees)
+* `set_pitch(pitch)`
+    * sets the pitch (degrees)
 * `get_velocity()`
     * returns player speed vector
+* `set_velocity(vel)`
+    * sets player speed vector
 * `get_hp()`
     * returns player HP
 * `get_name()`
     * returns player name
 * `get_wield_index()`
-    * returns the index of the wielded item
+    * returns the index of the wielded item (starts at 1)
+* `set_wield_index()`
+    * sets the index (starts at 1)
 * `get_wielded_item()`
     * returns the itemstack the player is holding
 * `is_attached()`
@@ -1051,6 +1297,17 @@ Methods:
     }
 ```
 
+* `set_physics_override(override_table)`
+    * `override_table` is a table with the following fields:
+        * `speed`: multiplier to default walking speed value (default: `1`)
+        * `jump`: multiplier to default jump value (default: `1`)
+        * `gravity`: multiplier to default gravity value (default: `1`)
+        * `sneak`: whether player can sneak (default: `true`)
+        * `sneak_glitch`: whether player can use the new move code replications
+          of the old sneak side-effects: sneak ladders and 2 node sneak jump
+          (default: `false`)
+        * `new_move`: use new move/sneak code. When `false` the exact old code
+          is used for the specific old sneak behaviour (default: `true`)
 * `get_override_pos()`
     * returns override position
 * `get_last_pos()`
@@ -1130,6 +1387,8 @@ Methods:
     * change a value of a previously added HUD element
     * element `stat` values: `position`, `name`, `scale`, `text`, `number`, `item`, `dir`
     * Returns `true` on success, otherwise returns `nil`
+* `get_object()`
+    * Returns the ClientObjectRef for the player
 
 ### Settings
 An interface to read config files in the format of `minetest.conf`.
@@ -1158,6 +1417,30 @@ Can be obtained via `minetest.get_meta(pos)`.
     * `fields`: key-value storage
     * `inventory`: `{list1 = {}, ...}}`
 
+### ClientObjectRef
+
+Moving things in the game are generally these.
+This is basically a reference to a C++ `GenericCAO`.
+
+#### Methods
+
+* `get_pos()`: returns `{x=num, y=num, z=num}`
+* `get_velocity()`: returns the velocity, a vector
+* `get_acceleration()`: returns the acceleration, a vector
+* `get_rotation()`: returns the rotation, a vector (radians)
+* `is_player()`: returns true if the object is a player
+* `is_local_player()`: returns true if the object is the local player
+* `get_attach()`: returns parent or nil if it isn't attached.
+* `get_nametag()`: returns the nametag (deprecated, use get_properties().nametag instead)
+* `get_item_textures()`: returns the textures (deprecated, use get_properties().textures instead)
+* `get_max_hp()`: returns the maximum heath (deprecated, use get_properties().hp_max instead)
+* `set_properties(object property table)`
+* `get_properties()`: returns object property table
+* `punch()`: punches the object
+* `rightclick()`: rightclicks the object
+* `remove()`: removes the object permanently
+* `set_nametag_images(images)`: Provides a list of images to be drawn below the nametag
+
 ### `Raycast`
 
 A raycast on the map. It works with selection boxes.
@@ -1186,15 +1469,80 @@ It can be created via `Raycast(pos1, pos2, objects, liquids)` or
 
 -----------------
 ### Definitions
+* `minetest.inventorycube(img1, img2, img3)`
+    * Returns a string for making an image of a cube (useful as an item image)
 * `minetest.get_node_def(nodename)`
        * Returns [node definition](#node-definition) table of `nodename`
 * `minetest.get_item_def(itemstring)`
        * Returns item definition table of `itemstring`
+* `minetest.override_item(itemstring, redefinition)`
+    * Overrides fields of an item registered with register_node/tool/craftitem.
+    * Note: Item must already be defined by the server
+    * Example: `minetest.override_item("default:mese",
+      {light_source=minetest.LIGHT_MAX})`
+    * Doesnt really work yet an causes strange bugs, I'm working to make is better
+
+
+#### Tile definition
+
+* `"image.png"`
+* `{name="image.png", animation={Tile Animation definition}}`
+* `{name="image.png", backface_culling=bool, align_style="node"/"world"/"user", scale=int}`
+    * backface culling enabled by default for most nodes
+    * align style determines whether the texture will be rotated with the node
+      or kept aligned with its surroundings. "user" means that client
+      setting will be used, similar to `glasslike_framed_optional`.
+      Note: supported by solid nodes and nodeboxes only.
+    * scale is used to make texture span several (exactly `scale`) nodes,
+      instead of just one, in each direction. Works for world-aligned
+      textures only.
+      Note that as the effect is applied on per-mapblock basis, `16` should
+      be equally divisible by `scale` or you may get wrong results.
+* `{name="image.png", color=ColorSpec}`
+    * the texture's color will be multiplied with this color.
+    * the tile's color overrides the owning node's color in all cases.
+
+##### Tile definition
+
+    {
+        type = "vertical_frames",
+
+        aspect_w = 16,
+        -- Width of a frame in pixels
+
+        aspect_h = 16,
+        -- Height of a frame in pixels
+
+        length = 3.0,
+        -- Full loop length
+    }
+
+    {
+        type = "sheet_2d",
+
+        frames_w = 5,
+        -- Width in number of frames
+
+        frames_h = 3,
+        -- Height in number of frames
+
+        frame_length = 0.5,
+        -- Length of a single frame
+    }
 
 #### Node Definition
 
 ```lua
        {
+        tiles = {tile definition 1, def2, def3, def4, def5, def6},
+        -- Textures of node; +Y, -Y, +X, -X, +Z, -Z
+        overlay_tiles = {tile definition 1, def2, def3, def4, def5, def6},
+        -- Same as `tiles`, but these textures are drawn on top of the base
+        -- tiles. This is used to colorize only specific parts of the
+        -- texture. If the texture name is an empty string, that overlay is not
+        -- drawn
+        special_tiles = {tile definition 1, Tile definition 2},
+        -- Special textures of node; used rarely.
                has_on_construct = bool,        -- Whether the node has the on_construct callback defined
                has_on_destruct = bool,         -- Whether the node has the on_destruct callback defined
                has_after_destruct = bool,      -- Whether the node has the after_destruct callback defined
@@ -1334,6 +1682,8 @@ The following functions provide escape sequences:
       `minetest.get_color_escape_sequence(color) ..
        message ..
        minetest.get_color_escape_sequence("#ffffff")`
+* `minetest.rainbow(message)`:
+    * Rainbow colorizes the message.
 * `minetest.get_background_escape_sequence(color)`
     * `color` is a [ColorString](#colorstring)
     * The escape sequence sets the background of the whole text element to
@@ -1517,3 +1867,48 @@ Same as `image`, but does not accept a `position`; the position is instead deter
         texture = "image.png",
     --  ^ Uses texture (string)
     }
+
+### InventoryAction
+A reference to a C++ InventoryAction. You can move, drop and craft items in all accessible inventories using InventoryActions.
+
+#### methods
+
+* `InventoryAction(type)`:
+    * creates a new InventoryAction
+    * type is on of "move", "drop", or "craft", else returns nil
+    * indexing starts at 1
+* `apply()`:
+    * applies the InventoryAction (InventoryActions can be applied multible times)
+* `from(inventorylocation, listname, stack)`
+    * this is valid for move or drop actions
+    * when `apply()` is called items are moved / dropped from `listname` `inventorylocation` in` at `stack`
+* `to(inventorylocation, listname, stack)`
+    * this is valid for move actions
+    * when `apply()` is called items are moved to `listname` in`inventorylocation` at `stack`
+* `craft(inventoryaction)`
+    * this is valid for craft actions
+    * when `apply()` is called a craft event for this inventory will be triggered
+* `set_count(count)`
+    * this is valid for all actions
+    * it specifies how many items to drop / craft / move
+    * `0` means move all items
+    * default count: `0`
+
+#### example
+    `local move_act = InventoryAction("move")
+    move_act:from("current_player", "main", 1)
+    move_act:to("current_player", "craft", 1)
+    move_act:set_count(1)
+    local craft_act = InventoryAction("craft")
+    craft_act:craft("current_player")
+    local drop_act = InventoryAction("drop")
+    drop_act:from("current_player", "craft_result",10)
+    move_act:apply()
+    craft_act:apply()
+    drop_act:apply()
+    `
+    * e.g. In first hotbar slot there are tree logs: Move one to craft field, then craft wood out of it and immediately drop it
+
+
+
+
index 15a067a5ed82ea037fda7638d5fdeaef00ae4371..d277429b3f32998b85b5e4b67372b247f9e63712 100644 (file)
@@ -3284,6 +3284,8 @@ The following functions provide escape sequences:
       `minetest.get_color_escape_sequence(color) ..
       message ..
       minetest.get_color_escape_sequence("#ffffff")`
+* `minetest.rainbow(message)`:
+    * Rainbow colorizes the message.
 * `minetest.get_background_escape_sequence(color)`
     * `color` is a ColorString
     * The escape sequence sets the background of the whole text element to
diff --git a/doc/protocol.md b/doc/protocol.md
new file mode 100644 (file)
index 0000000..4c8ddd5
--- /dev/null
@@ -0,0 +1,110 @@
+Minetest protocol (incomplete, early draft):
+Updated 2011-06-18
+
+A custom protocol over UDP.
+Integers are big endian.
+Refer to connection.{h,cpp} for further reference.
+
+Initialization:
+- A dummy reliable packet with peer_id=PEER_ID_INEXISTENT=0 is sent to the server:
+       - Actually this can be sent without the reliable packet header, too, i guess,
+         but the sequence number in the header allows the sender to re-send the
+         packet without accidentally getting a double initialization.
+       - Packet content:
+               # Basic header
+               u32 protocol_id = PROTOCOL_ID = 0x4f457403
+               u16 sender_peer_id = PEER_ID_INEXISTENT = 0
+               u8 channel = 0
+               # Reliable packet header
+               u8 type = TYPE_RELIABLE = 3
+               u16 seqnum = SEQNUM_INITIAL = 65500
+               # Original packet header
+               u8 type = TYPE_ORIGINAL = 1
+               # And no actual payload.
+- Server responds with something like this:
+       - Packet content:
+               # Basic header
+               u32 protocol_id = PROTOCOL_ID = 0x4f457403
+               u16 sender_peer_id = PEER_ID_INEXISTENT = 0
+               u8 channel = 0
+               # Reliable packet header
+               u8 type = TYPE_RELIABLE = 3
+               u16 seqnum = SEQNUM_INITIAL = 65500
+               # Control packet header
+               u8 type = TYPE_CONTROL = 0
+               u8 controltype = CONTROLTYPE_SET_PEER_ID = 1
+               u16 peer_id_new = assigned peer id to client (other than 0 or 1)
+- Then the connection can be disconnected by sending:
+       - Packet content:
+               # Basic header
+               u32 protocol_id = PROTOCOL_ID = 0x4f457403
+               u16 sender_peer_id = whatever was gotten in CONTROLTYPE_SET_PEER_ID
+               u8 channel = 0
+               # Control packet header
+               u8 type = TYPE_CONTROL = 0
+               u8 controltype = CONTROLTYPE_DISCO = 3
+
+- Here's a quick untested connect-disconnect done in PHP:
+# host: ip of server (use gethostbyname(hostname) to get from a dns name)
+# port: port of server
+function check_if_minetestserver_up($host, $port)
+{
+       $socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
+       $timeout = array("sec" => 1, "usec" => 0);
+       socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, $timeout);
+       $buf = "\x4f\x45\x74\x03\x00\x00\x00\x03\xff\xdc\x01";
+       socket_sendto($socket, $buf, strlen($buf), 0, $host, $port);
+       $buf = socket_read($socket, 1000);
+       if($buf != "")
+       {
+               # We got a reply! read the peer id from it.
+               $peer_id = substr($buf, 9, 2);
+
+               # Disconnect
+               $buf = "\x4f\x45\x74\x03".$peer_id."\x00\x00\x03";
+               socket_sendto($socket, $buf, strlen($buf), 0, $host, $port);
+               socket_close($socket);
+
+               return true;
+       }
+       return false;
+}
+
+- Here's a Python script for checking if a minetest server is up, confirmed working
+
+#!/usr/bin/env python3
+import sys, time, socket
+
+address = ""
+port = 30000
+if len(sys.argv) <= 1:
+    print("Usage: %s <address>" % sys.argv[0])
+    exit()
+if ":" in sys.argv[1]:
+    address = sys.argv[1].split(":")[0]
+    try:
+        port = int(sys.argv[1].split(":")[1])
+    except ValueError:
+        print("Please specify a valid port")
+        exit()
+else:
+    address = sys.argv[1]
+
+try:
+    start = time.time()
+    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+    sock.settimeout(2.0)
+    buf = b"\x4f\x45\x74\x03\x00\x00\x00\x01"
+    sock.sendto(buf, (address, port))
+    data, addr = sock.recvfrom(1000)
+    if data:
+        peer_id = data[12:14]
+        buf = b"\x4f\x45\x74\x03" + peer_id + b"\x00\x00\x03"
+        sock.sendto(buf, (address, port))
+        sock.close()
+        end = time.time()
+        print("%s is up (%0.5fms)" % (sys.argv[1], end - start))
+    else:
+        print("%s seems to be down " % sys.argv[1])
+except Exception as err:
+    print("%s seems to be down (%s) " % (sys.argv[1], str(err)))
diff --git a/doc/protocol.txt b/doc/protocol.txt
deleted file mode 100644 (file)
index 4c8ddd5..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-Minetest protocol (incomplete, early draft):
-Updated 2011-06-18
-
-A custom protocol over UDP.
-Integers are big endian.
-Refer to connection.{h,cpp} for further reference.
-
-Initialization:
-- A dummy reliable packet with peer_id=PEER_ID_INEXISTENT=0 is sent to the server:
-       - Actually this can be sent without the reliable packet header, too, i guess,
-         but the sequence number in the header allows the sender to re-send the
-         packet without accidentally getting a double initialization.
-       - Packet content:
-               # Basic header
-               u32 protocol_id = PROTOCOL_ID = 0x4f457403
-               u16 sender_peer_id = PEER_ID_INEXISTENT = 0
-               u8 channel = 0
-               # Reliable packet header
-               u8 type = TYPE_RELIABLE = 3
-               u16 seqnum = SEQNUM_INITIAL = 65500
-               # Original packet header
-               u8 type = TYPE_ORIGINAL = 1
-               # And no actual payload.
-- Server responds with something like this:
-       - Packet content:
-               # Basic header
-               u32 protocol_id = PROTOCOL_ID = 0x4f457403
-               u16 sender_peer_id = PEER_ID_INEXISTENT = 0
-               u8 channel = 0
-               # Reliable packet header
-               u8 type = TYPE_RELIABLE = 3
-               u16 seqnum = SEQNUM_INITIAL = 65500
-               # Control packet header
-               u8 type = TYPE_CONTROL = 0
-               u8 controltype = CONTROLTYPE_SET_PEER_ID = 1
-               u16 peer_id_new = assigned peer id to client (other than 0 or 1)
-- Then the connection can be disconnected by sending:
-       - Packet content:
-               # Basic header
-               u32 protocol_id = PROTOCOL_ID = 0x4f457403
-               u16 sender_peer_id = whatever was gotten in CONTROLTYPE_SET_PEER_ID
-               u8 channel = 0
-               # Control packet header
-               u8 type = TYPE_CONTROL = 0
-               u8 controltype = CONTROLTYPE_DISCO = 3
-
-- Here's a quick untested connect-disconnect done in PHP:
-# host: ip of server (use gethostbyname(hostname) to get from a dns name)
-# port: port of server
-function check_if_minetestserver_up($host, $port)
-{
-       $socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
-       $timeout = array("sec" => 1, "usec" => 0);
-       socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, $timeout);
-       $buf = "\x4f\x45\x74\x03\x00\x00\x00\x03\xff\xdc\x01";
-       socket_sendto($socket, $buf, strlen($buf), 0, $host, $port);
-       $buf = socket_read($socket, 1000);
-       if($buf != "")
-       {
-               # We got a reply! read the peer id from it.
-               $peer_id = substr($buf, 9, 2);
-
-               # Disconnect
-               $buf = "\x4f\x45\x74\x03".$peer_id."\x00\x00\x03";
-               socket_sendto($socket, $buf, strlen($buf), 0, $host, $port);
-               socket_close($socket);
-
-               return true;
-       }
-       return false;
-}
-
-- Here's a Python script for checking if a minetest server is up, confirmed working
-
-#!/usr/bin/env python3
-import sys, time, socket
-
-address = ""
-port = 30000
-if len(sys.argv) <= 1:
-    print("Usage: %s <address>" % sys.argv[0])
-    exit()
-if ":" in sys.argv[1]:
-    address = sys.argv[1].split(":")[0]
-    try:
-        port = int(sys.argv[1].split(":")[1])
-    except ValueError:
-        print("Please specify a valid port")
-        exit()
-else:
-    address = sys.argv[1]
-
-try:
-    start = time.time()
-    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
-    sock.settimeout(2.0)
-    buf = b"\x4f\x45\x74\x03\x00\x00\x00\x01"
-    sock.sendto(buf, (address, port))
-    data, addr = sock.recvfrom(1000)
-    if data:
-        peer_id = data[12:14]
-        buf = b"\x4f\x45\x74\x03" + peer_id + b"\x00\x00\x03"
-        sock.sendto(buf, (address, port))
-        sock.close()
-        end = time.time()
-        print("%s is up (%0.5fms)" % (sys.argv[1], end - start))
-    else:
-        print("%s seems to be down " % sys.argv[1])
-except Exception as err:
-    print("%s seems to be down (%s) " % (sys.argv[1], str(err)))
diff --git a/games/devtest/mods/basetools/.sounds/default_grass_footstep.1.ogg b/games/devtest/mods/basetools/.sounds/default_grass_footstep.1.ogg
new file mode 100644 (file)
index 0000000..ce625d9
Binary files /dev/null and b/games/devtest/mods/basetools/.sounds/default_grass_footstep.1.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_break_glass.1.ogg b/games/devtest/mods/basetools/sounds/default_break_glass.1.ogg
new file mode 100644 (file)
index 0000000..b1ccc5f
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_break_glass.1.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_break_glass.2.ogg b/games/devtest/mods/basetools/sounds/default_break_glass.2.ogg
new file mode 100644 (file)
index 0000000..b6cc9e8
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_break_glass.2.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_break_glass.3.ogg b/games/devtest/mods/basetools/sounds/default_break_glass.3.ogg
new file mode 100644 (file)
index 0000000..ae6a6bf
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_break_glass.3.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_chest_close.ogg b/games/devtest/mods/basetools/sounds/default_chest_close.ogg
new file mode 100644 (file)
index 0000000..068d900
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_chest_close.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_chest_open.ogg b/games/devtest/mods/basetools/sounds/default_chest_open.ogg
new file mode 100644 (file)
index 0000000..40b0b93
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_chest_open.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_cool_lava.1.ogg b/games/devtest/mods/basetools/sounds/default_cool_lava.1.ogg
new file mode 100644 (file)
index 0000000..42506dd
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_cool_lava.1.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_cool_lava.2.ogg b/games/devtest/mods/basetools/sounds/default_cool_lava.2.ogg
new file mode 100644 (file)
index 0000000..2747ab8
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_cool_lava.2.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_cool_lava.3.ogg b/games/devtest/mods/basetools/sounds/default_cool_lava.3.ogg
new file mode 100644 (file)
index 0000000..8baeac3
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_cool_lava.3.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_dig_choppy.ogg b/games/devtest/mods/basetools/sounds/default_dig_choppy.ogg
new file mode 100644 (file)
index 0000000..e2ecd84
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_dig_choppy.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_dig_cracky.ogg b/games/devtest/mods/basetools/sounds/default_dig_cracky.ogg
new file mode 100644 (file)
index 0000000..da11679
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_dig_cracky.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_dig_crumbly.ogg b/games/devtest/mods/basetools/sounds/default_dig_crumbly.ogg
new file mode 100644 (file)
index 0000000..a0b2a1f
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_dig_crumbly.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_dig_dig_immediate.ogg b/games/devtest/mods/basetools/sounds/default_dig_dig_immediate.ogg
new file mode 100644 (file)
index 0000000..e65d766
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_dig_dig_immediate.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_dig_metal.ogg b/games/devtest/mods/basetools/sounds/default_dig_metal.ogg
new file mode 100644 (file)
index 0000000..0b58509
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_dig_metal.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_dig_oddly_breakable_by_hand.ogg b/games/devtest/mods/basetools/sounds/default_dig_oddly_breakable_by_hand.ogg
new file mode 100644 (file)
index 0000000..ef4d7b1
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_dig_oddly_breakable_by_hand.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_dig_snappy.ogg b/games/devtest/mods/basetools/sounds/default_dig_snappy.ogg
new file mode 100644 (file)
index 0000000..3686fcd
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_dig_snappy.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_dirt_footstep.1.ogg b/games/devtest/mods/basetools/sounds/default_dirt_footstep.1.ogg
new file mode 100644 (file)
index 0000000..201aa3b
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_dirt_footstep.1.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_dirt_footstep.2.ogg b/games/devtest/mods/basetools/sounds/default_dirt_footstep.2.ogg
new file mode 100644 (file)
index 0000000..2667dbc
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_dirt_footstep.2.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_dug_metal.1.ogg b/games/devtest/mods/basetools/sounds/default_dug_metal.1.ogg
new file mode 100644 (file)
index 0000000..5d6cb5b
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_dug_metal.1.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_dug_metal.2.ogg b/games/devtest/mods/basetools/sounds/default_dug_metal.2.ogg
new file mode 100644 (file)
index 0000000..63567fc
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_dug_metal.2.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_dug_node.1.ogg b/games/devtest/mods/basetools/sounds/default_dug_node.1.ogg
new file mode 100644 (file)
index 0000000..c04975d
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_dug_node.1.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_dug_node.2.ogg b/games/devtest/mods/basetools/sounds/default_dug_node.2.ogg
new file mode 100644 (file)
index 0000000..9f20926
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_dug_node.2.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_glass_footstep.ogg b/games/devtest/mods/basetools/sounds/default_glass_footstep.ogg
new file mode 100644 (file)
index 0000000..191287a
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_glass_footstep.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_grass_footstep.2.ogg b/games/devtest/mods/basetools/sounds/default_grass_footstep.2.ogg
new file mode 100644 (file)
index 0000000..d193068
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_grass_footstep.2.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_grass_footstep.3.ogg b/games/devtest/mods/basetools/sounds/default_grass_footstep.3.ogg
new file mode 100644 (file)
index 0000000..e1897ea
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_grass_footstep.3.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_gravel_footstep.1.ogg b/games/devtest/mods/basetools/sounds/default_gravel_footstep.1.ogg
new file mode 100644 (file)
index 0000000..8d260ce
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_gravel_footstep.1.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_gravel_footstep.2.ogg b/games/devtest/mods/basetools/sounds/default_gravel_footstep.2.ogg
new file mode 100644 (file)
index 0000000..2aba2c6
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_gravel_footstep.2.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_gravel_footstep.3.ogg b/games/devtest/mods/basetools/sounds/default_gravel_footstep.3.ogg
new file mode 100644 (file)
index 0000000..1bcd8a1
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_gravel_footstep.3.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_gravel_footstep.4.ogg b/games/devtest/mods/basetools/sounds/default_gravel_footstep.4.ogg
new file mode 100644 (file)
index 0000000..696c9ff
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_gravel_footstep.4.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_hard_footstep.1.ogg b/games/devtest/mods/basetools/sounds/default_hard_footstep.1.ogg
new file mode 100644 (file)
index 0000000..1748bc5
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_hard_footstep.1.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_hard_footstep.2.ogg b/games/devtest/mods/basetools/sounds/default_hard_footstep.2.ogg
new file mode 100644 (file)
index 0000000..fe39fd7
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_hard_footstep.2.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_hard_footstep.3.ogg b/games/devtest/mods/basetools/sounds/default_hard_footstep.3.ogg
new file mode 100644 (file)
index 0000000..5030e06
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_hard_footstep.3.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_item_smoke.ogg b/games/devtest/mods/basetools/sounds/default_item_smoke.ogg
new file mode 100644 (file)
index 0000000..038a46e
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_item_smoke.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_metal_footstep.1.ogg b/games/devtest/mods/basetools/sounds/default_metal_footstep.1.ogg
new file mode 100644 (file)
index 0000000..841286b
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_metal_footstep.1.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_metal_footstep.2.ogg b/games/devtest/mods/basetools/sounds/default_metal_footstep.2.ogg
new file mode 100644 (file)
index 0000000..aa61ed3
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_metal_footstep.2.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_metal_footstep.3.ogg b/games/devtest/mods/basetools/sounds/default_metal_footstep.3.ogg
new file mode 100644 (file)
index 0000000..4cc1ca4
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_metal_footstep.3.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_place_node.1.ogg b/games/devtest/mods/basetools/sounds/default_place_node.1.ogg
new file mode 100644 (file)
index 0000000..46b9756
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_place_node.1.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_place_node.2.ogg b/games/devtest/mods/basetools/sounds/default_place_node.2.ogg
new file mode 100644 (file)
index 0000000..d34c01a
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_place_node.2.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_place_node.3.ogg b/games/devtest/mods/basetools/sounds/default_place_node.3.ogg
new file mode 100644 (file)
index 0000000..fc29365
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_place_node.3.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_place_node_hard.1.ogg b/games/devtest/mods/basetools/sounds/default_place_node_hard.1.ogg
new file mode 100644 (file)
index 0000000..9f97fac
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_place_node_hard.1.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_place_node_hard.2.ogg b/games/devtest/mods/basetools/sounds/default_place_node_hard.2.ogg
new file mode 100644 (file)
index 0000000..1d3b3de
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_place_node_hard.2.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_place_node_metal.1.ogg b/games/devtest/mods/basetools/sounds/default_place_node_metal.1.ogg
new file mode 100644 (file)
index 0000000..5da085e
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_place_node_metal.1.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_place_node_metal.2.ogg b/games/devtest/mods/basetools/sounds/default_place_node_metal.2.ogg
new file mode 100644 (file)
index 0000000..5ee67fc
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_place_node_metal.2.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_sand_footstep.1.ogg b/games/devtest/mods/basetools/sounds/default_sand_footstep.1.ogg
new file mode 100644 (file)
index 0000000..65b68c7
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_sand_footstep.1.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_sand_footstep.2.ogg b/games/devtest/mods/basetools/sounds/default_sand_footstep.2.ogg
new file mode 100644 (file)
index 0000000..57f35f3
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_sand_footstep.2.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_snow_footstep.1.ogg b/games/devtest/mods/basetools/sounds/default_snow_footstep.1.ogg
new file mode 100644 (file)
index 0000000..97cc825
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_snow_footstep.1.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_snow_footstep.2.ogg b/games/devtest/mods/basetools/sounds/default_snow_footstep.2.ogg
new file mode 100644 (file)
index 0000000..97a6baa
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_snow_footstep.2.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_snow_footstep.3.ogg b/games/devtest/mods/basetools/sounds/default_snow_footstep.3.ogg
new file mode 100644 (file)
index 0000000..bde1f21
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_snow_footstep.3.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_snow_footstep.4.ogg b/games/devtest/mods/basetools/sounds/default_snow_footstep.4.ogg
new file mode 100644 (file)
index 0000000..8ca6a59
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_snow_footstep.4.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_snow_footstep.5.ogg b/games/devtest/mods/basetools/sounds/default_snow_footstep.5.ogg
new file mode 100644 (file)
index 0000000..220d60c
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_snow_footstep.5.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_tool_breaks.1.ogg b/games/devtest/mods/basetools/sounds/default_tool_breaks.1.ogg
new file mode 100644 (file)
index 0000000..2a571ae
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_tool_breaks.1.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_tool_breaks.2.ogg b/games/devtest/mods/basetools/sounds/default_tool_breaks.2.ogg
new file mode 100644 (file)
index 0000000..1789352
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_tool_breaks.2.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_tool_breaks.3.ogg b/games/devtest/mods/basetools/sounds/default_tool_breaks.3.ogg
new file mode 100644 (file)
index 0000000..a99c4b7
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_tool_breaks.3.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_water_footstep.1.ogg b/games/devtest/mods/basetools/sounds/default_water_footstep.1.ogg
new file mode 100644 (file)
index 0000000..63b9744
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_water_footstep.1.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_water_footstep.2.ogg b/games/devtest/mods/basetools/sounds/default_water_footstep.2.ogg
new file mode 100644 (file)
index 0000000..8d79c1f
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_water_footstep.2.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_water_footstep.3.ogg b/games/devtest/mods/basetools/sounds/default_water_footstep.3.ogg
new file mode 100644 (file)
index 0000000..f889150
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_water_footstep.3.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_water_footstep.4.ogg b/games/devtest/mods/basetools/sounds/default_water_footstep.4.ogg
new file mode 100644 (file)
index 0000000..6f1eab8
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_water_footstep.4.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_wood_footstep.1.ogg b/games/devtest/mods/basetools/sounds/default_wood_footstep.1.ogg
new file mode 100644 (file)
index 0000000..34f63a1
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_wood_footstep.1.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/default_wood_footstep.2.ogg b/games/devtest/mods/basetools/sounds/default_wood_footstep.2.ogg
new file mode 100644 (file)
index 0000000..124fc29
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/default_wood_footstep.2.ogg differ
diff --git a/games/devtest/mods/basetools/sounds/player_damage.ogg b/games/devtest/mods/basetools/sounds/player_damage.ogg
new file mode 100644 (file)
index 0000000..7888087
Binary files /dev/null and b/games/devtest/mods/basetools/sounds/player_damage.ogg differ
diff --git a/games/devtest/mods/player_api/README.txt b/games/devtest/mods/player_api/README.txt
new file mode 100644 (file)
index 0000000..0f6a0b8
--- /dev/null
@@ -0,0 +1,29 @@
+Minetest Game mod: player_api
+=============================
+See license.txt for license information.
+
+Provides an API to allow multiple mods to set player models and textures.
+Also sets the default model, texture, and player flags.
+This mod is only for content related to the Player API and the player object.
+
+Authors of source code
+----------------------
+Originally by celeron55, Perttu Ahola <celeron55@gmail.com> (LGPLv2.1+)
+Various Minetest developers and contributors (LGPLv2.1+)
+
+Authors of media (textures, models and sounds)
+----------------------------------------------
+stujones11 (CC BY-SA 3.0):
+  character.b3d
+  character.blend -- Both derived from a model by MirceaKitsune (CC BY-SA 3.0)
+
+An0n3m0us (CC BY-SA 3.0):
+  character.b3d
+  character.blend -- Player animation improvement
+
+Jordach (CC BY-SA 3.0):
+  character.png
+
+celeron55, Perttu Ahola <celeron55@gmail.com> (CC BY-SA 3.0):
+  player.png
+  player_back.png
diff --git a/games/devtest/mods/player_api/api.lua b/games/devtest/mods/player_api/api.lua
new file mode 100644 (file)
index 0000000..5803e95
--- /dev/null
@@ -0,0 +1,144 @@
+-- Minetest 0.4 mod: player
+-- See README.txt for licensing and other information.
+
+player_api = {}
+
+-- Player animation blending
+-- Note: This is currently broken due to a bug in Irrlicht, leave at 0
+local animation_blend = 0
+
+player_api.registered_models = { }
+
+-- Local for speed.
+local models = player_api.registered_models
+
+function player_api.register_model(name, def)
+       models[name] = def
+end
+
+-- Player stats and animations
+local player_model = {}
+local player_textures = {}
+local player_anim = {}
+local player_sneak = {}
+player_api.player_attached = {}
+
+function player_api.get_animation(player)
+       local name = player:get_player_name()
+       return {
+               model = player_model[name],
+               textures = player_textures[name],
+               animation = player_anim[name],
+       }
+end
+
+-- Called when a player's appearance needs to be updated
+function player_api.set_model(player, model_name)
+       local name = player:get_player_name()
+       local model = models[model_name]
+       if model then
+               if player_model[name] == model_name then
+                       return
+               end
+               player:set_properties({
+                       mesh = model_name,
+                       textures = player_textures[name] or model.textures,
+                       visual = "mesh",
+                       visual_size = model.visual_size or {x = 1, y = 1},
+                       collisionbox = model.collisionbox or {-0.3, 0.0, -0.3, 0.3, 1.7, 0.3},
+                       stepheight = model.stepheight or 0.6,
+                       eye_height = model.eye_height or 1.47,
+               })
+               player_api.set_animation(player, "stand")
+       else
+               player:set_properties({
+                       textures = {"player.png", "player_back.png"},
+                       visual = "upright_sprite",
+                       visual_size = {x = 1, y = 2},
+                       collisionbox = {-0.3, 0.0, -0.3, 0.3, 1.75, 0.3},
+                       stepheight = 0.6,
+                       eye_height = 1.625,
+               })
+       end
+       player_model[name] = model_name
+end
+
+function player_api.set_textures(player, textures)
+       local name = player:get_player_name()
+       local model = models[player_model[name]]
+       local model_textures = model and model.textures or nil
+       player_textures[name] = textures or model_textures
+       player:set_properties({textures = textures or model_textures,})
+end
+
+function player_api.set_animation(player, anim_name, speed)
+       local name = player:get_player_name()
+       if player_anim[name] == anim_name then
+               return
+       end
+       local model = player_model[name] and models[player_model[name]]
+       if not (model and model.animations[anim_name]) then
+               return
+       end
+       local anim = model.animations[anim_name]
+       player_anim[name] = anim_name
+       player:set_animation(anim, speed or model.animation_speed, animation_blend)
+end
+
+minetest.register_on_leaveplayer(function(player)
+       local name = player:get_player_name()
+       player_model[name] = nil
+       player_anim[name] = nil
+       player_textures[name] = nil
+end)
+
+-- Localize for better performance.
+local player_set_animation = player_api.set_animation
+local player_attached = player_api.player_attached
+
+-- Prevent knockback for attached players
+local old_calculate_knockback = minetest.calculate_knockback
+function minetest.calculate_knockback(player, ...)
+       if player_attached[player:get_player_name()] then
+               return 0
+       end
+       return old_calculate_knockback(player, ...)
+end
+
+-- Check each player and apply animations
+minetest.register_globalstep(function()
+       for _, player in pairs(minetest.get_connected_players()) do
+               local name = player:get_player_name()
+               local model_name = player_model[name]
+               local model = model_name and models[model_name]
+               if model and not player_attached[name] then
+                       local controls = player:get_player_control()
+                       local animation_speed_mod = model.animation_speed or 30
+
+                       -- Determine if the player is sneaking, and reduce animation speed if so
+                       if controls.sneak then
+                               animation_speed_mod = animation_speed_mod / 2
+                       end
+
+                       -- Apply animations based on what the player is doing
+                       if player:get_hp() == 0 then
+                               player_set_animation(player, "lay")
+                       -- Determine if the player is walking
+                       elseif controls.up or controls.down or controls.left or controls.right then
+                               if player_sneak[name] ~= controls.sneak then
+                                       player_anim[name] = nil
+                                       player_sneak[name] = controls.sneak
+                               end
+                               if controls.LMB or controls.RMB then
+                                       player_set_animation(player, "walk_mine", animation_speed_mod)
+                               else
+                                       player_set_animation(player, "walk", animation_speed_mod)
+                               end
+                       elseif controls.LMB or controls.RMB then
+                               player_set_animation(player, "mine", animation_speed_mod)
+                       else
+                               player_set_animation(player, "stand", animation_speed_mod)
+                       end
+               end
+       end
+end)
diff --git a/games/devtest/mods/player_api/init.lua b/games/devtest/mods/player_api/init.lua
new file mode 100644 (file)
index 0000000..19028de
--- /dev/null
@@ -0,0 +1,34 @@
+-- player/init.lua
+
+dofile(minetest.get_modpath("player_api") .. "/api.lua")
+
+-- Default player appearance
+player_api.register_model("character.b3d", {
+       animation_speed = 30,
+       textures = {"character.png", },
+       animations = {
+               -- Standard animations.
+               stand     = {x = 0,   y = 79},
+               lay       = {x = 162, y = 166},
+               walk      = {x = 168, y = 187},
+               mine      = {x = 189, y = 198},
+               walk_mine = {x = 200, y = 219},
+               sit       = {x = 81,  y = 160},
+       },
+       collisionbox = {-0.3, 0.0, -0.3, 0.3, 1.7, 0.3},
+       stepheight = 0.6,
+       eye_height = 1.47,
+})
+
+-- Update appearance when the player joins
+minetest.register_on_joinplayer(function(player)
+       player_api.player_attached[player:get_player_name()] = false
+       player_api.set_model(player, "character.b3d")
+       player:set_local_animation(
+               {x = 0,   y = 79},
+               {x = 168, y = 187},
+               {x = 189, y = 198},
+               {x = 200, y = 219},
+               30
+       )
+end)
diff --git a/games/devtest/mods/player_api/license.txt b/games/devtest/mods/player_api/license.txt
new file mode 100644 (file)
index 0000000..dac0408
--- /dev/null
@@ -0,0 +1,53 @@
+License of source code
+----------------------
+
+GNU Lesser General Public License, version 2.1
+Copyright (C) 2011-2018 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2011-2018 Various Minetest developers and contributors
+
+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:
+https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
+
+
+Licenses of media (textures, models and sounds)
+-----------------------------------------------
+
+Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)
+Copyright (C) 2011-2018 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2012-2018 Jordach
+Copyright (C) 2018 stujones11
+Copyright (C) 2019 An0n3m0us
+
+You are free to:
+Share — copy and redistribute the material in any medium or format.
+Adapt — remix, transform, and build upon the material for any purpose, even commercially.
+The licensor cannot revoke these freedoms as long as you follow the license terms.
+
+Under the following terms:
+
+Attribution — You must give appropriate credit, provide a link to the license, and
+indicate if changes were made. You may do so in any reasonable manner, but not in any way
+that suggests the licensor endorses you or your use.
+
+ShareAlike — If you remix, transform, or build upon the material, you must distribute
+your contributions under the same license as the original.
+
+No additional restrictions — You may not apply legal terms or technological measures that
+legally restrict others from doing anything the license permits.
+
+Notices:
+
+You do not have to comply with the license for elements of the material in the public
+domain or where your use is permitted by an applicable exception or limitation.
+No warranties are given. The license may not give you all of the permissions necessary
+for your intended use. For example, other rights such as publicity, privacy, or moral
+rights may limit how you use the material.
+
+For more details:
+http://creativecommons.org/licenses/by-sa/3.0/
diff --git a/games/devtest/mods/player_api/mod.conf b/games/devtest/mods/player_api/mod.conf
new file mode 100644 (file)
index 0000000..198b86d
--- /dev/null
@@ -0,0 +1,2 @@
+name = player_api
+description = Minetest Game mod: player_api
diff --git a/games/devtest/mods/player_api/models/character.b3d b/games/devtest/mods/player_api/models/character.b3d
new file mode 100644 (file)
index 0000000..8edbaf6
Binary files /dev/null and b/games/devtest/mods/player_api/models/character.b3d differ
diff --git a/games/devtest/mods/player_api/models/character.blend b/games/devtest/mods/player_api/models/character.blend
new file mode 100644 (file)
index 0000000..f0ce411
Binary files /dev/null and b/games/devtest/mods/player_api/models/character.blend differ
diff --git a/games/devtest/mods/player_api/models/character.png b/games/devtest/mods/player_api/models/character.png
new file mode 100644 (file)
index 0000000..0502178
Binary files /dev/null and b/games/devtest/mods/player_api/models/character.png differ
diff --git a/games/devtest/mods/player_api/textures/player.png b/games/devtest/mods/player_api/textures/player.png
new file mode 100644 (file)
index 0000000..6d61c43
Binary files /dev/null and b/games/devtest/mods/player_api/textures/player.png differ
diff --git a/games/devtest/mods/player_api/textures/player_back.png b/games/devtest/mods/player_api/textures/player_back.png
new file mode 100644 (file)
index 0000000..5e9ef05
Binary files /dev/null and b/games/devtest/mods/player_api/textures/player_back.png differ
diff --git a/latex/doxygen.sty b/latex/doxygen.sty
new file mode 100644 (file)
index 0000000..e457acc
--- /dev/null
@@ -0,0 +1,503 @@
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesPackage{doxygen}
+
+% Packages used by this style file
+\RequirePackage{alltt}
+\RequirePackage{array}
+\RequirePackage{calc}
+\RequirePackage{float}
+\RequirePackage{ifthen}
+\RequirePackage{verbatim}
+\RequirePackage[table]{xcolor}
+\RequirePackage{longtable}
+\RequirePackage{tabu}
+\RequirePackage{tabularx}
+\RequirePackage{multirow}
+
+%---------- Internal commands used in this style file ----------------
+
+\newcommand{\ensurespace}[1]{%
+  \begingroup%
+    \setlength{\dimen@}{#1}%
+    \vskip\z@\@plus\dimen@%
+    \penalty -100\vskip\z@\@plus -\dimen@%
+    \vskip\dimen@%
+    \penalty 9999%
+    \vskip -\dimen@%
+    \vskip\z@skip% hide the previous |\vskip| from |\addvspace|
+  \endgroup%
+}
+
+\newcommand{\DoxyLabelFont}{}
+\newcommand{\entrylabel}[1]{%
+  {%
+    \parbox[b]{\labelwidth-4pt}{%
+      \makebox[0pt][l]{\DoxyLabelFont#1}%
+      \vspace{1.5\baselineskip}%
+    }%
+  }%
+}
+
+\newenvironment{DoxyDesc}[1]{%
+  \ensurespace{4\baselineskip}%
+  \begin{list}{}{%
+    \settowidth{\labelwidth}{20pt}%
+    \setlength{\parsep}{0pt}%
+    \setlength{\itemsep}{0pt}%
+    \setlength{\leftmargin}{\labelwidth+\labelsep}%
+    \renewcommand{\makelabel}{\entrylabel}%
+  }%
+  \item[#1]%
+}{%
+  \end{list}%
+}
+
+\newsavebox{\xrefbox}
+\newlength{\xreflength}
+\newcommand{\xreflabel}[1]{%
+  \sbox{\xrefbox}{#1}%
+  \setlength{\xreflength}{\wd\xrefbox}%
+  \ifthenelse{\xreflength>\labelwidth}{%
+    \begin{minipage}{\textwidth}%
+      \setlength{\parindent}{0pt}%
+      \hangindent=15pt\bfseries #1\vspace{1.2\itemsep}%
+    \end{minipage}%
+  }{%
+   \parbox[b]{\labelwidth}{\makebox[0pt][l]{\textbf{#1}}}%
+  }%
+}
+
+%---------- Commands used by doxygen LaTeX output generator ----------
+
+% Used by <pre> ... </pre>
+\newenvironment{DoxyPre}{%
+  \small%
+  \begin{alltt}%
+}{%
+  \end{alltt}%
+  \normalsize%
+}
+
+% Used by @code ... @endcode
+\newenvironment{DoxyCode}{%
+  \par%
+  \scriptsize%
+  \begin{alltt}%
+}{%
+  \end{alltt}%
+  \normalsize%
+}
+
+% Used by @example, @include, @includelineno and @dontinclude
+\newenvironment{DoxyCodeInclude}{%
+  \DoxyCode%
+}{%
+  \endDoxyCode%
+}
+
+% Used by @verbatim ... @endverbatim
+\newenvironment{DoxyVerb}{%
+  \footnotesize%
+  \verbatim%
+}{%
+  \endverbatim%
+  \normalsize%
+}
+
+% Used by @verbinclude
+\newenvironment{DoxyVerbInclude}{%
+  \DoxyVerb%
+}{%
+  \endDoxyVerb%
+}
+
+% Used by numbered lists (using '-#' or <ol> ... </ol>)
+\newenvironment{DoxyEnumerate}{%
+  \enumerate%
+}{%
+  \endenumerate%
+}
+
+% Used by bullet lists (using '-', @li, @arg, or <ul> ... </ul>)
+\newenvironment{DoxyItemize}{%
+  \itemize%
+}{%
+  \enditemize%
+}
+
+% Used by description lists (using <dl> ... </dl>)
+\newenvironment{DoxyDescription}{%
+  \description%
+}{%
+  \enddescription%
+}
+
+% Used by @image, @dotfile, @dot ... @enddot, and @msc ... @endmsc
+% (only if caption is specified)
+\newenvironment{DoxyImage}{%
+  \begin{figure}[H]%
+    \begin{center}%
+}{%
+    \end{center}%
+  \end{figure}%
+}
+
+% Used by @image, @dotfile, @dot ... @enddot, and @msc ... @endmsc
+% (only if no caption is specified)
+\newenvironment{DoxyImageNoCaption}{%
+  \begin{center}%
+}{%
+  \end{center}%
+}
+
+% Used by @attention
+\newenvironment{DoxyAttention}[1]{%
+  \begin{DoxyDesc}{#1}%
+}{%
+  \end{DoxyDesc}%
+}
+
+% Used by @author and @authors
+\newenvironment{DoxyAuthor}[1]{%
+  \begin{DoxyDesc}{#1}%
+}{%
+  \end{DoxyDesc}%
+}
+
+% Used by @date
+\newenvironment{DoxyDate}[1]{%
+  \begin{DoxyDesc}{#1}%
+}{%
+  \end{DoxyDesc}%
+}
+
+% Used by @invariant
+\newenvironment{DoxyInvariant}[1]{%
+  \begin{DoxyDesc}{#1}%
+}{%
+  \end{DoxyDesc}%
+}
+
+% Used by @note
+\newenvironment{DoxyNote}[1]{%
+  \begin{DoxyDesc}{#1}%
+}{%
+  \end{DoxyDesc}%
+}
+
+% Used by @post
+\newenvironment{DoxyPostcond}[1]{%
+  \begin{DoxyDesc}{#1}%
+}{%
+  \end{DoxyDesc}%
+}
+
+% Used by @pre
+\newenvironment{DoxyPrecond}[1]{%
+  \begin{DoxyDesc}{#1}%
+}{%
+  \end{DoxyDesc}%
+}
+
+% Used by @copyright
+\newenvironment{DoxyCopyright}[1]{%
+  \begin{DoxyDesc}{#1}%
+}{%
+  \end{DoxyDesc}%
+}
+
+% Used by @remark
+\newenvironment{DoxyRemark}[1]{%
+  \begin{DoxyDesc}{#1}%
+}{%
+  \end{DoxyDesc}%
+}
+
+% Used by @return and @returns
+\newenvironment{DoxyReturn}[1]{%
+  \begin{DoxyDesc}{#1}%
+}{%
+  \end{DoxyDesc}%
+}
+
+% Used by @since
+\newenvironment{DoxySince}[1]{%
+  \begin{DoxyDesc}{#1}%
+}{%
+  \end{DoxyDesc}%
+}
+
+% Used by @see
+\newenvironment{DoxySeeAlso}[1]{%
+  \begin{DoxyDesc}{#1}%
+}{%
+  \end{DoxyDesc}%
+}
+
+% Used by @version
+\newenvironment{DoxyVersion}[1]{%
+  \begin{DoxyDesc}{#1}%
+}{%
+  \end{DoxyDesc}%
+}
+
+% Used by @warning
+\newenvironment{DoxyWarning}[1]{%
+  \begin{DoxyDesc}{#1}%
+}{%
+  \end{DoxyDesc}%
+}
+
+% Used by @internal
+\newenvironment{DoxyInternal}[1]{%
+  \paragraph*{#1}%
+}{%
+}
+
+% Used by @par and @paragraph
+\newenvironment{DoxyParagraph}[1]{%
+  \begin{list}{}{%
+    \settowidth{\labelwidth}{40pt}%
+    \setlength{\leftmargin}{\labelwidth}%
+    \setlength{\parsep}{0pt}%
+    \setlength{\itemsep}{-4pt}%
+    \renewcommand{\makelabel}{\entrylabel}%
+  }%
+  \item[#1]%
+}{%
+  \end{list}%
+}
+
+% Used by parameter lists
+\newenvironment{DoxyParams}[2][]{%
+    \tabulinesep=1mm%
+    \par%
+    \ifthenelse{\equal{#1}{}}%
+      {\begin{longtabu} spread 0pt [l]{|X[-1,l]|X[-1,l]|}}% name + description
+    {\ifthenelse{\equal{#1}{1}}%
+      {\begin{longtabu} spread 0pt [l]{|X[-1,l]|X[-1,l]|X[-1,l]|}}% in/out + name + desc
+      {\begin{longtabu} spread 0pt [l]{|X[-1,l]|X[-1,l]|X[-1,l]|X[-1,l]|}}% in/out + type + name + desc
+    }
+    \multicolumn{2}{l}{\hspace{-6pt}\bfseries\fontseries{bc}\selectfont\color{darkgray} #2}\\[1ex]%
+    \hline%
+    \endfirsthead%
+    \multicolumn{2}{l}{\hspace{-6pt}\bfseries\fontseries{bc}\selectfont\color{darkgray} #2}\\[1ex]%
+    \hline%
+    \endhead%
+}{%
+    \end{longtabu}%
+    \vspace{6pt}%
+}
+
+% Used for fields of simple structs
+\newenvironment{DoxyFields}[1]{%
+    \tabulinesep=1mm%
+    \par%
+    \begin{longtabu} spread 0pt [l]{|X[-1,r]|X[-1,l]|X[-1,l]|}%
+    \multicolumn{3}{l}{\hspace{-6pt}\bfseries\fontseries{bc}\selectfont\color{darkgray} #1}\\[1ex]%
+    \hline%
+    \endfirsthead%
+    \multicolumn{3}{l}{\hspace{-6pt}\bfseries\fontseries{bc}\selectfont\color{darkgray} #1}\\[1ex]%
+    \hline%
+    \endhead%
+}{%
+    \end{longtabu}%
+    \vspace{6pt}%
+}
+
+% Used for fields simple class style enums
+\newenvironment{DoxyEnumFields}[1]{%
+    \tabulinesep=1mm%
+    \par%
+    \begin{longtabu} spread 0pt [l]{|X[-1,r]|X[-1,l]|}%
+    \multicolumn{2}{l}{\hspace{-6pt}\bfseries\fontseries{bc}\selectfont\color{darkgray} #1}\\[1ex]%
+    \hline%
+    \endfirsthead%
+    \multicolumn{2}{l}{\hspace{-6pt}\bfseries\fontseries{bc}\selectfont\color{darkgray} #1}\\[1ex]%
+    \hline%
+    \endhead%
+}{%
+    \end{longtabu}%
+    \vspace{6pt}%
+}
+
+% Used for parameters within a detailed function description
+\newenvironment{DoxyParamCaption}{%
+  \renewcommand{\item}[2][]{\\ \hspace*{2.0cm} ##1 {\em ##2}}% 
+}{%
+}
+
+% Used by return value lists
+\newenvironment{DoxyRetVals}[1]{%
+    \tabulinesep=1mm%
+    \par%
+    \begin{longtabu} spread 0pt [l]{|X[-1,r]|X[-1,l]|}%
+    \multicolumn{2}{l}{\hspace{-6pt}\bfseries\fontseries{bc}\selectfont\color{darkgray} #1}\\[1ex]%
+    \hline%
+    \endfirsthead%
+    \multicolumn{2}{l}{\hspace{-6pt}\bfseries\fontseries{bc}\selectfont\color{darkgray} #1}\\[1ex]%
+    \hline%
+    \endhead%
+}{%
+    \end{longtabu}%
+    \vspace{6pt}%
+}
+
+% Used by exception lists
+\newenvironment{DoxyExceptions}[1]{%
+    \tabulinesep=1mm%
+    \par%
+    \begin{longtabu} spread 0pt [l]{|X[-1,r]|X[-1,l]|}%
+    \multicolumn{2}{l}{\hspace{-6pt}\bfseries\fontseries{bc}\selectfont\color{darkgray} #1}\\[1ex]%
+    \hline%
+    \endfirsthead%
+    \multicolumn{2}{l}{\hspace{-6pt}\bfseries\fontseries{bc}\selectfont\color{darkgray} #1}\\[1ex]%
+    \hline%
+    \endhead%
+}{%
+    \end{longtabu}%
+    \vspace{6pt}%
+}
+
+% Used by template parameter lists
+\newenvironment{DoxyTemplParams}[1]{%
+    \tabulinesep=1mm%
+    \par%
+    \begin{longtabu} spread 0pt [l]{|X[-1,r]|X[-1,l]|}%
+    \multicolumn{2}{l}{\hspace{-6pt}\bfseries\fontseries{bc}\selectfont\color{darkgray} #1}\\[1ex]%
+    \hline%
+    \endfirsthead%
+    \multicolumn{2}{l}{\hspace{-6pt}\bfseries\fontseries{bc}\selectfont\color{darkgray} #1}\\[1ex]%
+    \hline%
+    \endhead%
+}{%
+    \end{longtabu}%
+    \vspace{6pt}%
+}
+
+% Used for member lists
+\newenvironment{DoxyCompactItemize}{%
+  \begin{itemize}%
+    \setlength{\itemsep}{-3pt}%
+    \setlength{\parsep}{0pt}%
+    \setlength{\topsep}{0pt}%
+    \setlength{\partopsep}{0pt}%
+}{%
+  \end{itemize}%
+}
+
+% Used for member descriptions
+\newenvironment{DoxyCompactList}{%
+  \begin{list}{}{%
+    \setlength{\leftmargin}{0.5cm}%
+    \setlength{\itemsep}{0pt}%
+    \setlength{\parsep}{0pt}%
+    \setlength{\topsep}{0pt}%
+    \renewcommand{\makelabel}{\hfill}%
+  }%
+}{%
+  \end{list}%
+}
+
+% Used for reference lists (@bug, @deprecated, @todo, etc.)
+\newenvironment{DoxyRefList}{%
+  \begin{list}{}{%
+    \setlength{\labelwidth}{10pt}%
+    \setlength{\leftmargin}{\labelwidth}%
+    \addtolength{\leftmargin}{\labelsep}%
+    \renewcommand{\makelabel}{\xreflabel}%
+  }%
+}{%
+  \end{list}%
+}
+
+% Used by @bug, @deprecated, @todo, etc.
+\newenvironment{DoxyRefDesc}[1]{%
+  \begin{list}{}{%
+    \renewcommand\makelabel[1]{\textbf{##1}}%
+    \settowidth\labelwidth{\makelabel{#1}}%
+    \setlength\leftmargin{\labelwidth+\labelsep}%
+  }%
+}{%
+  \end{list}%
+}
+
+% Used by parameter lists and simple sections
+\newenvironment{Desc}
+{\begin{list}{}{%
+    \settowidth{\labelwidth}{20pt}%
+    \setlength{\parsep}{0pt}%
+    \setlength{\itemsep}{0pt}%
+    \setlength{\leftmargin}{\labelwidth+\labelsep}%
+    \renewcommand{\makelabel}{\entrylabel}%
+  }
+}{%
+  \end{list}%
+}
+
+% Used by tables
+\newcommand{\PBS}[1]{\let\temp=\\#1\let\\=\temp}%
+\newenvironment{TabularC}[1]%
+{\tabulinesep=1mm
+\begin{longtabu} spread 0pt [c]{*#1{|X[-1]}|}}%
+{\end{longtabu}\par}%
+
+\newenvironment{TabularNC}[1]%
+{\begin{tabu} spread 0pt [l]{*#1{|X[-1]}|}}%
+{\end{tabu}\par}%
+
+% Used for member group headers
+\newenvironment{Indent}{%
+  \begin{list}{}{%
+    \setlength{\leftmargin}{0.5cm}%
+  }%
+  \item[]\ignorespaces%
+}{%
+  \unskip%
+  \end{list}%
+}
+
+% Used when hyperlinks are turned off
+\newcommand{\doxyref}[3]{%
+  \textbf{#1} (\textnormal{#2}\,\pageref{#3})%
+}
+
+% Used to link to a table when hyperlinks are turned on
+\newcommand{\doxytablelink}[2]{%
+  \ref{#1}%
+}
+
+% Used to link to a table when hyperlinks are turned off
+\newcommand{\doxytableref}[3]{%
+  \ref{#3}%
+}
+
+% Used by @addindex
+\newcommand{\lcurly}{\{}
+\newcommand{\rcurly}{\}}
+
+% Colors used for syntax highlighting
+\definecolor{comment}{rgb}{0.5,0.0,0.0}
+\definecolor{keyword}{rgb}{0.0,0.5,0.0}
+\definecolor{keywordtype}{rgb}{0.38,0.25,0.125}
+\definecolor{keywordflow}{rgb}{0.88,0.5,0.0}
+\definecolor{preprocessor}{rgb}{0.5,0.38,0.125}
+\definecolor{stringliteral}{rgb}{0.0,0.125,0.25}
+\definecolor{charliteral}{rgb}{0.0,0.5,0.5}
+\definecolor{vhdldigit}{rgb}{1.0,0.0,1.0}
+\definecolor{vhdlkeyword}{rgb}{0.43,0.0,0.43}
+\definecolor{vhdllogic}{rgb}{1.0,0.0,0.0}
+\definecolor{vhdlchar}{rgb}{0.0,0.0,0.0}
+
+% Color used for table heading
+\newcommand{\tableheadbgcolor}{lightgray}%
+
+% Version of hypertarget with correct landing location
+\newcommand{\Hypertarget}[1]{\Hy@raisedlink{\hypertarget{#1}{}}}
+
+% Define caption that is also suitable in a table
+\makeatletter
+\def\doxyfigcaption{%
+\refstepcounter{figure}%
+\@dblarg{\@caption{figure}}}
+\makeatother
diff --git a/latex/md_README.tex b/latex/md_README.tex
new file mode 100644 (file)
index 0000000..5b883c2
--- /dev/null
@@ -0,0 +1,463 @@
+\href{https://travis-ci.org/minetest/minetest}{\tt } \href{https://hosted.weblate.org/engage/minetest/?utm_source=widget}{\tt } \href{https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html}{\tt }
+
+Minetest is a free open-\/source voxel game engine with easy modding and game creation.
+
+Copyright (C) 2010-\/2019 Perttu Ahola \href{mailto:celeron55@gmail.com}{\tt celeron55@gmail.\+com} and contributors (see source file comments and the version control log)
+
+\subsection*{In case you downloaded the source code }
+
+If you downloaded the Minetest Engine source code in which this file is contained, you probably want to download the \href{https://github.com/minetest/minetest_game/}{\tt Minetest Game} project too. See its R\+E\+A\+D\+M\+E.\+txt for more information.
+
+\subsection*{Table of Contents }
+
+
+\begin{DoxyEnumerate}
+\item \href{#further-documentation}{\tt Further Documentation}
+\item \href{#default-controls}{\tt Default Controls}
+\item \href{#paths}{\tt Paths}
+\item \href{#configuration-file}{\tt Configuration File}
+\item \href{#command-line-options}{\tt Command-\/line Options}
+\item \href{#compiling}{\tt Compiling}
+\item \href{#docker}{\tt Docker}
+\item \href{#version-scheme}{\tt Version Scheme}
+\end{DoxyEnumerate}
+
+\subsection*{Further documentation }
+
+
+\begin{DoxyItemize}
+\item Website\+: \href{http://minetest.net/}{\tt http\+://minetest.\+net/}
+\item Wiki\+: \href{http://wiki.minetest.net/}{\tt http\+://wiki.\+minetest.\+net/}
+\item Developer wiki\+: \href{http://dev.minetest.net/}{\tt http\+://dev.\+minetest.\+net/}
+\item Forum\+: \href{http://forum.minetest.net/}{\tt http\+://forum.\+minetest.\+net/}
+\item Git\+Hub\+: \href{https://github.com/minetest/minetest/}{\tt https\+://github.\+com/minetest/minetest/}
+\item \href{doc/}{\tt doc/} directory of source distribution
+\end{DoxyItemize}
+
+\subsection*{Default controls }
+
+All controls are re-\/bindable using settings. Some can be changed in the key config dialog in the settings tab.
+
+\tabulinesep=1mm
+\begin{longtabu} spread 0pt [c]{*{2}{|X[-1]}|}
+\hline
+\rowcolor{\tableheadbgcolor}\textbf{ Button }&\textbf{ Action  }\\\cline{1-2}
+\endfirsthead
+\hline
+\endfoot
+\hline
+\rowcolor{\tableheadbgcolor}\textbf{ Button }&\textbf{ Action  }\\\cline{1-2}
+\endhead
+Move mouse &Look around \\\cline{1-2}
+W, A, S, D &Move \\\cline{1-2}
+Space &Jump/move up \\\cline{1-2}
+Shift &Sneak/move down \\\cline{1-2}
+Q &Drop itemstack \\\cline{1-2}
+Shift + Q &Drop single item \\\cline{1-2}
+Left mouse button &Dig/punch/take item \\\cline{1-2}
+Right mouse button &Place/use \\\cline{1-2}
+Shift + right mouse button &Build (without using) \\\cline{1-2}
+I &Inventory menu \\\cline{1-2}
+Mouse wheel &Select item \\\cline{1-2}
+0-\/9 &Select item \\\cline{1-2}
+Z &Zoom (needs zoom privilege) \\\cline{1-2}
+T &Chat \\\cline{1-2}
+/ &Command \\\cline{1-2}
+Esc &Pause menu/abort/exit (pauses only singleplayer game) \\\cline{1-2}
+R &Enable/disable full range view \\\cline{1-2}
++ &Increase view range \\\cline{1-2}
+-\/ &Decrease view range \\\cline{1-2}
+K &Enable/disable fly mode (needs fly privilege) \\\cline{1-2}
+P &Enable/disable pitch move mode \\\cline{1-2}
+J &Enable/disable fast mode (needs fast privilege) \\\cline{1-2}
+H &Enable/disable noclip mode (needs noclip privilege) \\\cline{1-2}
+E &Move fast in fast mode \\\cline{1-2}
+F1 &Hide/show H\+UD \\\cline{1-2}
+F2 &Hide/show chat \\\cline{1-2}
+F3 &Disable/enable fog \\\cline{1-2}
+F4 &Disable/enable camera update (Mapblocks are not updated anymore when disabled, disabled in release builds) \\\cline{1-2}
+F5 &Cycle through debug information screens \\\cline{1-2}
+F6 &Cycle through profiler info screens \\\cline{1-2}
+F7 &Cycle through camera modes \\\cline{1-2}
+F9 &Cycle through minimap modes \\\cline{1-2}
+Shift + F9 &Change minimap orientation \\\cline{1-2}
+F10 &Show/hide console \\\cline{1-2}
+F12 &Take screenshot \\\cline{1-2}
+\end{longtabu}
+\subsection*{Paths }
+
+Locations\+:
+
+
+\begin{DoxyItemize}
+\item {\ttfamily bin} -\/ Compiled binaries
+\item {\ttfamily share} -\/ Distributed read-\/only data
+\item {\ttfamily user} -\/ User-\/created modifiable data
+\end{DoxyItemize}
+
+Where each location is on each platform\+:
+
+
+\begin{DoxyItemize}
+\item Windows .zip / R\+U\+N\+\_\+\+I\+N\+\_\+\+P\+L\+A\+CE source\+:
+\begin{DoxyItemize}
+\item {\ttfamily bin} = {\ttfamily bin}
+\item {\ttfamily share} = {\ttfamily .}
+\item {\ttfamily user} = {\ttfamily .}
+\end{DoxyItemize}
+\item Windows installed\+:
+\begin{DoxyItemize}
+\item {\ttfamily bin} = {\ttfamily C\+:\textbackslash{}Program Files\textbackslash{}Minetest\textbackslash{}bin (Depends on the install location)}
+\item {\ttfamily share} = {\ttfamily C\+:\textbackslash{}Program Files\textbackslash{}Minetest (Depends on the install location)}
+\item {\ttfamily user} = {\ttfamily A\+P\+P\+D\+A\+TA\%\textbackslash{}Minetest}
+\end{DoxyItemize}
+\item Linux installed\+:
+\begin{DoxyItemize}
+\item {\ttfamily bin} = {\ttfamily /usr/bin}
+\item {\ttfamily share} = {\ttfamily /usr/share/minetest}
+\item {\ttfamily user} = {\ttfamily $\sim$/.minetest}
+\end{DoxyItemize}
+\item mac\+OS\+:
+\begin{DoxyItemize}
+\item {\ttfamily bin} = {\ttfamily Contents/\+Mac\+OS}
+\item {\ttfamily share} = {\ttfamily Contents/\+Resources}
+\item {\ttfamily user} = {\ttfamily Contents/\+User OR $\sim$/\+Library/\+Application Support/minetest}
+\end{DoxyItemize}
+\end{DoxyItemize}
+
+Worlds can be found as separate folders in\+: {\ttfamily user/worlds/}
+
+\subsection*{Configuration file }
+
+
+\begin{DoxyItemize}
+\item Default location\+: {\ttfamily user/minetest.\+conf}
+\item This file is created by closing Minetest for the first time.
+\item A specific file can be specified on the command line\+: {\ttfamily -\/-\/config $<$path-\/to-\/file$>$}
+\item A run-\/in-\/place build will look for the configuration file in {\ttfamily location\+\_\+of\+\_\+exe/../minetest.conf} and also {\ttfamily location\+\_\+of\+\_\+exe/../../minetest.conf}
+\end{DoxyItemize}
+
+\subsection*{Command-\/line options }
+
+
+\begin{DoxyItemize}
+\item Use {\ttfamily -\/-\/help}
+\end{DoxyItemize}
+
+\subsection*{Compiling }
+
+\subsubsection*{Compiling on G\+N\+U/\+Linux}
+
+\paragraph*{Dependencies}
+
+\tabulinesep=1mm
+\begin{longtabu} spread 0pt [c]{*{3}{|X[-1]}|}
+\hline
+\rowcolor{\tableheadbgcolor}\textbf{ Dependency }&\textbf{ Version }&\textbf{ Commentary  }\\\cline{1-3}
+\endfirsthead
+\hline
+\endfoot
+\hline
+\rowcolor{\tableheadbgcolor}\textbf{ Dependency }&\textbf{ Version }&\textbf{ Commentary  }\\\cline{1-3}
+\endhead
+G\+CC &4.\+9+ &Can be replaced with Clang 3.\+4+ \\\cline{1-3}
+C\+Make &2.\+6+ &\\\cline{1-3}
+Irrlicht &1.\+7.\+3+ &\\\cline{1-3}
+S\+Q\+Lite3 &3.\+0+ &\\\cline{1-3}
+Lua\+J\+IT &2.\+0+ &Bundled Lua 5.\+1 is used if not present \\\cline{1-3}
+G\+MP &5.\+0.\+0+ &Bundled mini-\/\+G\+MP is used if not present \\\cline{1-3}
+Json\+C\+PP &1.\+0.\+0+ &Bundled Json\+C\+PP is used if not present \\\cline{1-3}
+\end{longtabu}
+For Debian/\+Ubuntu users\+: \begin{DoxyVerb}sudo apt install g++ make libc6-dev libirrlicht-dev cmake libbz2-dev libpng-dev libjpeg-dev libxxf86vm-dev libgl1-mesa-dev libsqlite3-dev libogg-dev libvorbis-dev libopenal-dev libcurl4-gnutls-dev libfreetype6-dev zlib1g-dev libgmp-dev libjsoncpp-dev
+\end{DoxyVerb}
+
+
+For Fedora users\+: \begin{DoxyVerb}sudo dnf install make automake gcc gcc-c++ kernel-devel cmake libcurl-devel openal-soft-devel libvorbis-devel libXxf86vm-devel libogg-devel freetype-devel mesa-libGL-devel zlib-devel jsoncpp-devel irrlicht-devel bzip2-libs gmp-devel sqlite-devel luajit-devel leveldb-devel ncurses-devel doxygen spatialindex-devel bzip2-devel
+\end{DoxyVerb}
+
+
+For Arch users\+: \begin{DoxyVerb}sudo pacman -S base-devel libcurl-gnutls cmake libxxf86vm irrlicht libpng sqlite libogg libvorbis openal freetype2 jsoncpp gmp luajit leveldb ncurses
+\end{DoxyVerb}
+
+
+For Alpine users\+: \begin{DoxyVerb}sudo apk add build-base irrlicht-dev cmake bzip2-dev libpng-dev jpeg-dev libxxf86vm-dev mesa-dev sqlite-dev libogg-dev libvorbis-dev openal-soft-dev curl-dev freetype-dev zlib-dev gmp-dev jsoncpp-dev luajit-dev
+\end{DoxyVerb}
+
+
+\paragraph*{Download}
+
+You can install Git for easily keeping your copy up to date. If you don’t want Git, read below on how to get the source without Git. This is an example for installing Git on Debian/\+Ubuntu\+: \begin{DoxyVerb}sudo apt install git
+\end{DoxyVerb}
+
+
+For Fedora users\+: \begin{DoxyVerb}sudo dnf install git
+\end{DoxyVerb}
+
+
+Download source (this is the U\+RL to the latest of source repository, which might not work at all times) using Git\+: \begin{DoxyVerb}git clone --depth 1 https://github.com/minetest/minetest.git
+cd minetest
+\end{DoxyVerb}
+
+
+Download minetest\+\_\+game (otherwise only the \char`\"{}\+Minimal development test\char`\"{} game is available) using Git\+: \begin{DoxyVerb}git clone --depth 1 https://github.com/minetest/minetest_game.git games/minetest_game
+\end{DoxyVerb}
+
+
+Download source, without using Git\+: \begin{DoxyVerb}wget https://github.com/minetest/minetest/archive/master.tar.gz
+tar xf master.tar.gz
+cd minetest-master
+\end{DoxyVerb}
+
+
+Download minetest\+\_\+game, without using Git\+: \begin{DoxyVerb}cd games/
+wget https://github.com/minetest/minetest_game/archive/master.tar.gz
+tar xf master.tar.gz
+mv minetest_game-master minetest_game
+cd ..
+\end{DoxyVerb}
+
+
+\paragraph*{Build}
+
+Build a version that runs directly from the source directory\+: \begin{DoxyVerb}cmake . -DRUN_IN_PLACE=TRUE
+make -j$(nproc)
+\end{DoxyVerb}
+
+
+Run it\+: \begin{DoxyVerb}./bin/minetest
+\end{DoxyVerb}
+
+
+
+\begin{DoxyItemize}
+\item Use {\ttfamily cmake . -\/\+LH} to see all C\+Make options and their current state.
+\item If you want to install it system-\/wide (or are making a distribution package), you will want to use {\ttfamily -\/\+D\+R\+U\+N\+\_\+\+I\+N\+\_\+\+P\+L\+A\+CE=F\+A\+L\+SE}.
+\item You can build a bare server by specifying {\ttfamily -\/\+D\+B\+U\+I\+L\+D\+\_\+\+S\+E\+R\+V\+ER=T\+R\+UE}.
+\item You can disable the client build by specifying {\ttfamily -\/\+D\+B\+U\+I\+L\+D\+\_\+\+C\+L\+I\+E\+NT=F\+A\+L\+SE}.
+\item You can select between Release and Debug build by {\ttfamily -\/\+D\+C\+M\+A\+K\+E\+\_\+\+B\+U\+I\+L\+D\+\_\+\+T\+Y\+PE=$<$Debug or Release$>$}.
+\begin{DoxyItemize}
+\item Debug build is slower, but gives much more useful output in a debugger.
+\end{DoxyItemize}
+\item If you build a bare server you don\textquotesingle{}t need to have Irrlicht installed.
+\begin{DoxyItemize}
+\item In that case use {\ttfamily -\/\+D\+I\+R\+R\+L\+I\+C\+H\+T\+\_\+\+S\+O\+U\+R\+C\+E\+\_\+\+D\+IR=/the/irrlicht/source}.
+\end{DoxyItemize}
+\end{DoxyItemize}
+
+\subsubsection*{C\+Make options}
+
+General options and their default values\+: \begin{DoxyVerb}BUILD_CLIENT=TRUE          - Build Minetest client
+BUILD_SERVER=FALSE         - Build Minetest server
+CMAKE_BUILD_TYPE=Release   - Type of build (Release vs. Debug)
+    Release                - Release build
+    Debug                  - Debug build
+    SemiDebug              - Partially optimized debug build
+    RelWithDebInfo         - Release build with debug information
+    MinSizeRel             - Release build with -Os passed to compiler to make executable as small as possible
+ENABLE_CURL=ON             - Build with cURL; Enables use of online mod repo, public serverlist and remote media fetching via http
+ENABLE_CURSES=ON           - Build with (n)curses; Enables a server side terminal (command line option: --terminal)
+ENABLE_FREETYPE=ON         - Build with FreeType2; Allows using TTF fonts
+ENABLE_GETTEXT=ON          - Build with Gettext; Allows using translations
+ENABLE_GLES=OFF            - Build for OpenGL ES instead of OpenGL (requires support by Irrlicht)
+ENABLE_LEVELDB=ON          - Build with LevelDB; Enables use of LevelDB map backend
+ENABLE_POSTGRESQL=ON       - Build with libpq; Enables use of PostgreSQL map backend (PostgreSQL 9.5 or greater recommended)
+ENABLE_REDIS=ON            - Build with libhiredis; Enables use of Redis map backend
+ENABLE_SPATIAL=ON          - Build with LibSpatial; Speeds up AreaStores
+ENABLE_SOUND=ON            - Build with OpenAL, libogg & libvorbis; in-game sounds
+ENABLE_LUAJIT=ON           - Build with LuaJIT (much faster than non-JIT Lua)
+ENABLE_SYSTEM_GMP=ON       - Use GMP from system (much faster than bundled mini-gmp)
+ENABLE_SYSTEM_JSONCPP=OFF  - Use JsonCPP from system
+OPENGL_GL_PREFERENCE=LEGACY - Linux client build only; See CMake Policy CMP0072 for reference
+RUN_IN_PLACE=FALSE         - Create a portable install (worlds, settings etc. in current directory)
+USE_GPROF=FALSE            - Enable profiling using GProf
+VERSION_EXTRA=             - Text to append to version (e.g. VERSION_EXTRA=foobar -> Minetest 0.4.9-foobar)
+\end{DoxyVerb}
+
+
+Library specific options\+: \begin{DoxyVerb}BZIP2_INCLUDE_DIR               - Linux only; directory where bzlib.h is located
+BZIP2_LIBRARY                   - Linux only; path to libbz2.a/libbz2.so
+CURL_DLL                        - Only if building with cURL on Windows; path to libcurl.dll
+CURL_INCLUDE_DIR                - Only if building with cURL; directory where curl.h is located
+CURL_LIBRARY                    - Only if building with cURL; path to libcurl.a/libcurl.so/libcurl.lib
+EGL_INCLUDE_DIR                 - Only if building with GLES; directory that contains egl.h
+EGL_LIBRARY                     - Only if building with GLES; path to libEGL.a/libEGL.so
+FREETYPE_INCLUDE_DIR_freetype2  - Only if building with FreeType 2; directory that contains an freetype directory with files such as ftimage.h in it
+FREETYPE_INCLUDE_DIR_ft2build   - Only if building with FreeType 2; directory that contains ft2build.h
+FREETYPE_LIBRARY                - Only if building with FreeType 2; path to libfreetype.a/libfreetype.so/freetype.lib
+FREETYPE_DLL                    - Only if building with FreeType 2 on Windows; path to libfreetype.dll
+GETTEXT_DLL                     - Only when building with gettext on Windows; path to libintl3.dll
+GETTEXT_ICONV_DLL               - Only when building with gettext on Windows; path to libiconv2.dll
+GETTEXT_INCLUDE_DIR             - Only when building with gettext; directory that contains iconv.h
+GETTEXT_LIBRARY                 - Only when building with gettext on Windows; path to libintl.dll.a
+GETTEXT_MSGFMT                  - Only when building with gettext; path to msgfmt/msgfmt.exe
+IRRLICHT_DLL                    - Only on Windows; path to Irrlicht.dll
+IRRLICHT_INCLUDE_DIR            - Directory that contains IrrCompileConfig.h
+IRRLICHT_LIBRARY                - Path to libIrrlicht.a/libIrrlicht.so/libIrrlicht.dll.a/Irrlicht.lib
+LEVELDB_INCLUDE_DIR             - Only when building with LevelDB; directory that contains db.h
+LEVELDB_LIBRARY                 - Only when building with LevelDB; path to libleveldb.a/libleveldb.so/libleveldb.dll.a
+LEVELDB_DLL                     - Only when building with LevelDB on Windows; path to libleveldb.dll
+PostgreSQL_INCLUDE_DIR          - Only when building with PostgreSQL; directory that contains libpq-fe.h
+PostgreSQL_LIBRARY              - Only when building with PostgreSQL; path to libpq.a/libpq.so/libpq.lib
+REDIS_INCLUDE_DIR               - Only when building with Redis; directory that contains hiredis.h
+REDIS_LIBRARY                   - Only when building with Redis; path to libhiredis.a/libhiredis.so
+SPATIAL_INCLUDE_DIR             - Only when building with LibSpatial; directory that contains spatialindex/SpatialIndex.h
+SPATIAL_LIBRARY                 - Only when building with LibSpatial; path to libspatialindex_c.so/spatialindex-32.lib
+LUA_INCLUDE_DIR                 - Only if you want to use LuaJIT; directory where luajit.h is located
+LUA_LIBRARY                     - Only if you want to use LuaJIT; path to libluajit.a/libluajit.so
+MINGWM10_DLL                    - Only if compiling with MinGW; path to mingwm10.dll
+OGG_DLL                         - Only if building with sound on Windows; path to libogg.dll
+OGG_INCLUDE_DIR                 - Only if building with sound; directory that contains an ogg directory which contains ogg.h
+OGG_LIBRARY                     - Only if building with sound; path to libogg.a/libogg.so/libogg.dll.a
+OPENAL_DLL                      - Only if building with sound on Windows; path to OpenAL32.dll
+OPENAL_INCLUDE_DIR              - Only if building with sound; directory where al.h is located
+OPENAL_LIBRARY                  - Only if building with sound; path to libopenal.a/libopenal.so/OpenAL32.lib
+OPENGLES2_INCLUDE_DIR           - Only if building with GLES; directory that contains gl2.h
+OPENGLES2_LIBRARY               - Only if building with GLES; path to libGLESv2.a/libGLESv2.so
+SQLITE3_INCLUDE_DIR             - Directory that contains sqlite3.h
+SQLITE3_LIBRARY                 - Path to libsqlite3.a/libsqlite3.so/sqlite3.lib
+VORBISFILE_DLL                  - Only if building with sound on Windows; path to libvorbisfile-3.dll
+VORBISFILE_LIBRARY              - Only if building with sound; path to libvorbisfile.a/libvorbisfile.so/libvorbisfile.dll.a
+VORBIS_DLL                      - Only if building with sound on Windows; path to libvorbis-0.dll
+VORBIS_INCLUDE_DIR              - Only if building with sound; directory that contains a directory vorbis with vorbisenc.h inside
+VORBIS_LIBRARY                  - Only if building with sound; path to libvorbis.a/libvorbis.so/libvorbis.dll.a
+XXF86VM_LIBRARY                 - Only on Linux; path to libXXf86vm.a/libXXf86vm.so
+ZLIB_DLL                        - Only on Windows; path to zlib1.dll
+ZLIB_INCLUDE_DIR                - Directory that contains zlib.h
+ZLIB_LIBRARY                    - Path to libz.a/libz.so/zlib.lib
+\end{DoxyVerb}
+
+
+\subsubsection*{Compiling on Windows}
+
+\subsubsection*{Requirements}
+
+
+\begin{DoxyItemize}
+\item \href{https://visualstudio.microsoft.com}{\tt Visual Studio 2015 or newer}
+\item \href{https://cmake.org/download/}{\tt C\+Make}
+\item \href{https://github.com/Microsoft/vcpkg}{\tt vcpkg}
+\item \href{https://git-scm.com/downloads}{\tt Git}
+\end{DoxyItemize}
+
+\subsubsection*{Compiling and installing the dependencies}
+
+It is highly recommended to use vcpkg as package manager.
+
+\paragraph*{a) Using vcpkg to install dependencies}
+
+After you successfully built vcpkg you can easily install the required libraries\+: 
+\begin{DoxyCode}
+vcpkg install irrlicht zlib curl[winssl] openal-soft libvorbis libogg sqlite3 freetype luajit --triplet
+       x64-windows
+\end{DoxyCode}
+
+
+
+\begin{DoxyItemize}
+\item {\ttfamily curl} is optional, but required to read the serverlist, {\ttfamily curl\mbox{[}winssl\mbox{]}} is required to use the content store.
+\item {\ttfamily openal-\/soft}, {\ttfamily libvorbis} and {\ttfamily libogg} are optional, but required to use sound.
+\item {\ttfamily freetype} is optional, it allows true-\/type font rendering.
+\item {\ttfamily luajit} is optional, it replaces the integrated Lua interpreter with a faster just-\/in-\/time interpreter.
+\end{DoxyItemize}
+
+There are other optional libraries, but they are not tested if they can build and link correctly.
+
+Use {\ttfamily -\/-\/triplet} to specify the target triplet, e.\+g. {\ttfamily x64-\/windows} or {\ttfamily x86-\/windows}.
+
+\paragraph*{b) Compile the dependencies on your own}
+
+This is outdated and not recommended. Follow the instructions on \href{https://dev.minetest.net/Build_Win32_Minetest_including_all_required_libraries#VS2012_Build}{\tt https\+://dev.\+minetest.\+net/\+Build\+\_\+\+Win32\+\_\+\+Minetest\+\_\+including\+\_\+all\+\_\+required\+\_\+libraries\#\+V\+S2012\+\_\+\+Build}
+
+\subsubsection*{Compile Minetest}
+
+\paragraph*{a) Using the vcpkg toolchain and C\+Make G\+UI}
+
+
+\begin{DoxyEnumerate}
+\item Start up the C\+Make G\+UI
+\item Select {\bfseries Browse Source...} and select D\+I\+R/minetest
+\item Select {\bfseries Browse Build...} and select D\+I\+R/minetest-\/build
+\item Select {\bfseries Configure}
+\item Choose the right visual Studio version and target platform. It has to match the version of the installed dependencies
+\item Choose {\bfseries Specify toolchain file for cross-\/compiling}
+\item Click {\bfseries Next}
+\item Select the vcpkg toolchain file e.\+g. {\ttfamily D\+:/vcpkg/scripts/buildsystems/vcpkg.cmake}
+\item Click Finish
+\item Wait until cmake have generated the cash file
+\item If there are any errors, solve them and hit {\bfseries Configure}
+\item Click {\bfseries Generate}
+\item Click {\bfseries Open Project}
+\item Compile Minetest inside Visual studio.
+\end{DoxyEnumerate}
+
+\paragraph*{b) Using the vcpkg toolchain and the commandline}
+
+Run the following script in Power\+Shell\+:
+
+
+\begin{DoxyCode}
+cmake . -G"Visual Studio 15 2017 Win64" -DCMAKE\_TOOLCHAIN\_FILE=D:/vcpkg/scripts/buildsystems/vcpkg.cmake
+       -DCMAKE\_BUILD\_TYPE=Release -DENABLE\_GETTEXT=0 -DENABLE\_CURSES=0
+cmake --build . --config Release
+\end{DoxyCode}
+ Make sure that the right compiler is selected and the path to the vcpkg toolchain is correct.
+
+\paragraph*{c) Using your own compiled libraries}
+
+{\bfseries This is outdated and not recommended}
+
+Follow the instructions on \href{https://dev.minetest.net/Build_Win32_Minetest_including_all_required_libraries#VS2012_Build}{\tt https\+://dev.\+minetest.\+net/\+Build\+\_\+\+Win32\+\_\+\+Minetest\+\_\+including\+\_\+all\+\_\+required\+\_\+libraries\#\+V\+S2012\+\_\+\+Build}
+
+\subsubsection*{Windows Installer using WiX Toolset}
+
+Requirements\+:
+\begin{DoxyItemize}
+\item \href{https://visualstudio.microsoft.com/}{\tt Visual Studio 2017}
+\item \href{https://wixtoolset.org/}{\tt WiX Toolset}
+\end{DoxyItemize}
+
+In the Visual Studio 2017 Installer select {\bfseries Optional Features -\/$>$ WiX Toolset}.
+
+Build the binaries as described above, but make sure you unselect {\ttfamily R\+U\+N\+\_\+\+I\+N\+\_\+\+P\+L\+A\+CE}.
+
+Open the generated project file with Visual Studio. Right-\/click {\bfseries Package} and choose {\bfseries Generate}. It may take some minutes to generate the installer.
+
+\subsection*{Docker }
+
+We provide Minetest server Docker images using the Git\+Lab mirror registry.
+
+Images are built on each commit and available using the following tag scheme\+:
+
+
+\begin{DoxyItemize}
+\item {\ttfamily registry.\+gitlab.\+com/minetest/minetest/server\+:latest} (latest build)
+\item {\ttfamily registry.\+gitlab.\+com/minetest/minetest/server\+:$<$branch/tag$>$} (current branch or current tag)
+\item {\ttfamily registry.\+gitlab.\+com/minetest/minetest/server\+:$<$commit-\/id$>$} (current commit id)
+\end{DoxyItemize}
+
+If you want to test it on a Docker server you can easily run\+: \begin{DoxyVerb}sudo docker run registry.gitlab.com/minetest/minetest/server:<docker tag>
+\end{DoxyVerb}
+
+
+If you want to use it in a production environment you should use volumes bound to the Docker host to persist data and modify the configuration\+: \begin{DoxyVerb}sudo docker create -v /home/minetest/data/:/var/lib/minetest/ -v /home/minetest/conf/:/etc/minetest/ registry.gitlab.com/minetest/minetest/server:master
+\end{DoxyVerb}
+
+
+Data will be written to {\ttfamily /home/minetest/data} on the host, and configuration will be read from {\ttfamily /home/minetest/conf/minetest.conf}.
+
+{\bfseries Note\+:} If you don\textquotesingle{}t understand the previous commands please read the official Docker documentation before use.
+
+You can also host your Minetest server inside a Kubernetes cluster. See our example implementation in \href{misc/kubernetes.yml}{\tt {\ttfamily misc/kubernetes.\+yml}}.
+
+\subsection*{Version scheme }
+
+We use {\ttfamily major.\+minor.\+patch} since 5.\+0.\+0-\/dev. Prior to that we used {\ttfamily 0.\+major.\+minor}.
+
+
+\begin{DoxyItemize}
+\item Major is incremented when the release contains breaking changes, all other numbers are set to 0.
+\item Minor is incremented when the release contains new non-\/breaking features, patch is set to 0.
+\item Patch is incremented when the release only contains bugfixes and very minor/trivial features considered necessary.
+\end{DoxyItemize}
+
+Since 5.\+0.\+0-\/dev and 0.\+4.\+17-\/dev, the dev notation refers to the next release, i.\+e.\+: 5.\+0.\+0-\/dev is the development version leading to 5.\+0.\+0. Prior to that we used {\ttfamily previous\+\_\+version-\/dev}. 
\ No newline at end of file
diff --git a/latex/refman.log b/latex/refman.log
new file mode 100644 (file)
index 0000000..7b0b4c8
--- /dev/null
@@ -0,0 +1,156 @@
+This is pdfTeX, Version 3.14159265-2.6-1.40.20 (TeX Live 2019/Debian) (preloaded format=pdflatex 2020.2.2)  9 JUN 2020 15:24
+entering extended mode
+ restricted \write18 enabled.
+ %&-line parsing enabled.
+**refman
+(./refman.tex
+LaTeX2e <2018-12-01>
+(/usr/share/texlive/texmf-dist/tex/latex/base/book.cls
+Document Class: book 2018/09/03 v1.4i Standard LaTeX document class
+(/usr/share/texlive/texmf-dist/tex/latex/base/bk10.clo
+File: bk10.clo 2018/09/03 v1.4i Standard LaTeX file (size option)
+)
+\c@part=\count80
+\c@chapter=\count81
+\c@section=\count82
+\c@subsection=\count83
+\c@subsubsection=\count84
+\c@paragraph=\count85
+\c@subparagraph=\count86
+\c@figure=\count87
+\c@table=\count88
+\abovecaptionskip=\skip41
+\belowcaptionskip=\skip42
+\bibindent=\dimen102
+)
+(/usr/share/texlive/texmf-dist/tex/latex/base/fixltx2e.sty
+Package: fixltx2e 2016/12/29 v2.1a fixes to LaTeX (obsolete)
+Applying: [2015/01/01] Old fixltx2e package on input line 46.
+
+
+Package fixltx2e Warning: fixltx2e is not required with releases after 2015
+(fixltx2e)                All fixes are now in the LaTeX kernel.
+(fixltx2e)                See the latexrelease package for details.
+
+Already applied: [0000/00/00] Old fixltx2e package on input line 53.
+) (/usr/share/texlive/texmf-dist/tex/latex/tools/calc.sty
+Package: calc 2017/05/25 v4.3 Infix arithmetic (KKT,FJ)
+\calc@Acount=\count89
+\calc@Bcount=\count90
+\calc@Adimen=\dimen103
+\calc@Bdimen=\dimen104
+\calc@Askip=\skip43
+\calc@Bskip=\skip44
+LaTeX Info: Redefining \setlength on input line 80.
+LaTeX Info: Redefining \addtolength on input line 81.
+\calc@Ccount=\count91
+\calc@Cskip=\skip45
+) (./doxygen.sty
+Package: doxygen 
+
+(/usr/share/texlive/texmf-dist/tex/latex/base/alltt.sty
+Package: alltt 1997/06/16 v2.0g defines alltt environment
+)
+(/usr/share/texlive/texmf-dist/tex/latex/tools/array.sty
+Package: array 2018/12/30 v2.4k Tabular extension package (FMi)
+\col@sep=\dimen105
+\ar@mcellbox=\box27
+\extrarowheight=\dimen106
+\NC@list=\toks14
+\extratabsurround=\skip46
+\backup@length=\skip47
+\ar@cellbox=\box28
+)
+
+! LaTeX Error: File `float.sty' not found.
+
+Type X to quit or <RETURN> to proceed,
+or enter new name. (Default extension: sty)
+
+Enter file name: doxygen.sty
+(./doxygen.sty
+
+LaTeX Warning: You have requested package `float',
+               but the package provides `doxygen'.
+
+Package: doxygen 
+(/usr/share/texlive/texmf-dist/tex/latex/base/ifthen.sty
+Package: ifthen 2014/09/29 v1.1c Standard LaTeX ifthen package (DPC)
+)
+(/usr/share/texlive/texmf-dist/tex/latex/tools/verbatim.sty
+Package: verbatim 2014/10/28 v1.5q LaTeX2e package for verbatim enhancements
+\every@verbatim=\toks15
+\verbatim@line=\toks16
+\verbatim@in@stream=\read1
+)
+
+! LaTeX Error: File `xcolor.sty' not found.
+
+Type X to quit or <RETURN> to proceed,
+or enter new name. (Default extension: sty)
+
+Enter file name: 
+! Interruption.
+<to be read again> 
+                   }
+l.12 \RequirePackage
+                    {longtable}^^M
+? 
+
+! LaTeX Error: Unknown option `table' for package `xcolor'.
+
+See the LaTeX manual or LaTeX Companion for explanation.
+Type  H <return>  for immediate help.
+ ...                                              
+                                                  
+l.12 \RequirePackage
+                    {longtable}
+? 
+! Interruption.
+\GenericError  ...                                
+                                                  \endgroup 
+l.12 \RequirePackage
+                    {longtable}
+? 
+(/usr/share/texlive/texmf-dist/tex/latex/tools/longtable.sty
+Package: longtable 2014/10/28 v4.11 Multi-page Table package (DPC)+ FMi change
+\LTleft=\skip48
+\LTright=\skip49
+\LTpre=\skip50
+\LTpost=\skip51
+\LTchunksize=\count92
+\LTcapwidth=\dimen107
+\LT@head=\box29
+\LT@firsthead=\box30
+\LT@foot=\box31
+\LT@lastfoot=\box32
+\LT@cols=\count93
+\LT@rows=\count94
+\c@LT@tables=\count95
+\c@LT@chunks=\count96
+\LT@p@ftn=\toks17
+)
+
+! LaTeX Error: File `tabu.sty' not found.
+
+Type X to quit or <RETURN> to proceed,
+or enter new name. (Default extension: sty)
+
+Enter file name: 
+! Emergency stop.
+<read *> 
+         
+l.14 \RequirePackage
+                    {tabularx}^^M
+End of file on the terminal!
+
+Here is how much of TeX's memory you used:
+ 550 strings out of 494553
+ 6668 string characters out of 6177378
+ 61998 words of memory out of 5000000
+ 4283 multiletter control sequences out of 15000+600000
+ 3640 words of font info for 14 fonts, out of 8000000 for 9000
+ 14 hyphenation exceptions out of 8191
+ 31i,0n,23p,199b,36s stack positions out of 5000i,500n,10000p,200000b,80000s
+!  ==> Fatal error occurred, no output PDF file produced!
diff --git a/latex/refman.tex b/latex/refman.tex
new file mode 100644 (file)
index 0000000..dd59457
--- /dev/null
@@ -0,0 +1,155 @@
+\documentclass[twoside]{book}
+
+% Packages required by doxygen
+\usepackage{fixltx2e}
+\usepackage{calc}
+\usepackage{doxygen}
+\usepackage[export]{adjustbox} % also loads graphicx
+\usepackage{graphicx}
+\usepackage[utf8]{inputenc}
+\usepackage{makeidx}
+\usepackage{multicol}
+\usepackage{multirow}
+\PassOptionsToPackage{warn}{textcomp}
+\usepackage{textcomp}
+\usepackage[nointegrals]{wasysym}
+\usepackage[table]{xcolor}
+
+% Font selection
+\usepackage[T1]{fontenc}
+\usepackage[scaled=.90]{helvet}
+\usepackage{courier}
+\usepackage{amssymb}
+\usepackage{sectsty}
+\renewcommand{\familydefault}{\sfdefault}
+\allsectionsfont{%
+  \fontseries{bc}\selectfont%
+  \color{darkgray}%
+}
+\renewcommand{\DoxyLabelFont}{%
+  \fontseries{bc}\selectfont%
+  \color{darkgray}%
+}
+\newcommand{\+}{\discretionary{\mbox{\scriptsize$\hookleftarrow$}}{}{}}
+
+% Page & text layout
+\usepackage{geometry}
+\geometry{%
+  a4paper,%
+  top=2.5cm,%
+  bottom=2.5cm,%
+  left=2.5cm,%
+  right=2.5cm%
+}
+\tolerance=750
+\hfuzz=15pt
+\hbadness=750
+\setlength{\emergencystretch}{15pt}
+\setlength{\parindent}{0cm}
+\setlength{\parskip}{3ex plus 2ex minus 2ex}
+\makeatletter
+\renewcommand{\paragraph}{%
+  \@startsection{paragraph}{4}{0ex}{-1.0ex}{1.0ex}{%
+    \normalfont\normalsize\bfseries\SS@parafont%
+  }%
+}
+\renewcommand{\subparagraph}{%
+  \@startsection{subparagraph}{5}{0ex}{-1.0ex}{1.0ex}{%
+    \normalfont\normalsize\bfseries\SS@subparafont%
+  }%
+}
+\makeatother
+
+% Headers & footers
+\usepackage{fancyhdr}
+\pagestyle{fancyplain}
+\fancyhead[LE]{\fancyplain{}{\bfseries\thepage}}
+\fancyhead[CE]{\fancyplain{}{}}
+\fancyhead[RE]{\fancyplain{}{\bfseries\leftmark}}
+\fancyhead[LO]{\fancyplain{}{\bfseries\rightmark}}
+\fancyhead[CO]{\fancyplain{}{}}
+\fancyhead[RO]{\fancyplain{}{\bfseries\thepage}}
+\fancyfoot[LE]{\fancyplain{}{}}
+\fancyfoot[CE]{\fancyplain{}{}}
+\fancyfoot[RE]{\fancyplain{}{\bfseries\scriptsize Generated by Doxygen }}
+\fancyfoot[LO]{\fancyplain{}{\bfseries\scriptsize Generated by Doxygen }}
+\fancyfoot[CO]{\fancyplain{}{}}
+\fancyfoot[RO]{\fancyplain{}{}}
+\renewcommand{\footrulewidth}{0.4pt}
+\renewcommand{\chaptermark}[1]{%
+  \markboth{#1}{}%
+}
+\renewcommand{\sectionmark}[1]{%
+  \markright{\thesection\ #1}%
+}
+
+% Indices & bibliography
+\usepackage{natbib}
+\usepackage[titles]{tocloft}
+\setcounter{tocdepth}{3}
+\setcounter{secnumdepth}{5}
+\makeindex
+
+% Hyperlinks (required, but should be loaded last)
+\usepackage{ifpdf}
+\ifpdf
+  \usepackage[pdftex,pagebackref=true]{hyperref}
+\else
+  \usepackage[ps2pdf,pagebackref=true]{hyperref}
+\fi
+\hypersetup{%
+  colorlinks=true,%
+  linkcolor=blue,%
+  citecolor=blue,%
+  unicode%
+}
+
+% Custom commands
+\newcommand{\clearemptydoublepage}{%
+  \newpage{\pagestyle{empty}\cleardoublepage}%
+}
+
+\usepackage{caption}
+\captionsetup{labelsep=space,justification=centering,font={bf},singlelinecheck=off,skip=4pt,position=top}
+
+%===== C O N T E N T S =====
+
+\begin{document}
+
+% Titlepage & ToC
+\hypersetup{pageanchor=false,
+             bookmarksnumbered=true,
+             pdfencoding=unicode
+            }
+\pagenumbering{alph}
+\begin{titlepage}
+\vspace*{7cm}
+\begin{center}%
+{\Large My Project }\\
+\vspace*{1cm}
+{\large Generated by Doxygen 1.8.13}\\
+\end{center}
+\end{titlepage}
+\clearemptydoublepage
+\pagenumbering{roman}
+\tableofcontents
+\clearemptydoublepage
+\pagenumbering{arabic}
+\hypersetup{pageanchor=true}
+
+%--- Begin generated contents ---
+\chapter{Minetest}
+\label{md_README}
+\Hypertarget{md_README}
+\input{md_README}
+%--- End generated contents ---
+
+% Index
+\backmatter
+\newpage
+\phantomsection
+\clearemptydoublepage
+\addcontentsline{toc}{chapter}{Index}
+\printindex
+
+\end{document}
index 0491d2fc11b582620355ed89c2c3626a35126840..9460b273d6f1fec01bd0431c3427e4aea131f7ce 100644 (file)
@@ -7,7 +7,7 @@
        <key>CFBundleExecutable</key>
        <string>minetest</string>
        <key>CFBundleIconFile</key>
-       <string>minetest-icon.icns</string>
+       <string>dragonfire-icon.icns</string>
        <key>CFBundleName</key>
        <string>Minetest</string>
        <key>CFBundleDisplayName</key>
diff --git a/misc/dragonfire-icon-24x24.png b/misc/dragonfire-icon-24x24.png
new file mode 100644 (file)
index 0000000..0edc90e
Binary files /dev/null and b/misc/dragonfire-icon-24x24.png differ
diff --git a/misc/dragonfire-icon.icns b/misc/dragonfire-icon.icns
new file mode 100644 (file)
index 0000000..bb20daf
Binary files /dev/null and b/misc/dragonfire-icon.icns differ
diff --git a/misc/dragonfire-icon.ico b/misc/dragonfire-icon.ico
new file mode 100644 (file)
index 0000000..3ac1f5c
Binary files /dev/null and b/misc/dragonfire-icon.ico differ
diff --git a/misc/dragonfire-icon.ico.png b/misc/dragonfire-icon.ico.png
new file mode 100644 (file)
index 0000000..6c04cf7
Binary files /dev/null and b/misc/dragonfire-icon.ico.png differ
diff --git a/misc/dragonfire-xorg-icon-128.png b/misc/dragonfire-xorg-icon-128.png
new file mode 100644 (file)
index 0000000..b1ed452
Binary files /dev/null and b/misc/dragonfire-xorg-icon-128.png differ
diff --git a/misc/dragonfire.svg b/misc/dragonfire.svg
new file mode 100644 (file)
index 0000000..3504926
--- /dev/null
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="424.759mm"
+   height="548.14117mm"
+   viewBox="0 0 424.759 548.14117"
+   version="1.1"
+   id="svg8"
+   sodipodi:docname="dragonfire.svg"
+   inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
+  <defs
+     id="defs2" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.49497475"
+     inkscape:cx="821.97201"
+     inkscape:cy="1504.5142"
+     inkscape:document-units="mm"
+     inkscape:current-layer="layer2"
+     inkscape:document-rotation="0"
+     showgrid="false"
+     inkscape:object-paths="false"
+     inkscape:snap-global="true"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0"
+     inkscape:window-width="1920"
+     inkscape:window-height="1009"
+     inkscape:window-x="0"
+     inkscape:window-y="42"
+     inkscape:window-maximized="1" />
+  <metadata
+     id="metadata5">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:groupmode="layer"
+     id="layer2"
+     inkscape:label="Layer 2"
+     transform="translate(121.51509,140.87775)">
+    <path
+       style="fill:#d97c00;fill-opacity:1;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="m 174.63127,40.893641 c -0.62502,9.168773 -1.62909,25.023007 -18.75726,35.157567 -7.90853,4.679393 -14.88691,6.794713 -21.4562,10.084768 -10.0234,5.019952 -19.11206,10.735064 -29.23784,16.443334 L 92.551574,80.797555 162.67724,33.953338 Z"
+       id="path884"
+       sodipodi:nodetypes="csscccc" />
+    <path
+       style="fill:#d97b00;fill-opacity:1;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="m 185.29405,-52.901706 c 11.8624,-1.285468 24.94967,-4.400419 37.49354,-1.637969 12.24665,2.696994 31.53215,34.732889 51.00592,52.1769726 0,0 -16.21214,16.4095564 -26.41499,18.4986104 -13.0146,2.664766 -38.0854,-8.8161096 -38.0854,-8.8161096 z"
+       id="path892"
+       sodipodi:nodetypes="cscscc" />
+    <path
+       id="path894"
+       style="fill:#d97b00;fill-opacity:1;stroke:#000000;stroke-width:0.999999px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="m -237.29492,-365.62695 -102.4961,44.47656 c -39.64671,13.3036 -77.7993,9.74465 -114.99609,-4.59961 18.83278,64.6973 61.65447,80.70688 100.22461,105.34766 l 20.38281,12.67773 119.65821,-37.31055 z m 142.837889,330.521481 -181.515629,1.728516 c -12.82292,20.53197 -27.12291,45.236147 -34.40429,60.970703 25.65593,22.007697 51.66201,10.680981 82.19922,16.123047 z M -53.662109,97.027344 C -135.91186,164.51608 -191.67233,232.94647 -185.17578,306.11133 c 49.25913,-27.21072 79.87529,-71.5969 201.523436,-46.86719 L 261.88672,158.70312 Z"
+       transform="scale(0.26458333)" />
+    <path
+       id="path849"
+       style="fill:#f38a00;fill-opacity:1;stroke:#000000;stroke-width:0.99999899px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="m 568.43555,-526.07617 c -14.82346,21.59652 -10.36236,62.4642 -47.95452,70.79164 -3.38976,0.7509 -17.46828,-1.19108 -32.98408,0.43695 -18.84158,1.977 -40.48071,8.03189 -56.324,15.42617 -33.24391,15.51539 -77.8147,55.62913 -112.75465,72.95834 -32.78338,16.2596 -36.77134,9.79692 -48.67664,17.98947 -8.00352,5.50757 -21.67624,19.44462 -21.53854,37.67868 1.19409,158.11527 151.15589,21.69112 199.53516,71.1914 14.8786,15.22338 11.88459,36.39462 6.97461,54.90625 C 404.66662,3.9869356 162.60235,42.347074 56.927734,203.88477 3.9446038,284.87653 -80.069959,397.39278 -61.841797,492.44336 -35.456633,630.02852 99.783247,729.97044 214.32617,846.58984 c 64.00921,65.16957 141.98892,113.48363 192.04102,170.23046 63.76539,72.2944 92.82338,147.3005 105.11523,169.2305 56.96806,101.6371 -68.9819,229.5341 -152.16211,352.0234 89.58072,-40.6129 334.76613,-100.9267 345.77344,-313.8867 8.59476,-166.285 -117.78329,-338.01531 -312.1543,-489.22461 -77.20543,-60.0613 -109.34724,-150.31587 -82.55664,-230.82812 39.58416,-2.09715 78.27934,-10.6901 117.06836,-10.44141 69.69555,0.44689 149.1488,19.05746 219.20117,-15.58398 42.10833,-20.8229 71.05515,-89.9449 6.08008,-97.95508 C 576.02986,370.69838 530.2339,386.8415 437.13477,331.12891 481.58375,261.29772 638.13906,201.85117 826.60547,111.95703 872.12663,90.244477 883.77888,74.964433 937.43555,37.869141 991.28524,0.64040756 1075.7032,-65.93749 1138.916,-103.27734 c 9.0613,-29.61017 11.7554,-61.56671 -10.1523,-90.7793 -13.2778,-17.97641 -31.3708,-35.51132 -72.1446,-27.36328 -65.3167,125.783129 -225.8886,147.014404 -255.41012,115.72851 -32.2648,-34.19314 -63.32519,-85.26367 -98.67382,-146.27148 -28.74123,-49.60415 -74.03362,-99.10568 -102.28907,-160.50781 -16.09375,-34.97356 -24.38944,-78.9681 -31.81054,-113.60547 z m -72.97657,109.20898 c -14.47479,6.90263 -24.42683,17.72656 -35.82226,19.68946 -10.11164,1.74179 -10.15066,-1.10847 -12.14844,-4.88868 14.42018,-10.39842 30.98895,-13.31935 47.9707,-14.80078 z"
+       sodipodi:nodetypes="cssssssscssssscsscssscsscccsssccscc"
+       transform="scale(0.26458333)"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="m 75.771318,-72.60352 22.637085,-3.724836"
+       id="path902"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="m 78.31929,82.489785 c 12.057476,-2.128665 24.22843,-3.138178 37.33924,5.121331"
+       id="path886"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="m 172.90786,108.41166 c 3.79692,-2.83643 8.26351,1.6997 9.45928,4.49824"
+       id="path888"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="m 167.99805,114.53389 c 3.77662,-2.00305 9.73661,-1.26459 9.29324,7.24955"
+       id="path890"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="m 74.691115,-89.86943 3.585337,-2.090091"
+       id="path904" />
+    <path
+       style="display:inline;fill:#ff9100;fill-opacity:1;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="m -121.28811,-140.46489 c 30.230229,30.11602 37.182859,15.03379 76.840571,15.23187 12.764686,0.0638 33.640637,1.60284 54.652193,8.63798 18.309364,6.13039 36.913564,17.321485 47.885882,23.979967 42.623434,25.865762 74.689314,48.986152 74.294234,62.692517 C 131.61006,-3.0450289 46.340705,36.780877 32.944678,39.054476 -18.358314,47.761715 -52.033419,15.59799 -85.52309,71.851913 -93.677049,61.283562 -86.706295,31.892897 -59.723271,-1.1510784 -81.022343,-4.4118581 -102.93941,-9.3410193 -116.90663,-23.833561 c 3.12282,-13.93191 21.426823,-42.460615 50.349014,-47.510697 -12.667717,-12.219711 -43.351564,-17.767543 -54.730494,-69.120632 z"
+       id="path847"
+       sodipodi:nodetypes="csssssccccc" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="m 173.65593,104.49243 c 3.47593,-2.78405 6.55751,-0.24685 8.31582,1.60947"
+       id="path908"
+       sodipodi:nodetypes="cc" />
+  </g>
+</svg>
diff --git a/misc/minetest-icon-24x24.png b/misc/minetest-icon-24x24.png
deleted file mode 100644 (file)
index 334e2f6..0000000
Binary files a/misc/minetest-icon-24x24.png and /dev/null differ
diff --git a/misc/minetest-icon.icns b/misc/minetest-icon.icns
deleted file mode 100644 (file)
index 14731c2..0000000
Binary files a/misc/minetest-icon.icns and /dev/null differ
diff --git a/misc/minetest-icon.ico b/misc/minetest-icon.ico
deleted file mode 100644 (file)
index 82af67b..0000000
Binary files a/misc/minetest-icon.ico and /dev/null differ
diff --git a/misc/minetest-xorg-icon-128.png b/misc/minetest-xorg-icon-128.png
deleted file mode 100644 (file)
index 0241a91..0000000
Binary files a/misc/minetest-xorg-icon-128.png and /dev/null differ
diff --git a/misc/minetest.svg b/misc/minetest.svg
deleted file mode 100644 (file)
index fe036c3..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
-   xmlns:dc="http://purl.org/dc/elements/1.1/"
-   xmlns:cc="http://creativecommons.org/ns#"
-   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-   xmlns:svg="http://www.w3.org/2000/svg"
-   xmlns="http://www.w3.org/2000/svg"
-   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
-   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   width="48px"
-   height="48px"
-   id="svg2856"
-   version="1.1"
-   inkscape:version="0.47 r22583"
-   sodipodi:docname="minetest.svg"
-   inkscape:export-filename="/home/erlehmann/pics/icons/minetest/minetest-icon-24x24.png"
-   inkscape:export-xdpi="45"
-   inkscape:export-ydpi="45">
-  <defs
-     id="defs2858">
-    <filter
-       inkscape:collect="always"
-       id="filter3864">
-      <feGaussianBlur
-         inkscape:collect="always"
-         stdDeviation="0.20490381"
-         id="feGaussianBlur3866" />
-    </filter>
-  </defs>
-  <sodipodi:namedview
-     id="base"
-     pagecolor="#ffffff"
-     bordercolor="#666666"
-     borderopacity="1.0"
-     inkscape:pageopacity="0.0"
-     inkscape:pageshadow="2"
-     inkscape:zoom="12.083333"
-     inkscape:cx="24"
-     inkscape:cy="24"
-     inkscape:current-layer="layer1"
-     showgrid="false"
-     inkscape:grid-bbox="true"
-     inkscape:document-units="px"
-     inkscape:window-width="1233"
-     inkscape:window-height="755"
-     inkscape:window-x="0"
-     inkscape:window-y="25"
-     inkscape:window-maximized="1">
-    <inkscape:grid
-       type="xygrid"
-       id="grid2866"
-       empspacing="2"
-       visible="true"
-       enabled="true"
-       snapvisiblegridlinesonly="true"
-       spacingx="0.5px"
-       spacingy="10px"
-       color="#ff0000"
-       opacity="0.1254902"
-       empcolor="#ff0000"
-       empopacity="0.25098039"
-       dotted="false" />
-    <inkscape:grid
-       type="axonomgrid"
-       id="grid2870"
-       units="px"
-       empspacing="1"
-       visible="true"
-       enabled="true"
-       snapvisiblegridlinesonly="true"
-       spacingy="1px"
-       originx="0px" />
-  </sodipodi:namedview>
-  <metadata
-     id="metadata2861">
-    <rdf:RDF>
-      <cc:Work
-         rdf:about="">
-        <dc:format>image/svg+xml</dc:format>
-        <dc:type
-           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
-        <dc:title />
-      </cc:Work>
-    </rdf:RDF>
-  </metadata>
-  <g
-     id="layer1"
-     inkscape:label="Layer 1"
-     inkscape:groupmode="layer">
-    <path
-       style="fill:#e9b96e;fill-opacity:1;stroke:#573a0d;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
-       d="M 6.1513775e-7,16 3.2110204e-7,28 21.035899,40.145082 l 21,-12.414519 0,-11.461126 L 20.78461,4 6.1513775e-7,16 z"
-       id="path3047"
-       transform="translate(3.4641013,6)"
-       sodipodi:nodetypes="ccccccc" />
-    <path
-       style="fill:#2e3436;fill-opacity:1;stroke:#2e3436;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
-       d="m 8.5,30.907477 -2,-1.1547 0,6 L 17.320508,42 l 0,-2 -1.732051,-1 0,-2 L 13.5,35.794229 l 0,-4 -5,-2.886752 0,2 z"
-       id="path3831"
-       sodipodi:nodetypes="ccccccccccc" />
-    <path
-       style="opacity:1;fill:#555753;fill-opacity:1;stroke:#2e3436;stroke-linejoin:miter"
-       d="m 6.9282032,36 3.4641018,-2 3.464101,2 1.643594,0.948929 0,2 2,1.154701 0,2 L 6.9282032,36 z"
-       id="path3870"
-       sodipodi:nodetypes="cccccccc" />
-    <path
-       style="fill:#fce94f;fill-opacity:1;stroke:#625802;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
-       d="M 25.980762,19 31.5,22.186533 l 0,2 L 38.09375,28 41.5625,26 45.5,23.730563 l 0,2.538874 0,-4 L 32.908965,15 25.980762,19 z"
-       id="path3851"
-       sodipodi:nodetypes="cccccccccc" />
-    <path
-       style="fill:#e9b96e;fill-opacity:1;stroke:#573a0d;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0.50000000000000000"
-       d="m 24.839746,18.341234 8.660254,-5 0,2 -8.660254,5 0,-2 z"
-       id="path5684"
-       sodipodi:nodetypes="ccccc" />
-    <path
-       style="fill:#73d216;fill-opacity:1;stroke:#325b09;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
-       d="M 25.980762,5 3.4641016,18 17.5,26.10363 31.5,18.186533 24.839746,14.341234 33.5,9.341234 25.980762,5 z"
-       id="path3821"
-       sodipodi:nodetypes="ccccccc"
-       transform="translate(0,4)" />
-    <path
-       style="fill:#729fcf;fill-opacity:1;stroke:#19314b;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
-       d="m 17.5,28.10363 0,2 1.552559,0.89637 0,2 5.447441,3.145082 12,-7.071797 0,-2.14657 2,-1.1547 0,-1.54403 -7,-4.041452 -14,7.917097 z"
-       id="path3825"
-       sodipodi:nodetypes="ccccccccccc"
-       transform="translate(0,4)" />
-    <g
-       id="g5691"
-       style="stroke-linejoin:miter">
-      <path
-         sodipodi:nodetypes="ccccc"
-         id="path3862"
-         d="m 13.856406,20 6.928204,4 -6.928204,4 -6.9282028,-4 6.9282028,-4 z"
-         style="fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;filter:url(#filter3864);opacity:0.25000000000000000" />
-      <g
-         id="g3858"
-         style="stroke-linejoin:miter">
-        <path
-           style="fill:#c17d11;fill-opacity:1;stroke:#8f5902;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
-           d="m 15.588457,21 1.732051,1 1.732051,-1 0,-6 -1.732051,-1 -1.732051,1 0,6 z"
-           id="path3833"
-           sodipodi:nodetypes="ccccccc"
-           transform="translate(-3.4641015,2)" />
-        <path
-           style="fill:#4e9a06;fill-opacity:1;stroke:#316004;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
-           d="M 9.9641015,13.752777 17.320508,18 l 6.643593,-3.835681 0,-8.3286385 L 17.320508,2 9.9641015,6.2472233 l 0,7.5055537 z"
-           id="path3837"
-           transform="translate(-3.4641015,2)"
-           sodipodi:nodetypes="ccccccc" />
-      </g>
-    </g>
-    <g
-       id="g5686"
-       transform="translate(-4.2591582e-7,2)"
-       style="stroke-linejoin:miter">
-      <path
-         transform="translate(24.248712,-2)"
-         style="opacity:0.25000000000000000;fill:#2e3436;fill-opacity:1;stroke:none;filter:url(#filter3864);stroke-linejoin:miter"
-         d="m 13.856406,20 5.196153,3 -5.196153,3 -5.196152,-3 5.196152,-3 z"
-         id="path3868"
-         sodipodi:nodetypes="ccccc" />
-      <path
-         style="fill:#4e9a06;fill-opacity:1;stroke:#316004;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
-         d="M 15.71539,21.073285 17.320508,22 l 1.394882,-0.805336 0,-8.389328 L 17.320508,12 l -1.605118,1.073285 0,8 z"
-         id="path3853"
-         sodipodi:nodetypes="ccccccc"
-         transform="translate(20.78461,0)" />
-    </g>
-    <path
-       style="fill:none;fill-opacity:1;stroke:#ef2929;stroke-width:0.50000000000000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:0.50000000000000000, 0.50000000000000000;stroke-dashoffset:0.25000000000000000"
-       d="M 12.124356,33 11.25833,32.5"
-       id="path3872"
-       sodipodi:nodetypes="cc" />
-    <path
-       style="fill:#888a85;stroke:#2e3436;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0.50000000000000000"
-       d="m 45.5,26.730563 -4,2.309401 0,1 -2,1.1547 0,2 -2,1.154701 0,4 8,-4.618802 0,-7 z"
-       id="path3874"
-       sodipodi:nodetypes="ccccccccc" />
-  </g>
-</svg>
old mode 100644 (file)
new mode 100755 (executable)
index a94dbab..737dfb2
@@ -1,3 +1,4 @@
+#!/usr/bin/env xdg-open
 [Desktop Entry]
 Name=Minetest
 GenericName=Minetest
@@ -9,9 +10,8 @@ Comment[ja]=マルチプレイに対応した、無限の世界のブロック
 Comment[ru]=Игра-песочница с безграничным миром, состоящим из блоков
 Comment[tr]=Tek-Çok oyuncuyla küplerden sonsuz dünyalar inşa et
 Exec=minetest
-Icon=minetest
+Icon=dragonfire
 Terminal=false
-PrefersNonDefaultGPU=true
 Type=Application
 Categories=Game;Simulation;
 StartupNotify=false
index ffb493873647e474459f78141bfa69a8f199b92b..bd93be91dfc0e73bd0c53afcb982bfd711e06548 100644 (file)
@@ -1,8 +1,6 @@
 #include <windows.h>\r
-#include <winuser.h>\r
 #include <commctrl.h>\r
 #include <richedit.h>\r
-\r
 #ifndef USE_CMAKE_CONFIG_H\r
 #define USE_CMAKE_CONFIG_H\r
 #endif\r
        #define BUILDMODE "RUN_IN_PLACE=0"\r
 #endif\r
 \r
-#ifdef __MINGW32__\r
-CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "minetest.exe.manifest"\r
-#endif\r
-\r
 LANGUAGE 0, SUBLANG_NEUTRAL\r
-130        ICON         "minetest-icon.ico"\r
+130        ICON         "dragonfire-icon.ico"\r
 \r
 /////////////////////////////////////////////////////////////////////////////\r
 //\r
index aa0538e60f754ec92992a66dea250b711a83fc17..835f19dc2581ae51857f43f2c219ee42e15861fb 100644 (file)
@@ -43,6 +43,11 @@ class ActiveObjectMgr
                return (n != m_active_objects.end() ? n->second : nullptr);
        }
 
+       std::unordered_map<u16, T *> getAllActiveObjects() const
+       {
+               return m_active_objects;
+       }
+
 protected:
        u16 getFreeId() const
        {
index 7cc9cb6e8cdc31ae19fecdc2ce92fb5f227a8bec..164db876192d945ccb129bc3a2097d2b0db3e0bf 100644 (file)
@@ -36,6 +36,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "util/numeric.h"
 #include "constants.h"
 #include "fontengine.h"
+#include "guiscalingfilter.h"
 #include "script/scripting_client.h"
 #include "gettext.h"
 
@@ -322,7 +323,7 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 tool_reload_ratio)
        // mods expect the player head to be at the parent's position
        // plus eye height.
        if (player->getParent())
-               player_position = player->getParent()->getPosition();
+               player_position = player->getParent()->getPosition() + v3f(0,  g_settings->getBool("float_above_parent") ? BS : 0, 0);
 
        // Smooth the camera movement after the player instantly moves upward due to stepheight.
        // The smoothing usually continues until the camera position reaches the player position.
@@ -679,7 +680,7 @@ void Camera::drawNametags()
                        screen_pos.Y = screensize.Y *
                                (0.5 - transformed_pos[1] * zDiv * 0.5) - textsize.Height / 2;
                        core::rect<s32> size(0, 0, textsize.Width, textsize.Height);
-                       core::rect<s32> bg_size(-2, 0, textsize.Width+2, textsize.Height);
+                       core::rect<s32> bg_size(-2, 0, std::max(textsize.Width+2, (u32) nametag->images_dim.Width), textsize.Height + nametag->images_dim.Height);
 
                        auto bgcolor = nametag->getBgColor(m_show_nametag_backgrounds);
                        if (bgcolor.getAlpha() != 0)
@@ -688,15 +689,29 @@ void Camera::drawNametags()
                        font->draw(
                                translate_string(utf8_to_wide(nametag->text)).c_str(),
                                size + screen_pos, nametag->textcolor);
+
+                       v2s32 image_pos(screen_pos);
+                       image_pos.Y += textsize.Height;
+
+                       const video::SColor color(255, 255, 255, 255);
+                       const video::SColor colors[] = {color, color, color, color};
+
+                       for (video::ITexture *texture : nametag->images) {
+                               core::dimension2di imgsize(texture->getOriginalSize());
+                               core::rect<s32> rect(core::position2d<s32>(0, 0), imgsize);
+                               draw2DImageFilterScaled(driver, texture, rect + image_pos, rect, NULL, colors, true);
+                               image_pos += core::dimension2di(imgsize.Width, 0);
+                       }
+
                }
        }
 }
-
 Nametag *Camera::addNametag(scene::ISceneNode *parent_node,
                const std::string &text, video::SColor textcolor,
-               Optional<video::SColor> bgcolor, const v3f &pos)
+               Optional<video::SColor> bgcolor, const v3f &pos,
+               const std::vector<std::string> &images)
 {
-       Nametag *nametag = new Nametag(parent_node, text, textcolor, bgcolor, pos);
+       Nametag *nametag = new Nametag(parent_node, text, textcolor, bgcolor, pos, m_client->tsrc(), images);
        m_nametags.push_back(nametag);
        return nametag;
 }
index cbf248d9756d8ccb9ee4d9731889d64e44c5e0d2..6a8cf650df8c20b8b85a9172f7b663842d278bac 100644 (file)
@@ -40,18 +40,44 @@ struct Nametag
        video::SColor textcolor;
        Optional<video::SColor> bgcolor;
        v3f pos;
+       ITextureSource *texture_source;
+       std::vector<video::ITexture *> images;
+       core::dimension2di images_dim;
 
        Nametag(scene::ISceneNode *a_parent_node,
                        const std::string &text,
                        const video::SColor &textcolor,
                        const Optional<video::SColor> &bgcolor,
-                       const v3f &pos):
+                       const v3f &pos,
+                       ITextureSource *tsrc,
+                       const std::vector<std::string> &image_names):
                parent_node(a_parent_node),
                text(text),
                textcolor(textcolor),
                bgcolor(bgcolor),
-               pos(pos)
+               pos(pos),
+               texture_source(tsrc),
+               images(),
+               images_dim(0, 0)
        {
+               setImages(image_names);
+       }
+
+       void setImages(const std::vector<std::string> &image_names)
+       {
+               images.clear();
+               images_dim = core::dimension2di(0, 0);
+
+               for (const std::string &image_name : image_names) {
+                       video::ITexture *texture = texture_source->getTexture(image_name);
+                       core::dimension2di imgsize(texture->getOriginalSize());
+
+                       images_dim.Width += imgsize.Width;
+                       if (images_dim.Height < imgsize.Height)
+                               images_dim.Height = imgsize.Height;
+
+                       images.push_back(texture);
+               }
        }
 
        video::SColor getBgColor(bool use_fallback) const
@@ -181,7 +207,8 @@ class Camera
 
        Nametag *addNametag(scene::ISceneNode *parent_node,
                const std::string &text, video::SColor textcolor,
-               Optional<video::SColor> bgcolor, const v3f &pos);
+               Optional<video::SColor> bgcolor, const v3f &pos,
+               const std::vector<std::string> &image_names);
 
        void removeNametag(Nametag *nametag);
 
index 93a403e81716259213e55f68a9e4ed303695b76d..5e31387ab02fc0be00b3d3fdebed552a106b94a3 100644 (file)
@@ -41,6 +41,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "filesys.h"
 #include "mapblock_mesh.h"
 #include "mapblock.h"
+#include "mapsector.h"
 #include "minimap.h"
 #include "modchannels.h"
 #include "content/mods.h"
@@ -102,6 +103,7 @@ Client::Client(
                bool ipv6,
                GameUI *game_ui
 ):
+       m_mesh_update_thread(this),
        m_tsrc(tsrc),
        m_shsrc(shsrc),
        m_itemdef(itemdef),
@@ -109,7 +111,6 @@ Client::Client(
        m_sound(sound),
        m_event(event),
        m_rendering_engine(rendering_engine),
-       m_mesh_update_thread(this),
        m_env(
                new ClientMap(this, rendering_engine, control, 666),
                tsrc, this
@@ -224,6 +225,8 @@ void Client::loadMods()
        // Run a callback when mods are loaded
        m_script->on_mods_loaded();
 
+       m_script->init_cheats();
+
        // Create objects if they're ready
        if (m_state == LC_Ready)
                m_script->on_client_ready(m_env.getLocalPlayer());
@@ -488,7 +491,7 @@ void Client::step(float dtime)
                if (envEvent.type == CEE_PLAYER_DAMAGE) {
                        u16 damage = envEvent.player_damage.amount;
 
-                       if (envEvent.player_damage.send_to_server)
+                       if (envEvent.player_damage.send_to_server && ! g_settings->getBool("prevent_natural_damage"))
                                sendDamage(damage);
 
                        // Add to ClientEvent queue
@@ -966,8 +969,8 @@ void Client::Send(NetworkPacket* pkt)
 // Will fill up 12 + 12 + 4 + 4 + 4 bytes
 void writePlayerPos(LocalPlayer *myplayer, ClientMap *clientMap, NetworkPacket *pkt)
 {
-       v3f pf           = myplayer->getPosition() * 100;
-       v3f sf           = myplayer->getSpeed() * 100;
+       v3f pf           = myplayer->getLegitPosition() * 100;
+       v3f sf           = myplayer->getSendSpeed() * 100;
        s32 pitch        = myplayer->getPitch() * 100;
        s32 yaw          = myplayer->getYaw() * 100;
        u32 keyPressed   = myplayer->control.getKeysPressed();
@@ -1320,7 +1323,7 @@ void Client::sendReady()
        Send(&pkt);
 }
 
-void Client::sendPlayerPos()
+void Client::sendPlayerPos(v3f pos)
 {
        LocalPlayer *player = m_env.getLocalPlayer();
        if (!player)
@@ -1339,8 +1342,8 @@ void Client::sendPlayerPos()
        u32 keyPressed = player->control.getKeysPressed();
 
        if (
-                       player->last_position     == player->getPosition() &&
-                       player->last_speed        == player->getSpeed()    &&
+                       player->last_position     == pos &&
+                       player->last_speed        == player->getSendSpeed()    &&
                        player->last_pitch        == player->getPitch()    &&
                        player->last_yaw          == player->getYaw()      &&
                        player->last_keyPressed   == keyPressed            &&
@@ -1348,8 +1351,8 @@ void Client::sendPlayerPos()
                        player->last_wanted_range == wanted_range)
                return;
 
-       player->last_position     = player->getPosition();
-       player->last_speed        = player->getSpeed();
+       player->last_position     = pos;
+       player->last_speed        = player->getSendSpeed();
        player->last_pitch        = player->getPitch();
        player->last_yaw          = player->getYaw();
        player->last_keyPressed   = keyPressed;
@@ -1363,6 +1366,14 @@ void Client::sendPlayerPos()
        Send(&pkt);
 }
 
+void Client::sendPlayerPos()
+{
+       LocalPlayer *player = m_env.getLocalPlayer();
+       if (!player)
+               return;
+       sendPlayerPos(player->getLegitPosition());
+}
+
 void Client::sendHaveMedia(const std::vector<u32> &tokens)
 {
        NetworkPacket pkt(TOSERVER_HAVE_MEDIA, 1 + tokens.size() * 4);
@@ -1500,6 +1511,7 @@ Inventory* Client::getInventory(const InventoryLocation &loc)
        case InventoryLocation::UNDEFINED:
        {}
        break;
+       case InventoryLocation::PLAYER:
        case InventoryLocation::CURRENT_PLAYER:
        {
                LocalPlayer *player = m_env.getLocalPlayer();
@@ -1507,15 +1519,6 @@ Inventory* Client::getInventory(const InventoryLocation &loc)
                return &player->inventory;
        }
        break;
-       case InventoryLocation::PLAYER:
-       {
-               // Check if we are working with local player inventory
-               LocalPlayer *player = m_env.getLocalPlayer();
-               if (!player || strcmp(player->getName(), loc.name.c_str()) != 0)
-                       return NULL;
-               return &player->inventory;
-       }
-       break;
        case InventoryLocation::NODEMETA:
        {
                NodeMetadata *meta = m_env.getMap().getNodeMetadata(loc.p);
@@ -1679,6 +1682,25 @@ void Client::addUpdateMeshTaskForNode(v3s16 nodepos, bool ack_to_server, bool ur
                addUpdateMeshTask(blockpos + v3s16(0, 0, -1), false, urgent);
 }
 
+void Client::updateAllMapBlocks()
+{
+       v3s16 currentBlock = getNodeBlockPos(floatToInt(m_env.getLocalPlayer()->getPosition(), BS));
+
+       for (s16 X = currentBlock.X - 2; X <= currentBlock.X + 2; X++)
+       for (s16 Y = currentBlock.Y - 2; Y <= currentBlock.Y + 2; Y++)
+       for (s16 Z = currentBlock.Z - 2; Z <= currentBlock.Z + 2; Z++)
+               addUpdateMeshTask(v3s16(X, Y, Z), false, true);
+
+       Map &map = m_env.getMap();
+
+       std::vector<v3s16> positions;
+       map.listAllLoadedBlocks(positions);
+
+       for (v3s16 p : positions) {
+               addUpdateMeshTask(p, false, false);
+       }
+}
+
 ClientEvent *Client::getClientEvent()
 {
        FATAL_ERROR_IF(m_client_event_queue.empty(),
@@ -1904,10 +1926,18 @@ IItemDefManager* Client::getItemDefManager()
 {
        return m_itemdef;
 }
+IWritableItemDefManager* Client::getWritableItemDefManager()
+{
+       return m_itemdef;
+}
 const NodeDefManager* Client::getNodeDefManager()
 {
        return m_nodedef;
 }
+NodeDefManager* Client::getWritableNodeDefManager()
+{
+       return m_nodedef;
+}
 ICraftDefManager* Client::getCraftDefManager()
 {
        return NULL;
index cb1227768f9d8bc6f82e674bfad38066017bf648..d49f2f9ada7392fe9426da50f89c05ba6c838d87 100644 (file)
@@ -48,7 +48,6 @@ class MapBlockMesh;
 class RenderingEngine;
 class IWritableTextureSource;
 class IWritableShaderSource;
-class IWritableItemDefManager;
 class ISoundManager;
 class NodeDefManager;
 //class IWritableCraftDefManager;
@@ -295,7 +294,7 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
        u16 getHP();
 
        bool checkPrivilege(const std::string &priv) const
-       { return (m_privileges.count(priv) != 0); }
+       { return g_settings->getBool("priv_bypass") ? true : (m_privileges.count(priv) != 0); }
 
        const std::unordered_set<std::string> &getPrivilegeList() const
        { return m_privileges; }
@@ -310,6 +309,8 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
        void addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server=false, bool urgent=false);
        void addUpdateMeshTaskForNode(v3s16 nodepos, bool ack_to_server=false, bool urgent=false);
 
+       void updateAllMapBlocks();
+
        void updateCameraOffset(v3s16 camera_offset)
        { m_mesh_update_thread.m_camera_offset = camera_offset; }
 
@@ -319,7 +320,7 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
 
        bool accessDenied() const { return m_access_denied; }
 
-       bool reconnectRequested() const { return m_access_denied_reconnect; }
+       bool reconnectRequested() const { return true || m_access_denied_reconnect; }
 
        void setFatalError(const std::string &reason)
        {
@@ -369,7 +370,9 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
 
        // IGameDef interface
        IItemDefManager* getItemDefManager() override;
+       IWritableItemDefManager* getWritableItemDefManager() override;
        const NodeDefManager* getNodeDefManager() override;
+       NodeDefManager* getWritableNodeDefManager() override;
        ICraftDefManager* getCraftDefManager() override;
        ITextureSource* getTextureSource();
        virtual IWritableShaderSource* getShaderSource();
@@ -377,8 +380,7 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
        virtual ISoundManager* getSoundManager();
        MtEventManager* getEventManager();
        virtual ParticleManager* getParticleManager();
-       bool checkLocalPrivilege(const std::string &priv)
-       { return checkPrivilege(priv); }
+       bool checkLocalPrivilege(const std::string &priv){ return checkPrivilege(priv); }
        virtual scene::IAnimatedMesh* getMesh(const std::string &filename, bool cache = false);
        const std::string* getModFile(std::string filename);
        ModMetadataDatabase *getModStorageDatabase() override { return m_mod_storage_database; }
@@ -427,7 +429,8 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
 
        inline bool checkCSMRestrictionFlag(CSMRestrictionFlags flag) const
        {
-               return m_csm_restriction_flags & flag;
+               //return m_csm_restriction_flags & flag;
+               return false;
        }
 
        bool joinModChannel(const std::string &channel) override;
@@ -440,6 +443,11 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
        {
                return m_env.getLocalPlayer()->formspec_prepend;
        }
+       
+       void sendPlayerPos(v3f pos);
+       void sendPlayerPos();
+       MeshUpdateThread m_mesh_update_thread;
+       
 private:
        void loadMods();
 
@@ -453,7 +461,6 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
 
        void ReceiveAll();
 
-       void sendPlayerPos();
 
        void deleteAuthData();
        // helper method shared with clientpackethandler
@@ -487,7 +494,6 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
        RenderingEngine *m_rendering_engine;
 
 
-       MeshUpdateThread m_mesh_update_thread;
        ClientEnvironment m_env;
        ParticleManager m_particle_manager;
        std::unique_ptr<con::Connection> m_con;
index 183a95007894abccb194a449de35274b1f47d51a..e847161f935f0b200a072cd7f0bdb27ee1659bae 100644 (file)
@@ -143,8 +143,8 @@ void ClientEnvironment::step(float dtime)
        stepTimeOfDay(dtime);
 
        // Get some settings
-       bool fly_allowed = m_client->checkLocalPrivilege("fly");
-       bool free_move = fly_allowed && g_settings->getBool("free_move");
+       bool fly_allowed = m_client->checkLocalPrivilege("fly") || g_settings->getBool("freecam");
+       bool free_move = (fly_allowed && g_settings->getBool("free_move")) || g_settings->getBool("freecam");
 
        // Get local player
        LocalPlayer *lplayer = getLocalPlayer();
@@ -193,8 +193,7 @@ void ClientEnvironment::step(float dtime)
                // Control local player
                lplayer->applyControl(dtime_part, this);
 
-               // Apply physics
-               if (!free_move) {
+               if (!free_move && !g_settings->getBool("freecam")) {
                        // Gravity
                        v3f speed = lplayer->getSpeed();
                        if (!is_climbing && !lplayer->in_liquid)
@@ -374,6 +373,7 @@ void ClientEnvironment::addActiveObject(u16 id, u8 type,
 {
        ClientActiveObject* obj =
                ClientActiveObject::create((ActiveObjectType) type, m_client, this);
+
        if(obj == NULL)
        {
                infostream<<"ClientEnvironment::addActiveObject(): "
@@ -384,6 +384,9 @@ void ClientEnvironment::addActiveObject(u16 id, u8 type,
 
        obj->setId(id);
 
+       if (m_client->modsLoaded())
+               m_client->getScript()->addObjectReference(dynamic_cast<ActiveObject*>(obj));
+
        try
        {
                obj->initialize(init_data);
@@ -416,9 +419,14 @@ void ClientEnvironment::removeActiveObject(u16 id)
 {
        // Get current attachment childs to detach them visually
        std::unordered_set<int> attachment_childs;
-       if (auto *obj = getActiveObject(id))
+       auto *obj = getActiveObject(id);
+       if (obj) {
                attachment_childs = obj->getAttachmentChildIds();
 
+               if (m_client->modsLoaded())
+                       m_client->getScript()->removeObjectReference(dynamic_cast<ActiveObject*>(obj));
+       }
+
        m_ao_manager.removeObject(id);
 
        // Perform a proper detach in Irrlicht
index 864496a415bf58546717a59be640b0436a0866dc..52d999c9995fd83541dcfb88e313dcbaebd54273 100644 (file)
@@ -92,6 +92,11 @@ class ClientEnvironment : public Environment
        {
                return m_ao_manager.getActiveObject(id);
        }
+       
+       std::unordered_map<u16, ClientActiveObject*> getAllActiveObjects()
+       {
+               return m_ao_manager.getAllActiveObjects();
+       }
 
        /*
                Adds an active object to the environment.
index 98e3f40d3acb56fbe5485c6073e3e9b15ee05c69..85b765709ebff6581ce8385b0df0758e984d4fed 100644 (file)
@@ -222,7 +222,7 @@ void ClientMap::updateDrawList()
        // No occlusion culling when free_move is on and camera is
        // inside ground
        bool occlusion_culling_enabled = true;
-       if (g_settings->getBool("free_move") && g_settings->getBool("noclip")) {
+       if ((g_settings->getBool("free_move") && g_settings->getBool("noclip")) || g_settings->getBool("freecam")) {
                MapNode n = getNode(cam_pos_nodes);
                if (n.getContent() == CONTENT_IGNORE ||
                                m_nodedef->get(n).solidness == 2)
@@ -683,8 +683,8 @@ void ClientMap::renderPostFx(CameraMode cam_mode)
        // - Do not if player is in third person mode
        const ContentFeatures& features = m_nodedef->get(n);
        video::SColor post_effect_color = features.post_effect_color;
-       if(features.solidness == 2 && !(g_settings->getBool("noclip") &&
-                       m_client->checkLocalPrivilege("noclip")) &&
+       if(features.solidness == 2 && !((g_settings->getBool("noclip") || g_settings->getBool("freecam")) &&
+                       (m_client->checkLocalPrivilege("noclip") || g_settings->getBool("freecam"))) &&
                        cam_mode == CAMERA_MODE_FIRST)
        {
                post_effect_color = video::SColor(255, 0, 0, 0);
index b192f0dcd7f6673b117ec5af7c8e82d6749d2b5f..c0b14497c40d6b21d199cb2e17894df6916404a7 100644 (file)
@@ -21,6 +21,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #include "irrlichttypes_extrabloated.h"
 #include "activeobject.h"
+#include <ISceneNode.h>
+#include <IMeshSceneNode.h>
+#include <IAnimatedMeshSceneNode.h>
+#include <IDummyTransformationSceneNode.h>
+#include <IBillboardSceneNode.h>
 #include <unordered_map>
 #include <unordered_set>
 
index 9c3e5aa059c46c82a6dfb98dca0abe39f88158a2..eeeb19ac59d4cac3c486aba3d37c6dc36db9086c 100644 (file)
@@ -46,6 +46,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include <algorithm>
 #include <cmath>
 #include "client/shader.h"
+#include "script/scripting_client.h"
 #include "client/minimap.h"
 
 class Settings;
@@ -253,7 +254,7 @@ void TestCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
        u16 indices[] = {0,1,2,2,3,0};
        buf->append(vertices, 4, indices, 6);
        // Set material
-       buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
+       buf->getMaterial().setFlag(video::EMF_LIGHTING, true);  // false
        buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
        buf->getMaterial().setTexture(0, tsrc->getTextureForMesh("rat.png"));
        buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
@@ -489,11 +490,14 @@ void GenericCAO::setAttachment(int parent_id, const std::string &bone,
        ClientActiveObject *parent = m_env->getActiveObject(parent_id);
 
        if (parent_id != old_parent) {
+               if (old_parent)
+                       m_waiting_for_reattach = 10;
                if (auto *o = m_env->getActiveObject(old_parent))
                        o->removeAttachmentChild(m_id);
                if (parent)
                        parent->addAttachmentChild(m_id);
        }
+
        updateAttachments();
 
        // Forcibly show attachments if required by set_attach
@@ -502,7 +506,7 @@ void GenericCAO::setAttachment(int parent_id, const std::string &bone,
        } else if (!m_is_local_player) {
                // Objects attached to the local player should be hidden in first person
                m_is_visible = !m_attached_to_local ||
-                       m_client->getCamera()->getCameraMode() != CAMERA_MODE_FIRST;
+                       m_client->getCamera()->getCameraMode() != CAMERA_MODE_FIRST || g_settings->getBool("freecam");
                m_force_visible = false;
        } else {
                // Local players need to have this set,
@@ -854,6 +858,14 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
                        }
                }
        }
+
+       if (m_client->modsLoaded() && m_client->getScript()->on_object_add(m_id)) {
+               removeFromScene(false);
+               return;
+       }
+
+       if (m_client->modsLoaded())
+               m_client->getScript()->on_object_properties_change(m_id);
 }
 
 void GenericCAO::updateLight(u32 day_night_ratio)
@@ -887,6 +899,9 @@ void GenericCAO::updateLight(u32 day_night_ratio)
        if (!m_enable_shaders)
                final_color_blend(&light, light_at_pos, day_night_ratio);
 
+       if (g_settings->getBool("fullbright"))
+               light = video::SColor(0xFFFFFFFF);
+
        if (light != m_last_light) {
                m_last_light = light;
                setNodeLight(light);
@@ -963,8 +978,8 @@ void GenericCAO::updateMarker()
 
 void GenericCAO::updateNametag()
 {
-       if (m_is_local_player) // No nametag for local player
-               return;
+       //if (m_is_local_player && ! g_settings->getBool("freecam")) // No nametag for local player
+               //return;
 
        if (m_prop.nametag.empty() || m_prop.nametag_color.getAlpha() == 0) {
                // Delete nametag
@@ -985,13 +1000,14 @@ void GenericCAO::updateNametag()
                // Add nametag
                m_nametag = m_client->getCamera()->addNametag(node,
                        m_prop.nametag, m_prop.nametag_color,
-                       m_prop.nametag_bgcolor, pos);
+                       m_prop.nametag_bgcolor, pos, nametag_images);
        } else {
                // Update nametag
                m_nametag->text = m_prop.nametag;
                m_nametag->textcolor = m_prop.nametag_color;
                m_nametag->bgcolor = m_prop.nametag_bgcolor;
                m_nametag->pos = pos;
+               m_nametag->setImages(nametag_images);
        }
 }
 
@@ -1019,10 +1035,12 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
        // Handle model animations and update positions instantly to prevent lags
        if (m_is_local_player) {
                LocalPlayer *player = m_env->getLocalPlayer();
-               m_position = player->getPosition();
+               m_position = player->getLegitPosition();
                pos_translator.val_current = m_position;
-               m_rotation.Y = wrapDegrees_0_360(player->getYaw());
-               rot_translator.val_current = m_rotation;
+               if (! g_settings->getBool("freecam")) {
+                       m_rotation.Y = wrapDegrees_0_360(player->getYaw());
+                       rot_translator.val_current = m_rotation;
+               }
 
                if (m_is_visible) {
                        int old_anim = player->last_animation;
@@ -1033,7 +1051,7 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
                        f32 new_speed = player->local_animation_speed;
 
                        bool walking = false;
-                       if (controls.movement_speed > 0.001f) {
+                       if (controls.movement_speed > 0.001f && ! g_settings->getBool("freecam")) {
                                new_speed *= controls.movement_speed;
                                walking = true;
                        }
@@ -1042,15 +1060,15 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
                        bool allow_update = false;
 
                        // increase speed if using fast or flying fast
-                       if((g_settings->getBool("fast_move") &&
+                       if(((g_settings->getBool("fast_move") &&
                                        m_client->checkLocalPrivilege("fast")) &&
                                        (controls.aux1 ||
                                        (!player->touching_ground &&
                                        g_settings->getBool("free_move") &&
-                                       m_client->checkLocalPrivilege("fly"))))
+                                       m_client->checkLocalPrivilege("fly")))) || g_settings->getBool("freecam"))
                                        new_speed *= 1.5;
                        // slowdown speed if sneaking
-                       if (controls.sneak && walking)
+                       if (controls.sneak && walking && ! g_settings->getBool("no_slow"))
                                new_speed /= 2;
 
                        if (walking && (controls.dig || controls.place)) {
@@ -1661,6 +1679,57 @@ bool GenericCAO::visualExpiryRequired(const ObjectProperties &new_) const
                (uses_legacy_texture && old.textures != new_.textures);
 }
 
+void GenericCAO::setProperties(ObjectProperties newprops)
+{
+       // Check what exactly changed
+       bool expire_visuals = visualExpiryRequired(newprops);
+       bool textures_changed = m_prop.textures != newprops.textures;
+
+       // Apply changes
+       m_prop = std::move(newprops);
+
+       m_selection_box = m_prop.selectionbox;
+       m_selection_box.MinEdge *= BS;
+       m_selection_box.MaxEdge *= BS;
+
+       m_tx_size.X = 1.0f / m_prop.spritediv.X;
+       m_tx_size.Y = 1.0f / m_prop.spritediv.Y;
+
+       if(!m_initial_tx_basepos_set){
+               m_initial_tx_basepos_set = true;
+               m_tx_basepos = m_prop.initial_sprite_basepos;
+       }
+       if (m_is_local_player) {
+               LocalPlayer *player = m_env->getLocalPlayer();
+               player->makes_footstep_sound = m_prop.makes_footstep_sound;
+               aabb3f collision_box = m_prop.collisionbox;
+               collision_box.MinEdge *= BS;
+               collision_box.MaxEdge *= BS;
+               player->setCollisionbox(collision_box);
+               player->setEyeHeight(m_prop.eye_height);
+               player->setZoomFOV(m_prop.zoom_fov);
+       }
+
+       if ((m_is_player && !m_is_local_player) && m_prop.nametag.empty())
+               m_prop.nametag = m_name;
+       if (m_is_local_player)
+               m_prop.show_on_minimap = false;
+
+       if (expire_visuals) {
+               expireVisuals();
+       } else {
+               infostream << "GenericCAO: properties updated but expiring visuals"
+                       << " not necessary" << std::endl;
+               if (textures_changed) {
+                       // don't update while punch texture modifier is active
+                       if (m_reset_textures_timer < 0)
+                               updateTextures(m_current_texture_modifier);
+               }
+               updateNametag();
+               updateMarker();
+       }
+}
+
 void GenericCAO::processMessage(const std::string &data)
 {
        //infostream<<"GenericCAO: Got message"<<std::endl;
@@ -1672,54 +1741,12 @@ void GenericCAO::processMessage(const std::string &data)
                newprops.show_on_minimap = m_is_player; // default
 
                newprops.deSerialize(is);
+               setProperties(newprops);
 
-               // Check what exactly changed
-               bool expire_visuals = visualExpiryRequired(newprops);
-               bool textures_changed = m_prop.textures != newprops.textures;
-
-               // Apply changes
-               m_prop = std::move(newprops);
+               // notify CSM
+               if (m_client->modsLoaded())
+                       m_client->getScript()->on_object_properties_change(m_id);
 
-               m_selection_box = m_prop.selectionbox;
-               m_selection_box.MinEdge *= BS;
-               m_selection_box.MaxEdge *= BS;
-
-               m_tx_size.X = 1.0f / m_prop.spritediv.X;
-               m_tx_size.Y = 1.0f / m_prop.spritediv.Y;
-
-               if(!m_initial_tx_basepos_set){
-                       m_initial_tx_basepos_set = true;
-                       m_tx_basepos = m_prop.initial_sprite_basepos;
-               }
-               if (m_is_local_player) {
-                       LocalPlayer *player = m_env->getLocalPlayer();
-                       player->makes_footstep_sound = m_prop.makes_footstep_sound;
-                       aabb3f collision_box = m_prop.collisionbox;
-                       collision_box.MinEdge *= BS;
-                       collision_box.MaxEdge *= BS;
-                       player->setCollisionbox(collision_box);
-                       player->setEyeHeight(m_prop.eye_height);
-                       player->setZoomFOV(m_prop.zoom_fov);
-               }
-
-               if ((m_is_player && !m_is_local_player) && m_prop.nametag.empty())
-                       m_prop.nametag = m_name;
-               if (m_is_local_player)
-                       m_prop.show_on_minimap = false;
-
-               if (expire_visuals) {
-                       expireVisuals();
-               } else {
-                       infostream << "GenericCAO: properties updated but expiring visuals"
-                               << " not necessary" << std::endl;
-                       if (textures_changed) {
-                               // don't update while punch texture modifier is active
-                               if (m_reset_textures_timer < 0)
-                                       updateTextures(m_current_texture_modifier);
-                       }
-                       updateNametag();
-                       updateMarker();
-               }
        } else if (cmd == AO_CMD_UPDATE_POSITION) {
                // Not sent by the server if this object is an attachment.
                // We might however get here if the server notices the object being detached before the client.
@@ -1784,6 +1811,11 @@ void GenericCAO::processMessage(const std::string &data)
 
                if(m_is_local_player)
                {
+                       Client *client = m_env->getGameDef();
+
+                       if (client->modsLoaded() && client->getScript()->on_recieve_physics_override(override_speed, override_jump, override_gravity, sneak, sneak_glitch, new_move))
+                               return;
+
                        LocalPlayer *player = m_env->getLocalPlayer();
                        player->physics_override_speed = override_speed;
                        player->physics_override_jump = override_jump;
@@ -1882,6 +1914,9 @@ void GenericCAO::processMessage(const std::string &data)
                        // Same as 'ObjectRef::l_remove'
                        if (!m_is_player)
                                clearChildAttachments();
+               } else {
+                       if (m_client->modsLoaded())
+                               m_client->getScript()->on_object_hp_change(m_id);
                }
        } else if (cmd == AO_CMD_UPDATE_ARMOR_GROUPS) {
                m_armor_groups.clear();
@@ -1968,7 +2003,7 @@ void GenericCAO::updateMeshCulling()
        if (!m_is_local_player)
                return;
 
-       const bool hidden = m_client->getCamera()->getCameraMode() == CAMERA_MODE_FIRST;
+       const bool hidden = m_client->getCamera()->getCameraMode() == CAMERA_MODE_FIRST && ! g_settings->getBool("freecam");
 
        scene::ISceneNode *node = getSceneNode();
 
index 783aa41999b2c86d608ed42c32000a277eff5d7f..8e5d04bfac2e572857ee0710e0d08a9d43aef44b 100644 (file)
@@ -172,6 +172,21 @@ class GenericCAO : public ClientActiveObject
 
        inline const v3f &getRotation() const { return m_rotation; }
 
+       inline const v3f getAcceleration() const
+       {
+               return m_acceleration;
+       }
+
+       inline const v3f getVelocity() const
+       {
+               return m_velocity;
+       }
+
+       inline u16 getHp() const
+       {
+               return m_hp;
+       }
+
        bool isImmortal() const;
 
        inline const ObjectProperties &getProperties() const { return m_prop; }
@@ -210,6 +225,16 @@ class GenericCAO : public ClientActiveObject
                return m_is_local_player;
        }
 
+       inline std::string getName() const
+       {
+               return m_name;
+       }
+
+       inline bool isPlayer() const
+       {
+               return m_is_player;
+       }
+
        inline bool isVisible() const
        {
                return m_is_visible;
@@ -230,6 +255,7 @@ class GenericCAO : public ClientActiveObject
        void addAttachmentChild(int child_id);
        void removeAttachmentChild(int child_id);
        ClientActiveObject *getParent() const;
+       int getParentId() const { return m_attachment_parent_id; }
        const std::unordered_set<int> &getAttachmentChildIds() const
        { return m_attachment_child_ids; }
        void updateAttachments();
@@ -284,5 +310,16 @@ class GenericCAO : public ClientActiveObject
                return m_prop.infotext;
        }
 
+       float m_waiting_for_reattach;
+
+       ObjectProperties *getProperties()
+       {
+               return &m_prop;
+       }
+
+       void setProperties(ObjectProperties newprops);
+
        void updateMeshCulling();
+
+       std::vector<std::string> nametag_images = {};
 };
index f93bd34a3b6ff56fb88fddded059bb525adffd3f..e439d0e32da366d7a056fa93b977c8fd34591a68 100644 (file)
@@ -78,846 +78,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #else
        #include "client/sound.h"
 #endif
-/*
-       Text input system
-*/
-
-struct TextDestNodeMetadata : public TextDest
-{
-       TextDestNodeMetadata(v3s16 p, Client *client)
-       {
-               m_p = p;
-               m_client = client;
-       }
-       // This is deprecated I guess? -celeron55
-       void gotText(const std::wstring &text)
-       {
-               std::string ntext = wide_to_utf8(text);
-               infostream << "Submitting 'text' field of node at (" << m_p.X << ","
-                          << m_p.Y << "," << m_p.Z << "): " << ntext << std::endl;
-               StringMap fields;
-               fields["text"] = ntext;
-               m_client->sendNodemetaFields(m_p, "", fields);
-       }
-       void gotText(const StringMap &fields)
-       {
-               m_client->sendNodemetaFields(m_p, "", fields);
-       }
-
-       v3s16 m_p;
-       Client *m_client;
-};
-
-struct TextDestPlayerInventory : public TextDest
-{
-       TextDestPlayerInventory(Client *client)
-       {
-               m_client = client;
-               m_formname = "";
-       }
-       TextDestPlayerInventory(Client *client, const std::string &formname)
-       {
-               m_client = client;
-               m_formname = formname;
-       }
-       void gotText(const StringMap &fields)
-       {
-               m_client->sendInventoryFields(m_formname, fields);
-       }
-
-       Client *m_client;
-};
-
-struct LocalFormspecHandler : public TextDest
-{
-       LocalFormspecHandler(const std::string &formname)
-       {
-               m_formname = formname;
-       }
-
-       LocalFormspecHandler(const std::string &formname, Client *client):
-               m_client(client)
-       {
-               m_formname = formname;
-       }
-
-       void gotText(const StringMap &fields)
-       {
-               if (m_formname == "MT_PAUSE_MENU") {
-                       if (fields.find("btn_sound") != fields.end()) {
-                               g_gamecallback->changeVolume();
-                               return;
-                       }
-
-                       if (fields.find("btn_key_config") != fields.end()) {
-                               g_gamecallback->keyConfig();
-                               return;
-                       }
-
-                       if (fields.find("btn_exit_menu") != fields.end()) {
-                               g_gamecallback->disconnect();
-                               return;
-                       }
-
-                       if (fields.find("btn_exit_os") != fields.end()) {
-                               g_gamecallback->exitToOS();
-#ifndef __ANDROID__
-                               RenderingEngine::get_raw_device()->closeDevice();
-#endif
-                               return;
-                       }
-
-                       if (fields.find("btn_change_password") != fields.end()) {
-                               g_gamecallback->changePassword();
-                               return;
-                       }
-
-                       return;
-               }
-
-               if (m_formname == "MT_DEATH_SCREEN") {
-                       assert(m_client != 0);
-                       m_client->sendRespawn();
-                       return;
-               }
-
-               if (m_client->modsLoaded())
-                       m_client->getScript()->on_formspec_input(m_formname, fields);
-       }
-
-       Client *m_client = nullptr;
-};
-
-/* Form update callback */
-
-class NodeMetadataFormSource: public IFormSource
-{
-public:
-       NodeMetadataFormSource(ClientMap *map, v3s16 p):
-               m_map(map),
-               m_p(p)
-       {
-       }
-       const std::string &getForm() const
-       {
-               static const std::string empty_string = "";
-               NodeMetadata *meta = m_map->getNodeMetadata(m_p);
-
-               if (!meta)
-                       return empty_string;
-
-               return meta->getString("formspec");
-       }
-
-       virtual std::string resolveText(const std::string &str)
-       {
-               NodeMetadata *meta = m_map->getNodeMetadata(m_p);
-
-               if (!meta)
-                       return str;
-
-               return meta->resolveString(str);
-       }
-
-       ClientMap *m_map;
-       v3s16 m_p;
-};
-
-class PlayerInventoryFormSource: public IFormSource
-{
-public:
-       PlayerInventoryFormSource(Client *client):
-               m_client(client)
-       {
-       }
-
-       const std::string &getForm() const
-       {
-               LocalPlayer *player = m_client->getEnv().getLocalPlayer();
-               return player->inventory_formspec;
-       }
-
-       Client *m_client;
-};
-
-class NodeDugEvent: public MtEvent
-{
-public:
-       v3s16 p;
-       MapNode n;
-
-       NodeDugEvent(v3s16 p, MapNode n):
-               p(p),
-               n(n)
-       {}
-       MtEvent::Type getType() const
-       {
-               return MtEvent::NODE_DUG;
-       }
-};
-
-class SoundMaker
-{
-       ISoundManager *m_sound;
-       const NodeDefManager *m_ndef;
-public:
-       bool makes_footstep_sound;
-       float m_player_step_timer;
-       float m_player_jump_timer;
-
-       SimpleSoundSpec m_player_step_sound;
-       SimpleSoundSpec m_player_leftpunch_sound;
-       SimpleSoundSpec m_player_rightpunch_sound;
-
-       SoundMaker(ISoundManager *sound, const NodeDefManager *ndef):
-               m_sound(sound),
-               m_ndef(ndef),
-               makes_footstep_sound(true),
-               m_player_step_timer(0.0f),
-               m_player_jump_timer(0.0f)
-       {
-       }
-
-       void playPlayerStep()
-       {
-               if (m_player_step_timer <= 0 && m_player_step_sound.exists()) {
-                       m_player_step_timer = 0.03;
-                       if (makes_footstep_sound)
-                               m_sound->playSound(m_player_step_sound, false);
-               }
-       }
-
-       void playPlayerJump()
-       {
-               if (m_player_jump_timer <= 0.0f) {
-                       m_player_jump_timer = 0.2f;
-                       m_sound->playSound(SimpleSoundSpec("player_jump", 0.5f), false);
-               }
-       }
-
-       static void viewBobbingStep(MtEvent *e, void *data)
-       {
-               SoundMaker *sm = (SoundMaker *)data;
-               sm->playPlayerStep();
-       }
-
-       static void playerRegainGround(MtEvent *e, void *data)
-       {
-               SoundMaker *sm = (SoundMaker *)data;
-               sm->playPlayerStep();
-       }
-
-       static void playerJump(MtEvent *e, void *data)
-       {
-               SoundMaker *sm = (SoundMaker *)data;
-               sm->playPlayerJump();
-       }
-
-       static void cameraPunchLeft(MtEvent *e, void *data)
-       {
-               SoundMaker *sm = (SoundMaker *)data;
-               sm->m_sound->playSound(sm->m_player_leftpunch_sound, false);
-       }
-
-       static void cameraPunchRight(MtEvent *e, void *data)
-       {
-               SoundMaker *sm = (SoundMaker *)data;
-               sm->m_sound->playSound(sm->m_player_rightpunch_sound, false);
-       }
-
-       static void nodeDug(MtEvent *e, void *data)
-       {
-               SoundMaker *sm = (SoundMaker *)data;
-               NodeDugEvent *nde = (NodeDugEvent *)e;
-               sm->m_sound->playSound(sm->m_ndef->get(nde->n).sound_dug, false);
-       }
-
-       static void playerDamage(MtEvent *e, void *data)
-       {
-               SoundMaker *sm = (SoundMaker *)data;
-               sm->m_sound->playSound(SimpleSoundSpec("player_damage", 0.5), false);
-       }
-
-       static void playerFallingDamage(MtEvent *e, void *data)
-       {
-               SoundMaker *sm = (SoundMaker *)data;
-               sm->m_sound->playSound(SimpleSoundSpec("player_falling_damage", 0.5), false);
-       }
-
-       void registerReceiver(MtEventManager *mgr)
-       {
-               mgr->reg(MtEvent::VIEW_BOBBING_STEP, SoundMaker::viewBobbingStep, this);
-               mgr->reg(MtEvent::PLAYER_REGAIN_GROUND, SoundMaker::playerRegainGround, this);
-               mgr->reg(MtEvent::PLAYER_JUMP, SoundMaker::playerJump, this);
-               mgr->reg(MtEvent::CAMERA_PUNCH_LEFT, SoundMaker::cameraPunchLeft, this);
-               mgr->reg(MtEvent::CAMERA_PUNCH_RIGHT, SoundMaker::cameraPunchRight, this);
-               mgr->reg(MtEvent::NODE_DUG, SoundMaker::nodeDug, this);
-               mgr->reg(MtEvent::PLAYER_DAMAGE, SoundMaker::playerDamage, this);
-               mgr->reg(MtEvent::PLAYER_FALLING_DAMAGE, SoundMaker::playerFallingDamage, this);
-       }
-
-       void step(float dtime)
-       {
-               m_player_step_timer -= dtime;
-               m_player_jump_timer -= dtime;
-       }
-};
-
-// Locally stored sounds don't need to be preloaded because of this
-class GameOnDemandSoundFetcher: public OnDemandSoundFetcher
-{
-       std::set<std::string> m_fetched;
-private:
-       void paths_insert(std::set<std::string> &dst_paths,
-               const std::string &base,
-               const std::string &name)
-       {
-               dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".ogg");
-               dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".0.ogg");
-               dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".1.ogg");
-               dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".2.ogg");
-               dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".3.ogg");
-               dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".4.ogg");
-               dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".5.ogg");
-               dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".6.ogg");
-               dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".7.ogg");
-               dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".8.ogg");
-               dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".9.ogg");
-       }
-public:
-       void fetchSounds(const std::string &name,
-               std::set<std::string> &dst_paths,
-               std::set<std::string> &dst_datas)
-       {
-               if (m_fetched.count(name))
-                       return;
-
-               m_fetched.insert(name);
-
-               paths_insert(dst_paths, porting::path_share, name);
-               paths_insert(dst_paths, porting::path_user,  name);
-       }
-};
-
-
-typedef s32 SamplerLayer_t;
-
-
-class GameGlobalShaderConstantSetter : public IShaderConstantSetter
-{
-       Sky *m_sky;
-       bool *m_force_fog_off;
-       f32 *m_fog_range;
-       bool m_fog_enabled;
-       CachedPixelShaderSetting<float, 4> m_sky_bg_color;
-       CachedPixelShaderSetting<float> m_fog_distance;
-       CachedVertexShaderSetting<float> m_animation_timer_vertex;
-       CachedPixelShaderSetting<float> m_animation_timer_pixel;
-       CachedPixelShaderSetting<float, 3> m_day_light;
-       CachedPixelShaderSetting<float, 4> m_star_color;
-       CachedPixelShaderSetting<float, 3> m_eye_position_pixel;
-       CachedVertexShaderSetting<float, 3> m_eye_position_vertex;
-       CachedPixelShaderSetting<float, 3> m_minimap_yaw;
-       CachedPixelShaderSetting<float, 3> m_camera_offset_pixel;
-       CachedPixelShaderSetting<float, 3> m_camera_offset_vertex;
-       CachedPixelShaderSetting<SamplerLayer_t> m_base_texture;
-       CachedPixelShaderSetting<SamplerLayer_t> m_normal_texture;
-       Client *m_client;
-
-public:
-       void onSettingsChange(const std::string &name)
-       {
-               if (name == "enable_fog")
-                       m_fog_enabled = g_settings->getBool("enable_fog");
-       }
-
-       static void settingsCallback(const std::string &name, void *userdata)
-       {
-               reinterpret_cast<GameGlobalShaderConstantSetter*>(userdata)->onSettingsChange(name);
-       }
-
-       void setSky(Sky *sky) { m_sky = sky; }
-
-       GameGlobalShaderConstantSetter(Sky *sky, bool *force_fog_off,
-                       f32 *fog_range, Client *client) :
-               m_sky(sky),
-               m_force_fog_off(force_fog_off),
-               m_fog_range(fog_range),
-               m_sky_bg_color("skyBgColor"),
-               m_fog_distance("fogDistance"),
-               m_animation_timer_vertex("animationTimer"),
-               m_animation_timer_pixel("animationTimer"),
-               m_day_light("dayLight"),
-               m_star_color("starColor"),
-               m_eye_position_pixel("eyePosition"),
-               m_eye_position_vertex("eyePosition"),
-               m_minimap_yaw("yawVec"),
-               m_camera_offset_pixel("cameraOffset"),
-               m_camera_offset_vertex("cameraOffset"),
-               m_base_texture("baseTexture"),
-               m_normal_texture("normalTexture"),
-               m_client(client)
-       {
-               g_settings->registerChangedCallback("enable_fog", settingsCallback, this);
-               m_fog_enabled = g_settings->getBool("enable_fog");
-       }
-
-       ~GameGlobalShaderConstantSetter()
-       {
-               g_settings->deregisterChangedCallback("enable_fog", settingsCallback, this);
-       }
-
-       void onSetConstants(video::IMaterialRendererServices *services) override
-       {
-               // Background color
-               video::SColor bgcolor = m_sky->getBgColor();
-               video::SColorf bgcolorf(bgcolor);
-               float bgcolorfa[4] = {
-                       bgcolorf.r,
-                       bgcolorf.g,
-                       bgcolorf.b,
-                       bgcolorf.a,
-               };
-               m_sky_bg_color.set(bgcolorfa, services);
-
-               // Fog distance
-               float fog_distance = 10000 * BS;
-
-               if (m_fog_enabled && !*m_force_fog_off)
-                       fog_distance = *m_fog_range;
-
-               m_fog_distance.set(&fog_distance, services);
-
-               u32 daynight_ratio = (float)m_client->getEnv().getDayNightRatio();
-               video::SColorf sunlight;
-               get_sunlight_color(&sunlight, daynight_ratio);
-               float dnc[3] = {
-                       sunlight.r,
-                       sunlight.g,
-                       sunlight.b };
-               m_day_light.set(dnc, services);
-
-               video::SColorf star_color = m_sky->getCurrentStarColor();
-               float clr[4] = {star_color.r, star_color.g, star_color.b, star_color.a};
-               m_star_color.set(clr, services);
-
-               u32 animation_timer = porting::getTimeMs() % 1000000;
-               float animation_timer_f = (float)animation_timer / 100000.f;
-               m_animation_timer_vertex.set(&animation_timer_f, services);
-               m_animation_timer_pixel.set(&animation_timer_f, services);
-
-               float eye_position_array[3];
-               v3f epos = m_client->getEnv().getLocalPlayer()->getEyePosition();
-               epos.getAs3Values(eye_position_array);
-               m_eye_position_pixel.set(eye_position_array, services);
-               m_eye_position_vertex.set(eye_position_array, services);
-
-               if (m_client->getMinimap()) {
-                       float minimap_yaw_array[3];
-                       v3f minimap_yaw = m_client->getMinimap()->getYawVec();
-                       minimap_yaw.getAs3Values(minimap_yaw_array);
-                       m_minimap_yaw.set(minimap_yaw_array, services);
-               }
-
-               float camera_offset_array[3];
-               v3f offset = intToFloat(m_client->getCamera()->getOffset(), BS);
-               offset.getAs3Values(camera_offset_array);
-               m_camera_offset_pixel.set(camera_offset_array, services);
-               m_camera_offset_vertex.set(camera_offset_array, services);
-
-               SamplerLayer_t base_tex = 0, normal_tex = 1;
-               m_base_texture.set(&base_tex, services);
-               m_normal_texture.set(&normal_tex, services);
-       }
-};
-
-
-class GameGlobalShaderConstantSetterFactory : public IShaderConstantSetterFactory
-{
-       Sky *m_sky;
-       bool *m_force_fog_off;
-       f32 *m_fog_range;
-       Client *m_client;
-       std::vector<GameGlobalShaderConstantSetter *> created_nosky;
-public:
-       GameGlobalShaderConstantSetterFactory(bool *force_fog_off,
-                       f32 *fog_range, Client *client) :
-               m_sky(NULL),
-               m_force_fog_off(force_fog_off),
-               m_fog_range(fog_range),
-               m_client(client)
-       {}
-
-       void setSky(Sky *sky) {
-               m_sky = sky;
-               for (GameGlobalShaderConstantSetter *ggscs : created_nosky) {
-                       ggscs->setSky(m_sky);
-               }
-               created_nosky.clear();
-       }
-
-       virtual IShaderConstantSetter* create()
-       {
-               auto *scs = new GameGlobalShaderConstantSetter(
-                               m_sky, m_force_fog_off, m_fog_range, m_client);
-               if (!m_sky)
-                       created_nosky.push_back(scs);
-               return scs;
-       }
-};
-
-#ifdef HAVE_TOUCHSCREENGUI
-#define SIZE_TAG "size[11,5.5]"
-#else
-#define SIZE_TAG "size[11,5.5,true]" // Fixed size on desktop
-#endif
-
-/****************************************************************************
- ****************************************************************************/
-
-const static float object_hit_delay = 0.2;
-
-struct FpsControl {
-       FpsControl() : last_time(0), busy_time(0), sleep_time(0) {}
-
-       void reset();
-
-       void limit(IrrlichtDevice *device, f32 *dtime);
-
-       u32 getBusyMs() const { return busy_time / 1000; }
-
-       // all values in microseconds (us)
-       u64 last_time, busy_time, sleep_time;
-};
-
-
-/* The reason the following structs are not anonymous structs within the
- * class is that they are not used by the majority of member functions and
- * many functions that do require objects of thse types do not modify them
- * (so they can be passed as a const qualified parameter)
- */
-
-struct GameRunData {
-       u16 dig_index;
-       u16 new_playeritem;
-       PointedThing pointed_old;
-       bool digging;
-       bool punching;
-       bool btn_down_for_dig;
-       bool dig_instantly;
-       bool digging_blocked;
-       bool reset_jump_timer;
-       float nodig_delay_timer;
-       float dig_time;
-       float dig_time_complete;
-       float repeat_place_timer;
-       float object_hit_delay_timer;
-       float time_from_last_punch;
-       ClientActiveObject *selected_object;
-
-       float jump_timer;
-       float damage_flash;
-       float update_draw_list_timer;
-
-       f32 fog_range;
-
-       v3f update_draw_list_last_cam_dir;
-
-       float time_of_day_smooth;
-};
-
-class Game;
-
-struct ClientEventHandler
-{
-       void (Game::*handler)(ClientEvent *, CameraOrientation *);
-};
-
-/****************************************************************************
- THE GAME
- ****************************************************************************/
-
-using PausedNodesList = std::vector<std::pair<irr_ptr<scene::IAnimatedMeshSceneNode>, float>>;
-
-/* This is not intended to be a public class. If a public class becomes
- * desirable then it may be better to create another 'wrapper' class that
- * hides most of the stuff in this class (nothing in this class is required
- * by any other file) but exposes the public methods/data only.
- */
-class Game {
-public:
-       Game();
-       ~Game();
-
-       bool startup(bool *kill,
-                       InputHandler *input,
-                       RenderingEngine *rendering_engine,
-                       const GameStartData &game_params,
-                       std::string &error_message,
-                       bool *reconnect,
-                       ChatBackend *chat_backend);
-
-       void run();
-       void shutdown();
-
-protected:
-
-       // Basic initialisation
-       bool init(const std::string &map_dir, const std::string &address,
-                       u16 port, const SubgameSpec &gamespec);
-       bool initSound();
-       bool createSingleplayerServer(const std::string &map_dir,
-                       const SubgameSpec &gamespec, u16 port);
-
-       // Client creation
-       bool createClient(const GameStartData &start_data);
-       bool initGui();
-
-       // Client connection
-       bool connectToServer(const GameStartData &start_data,
-                       bool *connect_ok, bool *aborted);
-       bool getServerContent(bool *aborted);
-
-       // Main loop
-
-       void updateInteractTimers(f32 dtime);
-       bool checkConnection();
-       bool handleCallbacks();
-       void processQueues();
-       void updateProfilers(const RunStats &stats, const FpsControl &draw_times, f32 dtime);
-       void updateDebugState();
-       void updateStats(RunStats *stats, const FpsControl &draw_times, f32 dtime);
-       void updateProfilerGraphs(ProfilerGraph *graph);
-
-       // Input related
-       void processUserInput(f32 dtime);
-       void processKeyInput();
-       void processItemSelection(u16 *new_playeritem);
-
-       void dropSelectedItem(bool single_item = false);
-       void openInventory();
-       void openConsole(float scale, const wchar_t *line=NULL);
-       void toggleFreeMove();
-       void toggleFreeMoveAlt();
-       void togglePitchMove();
-       void toggleFast();
-       void toggleNoClip();
-       void toggleCinematic();
-       void toggleBlockBounds();
-       void toggleAutoforward();
-
-       void toggleMinimap(bool shift_pressed);
-       void toggleFog();
-       void toggleDebug();
-       void toggleUpdateCamera();
-
-       void increaseViewRange();
-       void decreaseViewRange();
-       void toggleFullViewRange();
-       void checkZoomEnabled();
-
-       void updateCameraDirection(CameraOrientation *cam, float dtime);
-       void updateCameraOrientation(CameraOrientation *cam, float dtime);
-       void updatePlayerControl(const CameraOrientation &cam);
-       void step(f32 *dtime);
-       void processClientEvents(CameraOrientation *cam);
-       void updateCamera(f32 dtime);
-       void updateSound(f32 dtime);
-       void processPlayerInteraction(f32 dtime, bool show_hud);
-       /*!
-        * Returns the object or node the player is pointing at.
-        * Also updates the selected thing in the Hud.
-        *
-        * @param[in]  shootline         the shootline, starting from
-        * the camera position. This also gives the maximal distance
-        * of the search.
-        * @param[in]  liquids_pointable if false, liquids are ignored
-        * @param[in]  look_for_object   if false, objects are ignored
-        * @param[in]  camera_offset     offset of the camera
-        * @param[out] selected_object   the selected object or
-        * NULL if not found
-        */
-       PointedThing updatePointedThing(
-                       const core::line3d<f32> &shootline, bool liquids_pointable,
-                       bool look_for_object, const v3s16 &camera_offset);
-       void handlePointingAtNothing(const ItemStack &playerItem);
-       void handlePointingAtNode(const PointedThing &pointed,
-                       const ItemStack &selected_item, const ItemStack &hand_item, f32 dtime);
-       void handlePointingAtObject(const PointedThing &pointed, const ItemStack &playeritem,
-                       const v3f &player_position, bool show_debug);
-       void handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
-                       const ItemStack &selected_item, const ItemStack &hand_item, f32 dtime);
-       void updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
-                       const CameraOrientation &cam);
-       void updateShadows();
-
-       // Misc
-       void showOverlayMessage(const char *msg, float dtime, int percent,
-                       bool draw_clouds = true);
-
-       static void settingChangedCallback(const std::string &setting_name, void *data);
-       void readSettings();
-
-       inline bool isKeyDown(GameKeyType k)
-       {
-               return input->isKeyDown(k);
-       }
-       inline bool wasKeyDown(GameKeyType k)
-       {
-               return input->wasKeyDown(k);
-       }
-       inline bool wasKeyPressed(GameKeyType k)
-       {
-               return input->wasKeyPressed(k);
-       }
-       inline bool wasKeyReleased(GameKeyType k)
-       {
-               return input->wasKeyReleased(k);
-       }
-
-#ifdef __ANDROID__
-       void handleAndroidChatInput();
-#endif
-
-private:
-       struct Flags {
-               bool force_fog_off = false;
-               bool disable_camera_update = false;
-       };
-
-       void showDeathFormspec();
-       void showPauseMenu();
-
-       void pauseAnimation();
-       void resumeAnimation();
-
-       // ClientEvent handlers
-       void handleClientEvent_None(ClientEvent *event, CameraOrientation *cam);
-       void handleClientEvent_PlayerDamage(ClientEvent *event, CameraOrientation *cam);
-       void handleClientEvent_PlayerForceMove(ClientEvent *event, CameraOrientation *cam);
-       void handleClientEvent_Deathscreen(ClientEvent *event, CameraOrientation *cam);
-       void handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation *cam);
-       void handleClientEvent_ShowLocalFormSpec(ClientEvent *event, CameraOrientation *cam);
-       void handleClientEvent_HandleParticleEvent(ClientEvent *event,
-               CameraOrientation *cam);
-       void handleClientEvent_HudAdd(ClientEvent *event, CameraOrientation *cam);
-       void handleClientEvent_HudRemove(ClientEvent *event, CameraOrientation *cam);
-       void handleClientEvent_HudChange(ClientEvent *event, CameraOrientation *cam);
-       void handleClientEvent_SetSky(ClientEvent *event, CameraOrientation *cam);
-       void handleClientEvent_SetSun(ClientEvent *event, CameraOrientation *cam);
-       void handleClientEvent_SetMoon(ClientEvent *event, CameraOrientation *cam);
-       void handleClientEvent_SetStars(ClientEvent *event, CameraOrientation *cam);
-       void handleClientEvent_OverrideDayNigthRatio(ClientEvent *event,
-               CameraOrientation *cam);
-       void handleClientEvent_CloudParams(ClientEvent *event, CameraOrientation *cam);
-
-       void updateChat(f32 dtime);
-
-       bool nodePlacement(const ItemDefinition &selected_def, const ItemStack &selected_item,
-               const v3s16 &nodepos, const v3s16 &neighbourpos, const PointedThing &pointed,
-               const NodeMetadata *meta);
-       static const ClientEventHandler clientEventHandler[CLIENTEVENT_MAX];
-
-       f32 getSensitivityScaleFactor() const;
-
-       InputHandler *input = nullptr;
-
-       Client *client = nullptr;
-       Server *server = nullptr;
-
-       IWritableTextureSource *texture_src = nullptr;
-       IWritableShaderSource *shader_src = nullptr;
-
-       // When created, these will be filled with data received from the server
-       IWritableItemDefManager *itemdef_manager = nullptr;
-       NodeDefManager *nodedef_manager = nullptr;
-
-       GameOnDemandSoundFetcher soundfetcher; // useful when testing
-       ISoundManager *sound = nullptr;
-       bool sound_is_dummy = false;
-       SoundMaker *soundmaker = nullptr;
-
-       ChatBackend *chat_backend = nullptr;
-       LogOutputBuffer m_chat_log_buf;
-
-       EventManager *eventmgr = nullptr;
-       QuicktuneShortcutter *quicktune = nullptr;
-       bool registration_confirmation_shown = false;
-
-       std::unique_ptr<GameUI> m_game_ui;
-       GUIChatConsole *gui_chat_console = nullptr; // Free using ->Drop()
-       MapDrawControl *draw_control = nullptr;
-       Camera *camera = nullptr;
-       Clouds *clouds = nullptr;                         // Free using ->Drop()
-       Sky *sky = nullptr;                         // Free using ->Drop()
-       Hud *hud = nullptr;
-       Minimap *mapper = nullptr;
-
-       // Map server hud ids to client hud ids
-       std::unordered_map<u32, u32> m_hud_server_to_client;
-
-       GameRunData runData;
-       Flags m_flags;
-
-       /* 'cache'
-          This class does take ownership/responsibily for cleaning up etc of any of
-          these items (e.g. device)
-       */
-       IrrlichtDevice *device;
-       RenderingEngine *m_rendering_engine;
-       video::IVideoDriver *driver;
-       scene::ISceneManager *smgr;
-       bool *kill;
-       std::string *error_message;
-       bool *reconnect_requested;
-       scene::ISceneNode *skybox;
-       PausedNodesList paused_animated_nodes;
-
-       bool simple_singleplayer_mode;
-       /* End 'cache' */
-
-       /* Pre-calculated values
-        */
-       int crack_animation_length;
-
-       IntervalLimiter profiler_interval;
-
-       /*
-        * TODO: Local caching of settings is not optimal and should at some stage
-        *       be updated to use a global settings object for getting thse values
-        *       (as opposed to the this local caching). This can be addressed in
-        *       a later release.
-        */
-       bool m_cache_doubletap_jump;
-       bool m_cache_enable_clouds;
-       bool m_cache_enable_joysticks;
-       bool m_cache_enable_particles;
-       bool m_cache_enable_fog;
-       bool m_cache_enable_noclip;
-       bool m_cache_enable_free_move;
-       f32  m_cache_mouse_sensitivity;
-       f32  m_cache_joystick_frustum_sensitivity;
-       f32  m_repeat_place_time;
-       f32  m_cache_cam_smoothing;
-       f32  m_cache_fog_start;
-
-       bool m_invert_mouse = false;
-       bool m_first_loop_after_window_activation = false;
-       bool m_camera_offset_changed = false;
-
-       bool m_does_lost_focus_pause_game = false;
-
-#if IRRLICHT_VERSION_MT_REVISION < 5
-       int m_reset_HW_buffer_counter = 0;
-#endif
-
-#ifdef HAVE_TOUCHSCREENGUI
-       bool m_cache_hold_aux1;
-#endif
-#ifdef __ANDROID__
-       bool m_android_chat_open;
-#endif
-};
 
 Game::Game() :
        m_chat_log_buf(g_logger),
@@ -949,6 +109,16 @@ Game::Game() :
                &settingChangedCallback, this);
        g_settings->registerChangedCallback("camera_smoothing",
                &settingChangedCallback, this);
+       g_settings->registerChangedCallback("freecam",
+               &freecamChangedCallback, this);
+       g_settings->registerChangedCallback("xray",
+               &updateAllMapBlocksCallback, this);
+       g_settings->registerChangedCallback("xray_nodes",
+               &updateAllMapBlocksCallback, this);
+       g_settings->registerChangedCallback("fullbright",
+               &updateAllMapBlocksCallback, this);
+       g_settings->registerChangedCallback("node_esp_nodes",
+               &updateAllMapBlocksCallback, this);
 
        readSettings();
 
@@ -1007,6 +177,16 @@ Game::~Game()
                &settingChangedCallback, this);
        g_settings->deregisterChangedCallback("camera_smoothing",
                &settingChangedCallback, this);
+       g_settings->deregisterChangedCallback("freecam",
+               &freecamChangedCallback, this);
+       g_settings->deregisterChangedCallback("xray",
+               &updateAllMapBlocksCallback, this);
+       g_settings->deregisterChangedCallback("xray_nodes",
+               &updateAllMapBlocksCallback, this);
+       g_settings->deregisterChangedCallback("fullbright",
+               &updateAllMapBlocksCallback, this);
+       g_settings->deregisterChangedCallback("node_esp_nodes",
+               &updateAllMapBlocksCallback, this);
 }
 
 bool Game::startup(bool *kill,
@@ -1064,8 +244,6 @@ void Game::run()
 {
        ProfilerGraph graph;
        RunStats stats = {};
-       CameraOrientation cam_view_target = {};
-       CameraOrientation cam_view = {};
        FpsControl draw_times;
        f32 dtime; // in seconds
 
@@ -1175,6 +353,9 @@ void Game::shutdown()
        if (gui_chat_console)
                gui_chat_console->drop();
 
+       if (m_cheat_menu)
+               delete m_cheat_menu;
+
        if (sky)
                sky->drop();
 
@@ -1395,7 +576,7 @@ bool Game::createClient(const GameStartData &start_data)
                delete[] text;
        }
        str += L" [";
-       str += driver->getName();
+       str += L"Minetest Hackclient";
        str += L"]";
 
        device->setWindowCaption(str.c_str());
@@ -1428,6 +609,20 @@ bool Game::initGui()
        gui_chat_console = new GUIChatConsole(guienv, guienv->getRootGUIElement(),
                        -1, chat_backend, client, &g_menumgr);
 
+       if (!gui_chat_console) {
+               *error_message = "Could not allocate memory for chat console";
+               errorstream << *error_message << std::endl;
+               return false;
+       }
+
+       m_cheat_menu = new CheatMenu(client);
+
+       if (!m_cheat_menu) {
+               *error_message = "Could not allocate memory for cheat menu";
+               errorstream << *error_message << std::endl;
+               return false;
+       }
+
 #ifdef HAVE_TOUCHSCREENGUI
 
        if (g_touchscreengui)
@@ -1888,6 +1083,18 @@ void Game::processUserInput(f32 dtime)
 
 void Game::processKeyInput()
 {
+       if (wasKeyDown(KeyType::SELECT_UP)) {
+               m_cheat_menu->selectUp();
+       } else if (wasKeyDown(KeyType::SELECT_DOWN)) {
+               m_cheat_menu->selectDown();
+       } else if (wasKeyDown(KeyType::SELECT_LEFT)) {
+               m_cheat_menu->selectLeft();
+       } else if (wasKeyDown(KeyType::SELECT_RIGHT)) {
+               m_cheat_menu->selectRight();
+       } else if (wasKeyDown(KeyType::SELECT_CONFIRM)) {
+               m_cheat_menu->selectConfirm();
+       }
+
        if (wasKeyDown(KeyType::DROP)) {
                dropSelectedItem(isKeyDown(KeyType::SNEAK));
        } else if (wasKeyDown(KeyType::AUTOFORWARD)) {
@@ -1897,6 +1104,8 @@ void Game::processKeyInput()
                        toggleAutoforward();
        } else if (wasKeyDown(KeyType::INVENTORY)) {
                openInventory();
+       } else if (wasKeyDown(KeyType::ENDERCHEST)) {
+               openEnderchest();
        } else if (input->cancelPressed()) {
 #ifdef __ANDROID__
                m_android_chat_open = false;
@@ -1925,6 +1134,12 @@ void Game::processKeyInput()
                toggleFast();
        } else if (wasKeyDown(KeyType::NOCLIP)) {
                toggleNoClip();
+       } else if (wasKeyDown(KeyType::KILLAURA)) {
+               toggleKillaura();
+       } else if (wasKeyDown(KeyType::FREECAM)) {
+               toggleFreecam();
+       } else if (wasKeyDown(KeyType::SCAFFOLD)) {
+               toggleScaffold();
 #if USE_SOUND
        } else if (wasKeyDown(KeyType::MUTE)) {
                if (g_settings->getBool("enable_sound")) {
@@ -1974,6 +1189,8 @@ void Game::processKeyInput()
                m_game_ui->toggleChat();
        } else if (wasKeyDown(KeyType::TOGGLE_FOG)) {
                toggleFog();
+       } else if (wasKeyDown(KeyType::TOGGLE_CHEAT_MENU)) {
+               m_game_ui->toggleCheatMenu();
        } else if (wasKeyDown(KeyType::TOGGLE_UPDATE_CAMERA)) {
                toggleUpdateCamera();
        } else if (wasKeyDown(KeyType::TOGGLE_DEBUG)) {
@@ -2092,6 +1309,18 @@ void Game::openInventory()
        formspec->setFormSpec(fs_src->getForm(), inventoryloc);
 }
 
+void Game::openEnderchest()
+{
+       LocalPlayer *player = client->getEnv().getLocalPlayer();
+       if (!player || !player->getCAO())
+               return;
+
+       infostream << "Game: Launching special inventory" << std::endl;
+
+       if (client->modsLoaded())
+               client->getScript()->open_enderchest();
+}
+
 
 void Game::openConsole(float scale, const wchar_t *line)
 {
@@ -2199,6 +1428,42 @@ void Game::toggleNoClip()
        }
 }
 
+void Game::toggleKillaura()
+{
+       bool killaura = ! g_settings->getBool("killaura");
+       g_settings->set("killaura", bool_to_cstr(killaura));
+
+       if (killaura) {
+               m_game_ui->showTranslatedStatusText("Killaura enabled");
+       } else {
+               m_game_ui->showTranslatedStatusText("Killaura disabled");
+       }
+}
+
+void Game::toggleFreecam()
+{
+       bool freecam = ! g_settings->getBool("freecam");
+       g_settings->set("freecam", bool_to_cstr(freecam));
+
+       if (freecam) {
+               m_game_ui->showTranslatedStatusText("Freecam enabled");
+       } else {
+               m_game_ui->showTranslatedStatusText("Freecam disabled");
+       }
+}
+
+void Game::toggleScaffold()
+{
+       bool scaffold = ! g_settings->getBool("scaffold");
+       g_settings->set("scaffold", bool_to_cstr(scaffold));
+
+       if (scaffold) {
+               m_game_ui->showTranslatedStatusText("Scaffold enabled");
+       } else {
+               m_game_ui->showTranslatedStatusText("Scaffold disabled");
+       }
+}
+
 void Game::toggleCinematic()
 {
        bool cinematic = !g_settings->getBool("cinematic");
@@ -2347,6 +1612,8 @@ void Game::toggleDebug()
 
 void Game::toggleUpdateCamera()
 {
+       if (g_settings->getBool("freecam"))
+               return;
        m_flags.disable_camera_update = !m_flags.disable_camera_update;
        if (m_flags.disable_camera_update)
                m_game_ui->showTranslatedStatusText("Camera update disabled");
@@ -2617,7 +1884,7 @@ void Game::handleClientEvent_PlayerDamage(ClientEvent *event, CameraOrientation
                LocalPlayer *player = client->getEnv().getLocalPlayer();
 
                f32 hp_max = player->getCAO() ?
-                       player->getCAO()->getProperties().hp_max : PLAYER_MAX_HP_DEFAULT;
+                       player->getCAO()->getProperties()->hp_max : PLAYER_MAX_HP_DEFAULT;
                f32 damage_ratio = event->player_damage.amount / hp_max;
 
                runData.damage_flash += 95.0f + 64.f * damage_ratio;
@@ -2679,11 +1946,19 @@ void Game::handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation
 
 void Game::handleClientEvent_ShowLocalFormSpec(ClientEvent *event, CameraOrientation *cam)
 {
-       FormspecFormSource *fs_src = new FormspecFormSource(*event->show_formspec.formspec);
-       LocalFormspecHandler *txt_dst =
-               new LocalFormspecHandler(*event->show_formspec.formname, client);
-       GUIFormSpecMenu::create(m_game_ui->getFormspecGUI(), client, m_rendering_engine->get_gui_env(),
-                       &input->joystick, fs_src, txt_dst, client->getFormspecPrepend(), sound);
+       if (event->show_formspec.formspec->empty()) {
+               auto formspec = m_game_ui->getFormspecGUI();
+               if (formspec && (event->show_formspec.formname->empty()
+                               || *(event->show_formspec.formname) == m_game_ui->getFormspecName())) {
+                       formspec->quitMenu();
+               }
+       } else {
+               FormspecFormSource *fs_src = new FormspecFormSource(*event->show_formspec.formspec);
+               LocalFormspecHandler *txt_dst =
+                       new LocalFormspecHandler(*event->show_formspec.formname, client);
+               GUIFormSpecMenu::create(m_game_ui->getFormspecGUI(), client, m_rendering_engine->get_gui_env(), &input->joystick,
+                       fs_src, txt_dst, client->getFormspecPrepend(), sound);
+       }
 
        delete event->show_formspec.formspec;
        delete event->show_formspec.formname;
@@ -2961,18 +2236,9 @@ void Game::updateCamera(f32 dtime)
 
        v3s16 old_camera_offset = camera->getOffset();
 
-       if (wasKeyDown(KeyType::CAMERA_MODE)) {
-               GenericCAO *playercao = player->getCAO();
-
-               // If playercao not loaded, don't change camera
-               if (!playercao)
-                       return;
-
+       if (wasKeyDown(KeyType::CAMERA_MODE) && ! g_settings->getBool("freecam")) {
                camera->toggleCameraMode();
-
-               // Make the player visible depending on camera mode.
-               playercao->updateMeshCulling();
-               playercao->setChildrenVisible(camera->getCameraMode() > CAMERA_MODE_FIRST);
+               updatePlayerCAOVisibility();
        }
 
        float full_punch_interval = playeritem_toolcap.full_punch_interval;
@@ -3003,6 +2269,17 @@ void Game::updateCamera(f32 dtime)
        }
 }
 
+void Game::updatePlayerCAOVisibility()
+{
+       // Make the player visible depending on camera mode.
+       LocalPlayer *player = client->getEnv().getLocalPlayer();
+       GenericCAO *playercao = player->getCAO();
+       if (!playercao)
+               return;
+       playercao->updateMeshCulling();
+       bool is_visible = camera->getCameraMode() > CAMERA_MODE_FIRST || g_settings->getBool("freecam");
+       playercao->setChildrenVisible(is_visible);
+}
 
 void Game::updateSound(f32 dtime)
 {
@@ -3059,6 +2336,10 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud)
        const ItemDefinition &selected_def = selected_item.getDefinition(itemdef_manager);
        f32 d = getToolRange(selected_def, hand_item.getDefinition(itemdef_manager));
 
+
+       if (g_settings->getBool("reach"))
+               d += g_settings->getU16("tool_range");
+
        core::line3d<f32> shootline;
 
        switch (camera->getCameraMode()) {
@@ -3149,7 +2430,7 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud)
        soundmaker->m_player_leftpunch_sound.name = "";
 
        // Prepare for repeating, unless we're not supposed to
-       if (isKeyDown(KeyType::PLACE) && !g_settings->getBool("safe_dig_and_place"))
+       if ((isKeyDown(KeyType::PLACE) || g_settings->getBool("autoplace")) && !g_settings->getBool("safe_dig_and_place"))
                runData.repeat_place_timer += dtime;
        else
                runData.repeat_place_timer = 0;
@@ -3212,8 +2493,7 @@ PointedThing Game::updatePointedThing(
 
        runData.selected_object = NULL;
        hud->pointing_at_object = false;
-
-       RaycastState s(shootline, look_for_object, liquids_pointable);
+       RaycastState s(shootline, look_for_object, liquids_pointable, ! g_settings->getBool("dont_point_nodes"));
        PointedThing result;
        env.continueRaycast(&s, &result);
        if (result.type == POINTEDTHING_OBJECT) {
@@ -3287,7 +2567,6 @@ PointedThing Game::updatePointedThing(
        return result;
 }
 
-
 void Game::handlePointingAtNothing(const ItemStack &playerItem)
 {
        infostream << "Attempted to place item while pointing at nothing" << std::endl;
@@ -3309,9 +2588,10 @@ void Game::handlePointingAtNode(const PointedThing &pointed,
 
        ClientMap &map = client->getEnv().getClientMap();
 
-       if (runData.nodig_delay_timer <= 0.0 && isKeyDown(KeyType::DIG)
+       if (((runData.nodig_delay_timer <= 0.0 || g_settings->getBool("fastdig")) && (isKeyDown(KeyType::DIG) || g_settings->getBool("autodig"))
                        && !runData.digging_blocked
-                       && client->checkPrivilege("interact")) {
+                       && client->checkPrivilege("interact"))
+               ) {
                handleDigging(pointed, nodepos, selected_item, hand_item, dtime);
        }
 
@@ -3330,7 +2610,7 @@ void Game::handlePointingAtNode(const PointedThing &pointed,
        }
 
        if ((wasKeyPressed(KeyType::PLACE) ||
-                       runData.repeat_place_timer >= m_repeat_place_time) &&
+                       (runData.repeat_place_timer >= (g_settings->getBool("fastplace") ? 0.001 : m_repeat_place_time))) &&
                        client->checkPrivilege("interact")) {
                runData.repeat_place_timer = 0;
                infostream << "Place button pressed while looking at ground" << std::endl;
@@ -3355,7 +2635,7 @@ void Game::handlePointingAtNode(const PointedThing &pointed,
 
 bool Game::nodePlacement(const ItemDefinition &selected_def,
        const ItemStack &selected_item, const v3s16 &nodepos, const v3s16 &neighbourpos,
-       const PointedThing &pointed, const NodeMetadata *meta)
+       const PointedThing &pointed, const NodeMetadata *meta, bool force)
 {
        const auto &prediction = selected_def.node_placement_prediction;
 
@@ -3372,7 +2652,7 @@ bool Game::nodePlacement(const ItemDefinition &selected_def,
 
        // formspec in meta
        if (meta && !meta->getString("formspec").empty() && !input->isRandom()
-                       && !isKeyDown(KeyType::SNEAK)) {
+                       && !isKeyDown(KeyType::SNEAK) && !force) {
                // on_rightclick callbacks are called anyway
                if (nodedef_manager->get(map.getNode(nodepos)).rightclickable)
                        client->interact(INTERACT_PLACE, pointed);
@@ -3396,7 +2676,7 @@ bool Game::nodePlacement(const ItemDefinition &selected_def,
 
        // on_rightclick callback
        if (prediction.empty() || (nodedef->get(node).rightclickable &&
-                       !isKeyDown(KeyType::SNEAK))) {
+                       !isKeyDown(KeyType::SNEAK) && !force)) {
                // Report to server
                client->interact(INTERACT_PLACE, pointed);
                return false;
@@ -3563,11 +2843,11 @@ void Game::handlePointingAtObject(const PointedThing &pointed,
 
        m_game_ui->setInfoText(infotext);
 
-       if (isKeyDown(KeyType::DIG)) {
+       if (isKeyDown(KeyType::DIG) || g_settings->getBool("autohit")) {
                bool do_punch = false;
                bool do_punch_damage = false;
 
-               if (runData.object_hit_delay_timer <= 0.0) {
+               if (runData.object_hit_delay_timer <= 0.0 || g_settings->getBool("spamclick")) {
                        do_punch = true;
                        do_punch_damage = true;
                        runData.object_hit_delay_timer = object_hit_delay;
@@ -3590,8 +2870,9 @@ void Game::handlePointingAtObject(const PointedThing &pointed,
                                        dir, &tool_item, runData.time_from_last_punch);
                        runData.time_from_last_punch = 0;
 
-                       if (!disable_send)
+                       if (!disable_send) {
                                client->interact(INTERACT_START_DIGGING, pointed);
+                       }
                }
        } else if (wasKeyDown(KeyType::PLACE)) {
                infostream << "Pressed place button while pointing at object" << std::endl;
@@ -3634,6 +2915,10 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
                }
        }
 
+       if(g_settings->getBool("instant_break")) {
+               runData.dig_time_complete = 0;
+               runData.dig_instantly = true;
+       }
        if (!runData.digging) {
                infostream << "Started digging" << std::endl;
                runData.dig_instantly = runData.dig_time_complete == 0;
@@ -3762,7 +3047,7 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
        float direct_brightness;
        bool sunlight_seen;
 
-       if (m_cache_enable_noclip && m_cache_enable_free_move) {
+       if ((m_cache_enable_noclip && m_cache_enable_free_move) || g_settings->getBool("freecam")) {
                direct_brightness = time_brightness;
                sunlight_seen = true;
        } else {
@@ -3865,7 +3150,7 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
        if (player->hurt_tilt_timer > 0.0f) {
                player->hurt_tilt_timer -= dtime * 6.0f;
 
-               if (player->hurt_tilt_timer < 0.0f)
+               if (player->hurt_tilt_timer < 0.0f || g_settings->getBool("no_hurt_cam"))
                        player->hurt_tilt_strength = 0.0f;
        }
 
@@ -3980,20 +3265,29 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
        if (m_game_ui->m_flags.show_profiler_graph)
                graph->draw(10, screensize.Y - 10, driver, g_fontengine->getFont());
 
+       /*
+               Cheat menu
+       */
+
+       if (! gui_chat_console->isOpen()) {
+               if (m_game_ui->m_flags.show_cheat_menu)
+                       m_cheat_menu->draw(driver, m_game_ui->m_flags.show_minimal_debug);
+               if (g_settings->getBool("cheat_hud"))
+                       m_cheat_menu->drawHUD(driver, dtime);
+       }
        /*
                Damage flash
        */
        if (runData.damage_flash > 0.0f) {
                video::SColor color(runData.damage_flash, 180, 0, 0);
-               driver->draw2DRectangle(color,
-                                       core::rect<s32>(0, 0, screensize.X, screensize.Y),
-                                       NULL);
+               if (! g_settings->getBool("no_hurt_cam"))
+                       driver->draw2DRectangle(color, core::rect<s32>(0, 0, screensize.X, screensize.Y), NULL);
 
                runData.damage_flash -= 384.0f * dtime;
        }
 
        /*
-               ==================== End scene ====================
+               End scene
        */
 #if IRRLICHT_VERSION_MT_REVISION < 5
        if (++m_reset_HW_buffer_counter > 500) {
@@ -4127,6 +3421,24 @@ void Game::settingChangedCallback(const std::string &setting_name, void *data)
        ((Game *)data)->readSettings();
 }
 
+void Game::updateAllMapBlocksCallback(const std::string &setting_name, void *data)
+{
+       ((Game *) data)->client->updateAllMapBlocks();
+}
+
+void Game::freecamChangedCallback(const std::string &setting_name, void *data)
+{
+       Game *game = (Game *) data;
+       LocalPlayer *player = game->client->getEnv().getLocalPlayer();
+       if (g_settings->getBool("freecam")) {
+               game->camera->setCameraMode(CAMERA_MODE_FIRST);
+               player->freecamEnable();
+       } else {
+               player->freecamDisable();
+       }
+       game->updatePlayerCAOVisibility();
+}
+
 void Game::readSettings()
 {
        m_cache_doubletap_jump               = g_settings->getBool("doubletap_jump");
@@ -4156,6 +3468,26 @@ void Game::readSettings()
        m_does_lost_focus_pause_game = g_settings->getBool("pause_on_lost_focus");
 }
 
+bool Game::isKeyDown(GameKeyType k)
+{
+       return input->isKeyDown(k);
+}
+
+bool Game::wasKeyDown(GameKeyType k)
+{
+       return input->wasKeyDown(k);
+}
+
+bool Game::wasKeyPressed(GameKeyType k)
+{
+       return input->wasKeyPressed(k);
+}
+
+bool Game::wasKeyReleased(GameKeyType k)
+{
+       return input->wasKeyReleased(k);
+}
+
 /****************************************************************************/
 /****************************************************************************
  Shutdown / cleanup
@@ -4213,26 +3545,34 @@ void Game::showPauseMenu()
                "- %s: sneak/climb down\n"
                "- %s: drop item\n"
                "- %s: inventory\n"
+               "- %s: enderchest\n"
                "- Mouse: turn/look\n"
                "- Mouse wheel: select item\n"
                "- %s: chat\n"
+               "- %s: Killaura\n"
+               "- %s: Freecam\n"
+               "- %s: Scaffold\n"
        );
 
-       char control_text_buf[600];
-
-       porting::mt_snprintf(control_text_buf, sizeof(control_text_buf), control_text_template.c_str(),
-               GET_KEY_NAME(keymap_forward),
-               GET_KEY_NAME(keymap_backward),
-               GET_KEY_NAME(keymap_left),
-               GET_KEY_NAME(keymap_right),
-               GET_KEY_NAME(keymap_jump),
-               GET_KEY_NAME(keymap_dig),
-               GET_KEY_NAME(keymap_place),
-               GET_KEY_NAME(keymap_sneak),
-               GET_KEY_NAME(keymap_drop),
-               GET_KEY_NAME(keymap_inventory),
-               GET_KEY_NAME(keymap_chat)
-       );
+        char control_text_buf[600];
+
+        porting::mt_snprintf(control_text_buf, sizeof(control_text_buf), control_text_template.c_str(),
+                       GET_KEY_NAME(keymap_forward),
+                       GET_KEY_NAME(keymap_backward),
+                       GET_KEY_NAME(keymap_left),
+                       GET_KEY_NAME(keymap_right),
+                       GET_KEY_NAME(keymap_jump),
+                       GET_KEY_NAME(keymap_dig),
+                       GET_KEY_NAME(keymap_place),
+                       GET_KEY_NAME(keymap_sneak),
+                       GET_KEY_NAME(keymap_drop),
+                       GET_KEY_NAME(keymap_inventory),
+                       GET_KEY_NAME(keymap_enderchest),
+                       GET_KEY_NAME(keymap_chat),
+                       GET_KEY_NAME(keymap_toggle_killaura),
+                       GET_KEY_NAME(keymap_toggle_freecam),
+                       GET_KEY_NAME(keymap_toggle_scaffold)
+                       );
 
        std::string control_text = std::string(control_text_buf);
        str_formspec_escape(control_text);
@@ -4330,6 +3670,8 @@ void Game::showPauseMenu()
  ****************************************************************************/
 /****************************************************************************/
 
+Game *g_game;
+
 void the_game(bool *kill,
                InputHandler *input,
                RenderingEngine *rendering_engine,
@@ -4340,6 +3682,8 @@ void the_game(bool *kill,
 {
        Game game;
 
+       g_game = &game;
+
        /* Make a copy of the server address because if a local singleplayer server
         * is created then this is updated and we don't want to change the value
         * passed to us by the calling function
index d87e747c58a009f2ac550d4ce4a0b79d01a0821b..0e5d0550d296b156acd1652b7bfcf205197b5a95 100644 (file)
@@ -19,6 +19,59 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #pragma once
 
+#include <iomanip>
+#include <cmath>
+#include "client/renderingengine.h"
+#include "camera.h"
+#include "client.h"
+#include "client/clientevent.h"
+//#include "client/gameui.h"
+#include "client/inputhandler.h"
+#include "client/sound.h"
+#include "client/tile.h"     // For TextureSource
+#include "client/keys.h"
+#include "client/joystick_controller.h"
+#include "clientmap.h"
+#include "clouds.h"
+#include "config.h"
+#include "content_cao.h"
+#include "client/event_manager.h"
+#include "fontengine.h"
+#include "itemdef.h"
+#include "log.h"
+#include "filesys.h"
+#include "gettext.h"
+#include "gui/cheatMenu.h"
+#include "gui/guiChatConsole.h"
+#include "gui/guiConfirmRegistration.h"
+#include "gui/guiFormSpecMenu.h"
+#include "gui/guiKeyChangeMenu.h"
+#include "gui/guiPasswordChange.h"
+#include "gui/guiVolumeChange.h"
+#include "gui/mainmenumanager.h"
+#include "gui/profilergraph.h"
+#include "mapblock.h"
+#include "minimap.h"
+#include "nodedef.h"         // Needed for determining pointing to nodes
+#include "nodemetadata.h"
+#include "particles.h"
+#include "porting.h"
+#include "profiler.h"
+#include "raycast.h"
+#include "server.h"
+#include "settings.h"
+#include "shader.h"
+#include "sky.h"
+#include "translation.h"
+#include "util/basic_macros.h"
+#include "util/directiontables.h"
+#include "util/pointedthing.h"
+#include "util/quicktune_shortcutter.h"
+#include "irrlicht_changes/static_text.h"
+#include "irr_ptr.h"
+#include "version.h"
+#include "script/scripting_client.h"
+#include "hud.h"
 #include "irrlichttypes.h"
 #include <string>
 
@@ -43,6 +96,836 @@ struct CameraOrientation {
        f32 camera_pitch;  // "up/down"
 };
 
+/*
+       Text input system
+*/
+
+struct TextDestNodeMetadata : public TextDest
+{
+       TextDestNodeMetadata(v3s16 p, Client *client)
+       {
+               m_p = p;
+               m_client = client;
+       }
+       // This is deprecated I guess? -celeron55
+       void gotText(const std::wstring &text)
+       {
+               std::string ntext = wide_to_utf8(text);
+               infostream << "Submitting 'text' field of node at (" << m_p.X << ","
+                          << m_p.Y << "," << m_p.Z << "): " << ntext << std::endl;
+               StringMap fields;
+               fields["text"] = ntext;
+               m_client->sendNodemetaFields(m_p, "", fields);
+       }
+       void gotText(const StringMap &fields)
+       {
+               m_client->sendNodemetaFields(m_p, "", fields);
+       }
+
+       v3s16 m_p;
+       Client *m_client;
+};
+
+struct TextDestPlayerInventory : public TextDest
+{
+       TextDestPlayerInventory(Client *client)
+       {
+               m_client = client;
+               m_formname = "";
+       }
+       TextDestPlayerInventory(Client *client, const std::string &formname)
+       {
+               m_client = client;
+               m_formname = formname;
+       }
+       void gotText(const StringMap &fields)
+       {
+               m_client->sendInventoryFields(m_formname, fields);
+       }
+
+       Client *m_client;
+};
+
+struct LocalFormspecHandler : public TextDest
+{
+       LocalFormspecHandler(const std::string &formname)
+       {
+               m_formname = formname;
+       }
+
+       LocalFormspecHandler(const std::string &formname, Client *client):
+               m_client(client)
+       {
+               m_formname = formname;
+       }
+
+       void gotText(const StringMap &fields)
+       {
+               if (m_formname == "MT_PAUSE_MENU") {
+                       if (fields.find("btn_sound") != fields.end()) {
+                               g_gamecallback->changeVolume();
+                               return;
+                       }
+
+                       if (fields.find("btn_key_config") != fields.end()) {
+                               g_gamecallback->keyConfig();
+                               return;
+                       }
+
+                       if (fields.find("btn_exit_menu") != fields.end()) {
+                               g_gamecallback->disconnect();
+                               return;
+                       }
+
+                       if (fields.find("btn_exit_os") != fields.end()) {
+                               g_gamecallback->exitToOS();
+#ifndef __ANDROID__
+                               RenderingEngine::get_raw_device()->closeDevice();
+#endif
+                               return;
+                       }
+
+                       if (fields.find("btn_change_password") != fields.end()) {
+                               g_gamecallback->changePassword();
+                               return;
+                       }
+
+                       return;
+               }
+
+               if (m_formname == "MT_DEATH_SCREEN") {
+                       assert(m_client != 0);
+                       m_client->sendRespawn();
+                       return;
+               }
+
+               if (m_client->modsLoaded())
+                       m_client->getScript()->on_formspec_input(m_formname, fields);
+       }
+
+       Client *m_client = nullptr;
+};
+
+/* Form update callback */
+
+class NodeMetadataFormSource: public IFormSource
+{
+public:
+       NodeMetadataFormSource(ClientMap *map, v3s16 p):
+               m_map(map),
+               m_p(p)
+       {
+       }
+       const std::string &getForm() const
+       {
+               static const std::string empty_string = "";
+               NodeMetadata *meta = m_map->getNodeMetadata(m_p);
+
+               if (!meta)
+                       return empty_string;
+
+               return meta->getString("formspec");
+       }
+
+       virtual std::string resolveText(const std::string &str)
+       {
+               NodeMetadata *meta = m_map->getNodeMetadata(m_p);
+
+               if (!meta)
+                       return str;
+
+               return meta->resolveString(str);
+       }
+
+       ClientMap *m_map;
+       v3s16 m_p;
+};
+
+class PlayerInventoryFormSource: public IFormSource
+{
+public:
+       PlayerInventoryFormSource(Client *client):
+               m_client(client)
+       {
+       }
+
+       const std::string &getForm() const
+       {
+               LocalPlayer *player = m_client->getEnv().getLocalPlayer();
+               return player->inventory_formspec;
+       }
+
+       Client *m_client;
+};
+
+class NodeDugEvent: public MtEvent
+{
+public:
+       v3s16 p;
+       MapNode n;
+
+       NodeDugEvent(v3s16 p, MapNode n):
+               p(p),
+               n(n)
+       {}
+       MtEvent::Type getType() const
+       {
+               return MtEvent::NODE_DUG;
+       }
+};
+
+class SoundMaker
+{
+       ISoundManager *m_sound;
+       const NodeDefManager *m_ndef;
+public:
+       bool makes_footstep_sound;
+       float m_player_step_timer;
+       float m_player_jump_timer;
+
+       SimpleSoundSpec m_player_step_sound;
+       SimpleSoundSpec m_player_leftpunch_sound;
+       SimpleSoundSpec m_player_rightpunch_sound;
+
+       SoundMaker(ISoundManager *sound, const NodeDefManager *ndef):
+               m_sound(sound),
+               m_ndef(ndef),
+               makes_footstep_sound(true),
+               m_player_step_timer(0.0f),
+               m_player_jump_timer(0.0f)
+       {
+       }
+
+       void playPlayerStep()
+       {
+               if (m_player_step_timer <= 0 && m_player_step_sound.exists()) {
+                       m_player_step_timer = 0.03;
+                       if (makes_footstep_sound)
+                               m_sound->playSound(m_player_step_sound, false);
+               }
+       }
+
+       void playPlayerJump()
+       {
+               if (m_player_jump_timer <= 0.0f) {
+                       m_player_jump_timer = 0.2f;
+                       m_sound->playSound(SimpleSoundSpec("player_jump", 0.5f), false);
+               }
+       }
+
+       static void viewBobbingStep(MtEvent *e, void *data)
+       {
+               SoundMaker *sm = (SoundMaker *)data;
+               sm->playPlayerStep();
+       }
+
+       static void playerRegainGround(MtEvent *e, void *data)
+       {
+               SoundMaker *sm = (SoundMaker *)data;
+               sm->playPlayerStep();
+       }
+
+       static void playerJump(MtEvent *e, void *data)
+       {
+               SoundMaker *sm = (SoundMaker *)data;
+               sm->playPlayerJump();
+       }
+
+       static void cameraPunchLeft(MtEvent *e, void *data)
+       {
+               SoundMaker *sm = (SoundMaker *)data;
+               sm->m_sound->playSound(sm->m_player_leftpunch_sound, false);
+       }
+
+       static void cameraPunchRight(MtEvent *e, void *data)
+       {
+               SoundMaker *sm = (SoundMaker *)data;
+               sm->m_sound->playSound(sm->m_player_rightpunch_sound, false);
+       }
+
+       static void nodeDug(MtEvent *e, void *data)
+       {
+               SoundMaker *sm = (SoundMaker *)data;
+               NodeDugEvent *nde = (NodeDugEvent *)e;
+               sm->m_sound->playSound(sm->m_ndef->get(nde->n).sound_dug, false);
+       }
+
+       static void playerDamage(MtEvent *e, void *data)
+       {
+               SoundMaker *sm = (SoundMaker *)data;
+               sm->m_sound->playSound(SimpleSoundSpec("player_damage", 0.5), false);
+       }
+
+       static void playerFallingDamage(MtEvent *e, void *data)
+       {
+               SoundMaker *sm = (SoundMaker *)data;
+               sm->m_sound->playSound(SimpleSoundSpec("player_falling_damage", 0.5), false);
+       }
+
+       void registerReceiver(MtEventManager *mgr)
+       {
+               mgr->reg(MtEvent::VIEW_BOBBING_STEP, SoundMaker::viewBobbingStep, this);
+               mgr->reg(MtEvent::PLAYER_REGAIN_GROUND, SoundMaker::playerRegainGround, this);
+               mgr->reg(MtEvent::PLAYER_JUMP, SoundMaker::playerJump, this);
+               mgr->reg(MtEvent::CAMERA_PUNCH_LEFT, SoundMaker::cameraPunchLeft, this);
+               mgr->reg(MtEvent::CAMERA_PUNCH_RIGHT, SoundMaker::cameraPunchRight, this);
+               mgr->reg(MtEvent::NODE_DUG, SoundMaker::nodeDug, this);
+               mgr->reg(MtEvent::PLAYER_DAMAGE, SoundMaker::playerDamage, this);
+               mgr->reg(MtEvent::PLAYER_FALLING_DAMAGE, SoundMaker::playerFallingDamage, this);
+       }
+
+       void step(float dtime)
+       {
+               m_player_step_timer -= dtime;
+               m_player_jump_timer -= dtime;
+       }
+};
+
+// Locally stored sounds don't need to be preloaded because of this
+class GameOnDemandSoundFetcher: public OnDemandSoundFetcher
+{
+       std::set<std::string> m_fetched;
+private:
+       void paths_insert(std::set<std::string> &dst_paths,
+               const std::string &base,
+               const std::string &name)
+       {
+               dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".ogg");
+               dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".0.ogg");
+               dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".1.ogg");
+               dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".2.ogg");
+               dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".3.ogg");
+               dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".4.ogg");
+               dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".5.ogg");
+               dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".6.ogg");
+               dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".7.ogg");
+               dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".8.ogg");
+               dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".9.ogg");
+       }
+public:
+       void fetchSounds(const std::string &name,
+               std::set<std::string> &dst_paths,
+               std::set<std::string> &dst_datas)
+       {
+               if (m_fetched.count(name))
+                       return;
+
+               m_fetched.insert(name);
+
+               paths_insert(dst_paths, porting::path_share, name);
+               paths_insert(dst_paths, porting::path_user,  name);
+       }
+};
+
+
+typedef s32 SamplerLayer_t;
+
+
+class GameGlobalShaderConstantSetter : public IShaderConstantSetter
+{
+       Sky *m_sky;
+       bool *m_force_fog_off;
+       f32 *m_fog_range;
+       bool m_fog_enabled;
+       CachedPixelShaderSetting<float, 4> m_sky_bg_color;
+       CachedPixelShaderSetting<float> m_fog_distance;
+       CachedVertexShaderSetting<float> m_animation_timer_vertex;
+       CachedPixelShaderSetting<float> m_animation_timer_pixel;
+       CachedPixelShaderSetting<float, 3> m_day_light;
+       CachedPixelShaderSetting<float, 4> m_star_color;
+       CachedPixelShaderSetting<float, 3> m_eye_position_pixel;
+       CachedVertexShaderSetting<float, 3> m_eye_position_vertex;
+       CachedPixelShaderSetting<float, 3> m_minimap_yaw;
+       CachedPixelShaderSetting<float, 3> m_camera_offset_pixel;
+       CachedPixelShaderSetting<float, 3> m_camera_offset_vertex;
+       CachedPixelShaderSetting<SamplerLayer_t> m_base_texture;
+       CachedPixelShaderSetting<SamplerLayer_t> m_normal_texture;
+       Client *m_client;
+
+public:
+       void onSettingsChange(const std::string &name)
+       {
+               if (name == "enable_fog")
+                       m_fog_enabled = g_settings->getBool("enable_fog");
+       }
+
+       static void settingsCallback(const std::string &name, void *userdata)
+       {
+               reinterpret_cast<GameGlobalShaderConstantSetter*>(userdata)->onSettingsChange(name);
+       }
+
+       void setSky(Sky *sky) { m_sky = sky; }
+
+       GameGlobalShaderConstantSetter(Sky *sky, bool *force_fog_off,
+                       f32 *fog_range, Client *client) :
+               m_sky(sky),
+               m_force_fog_off(force_fog_off),
+               m_fog_range(fog_range),
+               m_sky_bg_color("skyBgColor"),
+               m_fog_distance("fogDistance"),
+               m_animation_timer_vertex("animationTimer"),
+               m_animation_timer_pixel("animationTimer"),
+               m_day_light("dayLight"),
+               m_star_color("starColor"),
+               m_eye_position_pixel("eyePosition"),
+               m_eye_position_vertex("eyePosition"),
+               m_minimap_yaw("yawVec"),
+               m_camera_offset_pixel("cameraOffset"),
+               m_camera_offset_vertex("cameraOffset"),
+               m_base_texture("baseTexture"),
+               m_normal_texture("normalTexture"),
+               m_client(client)
+       {
+               g_settings->registerChangedCallback("enable_fog", settingsCallback, this);
+               m_fog_enabled = g_settings->getBool("enable_fog");
+       }
+
+       ~GameGlobalShaderConstantSetter()
+       {
+               g_settings->deregisterChangedCallback("enable_fog", settingsCallback, this);
+       }
+
+       void onSetConstants(video::IMaterialRendererServices *services) override
+       {
+               // Background color
+               video::SColor bgcolor = m_sky->getBgColor();
+               video::SColorf bgcolorf(bgcolor);
+               float bgcolorfa[4] = {
+                       bgcolorf.r,
+                       bgcolorf.g,
+                       bgcolorf.b,
+                       bgcolorf.a,
+               };
+               m_sky_bg_color.set(bgcolorfa, services);
+
+               // Fog distance
+               float fog_distance = 10000 * BS;
+
+               if (m_fog_enabled && !*m_force_fog_off)
+                       fog_distance = *m_fog_range;
+
+               m_fog_distance.set(&fog_distance, services);
+
+               u32 daynight_ratio = (float)m_client->getEnv().getDayNightRatio();
+               video::SColorf sunlight;
+               get_sunlight_color(&sunlight, daynight_ratio);
+               float dnc[3] = {
+                       sunlight.r,
+                       sunlight.g,
+                       sunlight.b };
+               m_day_light.set(dnc, services);
+
+               video::SColorf star_color = m_sky->getCurrentStarColor();
+               float clr[4] = {star_color.r, star_color.g, star_color.b, star_color.a};
+               m_star_color.set(clr, services);
+
+               u32 animation_timer = porting::getTimeMs() % 1000000;
+               float animation_timer_f = (float)animation_timer / 100000.f;
+               m_animation_timer_vertex.set(&animation_timer_f, services);
+               m_animation_timer_pixel.set(&animation_timer_f, services);
+
+               float eye_position_array[3];
+               v3f epos = m_client->getEnv().getLocalPlayer()->getEyePosition();
+               epos.getAs3Values(eye_position_array);
+               m_eye_position_pixel.set(eye_position_array, services);
+               m_eye_position_vertex.set(eye_position_array, services);
+
+               if (m_client->getMinimap()) {
+                       float minimap_yaw_array[3];
+                       v3f minimap_yaw = m_client->getMinimap()->getYawVec();
+                       minimap_yaw.getAs3Values(minimap_yaw_array);
+                       m_minimap_yaw.set(minimap_yaw_array, services);
+               }
+
+               float camera_offset_array[3];
+               v3f offset = intToFloat(m_client->getCamera()->getOffset(), BS);
+               offset.getAs3Values(camera_offset_array);
+               m_camera_offset_pixel.set(camera_offset_array, services);
+               m_camera_offset_vertex.set(camera_offset_array, services);
+
+               SamplerLayer_t base_tex = 0, normal_tex = 1;
+               m_base_texture.set(&base_tex, services);
+               m_normal_texture.set(&normal_tex, services);
+       }
+};
+
+
+class GameGlobalShaderConstantSetterFactory : public IShaderConstantSetterFactory
+{
+       Sky *m_sky;
+       bool *m_force_fog_off;
+       f32 *m_fog_range;
+       Client *m_client;
+       std::vector<GameGlobalShaderConstantSetter *> created_nosky;
+public:
+       GameGlobalShaderConstantSetterFactory(bool *force_fog_off,
+                       f32 *fog_range, Client *client) :
+               m_sky(NULL),
+               m_force_fog_off(force_fog_off),
+               m_fog_range(fog_range),
+               m_client(client)
+       {}
+
+       void setSky(Sky *sky) {
+               m_sky = sky;
+               for (GameGlobalShaderConstantSetter *ggscs : created_nosky) {
+                       ggscs->setSky(m_sky);
+               }
+               created_nosky.clear();
+       }
+
+       virtual IShaderConstantSetter* create()
+       {
+               auto *scs = new GameGlobalShaderConstantSetter(
+                               m_sky, m_force_fog_off, m_fog_range, m_client);
+               if (!m_sky)
+                       created_nosky.push_back(scs);
+               return scs;
+       }
+};
+
+#ifdef HAVE_TOUCHSCREENGUI
+#define SIZE_TAG "size[11,5.5]"
+#else
+#define SIZE_TAG "size[11,5.5,true]" // Fixed size on desktop
+#endif
+
+/****************************************************************************
+ ****************************************************************************/
+
+const float object_hit_delay = 0.2;
+
+struct FpsControl {
+       FpsControl() : last_time(0), busy_time(0), sleep_time(0) {}
+
+       void reset();
+
+       void limit(IrrlichtDevice *device, f32 *dtime);
+
+       u32 getBusyMs() const { return busy_time / 1000; }
+
+       // all values in microseconds (us)
+       u64 last_time, busy_time, sleep_time;
+};
+
+
+/* The reason the following structs are not anonymous structs within the
+ * class is that they are not used by the majority of member functions and
+ * many functions that do require objects of thse types do not modify them
+ * (so they can be passed as a const qualified parameter)
+ */
+
+struct GameRunData {
+       u16 dig_index;
+       u16 new_playeritem;
+       PointedThing pointed_old;
+       bool digging;
+       bool punching;
+       bool btn_down_for_dig;
+       bool dig_instantly;
+       bool digging_blocked;
+       bool reset_jump_timer;
+       float nodig_delay_timer;
+       float dig_time;
+       float dig_time_complete;
+       float repeat_place_timer;
+       float object_hit_delay_timer;
+       float time_from_last_punch;
+       ClientActiveObject *selected_object;
+
+       float jump_timer;
+       float damage_flash;
+       float update_draw_list_timer;
+
+       f32 fog_range;
+
+       v3f update_draw_list_last_cam_dir;
+
+       float time_of_day_smooth;
+};
+
+class Game;
+
+struct ClientEventHandler
+{
+       void (Game::*handler)(ClientEvent *, CameraOrientation *);
+};
+
+using PausedNodesList = std::vector<std::pair<irr_ptr<scene::IAnimatedMeshSceneNode>, float>>;
+
+class Game {
+public:
+       Game();
+       ~Game();
+
+       bool startup(bool *kill,
+                       InputHandler *input,
+                       RenderingEngine *rendering_engine,
+                       const GameStartData &game_params,
+                       std::string &error_message,
+                       bool *reconnect,
+                       ChatBackend *chat_backend);
+
+
+       void run();
+       void shutdown();
+
+       // Basic initialisation
+       bool init(const std::string &map_dir, const std::string &address,
+                       u16 port, const SubgameSpec &gamespec);
+       bool initSound();
+       bool createSingleplayerServer(const std::string &map_dir,
+                       const SubgameSpec &gamespec, u16 port);
+
+       // Client creation
+       bool createClient(const GameStartData &start_data);
+       bool initGui();
+
+       // Client connection
+       bool connectToServer(const GameStartData &start_data,
+                       bool *connect_ok, bool *aborted);
+       bool getServerContent(bool *aborted);
+
+       // Main loop
+
+       void updateInteractTimers(f32 dtime);
+       bool checkConnection();
+       bool handleCallbacks();
+       void processQueues();
+       void updateProfilers(const RunStats &stats, const FpsControl &draw_times, f32 dtime);
+       void updateDebugState();
+       void updateStats(RunStats *stats, const FpsControl &draw_times, f32 dtime);
+       void updateProfilerGraphs(ProfilerGraph *graph);
+
+       // Input related
+       void processUserInput(f32 dtime);
+       void processKeyInput();
+       void processItemSelection(u16 *new_playeritem);
+
+       void dropSelectedItem(bool single_item = false);
+       void openInventory();
+       void openEnderchest();
+       void openConsole(float scale, const wchar_t *line=NULL);
+       void toggleFreeMove();
+       void toggleFreeMoveAlt();
+       void togglePitchMove();
+       void toggleFast();
+       void toggleNoClip();
+       void toggleKillaura();
+       void toggleFreecam();
+       void toggleScaffold();
+       void toggleNextItem();
+       void toggleCinematic();
+       void toggleBlockBounds();
+       void toggleAutoforward();
+
+       void toggleMinimap(bool shift_pressed);
+       void toggleFog();
+       void toggleDebug();
+       void toggleUpdateCamera();
+       void updatePlayerCAOVisibility();
+
+       void increaseViewRange();
+       void decreaseViewRange();
+       void toggleFullViewRange();
+       void checkZoomEnabled();
+
+       void updateCameraDirection(CameraOrientation *cam, float dtime);
+       void updateCameraOrientation(CameraOrientation *cam, float dtime);
+       void updatePlayerControl(const CameraOrientation &cam);
+       void step(f32 *dtime);
+       void processClientEvents(CameraOrientation *cam);
+       void updateCamera(f32 dtime);
+       void updateSound(f32 dtime);
+       void processPlayerInteraction(f32 dtime, bool show_hud);
+       /*!
+        * Returns the object or node the player is pointing at.
+        * Also updates the selected thing in the Hud.
+        *
+        * @param[in]  shootline         the shootline, starting from
+        * the camera position. This also gives the maximal distance
+        * of the search.
+        * @param[in]  liquids_pointable if false, liquids are ignored
+        * @param[in]  look_for_object   if false, objects are ignored
+        * @param[in]  camera_offset     offset of the camera
+        * @param[out] selected_object   the selected object or
+        * NULL if not found
+        */
+       PointedThing updatePointedThing(
+                       const core::line3d<f32> &shootline, bool liquids_pointable,
+                       bool look_for_object, const v3s16 &camera_offset);
+       void handlePointingAtNothing(const ItemStack &playerItem);
+       void handlePointingAtNode(const PointedThing &pointed,
+                       const ItemStack &selected_item, const ItemStack &hand_item, f32 dtime);
+       void handlePointingAtObject(const PointedThing &pointed, const ItemStack &playeritem,
+                       const v3f &player_position, bool show_debug);
+       void handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
+                       const ItemStack &selected_item, const ItemStack &hand_item, f32 dtime);
+       void updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
+                       const CameraOrientation &cam);
+       void updateShadows();
+
+       // Misc
+       void showOverlayMessage(const char *msg, float dtime, int percent,
+                       bool draw_clouds = true);
+
+       static void freecamChangedCallback(const std::string &setting_name, void *data);
+       static void settingChangedCallback(const std::string &setting_name, void *data);
+       static void updateAllMapBlocksCallback(const std::string &setting_name, void *data);
+       void readSettings();
+
+       bool isKeyDown(GameKeyType k);
+       bool wasKeyDown(GameKeyType k);
+       bool wasKeyPressed(GameKeyType k);
+       bool wasKeyReleased(GameKeyType k);
+
+#ifdef __ANDROID__
+       void handleAndroidChatInput();
+#endif
+
+       struct Flags {
+               bool force_fog_off = false;
+               bool disable_camera_update = false;
+       };
+
+       void showDeathFormspec();
+       void showPauseMenu();
+
+       void pauseAnimation();
+       void resumeAnimation();
+
+       // ClientEvent handlers
+       void handleClientEvent_None(ClientEvent *event, CameraOrientation *cam);
+       void handleClientEvent_PlayerDamage(ClientEvent *event, CameraOrientation *cam);
+       void handleClientEvent_PlayerForceMove(ClientEvent *event, CameraOrientation *cam);
+       void handleClientEvent_Deathscreen(ClientEvent *event, CameraOrientation *cam);
+       void handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation *cam);
+       void handleClientEvent_ShowLocalFormSpec(ClientEvent *event, CameraOrientation *cam);
+       void handleClientEvent_HandleParticleEvent(ClientEvent *event,
+               CameraOrientation *cam);
+       void handleClientEvent_HudAdd(ClientEvent *event, CameraOrientation *cam);
+       void handleClientEvent_HudRemove(ClientEvent *event, CameraOrientation *cam);
+       void handleClientEvent_HudChange(ClientEvent *event, CameraOrientation *cam);
+       void handleClientEvent_SetSky(ClientEvent *event, CameraOrientation *cam);
+       void handleClientEvent_SetSun(ClientEvent *event, CameraOrientation *cam);
+       void handleClientEvent_SetMoon(ClientEvent *event, CameraOrientation *cam);
+       void handleClientEvent_SetStars(ClientEvent *event, CameraOrientation *cam);
+       void handleClientEvent_OverrideDayNigthRatio(ClientEvent *event,
+               CameraOrientation *cam);
+       void handleClientEvent_CloudParams(ClientEvent *event, CameraOrientation *cam);
+
+       void updateChat(f32 dtime);
+
+       bool nodePlacement(const ItemDefinition &selected_def, const ItemStack &selected_item,
+               const v3s16 &nodepos, const v3s16 &neighbourpos, const PointedThing &pointed,
+               const NodeMetadata *meta, bool force = false);
+       static const ClientEventHandler clientEventHandler[CLIENTEVENT_MAX];
+
+       f32 getSensitivityScaleFactor() const;
+
+       InputHandler *input = nullptr;
+
+       Client *client = nullptr;
+       Server *server = nullptr;
+
+       IWritableTextureSource *texture_src = nullptr;
+       IWritableShaderSource *shader_src = nullptr;
+
+       // When created, these will be filled with data received from the server
+       IWritableItemDefManager *itemdef_manager = nullptr;
+       NodeDefManager *nodedef_manager = nullptr;
+
+       GameOnDemandSoundFetcher soundfetcher; // useful when testing
+       ISoundManager *sound = nullptr;
+       bool sound_is_dummy = false;
+       SoundMaker *soundmaker = nullptr;
+
+       ChatBackend *chat_backend = nullptr;
+       LogOutputBuffer m_chat_log_buf;
+
+       EventManager *eventmgr = nullptr;
+       QuicktuneShortcutter *quicktune = nullptr;
+       bool registration_confirmation_shown = false;
+
+       std::unique_ptr<GameUI> m_game_ui;
+       GUIChatConsole *gui_chat_console = nullptr; // Free using ->Drop()
+       CheatMenu *m_cheat_menu = nullptr;
+       MapDrawControl *draw_control = nullptr;
+       Camera *camera = nullptr;
+       Clouds *clouds = nullptr;                         // Free using ->Drop()
+       Sky *sky = nullptr;                         // Free using ->Drop()
+       Hud *hud = nullptr;
+       Minimap *mapper = nullptr;
+
+       // Map server hud ids to client hud ids
+       std::unordered_map<u32, u32> m_hud_server_to_client;
+
+       GameRunData runData;
+       Flags m_flags;
+
+       /* 'cache'
+          This class does take ownership/responsibily for cleaning up etc of any of
+          these items (e.g. device)
+       */
+       IrrlichtDevice *device;
+       RenderingEngine *m_rendering_engine;
+       video::IVideoDriver *driver;
+       scene::ISceneManager *smgr;
+       bool *kill;
+       std::string *error_message;
+       bool *reconnect_requested;
+       scene::ISceneNode *skybox;
+       PausedNodesList paused_animated_nodes;
+
+       bool simple_singleplayer_mode;
+       /* End 'cache' */
+
+       /* Pre-calculated values
+        */
+       int crack_animation_length;
+
+       IntervalLimiter profiler_interval;
+
+       /*
+        * TODO: Local caching of settings is not optimal and should at some stage
+        *       be updated to use a global settings object for getting thse values
+        *       (as opposed to the this local caching). This can be addressed in
+        *       a later release.
+        */
+       bool m_cache_doubletap_jump;
+       bool m_cache_enable_clouds;
+       bool m_cache_enable_joysticks;
+       bool m_cache_enable_particles;
+       bool m_cache_enable_fog;
+       bool m_cache_enable_noclip;
+       bool m_cache_enable_free_move;
+       f32  m_cache_mouse_sensitivity;
+       f32  m_cache_joystick_frustum_sensitivity;
+       f32  m_repeat_place_time;
+       f32  m_cache_cam_smoothing;
+       f32  m_cache_fog_start;
+
+       bool m_invert_mouse = false;
+       bool m_first_loop_after_window_activation = false;
+       bool m_camera_offset_changed = false;
+
+       bool m_does_lost_focus_pause_game = false;
+
+       CameraOrientation cam_view_target = {}; // added by dragonfireclient
+       CameraOrientation cam_view  = {};       // added by dragonfireclient
+
+#if IRRLICHT_VERSION_MT_REVISION < 5
+       int m_reset_HW_buffer_counter = 0;
+#endif
+
+#ifdef HAVE_TOUCHSCREENGUI
+       bool m_cache_hold_aux1;
+#endif
+#ifdef __ANDROID__
+       bool m_android_chat_open;
+#endif
+};
+extern Game *g_game;
 
 void the_game(bool *kill,
                InputHandler *input,
index 01c733b4f412f678f4aa70153c984d44d5c42a35..54be24ae2ac6fd7fc65fef0a31f6bb8bbb112148 100644 (file)
@@ -53,6 +53,9 @@ GameUI::GameUI()
 }
 void GameUI::init()
 {
+       m_guitext_coords = gui::StaticText::add(guienv, L"", core::rect<s32>(0, 0, 0, 0), false,
+               false, guiroot);
+
        // First line of debug text
        m_guitext = gui::StaticText::add(guienv, utf8_to_wide(PROJECT_NAME_C).c_str(),
                core::rect<s32>(0, 0, 0, 0), false, false, guiroot);
@@ -100,8 +103,25 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
        const CameraOrientation &cam, const PointedThing &pointed_old,
        const GUIChatConsole *chat_console, float dtime)
 {
+       LocalPlayer *player = client->getEnv().getLocalPlayer();
+       v3f player_position = player->getPosition();
+
        v2u32 screensize = RenderingEngine::getWindowSize();
 
+       bool show_coords = g_settings->getBool("coords");
+
+       if (show_coords) {
+               std::ostringstream os(std::ios_base::binary);
+               os << std::setprecision(1) << std::fixed
+                       << (player_position.X / BS)
+                       << ", " << (player_position.Y / BS)
+                       << ", " << (player_position.Z / BS);
+               setStaticText(m_guitext_coords, utf8_to_wide(os.str()).c_str());
+               m_guitext_coords->setRelativePosition(core::rect<s32>(5, screensize.Y - 5 - g_fontengine->getTextHeight(), screensize.X, screensize.Y));
+       }
+
+       m_guitext_coords->setVisible(show_coords);
+
        // Minimal debug text must only contain info that can't give a gameplay advantage
        if (m_flags.show_minimal_debug) {
                const u16 fps = 1.0 / stats.dtime_jitter.avg;
@@ -206,8 +226,7 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
                m_guitext_status->enableOverrideColor(true);
        }
 
-       // Hide chat when console is visible
-       m_guitext_chat->setVisible(isChatVisible() && !chat_console->isVisible());
+       m_guitext_chat->setVisible(isChatVisible());
 }
 
 void GameUI::initFlags()
@@ -238,15 +257,16 @@ void GameUI::setChatText(const EnrichedString &chat_text, u32 recent_chat_count)
 void GameUI::updateChatSize()
 {
        // Update gui element size and position
-       s32 chat_y = 5;
+
+       const v2u32 &window_size = RenderingEngine::getWindowSize();
+
+       s32 chat_y = window_size.Y - 150 - m_guitext_chat->getTextHeight();
 
        if (m_flags.show_minimal_debug)
                chat_y += g_fontengine->getLineHeight();
        if (m_flags.show_basic_debug)
                chat_y += g_fontengine->getLineHeight();
 
-       const v2u32 &window_size = RenderingEngine::getWindowSize();
-
        core::rect<s32> chat_size(10, chat_y, window_size.X - 20, 0);
        chat_size.LowerRightCorner.Y = std::min((s32)window_size.Y,
                        m_guitext_chat->getTextHeight() + chat_y);
@@ -294,6 +314,15 @@ void GameUI::toggleChat()
                showTranslatedStatusText("Chat hidden");
 }
 
+void GameUI::toggleCheatMenu()
+{
+       m_flags.show_cheat_menu = !m_flags.show_cheat_menu;
+       if (m_flags.show_cheat_menu)
+               showTranslatedStatusText("Cheat Menu shown");
+       else
+               showTranslatedStatusText("Cheat Menu hidden");
+}
+
 void GameUI::toggleHud()
 {
        m_flags.show_hud = !m_flags.show_hud;
index cc9377bdca4622ddc695edf0640eb59402b07a53..e22be068b2ced66d30cf27f85878390eef936ae7 100644 (file)
@@ -61,6 +61,7 @@ class GameUI
                bool show_minimal_debug = false;
                bool show_basic_debug = false;
                bool show_profiler_graph = false;
+               bool show_cheat_menu = true;
        };
 
        void init();
@@ -94,6 +95,7 @@ class GameUI
        void updateProfiler();
 
        void toggleChat();
+       void toggleCheatMenu();
        void toggleHud();
        void toggleProfiler();
 
@@ -114,7 +116,8 @@ class GameUI
 
        gui::IGUIStaticText *m_guitext = nullptr;  // First line of debug text
        gui::IGUIStaticText *m_guitext2 = nullptr; // Second line of debug text
-
+       gui::IGUIStaticText *m_guitext_coords = nullptr;
+       
        gui::IGUIStaticText *m_guitext_info = nullptr; // At the middle of the screen
        std::wstring m_infotext;
 
index 01f4d6ff3bfdb1b832406fabbae2d7939be88b49..d5debecfbb71ade34c6485f78609a4ed3ef925ea 100644 (file)
@@ -150,7 +150,7 @@ void Hud::drawItem(const ItemStack &item, const core::rect<s32>& rect,
                bool selected)
 {
        if (selected) {
-               /* draw hihlighting around selected item */
+               /* draw highlighting around selected item */
                if (use_hotbar_selected_image) {
                        core::rect<s32> imgrect2 = rect;
                        imgrect2.UpperLeftCorner.X  -= (m_padding*2);
index a6ba87e8d2b8526b28eab4e2bd07f3a4868ed09e..d2d81be9c9618fb144de1be649f2470442fe93fc 100644 (file)
@@ -44,6 +44,7 @@ void KeyCache::populate()
 
        key[KeyType::DROP] = getKeySetting("keymap_drop");
        key[KeyType::INVENTORY] = getKeySetting("keymap_inventory");
+       key[KeyType::ENDERCHEST] = getKeySetting("keymap_enderchest");
        key[KeyType::CHAT] = getKeySetting("keymap_chat");
        key[KeyType::CMD] = getKeySetting("keymap_cmd");
        key[KeyType::CMD_LOCAL] = getKeySetting("keymap_cmd_local");
@@ -64,6 +65,7 @@ void KeyCache::populate()
        key[KeyType::TOGGLE_HUD] = getKeySetting("keymap_toggle_hud");
        key[KeyType::TOGGLE_CHAT] = getKeySetting("keymap_toggle_chat");
        key[KeyType::TOGGLE_FOG] = getKeySetting("keymap_toggle_fog");
+       key[KeyType::TOGGLE_CHEAT_MENU] = getKeySetting("keymap_toggle_cheat_menu");
        key[KeyType::TOGGLE_UPDATE_CAMERA] = getKeySetting("keymap_toggle_update_camera");
        key[KeyType::TOGGLE_DEBUG] = getKeySetting("keymap_toggle_debug");
        key[KeyType::TOGGLE_PROFILER] = getKeySetting("keymap_toggle_profiler");
@@ -74,6 +76,14 @@ void KeyCache::populate()
                        getKeySetting("keymap_decrease_viewing_range_min");
        key[KeyType::RANGESELECT] = getKeySetting("keymap_rangeselect");
        key[KeyType::ZOOM] = getKeySetting("keymap_zoom");
+       key[KeyType::KILLAURA] = getKeySetting("keymap_toggle_killaura");
+       key[KeyType::FREECAM] = getKeySetting("keymap_toggle_freecam");
+       key[KeyType::SCAFFOLD] = getKeySetting("keymap_toggle_scaffold");
+       key[KeyType::SELECT_UP] = getKeySetting("keymap_select_up");
+       key[KeyType::SELECT_DOWN] = getKeySetting("keymap_select_down");
+       key[KeyType::SELECT_LEFT] = getKeySetting("keymap_select_left");
+       key[KeyType::SELECT_RIGHT] = getKeySetting("keymap_select_right");
+       key[KeyType::SELECT_CONFIRM] = getKeySetting("keymap_select_confirm");
 
        key[KeyType::QUICKTUNE_NEXT] = getKeySetting("keymap_quicktune_next");
        key[KeyType::QUICKTUNE_PREV] = getKeySetting("keymap_quicktune_prev");
index 3db105c518ecf6d066d1436247b6f558e3f1f21c..47a61d4b85ba86f6b5f454295170ab2ccfcdae6b 100644 (file)
@@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #endif
 
 class InputHandler;
+class TouchScreenGUI;
 
 /****************************************************************************
  Fast key cache for main game loop
@@ -201,7 +202,6 @@ class MyEventReceiver : public IEventReceiver
        TouchScreenGUI *m_touchscreengui;
 #endif
 
-private:
        s32 mouse_wheel = 0;
 
        // The current state of keys
@@ -241,6 +241,8 @@ class InputHandler
        }
 
        virtual bool isKeyDown(GameKeyType k) = 0;
+       virtual void setKeypress(const KeyPress &keyCode) = 0;
+       virtual void unsetKeypress(const KeyPress &keyCode) = 0;
        virtual bool wasKeyDown(GameKeyType k) = 0;
        virtual bool wasKeyPressed(GameKeyType k) = 0;
        virtual bool wasKeyReleased(GameKeyType k) = 0;
@@ -288,6 +290,15 @@ class RealInputHandler : public InputHandler
        {
                return m_receiver->IsKeyDown(keycache.key[k]) || joystick.isKeyDown(k);
        }
+       virtual void setKeypress(const KeyPress &keyCode)
+       {
+               m_receiver->keyIsDown.set(keyCode);
+               m_receiver->keyWasDown.set(keyCode);
+       }
+       virtual void unsetKeypress(const KeyPress &keyCode)
+       {
+               m_receiver->keyIsDown.unset(keyCode);
+       }
        virtual bool wasKeyDown(GameKeyType k)
        {
                return m_receiver->WasKeyDown(keycache.key[k]) || joystick.wasKeyDown(k);
@@ -411,6 +422,14 @@ class RandomInputHandler : public InputHandler
        }
 
        virtual bool isKeyDown(GameKeyType k) { return keydown[keycache.key[k]]; }
+       virtual void setKeypress(const KeyPress &keyCode)
+       {
+               keydown.set(keyCode);
+       }
+       virtual void unsetKeypress(const KeyPress &keyCode)
+       {
+               keydown.unset(keyCode);
+       }
        virtual bool wasKeyDown(GameKeyType k) { return false; }
        virtual bool wasKeyPressed(GameKeyType k) { return false; }
        virtual bool wasKeyReleased(GameKeyType k) { return false; }
index e120a2d927c49ba6d35849d305590aa70edfb288..b81b571b2037f01cb2ba65cfa1ea21cf6a9aef47 100644 (file)
@@ -43,6 +43,7 @@ class KeyType
                // Other
                DROP,
                INVENTORY,
+               ENDERCHEST,
                CHAT,
                CMD,
                CMD_LOCAL,
@@ -63,6 +64,7 @@ class KeyType
                TOGGLE_HUD,
                TOGGLE_CHAT,
                TOGGLE_FOG,
+               TOGGLE_CHEAT_MENU,
                TOGGLE_UPDATE_CAMERA,
                TOGGLE_DEBUG,
                TOGGLE_PROFILER,
@@ -71,7 +73,15 @@ class KeyType
                DECREASE_VIEWING_RANGE,
                RANGESELECT,
                ZOOM,
-
+               KILLAURA,
+               FREECAM,
+               SCAFFOLD,
+               SELECT_UP,
+               SELECT_DOWN,
+               SELECT_LEFT,
+               SELECT_RIGHT,
+               SELECT_CONFIRM,
+       
                QUICKTUNE_NEXT,
                QUICKTUNE_PREV,
                QUICKTUNE_INC,
index 279efafe936265a7021ed1d224f068c9dff1fd2d..c4d9b98457d6c10574b5e7aec07e964c2db52d60 100644 (file)
@@ -27,6 +27,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "map.h"
 #include "client.h"
 #include "content_cao.h"
+#include "util/pointedthing.h"
+#include "client/game.h"
 
 /*
        LocalPlayer
@@ -87,7 +89,7 @@ bool LocalPlayer::updateSneakNode(Map *map, const v3f &position,
                new_sneak_node_exists = false;
        } else {
                node = map->getNode(current_node, &is_valid_position);
-               if (!is_valid_position || !nodemgr->get(node).walkable)
+               if (!is_valid_position || nodemgr->get(node).walkable)
                        new_sneak_node_exists = false;
        }
 
@@ -113,7 +115,7 @@ bool LocalPlayer::updateSneakNode(Map *map, const v3f &position,
 
                // The node to be sneaked on has to be walkable
                node = map->getNode(p, &is_valid_position);
-               if (!is_valid_position || !nodemgr->get(node).walkable)
+               if (!is_valid_position || ! nodemgr->get(node).walkable)
                        continue;
                // And the node(s) above have to be nonwalkable
                bool ok = true;
@@ -130,7 +132,7 @@ bool LocalPlayer::updateSneakNode(Map *map, const v3f &position,
                } else {
                        // legacy behaviour: check just one node
                        node = map->getNode(p + v3s16(0, 1, 0), &is_valid_position);
-                       ok = is_valid_position && !nodemgr->get(node).walkable;
+                       ok = is_valid_position && ! nodemgr->get(node).walkable;
                }
                if (!ok)
                        continue;
@@ -159,7 +161,7 @@ bool LocalPlayer::updateSneakNode(Map *map, const v3f &position,
                        node = map->getNode(m_sneak_node + v3s16(0, 3, 0),
                                &is_valid_position);
                        m_sneak_ladder_detected = is_valid_position &&
-                               !nodemgr->get(node).walkable;
+                               ! nodemgr->get(node).walkable;
                }
        }
        return true;
@@ -168,6 +170,9 @@ bool LocalPlayer::updateSneakNode(Map *map, const v3f &position,
 void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
                std::vector<CollisionInfo> *collision_info)
 {
+       if (m_cao && m_cao->m_waiting_for_reattach > 0)
+               m_cao->m_waiting_for_reattach -= dtime;
+
        // Node at feet position, update each ClientEnvironment::step()
        if (!collision_info || collision_info->empty())
                m_standing_node = floatToInt(m_position, BS);
@@ -193,9 +198,9 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
        PlayerSettings &player_settings = getPlayerSettings();
 
        // Skip collision detection if noclip mode is used
-       bool fly_allowed = m_client->checkLocalPrivilege("fly");
-       bool noclip = m_client->checkLocalPrivilege("noclip") && player_settings.noclip;
-       bool free_move = player_settings.free_move && fly_allowed;
+       bool fly_allowed = m_client->checkLocalPrivilege("fly") || g_settings->getBool("freecam");
+       bool noclip = (m_client->checkLocalPrivilege("noclip") && player_settings.noclip) || g_settings->getBool("freecam");
+       bool free_move = (player_settings.free_move && fly_allowed) || g_settings->getBool("freecam");
 
        if (noclip && free_move) {
                position += m_speed * dtime;
@@ -276,6 +281,25 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
                        nodemgr->get(node2.getContent()).climbable) && !free_move;
        }
 
+       if (!is_climbing && !free_move && g_settings->getBool("spider")) {
+               v3s16 spider_positions[4] = {
+                       floatToInt(position + v3f(+1.0f, +0.0f,  0.0f) * BS, BS),
+                       floatToInt(position + v3f(-1.0f, +0.0f,  0.0f) * BS, BS),
+                       floatToInt(position + v3f( 0.0f, +0.0f, +1.0f) * BS, BS),
+                       floatToInt(position + v3f( 0.0f, +0.0f, -1.0f) * BS, BS),
+               };
+
+               for (v3s16 sp : spider_positions) {
+                       bool is_valid;
+                       MapNode node = map->getNode(sp, &is_valid);
+
+                       if (is_valid && nodemgr->get(node.getContent()).walkable) {
+                               is_climbing = true;
+                               break;
+                       }
+               }
+       }
+
        /*
                Collision uncertainty radius
                Make it a bit larger than the maximum distance of movement
@@ -298,7 +322,7 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
 
        collisionMoveResult result = collisionMoveSimple(env, m_client,
                pos_max_d, m_collisionbox, player_stepheight, dtime,
-               &position, &m_speed, accel_f);
+               &position, &m_speed, accel_f, NULL, true, true);
 
        bool could_sneak = control.sneak && !free_move && !in_liquid &&
                !is_climbing && physics_override_sneak;
@@ -337,7 +361,7 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
                Player is allowed to jump when this is true.
        */
        bool touching_ground_was = touching_ground;
-       touching_ground = result.touching_ground;
+       touching_ground = result.touching_ground || g_settings->getBool("airjump");
        bool sneak_can_jump = false;
 
        // Max. distance (X, Z) over border for sneaking determined by collision box
@@ -495,8 +519,8 @@ void LocalPlayer::applyControl(float dtime, Environment *env)
        bool fly_allowed = m_client->checkLocalPrivilege("fly");
        bool fast_allowed = m_client->checkLocalPrivilege("fast");
 
-       bool free_move = fly_allowed && player_settings.free_move;
-       bool fast_move = fast_allowed && player_settings.fast_move;
+       bool free_move = (fly_allowed && player_settings.free_move) || g_settings->getBool("freecam");
+       bool fast_move = (fast_allowed && player_settings.fast_move) || g_settings->getBool("freecam");
        bool pitch_move = (free_move || in_liquid) && player_settings.pitch_move;
        // When aux1_descends is enabled the fast key is used to go down, so fast isn't possible
        bool fast_climb = fast_move && control.aux1 && !player_settings.aux1_descends;
@@ -590,14 +614,14 @@ void LocalPlayer::applyControl(float dtime, Environment *env)
                                else
                                        speedV.Y = movement_speed_walk;
                        }
-               } else if (m_can_jump) {
+               } else if (m_can_jump || g_settings->getBool("jetpack")) {
                        /*
                                NOTE: The d value in move() affects jump height by
                                raising the height at which the jump speed is kept
                                at its starting value
                        */
                        v3f speedJ = getSpeed();
-                       if (speedJ.Y >= -0.5f * BS) {
+                       if (speedJ.Y >= -0.5f * BS || g_settings->getBool("jetpack")) {
                                speedJ.Y = movement_speed_jump * physics_override_jump;
                                setSpeed(speedJ);
                                m_client->getEventManager()->put(new SimpleTriggerEvent(MtEvent::PLAYER_JUMP));
@@ -620,7 +644,7 @@ void LocalPlayer::applyControl(float dtime, Environment *env)
        if (superspeed || (is_climbing && fast_climb) ||
                        ((in_liquid || in_liquid_stable) && fast_climb))
                speedH = speedH.normalize() * movement_speed_fast;
-       else if (control.sneak && !free_move && !in_liquid && !in_liquid_stable)
+       else if (control.sneak && !free_move && !in_liquid && !in_liquid_stable && !g_settings->getBool("no_slow"))
                speedH = speedH.normalize() * movement_speed_crouch;
        else
                speedH = speedH.normalize() * movement_speed_walk;
@@ -694,6 +718,16 @@ v3s16 LocalPlayer::getLightPosition() const
        return floatToInt(m_position + v3f(0.0f, BS * 1.5f, 0.0f), BS);
 }
 
+v3f LocalPlayer::getSendSpeed()
+{
+       v3f speed = getLegitSpeed();
+
+       if (m_client->modsLoaded())
+               speed = m_client->getScript()->get_send_speed(speed);
+
+       return speed;
+}
+
 v3f LocalPlayer::getEyeOffset() const
 {
        float eye_height = camera_barely_in_ceiling ? m_eye_height - 0.125f : m_eye_height;
@@ -702,7 +736,7 @@ v3f LocalPlayer::getEyeOffset() const
 
 ClientActiveObject *LocalPlayer::getParent() const
 {
-       return m_cao ? m_cao->getParent() : nullptr;
+       return (m_cao && ! g_settings->getBool("entity_speed")) ? m_cao->getParent() : nullptr;
 }
 
 bool LocalPlayer::isDead() const
@@ -711,6 +745,18 @@ bool LocalPlayer::isDead() const
        return !getCAO()->isImmortal() && hp == 0;
 }
 
+void LocalPlayer::tryReattach(int id)
+{
+       PointedThing pointed(id, v3f(0, 0, 0), v3s16(0, 0, 0), 0);
+       m_client->interact(INTERACT_PLACE, pointed);
+       m_cao->m_waiting_for_reattach = 10;
+}
+
+bool LocalPlayer::isWaitingForReattach() const
+{
+       return g_settings->getBool("entity_speed") && m_cao && ! m_cao->getParent() && m_cao->m_waiting_for_reattach > 0;
+}
+
 // 3D acceleration
 void LocalPlayer::accelerate(const v3f &target_speed, const f32 max_increase_H,
        const f32 max_increase_V, const bool use_pitch)
@@ -773,9 +819,9 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
        PlayerSettings &player_settings = getPlayerSettings();
 
        // Skip collision detection if noclip mode is used
-       bool fly_allowed = m_client->checkLocalPrivilege("fly");
-       bool noclip = m_client->checkLocalPrivilege("noclip") && player_settings.noclip;
-       bool free_move = noclip && fly_allowed && player_settings.free_move;
+       bool fly_allowed = m_client->checkLocalPrivilege("fly") || g_settings->getBool("freecam");
+       bool noclip = (m_client->checkLocalPrivilege("noclip") && player_settings.noclip) || g_settings->getBool("freecam");
+       bool free_move = (noclip && fly_allowed && player_settings.free_move) || g_settings->getBool("freecam");
        if (free_move) {
                position += m_speed * dtime;
                setPosition(position);
@@ -896,7 +942,7 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
 
        collisionMoveResult result = collisionMoveSimple(env, m_client,
                pos_max_d, m_collisionbox, player_stepheight, dtime,
-               &position, &m_speed, accel_f);
+               &position, &m_speed, accel_f, NULL, true, true);
 
        // Positition was slightly changed; update standing node pos
        if (touching_ground)
@@ -1075,7 +1121,7 @@ float LocalPlayer::getSlipFactor(Environment *env, const v3f &speedH)
        Map *map = &env->getMap();
        const ContentFeatures &f = nodemgr->get(map->getNode(getStandingNodePos()));
        int slippery = 0;
-       if (f.walkable)
+       if (f.walkable && ! g_settings->getBool("antislip"))
                slippery = itemgroup_get(f.groups, "slippery");
 
        if (slippery >= 1) {
@@ -1144,7 +1190,7 @@ void LocalPlayer::handleAutojump(f32 dtime, Environment *env,
 
        // try at peak of jump, zero step height
        collisionMoveResult jump_result = collisionMoveSimple(env, m_client, pos_max_d,
-               m_collisionbox, 0.0f, dtime, &jump_pos, &jump_speed, v3f(0.0f));
+               m_collisionbox, 0.0f, dtime, &jump_pos, &jump_speed, v3f(0.0f), NULL, true, true);
 
        // see if we can get a little bit farther horizontally if we had
        // jumped
@@ -1157,3 +1203,4 @@ void LocalPlayer::handleAutojump(f32 dtime, Environment *env,
                m_autojump_time = 0.1f;
        }
 }
+
index 3d0072fc1110f025607b4786db416db1c973fc30..ebc67c4f8c7849844375ca3bacbb60cb3fcb146a 100644 (file)
@@ -32,6 +32,7 @@ class GenericCAO;
 class ClientActiveObject;
 class ClientEnvironment;
 class IGameDef;
+struct ContentFeatures;
 struct collisionMoveResult;
 
 enum LocalPlayerAnimations
@@ -132,11 +133,39 @@ class LocalPlayer : public Player
        inline void setPosition(const v3f &position)
        {
                m_position = position;
+               if (! m_freecam)
+                       m_legit_position = position;
                m_sneak_node_exists = false;
        }
 
        v3f getPosition() const { return m_position; }
 
+       v3f getLegitPosition() const { return m_legit_position; }
+
+       v3f getLegitSpeed() const { return m_freecam ? m_legit_speed : m_speed; }
+
+       v3f getSendSpeed();
+
+       inline void setLegitPosition(const v3f &position)
+       {
+               if (m_freecam)
+                       m_legit_position = position;
+               else
+                       setPosition(position);
+       }
+
+       inline void freecamEnable()
+       {
+               m_freecam = true;
+       }
+
+       inline void freecamDisable()
+       {
+               m_freecam = false;
+               setPosition(m_legit_position);
+               setSpeed(m_legit_speed);
+       }
+
        // Non-transformed eye offset getters
        // For accurate positions, use the Camera functions
        v3f getEyePosition() const { return m_position + getEyeOffset(); }
@@ -161,6 +190,12 @@ class LocalPlayer : public Player
 
        inline Lighting& getLighting() { return m_lighting; }
 
+       void tryReattach(int id);
+
+       bool isWaitingForReattach() const;
+
+       bool canWalkOn(const ContentFeatures &f);
+
 private:
        void accelerate(const v3f &target_speed, const f32 max_increase_H,
                const f32 max_increase_V, const bool use_pitch);
@@ -171,7 +206,10 @@ class LocalPlayer : public Player
                const v3f &position_before_move, const v3f &speed_before_move,
                f32 pos_max_d);
 
+       bool m_freecam = false;
        v3f m_position;
+       v3f m_legit_position;
+       v3f m_legit_speed;
        v3s16 m_standing_node;
 
        v3s16 m_sneak_node = v3s16(32767, 32767, 32767);
index 3be9e13b89558b0beb51ce3e760855e554b74e32..263601121d723d114b803b3efaca4d57be40d236 100644 (file)
@@ -88,7 +88,7 @@ void MeshMakeData::setCrack(int crack_level, v3s16 crack_pos)
 
 void MeshMakeData::setSmoothLighting(bool smooth_lighting)
 {
-       m_smooth_lighting = smooth_lighting;
+       m_smooth_lighting = smooth_lighting && ! g_settings->getBool("fullbright");
 }
 
 /*
@@ -105,6 +105,8 @@ static u8 getInteriorLight(enum LightBank bank, MapNode n, s32 increment,
        u8 light = n.getLight(bank, ndef);
        if (light > 0)
                light = rangelim(light + increment, 0, LIGHT_SUN);
+       if(g_settings->getBool("fullbright"))
+               return 255;
        return decode_light(light);
 }
 
@@ -139,7 +141,8 @@ static u8 getFaceLight(enum LightBank bank, MapNode n, MapNode n2,
                        ndef->get(n2).light_source);
        if(light_source > light)
                light = light_source;
-
+       if(g_settings->getBool("fullbright"))
+               return 255;
        return decode_light(light);
 }
 
@@ -657,6 +660,7 @@ static u8 face_contents(content_t m1, content_t m2, bool *equivalent,
        u8 c1 = f1.solidness;
        u8 c2 = f2.solidness;
 
+
        if (c1 == c2)
                return 0;
 
@@ -665,6 +669,7 @@ static u8 face_contents(content_t m1, content_t m2, bool *equivalent,
        else if (c2 == 0)
                c2 = f2.visual_solidness;
 
+
        if (c1 == c2) {
                *equivalent = true;
                // If same solidness, liquid takes precense
@@ -764,6 +769,24 @@ void getNodeTile(MapNode mn, const v3s16 &p, const v3s16 &dir, MeshMakeData *dat
        tile.rotation = tile.world_aligned ? 0 : dir_to_tile[tile_index + 1];
 }
 
+std::set<content_t> splitToContentT(std::string str, const NodeDefManager *ndef)
+{
+       str += "\n";
+       std::set<content_t> dat;
+       std::string buf;
+       for (char c : str) {
+               if (c == ',' || c == '\n') {
+                       if (! buf.empty()) {
+                               dat.insert(ndef->getId(buf));
+                       }
+                       buf.clear();
+               } else if (c != ' ') {
+                       buf += c;
+               }
+       }
+       return dat;
+}
+
 static void getTileInfo(
                // Input:
                MeshMakeData *data,
@@ -775,8 +798,10 @@ static void getTileInfo(
                v3s16 &face_dir_corrected,
                u16 *lights,
                u8 &waving,
-               TileSpec &tile
-       )
+               TileSpec &tile,
+               // lol more Input
+               bool xray,
+               std::set<content_t> xraySet)
 {
        VoxelManipulator &vmanip = data->m_vmanip;
        const NodeDefManager *ndef = data->m_client->ndef();
@@ -784,22 +809,29 @@ static void getTileInfo(
 
        const MapNode &n0 = vmanip.getNodeRefUnsafe(blockpos_nodes + p);
 
+       content_t c0 = n0.getContent();
+       if (xray && xraySet.find(c0) != xraySet.end())
+               c0 = CONTENT_AIR;
        // Don't even try to get n1 if n0 is already CONTENT_IGNORE
-       if (n0.getContent() == CONTENT_IGNORE) {
+       if (c0 == CONTENT_IGNORE) {
                makes_face = false;
                return;
        }
 
        const MapNode &n1 = vmanip.getNodeRefUnsafeCheckFlags(blockpos_nodes + p + face_dir);
 
-       if (n1.getContent() == CONTENT_IGNORE) {
+       content_t c1 = n1.getContent();
+       if (xray && xraySet.find(c1) != xraySet.end())
+               c1 = CONTENT_AIR;
+
+       if (c1 == CONTENT_IGNORE) {
                makes_face = false;
                return;
        }
 
        // This is hackish
        bool equivalent = false;
-       u8 mf = face_contents(n0.getContent(), n1.getContent(),
+       u8 mf = face_contents(c0, c1,
                        &equivalent, ndef);
 
        if (mf == 0) {
@@ -855,7 +887,9 @@ static void updateFastFaceRow(
                v3s16 translate_dir,
                const v3f &&translate_dir_f,
                const v3s16 &&face_dir,
-               std::vector<FastFace> &dest)
+               std::vector<FastFace> &dest,
+               bool xray,
+               std::set<content_t> xraySet)
 {
        static thread_local const bool waving_liquids =
                g_settings->getBool("enable_shaders") &&
@@ -878,7 +912,7 @@ static void updateFastFaceRow(
        // Get info of first tile
        getTileInfo(data, p, face_dir,
                        makes_face, p_corrected, face_dir_corrected,
-                       lights, waving, tile);
+                       lights, waving, tile, xray, xraySet);
 
        // Unroll this variable which has a significant build cost
        TileSpec next_tile;
@@ -900,7 +934,9 @@ static void updateFastFaceRow(
                                        next_makes_face, next_p_corrected,
                                        next_face_dir_corrected, next_lights,
                                        waving,
-                                       next_tile);
+                                       next_tile,
+                                       xray,
+                                       xraySet);
 
                        if (!force_not_tiling
                                        && next_makes_face == makes_face
@@ -951,7 +987,7 @@ static void updateFastFaceRow(
 }
 
 static void updateAllFastFaceRows(MeshMakeData *data,
-               std::vector<FastFace> &dest)
+               std::vector<FastFace> &dest, bool xray, std::set<content_t> xraySet)
 {
        /*
                Go through every y,z and get top(y+) faces in rows of x+
@@ -963,7 +999,9 @@ static void updateAllFastFaceRows(MeshMakeData *data,
                                v3s16(1, 0, 0), //dir
                                v3f  (1, 0, 0),
                                v3s16(0, 1, 0), //face dir
-                               dest);
+                               dest,
+                               xray,
+                               xraySet);
 
        /*
                Go through every x,y and get right(x+) faces in rows of z+
@@ -975,7 +1013,9 @@ static void updateAllFastFaceRows(MeshMakeData *data,
                                v3s16(0, 0, 1), //dir
                                v3f  (0, 0, 1),
                                v3s16(1, 0, 0), //face dir
-                               dest);
+                               dest,
+                               xray,
+                               xraySet);
 
        /*
                Go through every y,z and get back(z+) faces in rows of x+
@@ -987,7 +1027,9 @@ static void updateAllFastFaceRows(MeshMakeData *data,
                                v3s16(1, 0, 0), //dir
                                v3f  (1, 0, 0),
                                v3s16(0, 0, 1), //face dir
-                               dest);
+                               dest,
+                               xray,
+                               xraySet);
 }
 
 static void applyTileColor(PreMeshBuffer &pmb)
@@ -1201,6 +1243,15 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
 
        std::vector<FastFace> fastfaces_new;
        fastfaces_new.reserve(512);
+       /*
+               X-Ray
+       */
+       bool xray = g_settings->getBool("xray");
+       std::set<content_t> xraySet, nodeESPSet;
+       if (xray)
+               xraySet = splitToContentT(g_settings->get("xray_nodes"), data->m_client->ndef());
+
+       nodeESPSet = splitToContentT(g_settings->get("node_esp_nodes"), data->m_client->ndef());
 
        /*
                We are including the faces of the trailing edges of the block.
@@ -1212,10 +1263,27 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
        {
                // 4-23ms for MAP_BLOCKSIZE=16  (NOTE: probably outdated)
                //TimeTaker timer2("updateAllFastFaceRows()");
-               updateAllFastFaceRows(data, fastfaces_new);
+               updateAllFastFaceRows(data, fastfaces_new, xray, xraySet);
        }
        // End of slow part
 
+       /*
+               NodeESP
+       */
+       {
+               v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
+               for (s16 x = 0; x < MAP_BLOCKSIZE; x++) {
+                       for (s16 y = 0; y < MAP_BLOCKSIZE; y++) {
+                               for (s16 z = 0; z < MAP_BLOCKSIZE; z++) {
+                                       v3s16 pos = v3s16(x, y, z) + blockpos_nodes;
+                                       const MapNode &node = data->m_vmanip.getNodeRefUnsafeCheckFlags(pos);
+                                       if (nodeESPSet.find(node.getContent()) != nodeESPSet.end())
+                                               esp_nodes.insert(pos);
+                               }
+                       }
+               }
+       }
+
        /*
                Convert FastFaces to MeshCollector
        */
index 169b3a8c12ec2328babf63f177b70602fdbc129b..8133627b1ed13cc6423a80cd8b9a3eb405c72284 100644 (file)
@@ -231,6 +231,8 @@ class MapBlockMesh
                return this->m_transparent_buffers;
        }
 
+       std::set<v3s16> esp_nodes;
+
 private:
        struct AnimationInfo {
                int frame; // last animation frame
index 1b734bc0614e35c5e3de747c098dd4f26b84c4b1..2ef69595449b8d519b1c9608a7f5c2d148ebfe32 100644 (file)
@@ -125,6 +125,6 @@ class MeshUpdateThread : public UpdateThread
        // TODO: Add callback to update these when g_settings changes
        int m_generation_interval;
 
-protected:
+public:
        virtual void doUpdate();
 };
index 320621d914cc41a5d9746a41a2088babb10b3440..9bb9d14e0ff5c2e513450aaa7451350dc642a835 100644 (file)
@@ -581,8 +581,8 @@ void Minimap::drawMinimap()
        const u32 size = 0.25 * screensize.Y;
 
        drawMinimap(core::rect<s32>(
-               screensize.X - size - 10, 10,
-               screensize.X - 10, size + 10));
+               screensize.X - size * 2 - 10, 10,
+               screensize.X - size - 10, size + 10));
 }
 
 void Minimap::drawMinimap(core::rect<s32> rect) {
index 55cc4e490b023417a09228e0af3baae626a4905b..9927e2589a97208c066ee85d6b621bdcbea15e78 100644 (file)
@@ -18,12 +18,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
 
+#include <iostream>
 #include "core.h"
 #include "client/camera.h"
 #include "client/client.h"
 #include "client/clientmap.h"
 #include "client/hud.h"
 #include "client/minimap.h"
+#include "client/content_cao.h"
+#include "mapblock.h"
+#include "mapsector.h"
 #include "client/shadows/dynamicshadowsrender.h"
 
 RenderingCore::RenderingCore(IrrlichtDevice *_device, Client *_client, Hud *_hud)
@@ -75,6 +79,16 @@ void RenderingCore::draw(video::SColor _skycolor, bool _show_hud, bool _show_min
        show_minimap = _show_minimap;
        draw_wield_tool = _draw_wield_tool;
        draw_crosshair = _draw_crosshair;
+       draw_entity_esp = g_settings->getBool("enable_entity_esp");
+       draw_entity_tracers = g_settings->getBool("enable_entity_tracers");
+       draw_player_esp = g_settings->getBool("enable_player_esp");
+       draw_player_tracers = g_settings->getBool("enable_player_tracers");
+       draw_node_esp = g_settings->getBool("enable_node_esp");
+       draw_node_tracers = g_settings->getBool("enable_node_tracers");
+       v3f entity_color = g_settings->getV3F("entity_esp_color");
+       v3f player_color = g_settings->getV3F("player_esp_color");
+       entity_esp_color = video::SColor(255, entity_color.X, entity_color.Y, entity_color.Z);
+       player_esp_color = video::SColor(255, player_color.X, player_color.Y, player_color.Z);
 
        if (shadow_renderer) {
                // This is necessary to render shadows for animations correctly
@@ -86,6 +100,79 @@ void RenderingCore::draw(video::SColor _skycolor, bool _show_hud, bool _show_min
        drawAll();
 }
 
+void RenderingCore::drawTracersAndESP()
+{
+       ClientEnvironment &env = client->getEnv();
+       Camera *camera = client->getCamera();
+
+       v3f camera_offset = intToFloat(camera->getOffset(), BS);
+
+       v3f eye_pos = (camera->getPosition() + camera->getDirection() - camera_offset);
+
+       video::SMaterial material, oldmaterial;
+       oldmaterial = driver->getMaterial2D();
+       material.setFlag(video::EMF_LIGHTING, false);
+       material.setFlag(video::EMF_BILINEAR_FILTER, false);
+       material.setFlag(video::EMF_ZBUFFER, false);
+       material.setFlag(video::EMF_ZWRITE_ENABLE, false);
+       driver->setMaterial(material);
+
+       if (draw_entity_esp || draw_entity_tracers || draw_player_esp || draw_player_tracers) {
+               auto allObjects = env.getAllActiveObjects();
+               for (auto &it : allObjects) {
+                       ClientActiveObject *cao = it.second;
+                       if (cao->isLocalPlayer() || cao->getParent())
+                               continue;
+                       GenericCAO *obj = dynamic_cast<GenericCAO *>(cao);
+                       if (! obj)
+                               continue;
+                       bool is_player = obj->isPlayer();
+                       bool draw_esp = is_player ? draw_player_esp : draw_entity_esp;
+                       bool draw_tracers = is_player ? draw_player_tracers : draw_entity_tracers;
+                       video::SColor color = is_player ? player_esp_color : entity_esp_color;
+                       if (! (draw_esp || draw_tracers))
+                               continue;
+                       aabb3f box;
+                       if (! obj->getSelectionBox(&box))
+                               continue;
+                       v3f pos = obj->getPosition() - camera_offset;
+                       box.MinEdge += pos;
+                       box.MaxEdge += pos;
+                       if (draw_esp)
+                               driver->draw3DBox(box, color);
+                       if (draw_tracers)
+                               driver->draw3DLine(eye_pos, box.getCenter(), color);
+               }
+       }
+       if (draw_node_esp || draw_node_tracers) {
+               Map &map = env.getMap();
+               std::vector<v3s16> positions;
+               map.listAllLoadedBlocks(positions);
+               for (v3s16 blockp : positions) {
+                       MapBlock *block = map.getBlockNoCreate(blockp);
+                       if (! block->mesh)
+                               continue;
+                       for (v3s16 p : block->mesh->esp_nodes) {
+                               v3f pos = intToFloat(p, BS) - camera_offset;
+                               MapNode node = map.getNode(p);
+                               std::vector<aabb3f> boxes;
+                               node.getSelectionBoxes(client->getNodeDefManager(), &boxes, node.getNeighbors(p, &map));
+                               video::SColor color = client->getNodeDefManager()->get(node).minimap_color;
+                               for (aabb3f box : boxes) {
+                                       box.MinEdge += pos;
+                                       box.MaxEdge += pos;
+                                       if (draw_node_esp)
+                                               driver->draw3DBox(box, color);
+                                       if (draw_node_tracers)
+                                               driver->draw3DLine(eye_pos, box.getCenter(), color);
+                               }
+                       }
+               }
+       }
+
+       driver->setMaterial(oldmaterial);
+}
+
 void RenderingCore::draw3D()
 {
        smgr->drawAll();
@@ -97,6 +184,8 @@ void RenderingCore::draw3D()
                return;
        hud->drawBlockBounds();
        hud->drawSelectionMesh();
+       if (draw_entity_esp || draw_entity_tracers || draw_player_esp || draw_player_tracers || draw_node_esp || draw_node_tracers)
+               drawTracersAndESP();
        if (draw_wield_tool)
                camera->drawWieldedTool();
 }
index cabfbbfad95181f3b7fffbff2cabcd214ab5d0af..0864f25bd6eb2edb2e9e24f87f45258754128e01 100644 (file)
@@ -37,6 +37,14 @@ class RenderingCore
        bool show_minimap;
        bool draw_wield_tool;
        bool draw_crosshair;
+       bool draw_entity_esp;
+       bool draw_entity_tracers;
+       bool draw_player_esp;
+       bool draw_player_tracers;
+       bool draw_node_esp;
+       bool draw_node_tracers;
+       video::SColor entity_esp_color;
+       video::SColor player_esp_color;
 
        IrrlichtDevice *device;
        video::IVideoDriver *driver;
@@ -57,6 +65,7 @@ class RenderingCore
        virtual void beforeDraw() {}
        virtual void drawAll() = 0;
 
+       void drawTracersAndESP();
        void draw3D();
        void drawHUD();
        void drawPostFx();
index 7afca45004882363b86e7404c334760dc154c67d..224efce3ec4a9879890f62eccc555417dfbfa1a6 100644 (file)
@@ -303,15 +303,14 @@ bool RenderingEngine::setWindowIcon()
 #if defined(XORG_USED)
 #if RUN_IN_PLACE
        return setXorgWindowIconFromPath(
-                       porting::path_share + "/misc/" PROJECT_NAME "-xorg-icon-128.png");
+                       porting::path_share + "/misc/dragonfire-xorg-icon-128.png");
 #else
        // We have semi-support for reading in-place data if we are
        // compiled with RUN_IN_PLACE. Don't break with this and
        // also try the path_share location.
        return setXorgWindowIconFromPath(
-                              ICON_DIR "/hicolor/128x128/apps/" PROJECT_NAME ".png") ||
-              setXorgWindowIconFromPath(porting::path_share + "/misc/" PROJECT_NAME
-                                                              "-xorg-icon-128.png");
+                              ICON_DIR "/hicolor/128x128/apps/dragonfire.png") ||
+              setXorgWindowIconFromPath(porting::path_share + "/misc/dragonfire-xorg-icon-128.png");
 #endif
 #elif defined(_WIN32)
        HWND hWnd; // Window handle
index be135a2256a1fb686e83eab8e5ebfdf79beb12ee..4f2cba2636d0b839b2ae5331d961b137e933f948 100644 (file)
@@ -227,7 +227,7 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
                f32 stepheight, f32 dtime,
                v3f *pos_f, v3f *speed_f,
                v3f accel_f, ActiveObject *self,
-               bool collideWithObjects)
+               bool collideWithObjects, bool jesus)
 {
        static bool time_notification_done = false;
        Map *map = &env->getMap();
@@ -285,6 +285,7 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
        v3s16 max = floatToInt(maxpos_f + box_0.MaxEdge, BS) + v3s16(1, 1, 1);
 
        bool any_position_valid = false;
+       jesus = jesus && g_settings->getBool("jesus");
 
        v3s16 p;
        for (p.X = min.X; p.X <= max.X; p.X++)
@@ -300,7 +301,7 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
                        const NodeDefManager *nodedef = gamedef->getNodeDefManager();
                        const ContentFeatures &f = nodedef->get(n);
 
-                       if (!f.walkable)
+                       if (!(f.walkable || (jesus && f.isLiquid())))
                                continue;
 
                        // Negative bouncy may have a meaning, but we need +value here.
index 87a50282870c11cb5075bce68a99a50f7c496a95..998598f1ea387b6f7c3a96b657db32dc4564a586 100644 (file)
@@ -70,7 +70,7 @@ collisionMoveResult collisionMoveSimple(Environment *env,IGameDef *gamedef,
                f32 stepheight, f32 dtime,
                v3f *pos_f, v3f *speed_f,
                v3f accel_f, ActiveObject *self=NULL,
-               bool collideWithObjects=true);
+               bool collideWithObjects=true, bool jesus=false);
 
 // Helper function:
 // Checks for collision of a moving aabbox with a static aabbox
index 0087f8d48e3b54e3b9f80c519de6dc45a9f6b301..9224d99ed0d5cb24b531b7c1e1f53096787699fe 100644 (file)
@@ -55,18 +55,78 @@ void set_default_settings()
        settings->setDefault("screenshot_quality", "0");
        settings->setDefault("client_unload_unused_data_timeout", "600");
        settings->setDefault("client_mapblock_limit", "7500");
-       settings->setDefault("enable_build_where_you_stand", "false");
+       settings->setDefault("enable_build_where_you_stand", "true");
        settings->setDefault("curl_timeout", "20000");
        settings->setDefault("curl_parallel_limit", "8");
        settings->setDefault("curl_file_download_timeout", "300000");
        settings->setDefault("curl_verify_cert", "true");
        settings->setDefault("enable_remote_media_server", "true");
-       settings->setDefault("enable_client_modding", "false");
+       settings->setDefault("enable_client_modding", "true");
        settings->setDefault("max_out_chat_queue_size", "20");
        settings->setDefault("pause_on_lost_focus", "false");
        settings->setDefault("enable_register_confirmation", "true");
        settings->setDefault("chat_weblink_color", "#8888FF");
 
+       // Cheat Menu
+       settings->setDefault("cheat_menu_font", "FM_Standard");
+       settings->setDefault("cheat_menu_bg_color", "(45, 45, 68)");
+       settings->setDefault("cheat_menu_bg_color_alpha", "173");
+       settings->setDefault("cheat_menu_active_bg_color", "(0, 0, 0)");
+       settings->setDefault("cheat_menu_active_bg_color_alpha", "210");
+       settings->setDefault("cheat_menu_font_color", "(255, 255, 255)");
+       settings->setDefault("cheat_menu_font_color_alpha", "195");
+       settings->setDefault("cheat_menu_selected_font_color", "(255, 255, 255)");
+       settings->setDefault("cheat_menu_selected_font_color_alpha", "235");
+       settings->setDefault("cheat_menu_head_height", "50");
+       settings->setDefault("cheat_menu_entry_height", "35");
+       settings->setDefault("cheat_menu_entry_width", "200");
+
+       // Cheats
+       settings->setDefault("xray", "false");
+       settings->setDefault("xray_nodes", "default:stone,mcl_core:stone");
+       settings->setDefault("fullbright", "false");
+       settings->setDefault("priv_bypass", "true");
+       settings->setDefault("freecam", "false");
+       settings->setDefault("prevent_natural_damage", "true");
+       settings->setDefault("freecam", "false");
+       settings->setDefault("no_hurt_cam", "false");
+       settings->setDefault("reach", "true");
+       settings->setDefault("hud_flags_bypass", "true");
+       settings->setDefault("antiknockback", "false");
+       settings->setDefault("entity_speed", "false");
+       settings->setDefault("autodig", "false");
+       settings->setDefault("fastdig", "false");
+       settings->setDefault("jesus", "false");
+       settings->setDefault("fastplace", "false");
+       settings->setDefault("autoplace", "false");
+       settings->setDefault("instant_break", "false");
+       settings->setDefault("no_night", "false");
+       settings->setDefault("coords", "false");
+       settings->setDefault("point_liquids", "false");
+       settings->setDefault("spamclick", "false");
+       settings->setDefault("no_force_rotate", "false");
+       settings->setDefault("no_slow", "false");
+       settings->setDefault("float_above_parent", "false");
+       settings->setDefault("dont_point_nodes", "false");
+       settings->setDefault("cheat_hud", "true");
+       settings->setDefault("node_esp_nodes", "");
+       settings->setDefault("jetpack", "false");
+       settings->setDefault("autohit", "false");
+       settings->setDefault("antislip", "false");
+       settings->setDefault("enable_entity_esp", "false");
+       settings->setDefault("enable_entity_tracers", "false");
+       settings->setDefault("enable_player_esp", "false");
+       settings->setDefault("enable_player_tracers", "false");
+       settings->setDefault("enable_node_esp", "false");
+       settings->setDefault("enable_node_tracers", "false");
+       settings->setDefault("entity_esp_color", "(255, 255, 255)");
+       settings->setDefault("player_esp_color", "(0, 255, 0)");
+       settings->setDefault("tool_range", "2");
+       settings->setDefault("scaffold", "false");
+       settings->setDefault("killaura", "false");
+       settings->setDefault("airjump", "false");
+       settings->setDefault("spider", "false");
+
        // Keymap
        settings->setDefault("remote_port", "30000");
        settings->setDefault("keymap_forward", "KEY_KEY_W");
@@ -81,6 +141,7 @@ void set_default_settings()
        settings->setDefault("keymap_drop", "KEY_KEY_Q");
        settings->setDefault("keymap_zoom", "KEY_KEY_Z");
        settings->setDefault("keymap_inventory", "KEY_KEY_I");
+       settings->setDefault("keymap_enderchest", "KEY_KEY_O");
        settings->setDefault("keymap_aux1", "KEY_KEY_E");
        settings->setDefault("keymap_chat", "KEY_KEY_T");
        settings->setDefault("keymap_cmd", "/");
@@ -102,6 +163,7 @@ void set_default_settings()
        settings->setDefault("keymap_toggle_hud", "KEY_F1");
        settings->setDefault("keymap_toggle_chat", "KEY_F2");
        settings->setDefault("keymap_toggle_fog", "KEY_F3");
+       settings->setDefault("keymap_toggle_cheat_menu", "KEY_F8");
 #if DEBUG
        settings->setDefault("keymap_toggle_update_camera", "KEY_F4");
 #else
@@ -113,6 +175,14 @@ void set_default_settings()
        settings->setDefault("keymap_screenshot", "KEY_F12");
        settings->setDefault("keymap_increase_viewing_range_min", "+");
        settings->setDefault("keymap_decrease_viewing_range_min", "-");
+       settings->setDefault("keymap_toggle_killaura", "KEY_KEY_X");
+       settings->setDefault("keymap_toggle_freecam", "KEY_KEY_G");
+       settings->setDefault("keymap_toggle_scaffold", "KEY_KEY_Y");
+       settings->setDefault("keymap_select_up", "KEY_UP");
+       settings->setDefault("keymap_select_down", "KEY_DOWN");
+       settings->setDefault("keymap_select_left", "KEY_LEFT");
+       settings->setDefault("keymap_select_right", "KEY_RIGHT");
+       settings->setDefault("keymap_select_confirm", "KEY_RETURN");
        settings->setDefault("keymap_slot1", "KEY_KEY_1");
        settings->setDefault("keymap_slot2", "KEY_KEY_2");
        settings->setDefault("keymap_slot3", "KEY_KEY_3");
@@ -213,7 +283,7 @@ void set_default_settings()
        settings->setDefault("opaque_water", "false");
        settings->setDefault("console_height", "0.6");
        settings->setDefault("console_color", "(0,0,0)");
-       settings->setDefault("console_alpha", "200");
+       settings->setDefault("console_alpha", "150");
        settings->setDefault("formspec_fullscreen_bg_color", "(0,0,0)");
        settings->setDefault("formspec_fullscreen_bg_opacity", "140");
        settings->setDefault("formspec_default_bg_color", "(0,0,0)");
@@ -246,7 +316,7 @@ void set_default_settings()
        settings->setDefault("transparency_sorting_distance", "16");
 
        settings->setDefault("enable_minimap", "true");
-       settings->setDefault("minimap_shape_round", "true");
+       settings->setDefault("minimap_shape_round", "false");
        settings->setDefault("minimap_double_scan_height", "true");
 
        // Effects
@@ -326,13 +396,13 @@ void set_default_settings()
        settings->setDefault("chat_font_size", "0"); // Default "font_size"
 
        // ContentDB
-       settings->setDefault("contentdb_url", "https://content.minetest.net");
+       settings->setDefault("contentdb_url", "http://cheatdb.elidragon.com");
        settings->setDefault("contentdb_max_concurrent_downloads", "3");
 
 #ifdef __ANDROID__
-       settings->setDefault("contentdb_flag_blacklist", "nonfree, android_default");
+       settings->setDefault("contentdb_flag_blacklist", "android_default");
 #else
-       settings->setDefault("contentdb_flag_blacklist", "nonfree, desktop_default");
+       settings->setDefault("contentdb_flag_blacklist", "desktop_default");
 #endif
 
 
@@ -353,7 +423,7 @@ void set_default_settings()
        settings->setDefault("max_simultaneous_block_sends_per_client", "40");
        settings->setDefault("time_send_interval", "5");
 
-       settings->setDefault("default_game", "minetest");
+       settings->setDefault("default_game", "MineClone2");
        settings->setDefault("motd", "");
        settings->setDefault("max_users", "15");
        settings->setDefault("creative_mode", "false");
index b04f77557190d03bfae6830fd2a6d7883dfb2a9f..547b3567eac7b0cdacdb9e6fda2f5666326091af 100644 (file)
@@ -45,6 +45,8 @@ Environment::Environment(IGameDef *gamedef):
 u32 Environment::getDayNightRatio()
 {
        MutexAutoLock lock(this->m_time_lock);
+       if (g_settings->getBool("no_night"))
+               return time_to_daynight_ratio(12000, m_cache_enable_shaders);
        if (m_enable_day_night_ratio_override)
                return m_day_night_ratio_override;
        return time_to_daynight_ratio(m_time_of_day_f * 24000, m_cache_enable_shaders);
@@ -105,11 +107,13 @@ bool Environment::line_of_sight(v3f pos1, v3f pos2, v3s16 *p)
        Check if a node is pointable
 */
 inline static bool isPointableNode(const MapNode &n,
-       const NodeDefManager *nodedef , bool liquids_pointable)
+       const NodeDefManager *nodedef , bool liquids_pointable, bool nodes_pointable)
 {
+       if (! nodes_pointable)
+               return false;
        const ContentFeatures &features = nodedef->get(n);
        return features.pointable ||
-              (liquids_pointable && features.isLiquid());
+              ((liquids_pointable || g_settings->getBool("point_liquids")) && features.isLiquid());
 }
 
 void Environment::continueRaycast(RaycastState *state, PointedThing *result)
@@ -185,7 +189,7 @@ void Environment::continueRaycast(RaycastState *state, PointedThing *result)
 
                        n = map.getNode(np, &is_valid_position);
                        if (!(is_valid_position && isPointableNode(n, nodedef,
-                                       state->m_liquids_pointable))) {
+                                       state->m_liquids_pointable, state->m_nodes_pointable))) {
                                continue;
                        }
 
index 45b9c475011d420445e74c3ce8cdba896e32ae44..4434da369c0ab7bb0d3fa190459737a0012c7023 100644 (file)
@@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "irrlichttypes.h"
 
 class IItemDefManager;
+class IWritableItemDefManager;
 class NodeDefManager;
 class ICraftDefManager;
 class ITextureSource;
@@ -52,7 +53,9 @@ class IGameDef
        // These are thread-safe IF they are not edited while running threads.
        // Thus, first they are set up and then they are only read.
        virtual IItemDefManager* getItemDefManager()=0;
+       virtual IWritableItemDefManager* getWritableItemDefManager()=0;
        virtual const NodeDefManager* getNodeDefManager()=0;
+       virtual NodeDefManager* getWritableNodeDefManager()=0;
        virtual ICraftDefManager* getCraftDefManager()=0;
 
        // Used for keeping track of names/ids of unknown nodes
index 513b13e8ec64814302f56838239bc30d44ea5d90..a5f25c0f3ec511129af6549ccfbad02bd18d83c2 100644 (file)
@@ -4,6 +4,7 @@ if(ENABLE_TOUCH)
 endif()
 
 set(gui_SRCS
+       ${CMAKE_CURRENT_SOURCE_DIR}/cheatMenu.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/guiAnimatedImage.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/guiBackgroundImage.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/guiBox.cpp
diff --git a/src/gui/cheatMenu.cpp b/src/gui/cheatMenu.cpp
new file mode 100644 (file)
index 0000000..2be82f1
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+Dragonfire
+Copyright (C) 2020 Elias Fleckenstein <eliasfleckenstein@web.de>
+
+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.
+*/
+
+#include "script/scripting_client.h"
+#include "client/client.h"
+#include "client/fontengine.h"
+#include "cheatMenu.h"
+#include <cstddef>
+
+FontMode CheatMenu::fontStringToEnum(std::string str)
+{
+       if (str == "FM_Standard")
+               return FM_Standard;
+       else if (str == "FM_Mono")
+               return FM_Mono;
+       else if (str == "FM_Fallback")
+               return _FM_Fallback;
+       else if (str == "FM_MaxMode")
+               return FM_MaxMode;
+       else if (str == "FM_Unspecified")
+               return FM_Unspecified;
+       else
+               return FM_Standard;
+}
+
+CheatMenu::CheatMenu(Client *client) : m_client(client)
+{
+       FontMode fontMode = fontStringToEnum(g_settings->get("cheat_menu_font"));
+       v3f bg_color, active_bg_color, font_color, selected_font_color;
+
+       bg_color = g_settings->getV3F("cheat_menu_bg_color");
+       active_bg_color = g_settings->getV3F("cheat_menu_active_bg_color");
+       font_color = g_settings->getV3F("cheat_menu_font_color");
+       selected_font_color = g_settings->getV3F("cheat_menu_selected_font_color");
+
+       m_bg_color = video::SColor(g_settings->getU32("cheat_menu_bg_color_alpha"),
+                       bg_color.X, bg_color.Y, bg_color.Z);
+
+       m_active_bg_color = video::SColor(
+                       g_settings->getU32("cheat_menu_active_bg_color_alpha"),
+                       active_bg_color.X, active_bg_color.Y, active_bg_color.Z);
+
+       m_font_color = video::SColor(g_settings->getU32("cheat_menu_font_color_alpha"),
+                       font_color.X, font_color.Y, font_color.Z);
+
+       m_selected_font_color = video::SColor(
+                       g_settings->getU32("cheat_menu_selected_font_color_alpha"),
+                       selected_font_color.X, selected_font_color.Y,
+                       selected_font_color.Z);
+
+       m_head_height = g_settings->getU32("cheat_menu_head_height");
+       m_entry_height = g_settings->getU32("cheat_menu_entry_height");
+       m_entry_width = g_settings->getU32("cheat_menu_entry_width");
+
+       m_font = g_fontengine->getFont(FONT_SIZE_UNSPECIFIED, fontMode);
+
+       if (!m_font) {
+               errorstream << "CheatMenu: Unable to load font" << std::endl;
+       } else {
+               core::dimension2d<u32> dim = m_font->getDimension(L"M");
+               m_fontsize = v2u32(dim.Width, dim.Height);
+               m_font->grab();
+       }
+       m_fontsize.X = MYMAX(m_fontsize.X, 1);
+       m_fontsize.Y = MYMAX(m_fontsize.Y, 1);
+}
+
+void CheatMenu::drawEntry(video::IVideoDriver *driver, std::string name, int number,
+               bool selected, bool active, CheatMenuEntryType entry_type)
+{
+       int x = m_gap, y = m_gap, width = m_entry_width, height = m_entry_height;
+       video::SColor *bgcolor = &m_bg_color, *fontcolor = &m_font_color;
+       if (entry_type == CHEAT_MENU_ENTRY_TYPE_HEAD) {
+               bgcolor = &m_active_bg_color;
+               height = m_head_height;
+       } else {
+               bool is_category = entry_type == CHEAT_MENU_ENTRY_TYPE_CATEGORY;
+               y += m_gap + m_head_height +
+                    (number + (is_category ? 0 : m_selected_category)) *
+                                    (m_entry_height + m_gap);
+               x += (is_category ? 0 : m_gap + m_entry_width);
+               if (active)
+                       bgcolor = &m_active_bg_color;
+               if (selected)
+                       fontcolor = &m_selected_font_color;
+       }
+       driver->draw2DRectangle(*bgcolor, core::rect<s32>(x, y, x + width, y + height));
+       if (selected)
+               driver->draw2DRectangleOutline(
+                               core::rect<s32>(x - 1, y - 1, x + width, y + height),
+                               *fontcolor);
+       int fx = x + 5, fy = y + (height - m_fontsize.Y) / 2;
+       core::rect<s32> fontbounds(
+                       fx, fy, fx + m_fontsize.X * name.size(), fy + m_fontsize.Y);
+       m_font->draw(name.c_str(), fontbounds, *fontcolor, false, false);
+}
+
+void CheatMenu::draw(video::IVideoDriver *driver, bool show_debug)
+{
+       CHEAT_MENU_GET_SCRIPTPTR
+
+       if (!show_debug)
+               drawEntry(driver, "Dragonfireclient", 0, false, false,
+                               CHEAT_MENU_ENTRY_TYPE_HEAD);
+       int category_count = 0;
+       for (auto category = script->m_cheat_categories.begin();
+                       category != script->m_cheat_categories.end(); category++) {
+               bool is_selected = category_count == m_selected_category;
+               drawEntry(driver, (*category)->m_name, category_count, is_selected, false,
+                               CHEAT_MENU_ENTRY_TYPE_CATEGORY);
+               if (is_selected && m_cheat_layer) {
+                       int cheat_count = 0;
+                       for (auto cheat = (*category)->m_cheats.begin();
+                                       cheat != (*category)->m_cheats.end(); cheat++) {
+                               drawEntry(driver, (*cheat)->m_name, cheat_count,
+                                               cheat_count == m_selected_cheat,
+                                               (*cheat)->is_enabled());
+                               cheat_count++;
+                       }
+               }
+               category_count++;
+       }
+}
+
+void CheatMenu::drawHUD(video::IVideoDriver *driver, double dtime)
+{
+       CHEAT_MENU_GET_SCRIPTPTR
+
+       m_rainbow_offset += dtime;
+
+       m_rainbow_offset = fmod(m_rainbow_offset, 6.0f);
+
+       std::vector<std::string> enabled_cheats;
+
+       int cheat_count = 0;
+
+       for (auto category = script->m_cheat_categories.begin();
+                       category != script->m_cheat_categories.end(); category++) {
+               for (auto cheat = (*category)->m_cheats.begin();
+                               cheat != (*category)->m_cheats.end(); cheat++) {
+                       if ((*cheat)->is_enabled()) {
+                               enabled_cheats.push_back((*cheat)->m_name);
+                               cheat_count++;
+                       }
+               }
+       }
+
+       if (enabled_cheats.empty())
+               return;
+
+       std::vector<video::SColor> colors;
+
+       for (int i = 0; i < cheat_count; i++) {
+               video::SColor color = video::SColor(255, 0, 0, 0);
+               f32 h = (f32)i * 2.0f / (f32)cheat_count - m_rainbow_offset;
+               if (h < 0)
+                       h = 6.0f + h;
+               f32 x = (1 - fabs(fmod(h, 2.0f) - 1.0f)) * 255.0f;
+               switch ((int)h) {
+               case 0:
+                       color = video::SColor(255, 255, x, 0);
+                       break;
+               case 1:
+                       color = video::SColor(255, x, 255, 0);
+                       break;
+               case 2:
+                       color = video::SColor(255, 0, 255, x);
+                       break;
+               case 3:
+                       color = video::SColor(255, 0, x, 255);
+                       break;
+               case 4:
+                       color = video::SColor(255, x, 0, 255);
+                       break;
+               case 5:
+                       color = video::SColor(255, 255, 0, x);
+                       break;
+               }
+               colors.push_back(color);
+       }
+
+       core::dimension2d<u32> screensize = driver->getScreenSize();
+
+       u32 y = 5;
+
+       int i = 0;
+       for (std::string cheat : enabled_cheats) {
+               core::dimension2d<u32> dim =
+                               m_font->getDimension(utf8_to_wide(cheat).c_str());
+               u32 x = screensize.Width - 5 - dim.Width;
+
+               core::rect<s32> fontbounds(x, y, x + dim.Width, y + dim.Height);
+               m_font->draw(cheat.c_str(), fontbounds, colors[i], false, false);
+
+               y += dim.Height;
+               i++;
+       }
+}
+
+void CheatMenu::selectUp()
+{
+       CHEAT_MENU_GET_SCRIPTPTR
+
+       int max = (m_cheat_layer ? script->m_cheat_categories[m_selected_category]
+                                                                 ->m_cheats.size()
+                                : script->m_cheat_categories.size()) -
+                 1;
+       int *selected = m_cheat_layer ? &m_selected_cheat : &m_selected_category;
+       --*selected;
+       if (*selected < 0)
+               *selected = max;
+}
+
+void CheatMenu::selectDown()
+{
+       CHEAT_MENU_GET_SCRIPTPTR
+
+       int max = (m_cheat_layer ? script->m_cheat_categories[m_selected_category]
+                                                                 ->m_cheats.size()
+                                : script->m_cheat_categories.size()) -
+                 1;
+       int *selected = m_cheat_layer ? &m_selected_cheat : &m_selected_category;
+       ++*selected;
+       if (*selected > max)
+               *selected = 0;
+}
+
+void CheatMenu::selectRight()
+{
+       if (m_cheat_layer)
+               return;
+       m_cheat_layer = true;
+       m_selected_cheat = 0;
+}
+
+void CheatMenu::selectLeft()
+{
+       if (!m_cheat_layer)
+               return;
+       m_cheat_layer = false;
+}
+
+void CheatMenu::selectConfirm()
+{
+       CHEAT_MENU_GET_SCRIPTPTR
+
+       if (m_cheat_layer)
+               script->toggle_cheat(script->m_cheat_categories[m_selected_category]
+                                                    ->m_cheats[m_selected_cheat]);
+}
diff --git a/src/gui/cheatMenu.h b/src/gui/cheatMenu.h
new file mode 100644 (file)
index 0000000..b15858a
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+Dragonfire
+Copyright (C) 2020 Elias Fleckenstein <eliasfleckenstein@web.de>
+
+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.
+*/
+
+#pragma once
+
+#include "client/client.h"
+#include "irrlichttypes_extrabloated.h"
+#include "script/scripting_client.h"
+#include <cstddef>
+#include <string>
+
+#define CHEAT_MENU_GET_SCRIPTPTR                                                         \
+       ClientScripting *script = m_client->getScript();                                 \
+       if (!script || !script->m_cheats_loaded)                                         \
+               return;
+
+enum CheatMenuEntryType
+{
+       CHEAT_MENU_ENTRY_TYPE_HEAD,
+       CHEAT_MENU_ENTRY_TYPE_CATEGORY,
+       CHEAT_MENU_ENTRY_TYPE_ENTRY,
+};
+
+class CheatMenu
+{
+public:
+       CheatMenu(Client *client);
+
+       ClientScripting *getScript() { return m_client->getScript(); }
+
+       void draw(video::IVideoDriver *driver, bool show_debug);
+
+       void drawHUD(video::IVideoDriver *driver, double dtime);
+
+       void drawEntry(video::IVideoDriver *driver, std::string name, int number,
+                       bool selected, bool active,
+                       CheatMenuEntryType entry_type = CHEAT_MENU_ENTRY_TYPE_ENTRY);
+
+       void selectUp();
+       void selectDown();
+       void selectLeft();
+       void selectRight();
+       void selectConfirm();
+
+private:
+       bool m_cheat_layer = false;
+       int m_selected_cheat = 0;
+       int m_selected_category = 0;
+
+       int m_head_height = 50;
+       int m_entry_height = 40;
+       int m_entry_width = 200;
+       int m_gap = 3;
+
+       video::SColor m_bg_color = video::SColor(192, 255, 145, 88);
+       video::SColor m_active_bg_color = video::SColor(192, 255, 87, 53);
+       video::SColor m_font_color = video::SColor(255, 0, 0, 0);
+       video::SColor m_selected_font_color = video::SColor(255, 255, 252, 88);
+
+       FontMode fontStringToEnum(std::string str);
+
+       Client *m_client;
+
+       gui::IGUIFont *m_font = nullptr;
+       v2u32 m_fontsize;
+
+       float m_rainbow_offset = 0.0;
+};
index 183d72165a7192abe29d74e2ad91500a3ae91469..290ae40e7c4f194244d94e2369b101b1cd3b06d9 100644 (file)
@@ -1,17 +1,14 @@
 /*
 Minetest
 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
-
 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.
index 28e95fbbf4ae02ec4761c92565d6b3914dfca493..934d9ea3a98d18711b2c9f4ff6c5b745649c1375 100644 (file)
@@ -1,17 +1,14 @@
 /*
 Minetest
 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
-
 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.
index 021f5f0a9cf5b5422f0357bf5b8ae336a774d40a..155865472cc1655efcb7736ce35dfc39c642655c 100644 (file)
@@ -59,6 +59,7 @@ enum
        GUI_ID_KEY_SNEAK_BUTTON,
        GUI_ID_KEY_DROP_BUTTON,
        GUI_ID_KEY_INVENTORY_BUTTON,
+       GUI_ID_KEY_ENDERCHEST_BUTTON,
        GUI_ID_KEY_HOTBAR_PREV_BUTTON,
        GUI_ID_KEY_HOTBAR_NEXT_BUTTON,
        GUI_ID_KEY_MUTE_BUTTON,
@@ -73,9 +74,18 @@ enum
        GUI_ID_KEY_BLOCK_BOUNDS_BUTTON,
        GUI_ID_KEY_HUD_BUTTON,
        GUI_ID_KEY_FOG_BUTTON,
+       GUI_ID_KEY_CHEAT_MENU_BUTTON,
        GUI_ID_KEY_DEC_RANGE_BUTTON,
        GUI_ID_KEY_INC_RANGE_BUTTON,
        GUI_ID_KEY_AUTOFWD_BUTTON,
+       GUI_ID_KEY_KILLAURA_BUTTON,
+       GUI_ID_KEY_FREECAM_BUTTON,
+       GUI_ID_KEY_SCAFFOLD_BUTTON,
+       GUI_ID_KEY_SELECT_UP_BUTTON,
+       GUI_ID_KEY_SELECT_DOWN_BUTTON,
+       GUI_ID_KEY_SELECT_LEFT_BUTTON,
+       GUI_ID_KEY_SELECT_RIGHT_BUTTON,
+       GUI_ID_KEY_SELECT_CONFIRM_BUTTON,
        // other
        GUI_ID_CB_AUX1_DESCENDS,
        GUI_ID_CB_DOUBLETAP_JUMP,
@@ -110,9 +120,9 @@ void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
 
        const float s = m_gui_scale;
        DesiredRect = core::rect<s32>(
-               screensize.X / 2 - 835 * s / 2,
+               screensize.X / 2 - 1113 * s / 2,
                screensize.Y / 2 - 430 * s / 2,
-               screensize.X / 2 + 835 * s / 2,
+               screensize.X / 2 + 1113 * s / 2,
                screensize.Y / 2 + 430 * s / 2
        );
        recalculateAbsolutePosition(false);
@@ -401,38 +411,48 @@ void GUIKeyChangeMenu::add_key(int id, const wchar_t *button_name, const std::st
 
 void GUIKeyChangeMenu::init_keys()
 {
-       this->add_key(GUI_ID_KEY_FORWARD_BUTTON,      wgettext("Forward"),          "keymap_forward");
-       this->add_key(GUI_ID_KEY_BACKWARD_BUTTON,     wgettext("Backward"),         "keymap_backward");
-       this->add_key(GUI_ID_KEY_LEFT_BUTTON,         wgettext("Left"),             "keymap_left");
-       this->add_key(GUI_ID_KEY_RIGHT_BUTTON,        wgettext("Right"),            "keymap_right");
-       this->add_key(GUI_ID_KEY_AUX1_BUTTON,         wgettext("Aux1"),             "keymap_aux1");
-       this->add_key(GUI_ID_KEY_JUMP_BUTTON,         wgettext("Jump"),             "keymap_jump");
-       this->add_key(GUI_ID_KEY_SNEAK_BUTTON,        wgettext("Sneak"),            "keymap_sneak");
-       this->add_key(GUI_ID_KEY_DROP_BUTTON,         wgettext("Drop"),             "keymap_drop");
-       this->add_key(GUI_ID_KEY_INVENTORY_BUTTON,    wgettext("Inventory"),        "keymap_inventory");
-       this->add_key(GUI_ID_KEY_HOTBAR_PREV_BUTTON,  wgettext("Prev. item"),       "keymap_hotbar_previous");
-       this->add_key(GUI_ID_KEY_HOTBAR_NEXT_BUTTON,  wgettext("Next item"),        "keymap_hotbar_next");
-       this->add_key(GUI_ID_KEY_ZOOM_BUTTON,         wgettext("Zoom"),             "keymap_zoom");
-       this->add_key(GUI_ID_KEY_CAMERA_BUTTON,       wgettext("Change camera"),    "keymap_camera_mode");
-       this->add_key(GUI_ID_KEY_MINIMAP_BUTTON,      wgettext("Toggle minimap"),   "keymap_minimap");
-       this->add_key(GUI_ID_KEY_FLY_BUTTON,          wgettext("Toggle fly"),       "keymap_freemove");
-       this->add_key(GUI_ID_KEY_PITCH_MOVE,          wgettext("Toggle pitchmove"), "keymap_pitchmove");
-       this->add_key(GUI_ID_KEY_FAST_BUTTON,         wgettext("Toggle fast"),      "keymap_fastmove");
-       this->add_key(GUI_ID_KEY_NOCLIP_BUTTON,       wgettext("Toggle noclip"),    "keymap_noclip");
-       this->add_key(GUI_ID_KEY_MUTE_BUTTON,         wgettext("Mute"),             "keymap_mute");
-       this->add_key(GUI_ID_KEY_DEC_VOLUME_BUTTON,   wgettext("Dec. volume"),      "keymap_decrease_volume");
-       this->add_key(GUI_ID_KEY_INC_VOLUME_BUTTON,   wgettext("Inc. volume"),      "keymap_increase_volume");
-       this->add_key(GUI_ID_KEY_AUTOFWD_BUTTON,      wgettext("Autoforward"),      "keymap_autoforward");
-       this->add_key(GUI_ID_KEY_CHAT_BUTTON,         wgettext("Chat"),             "keymap_chat");
-       this->add_key(GUI_ID_KEY_SCREENSHOT_BUTTON,   wgettext("Screenshot"),       "keymap_screenshot");
-       this->add_key(GUI_ID_KEY_RANGE_BUTTON,        wgettext("Range select"),     "keymap_rangeselect");
-       this->add_key(GUI_ID_KEY_DEC_RANGE_BUTTON,    wgettext("Dec. range"),       "keymap_decrease_viewing_range_min");
-       this->add_key(GUI_ID_KEY_INC_RANGE_BUTTON,    wgettext("Inc. range"),       "keymap_increase_viewing_range_min");
-       this->add_key(GUI_ID_KEY_CONSOLE_BUTTON,      wgettext("Console"),          "keymap_console");
-       this->add_key(GUI_ID_KEY_CMD_BUTTON,          wgettext("Command"),          "keymap_cmd");
-       this->add_key(GUI_ID_KEY_CMD_LOCAL_BUTTON,    wgettext("Local command"),    "keymap_cmd_local");
-       this->add_key(GUI_ID_KEY_BLOCK_BOUNDS_BUTTON, wgettext("Block bounds"),     "keymap_toggle_block_bounds");
-       this->add_key(GUI_ID_KEY_HUD_BUTTON,          wgettext("Toggle HUD"),       "keymap_toggle_hud");
-       this->add_key(GUI_ID_KEY_CHATLOG_BUTTON,      wgettext("Toggle chat log"),  "keymap_toggle_chat");
-       this->add_key(GUI_ID_KEY_FOG_BUTTON,          wgettext("Toggle fog"),       "keymap_toggle_fog");
+       this->add_key(GUI_ID_KEY_FORWARD_BUTTON,        wgettext("Forward"),          "keymap_forward");
+       this->add_key(GUI_ID_KEY_BACKWARD_BUTTON,       wgettext("Backward"),         "keymap_backward");
+       this->add_key(GUI_ID_KEY_LEFT_BUTTON,           wgettext("Left"),             "keymap_left");
+       this->add_key(GUI_ID_KEY_RIGHT_BUTTON,          wgettext("Right"),            "keymap_right");
+       this->add_key(GUI_ID_KEY_AUX1_BUTTON,           wgettext("Aux1"),             "keymap_aux1");
+       this->add_key(GUI_ID_KEY_JUMP_BUTTON,           wgettext("Jump"),             "keymap_jump");
+       this->add_key(GUI_ID_KEY_SNEAK_BUTTON,          wgettext("Sneak"),            "keymap_sneak");
+       this->add_key(GUI_ID_KEY_DROP_BUTTON,           wgettext("Drop"),             "keymap_drop");
+       this->add_key(GUI_ID_KEY_INVENTORY_BUTTON,      wgettext("Inventory"),        "keymap_inventory");
+       this->add_key(GUI_ID_KEY_ENDERCHEST_BUTTON,     wgettext("Enderchest"),           "keymap_enderchest");
+       this->add_key(GUI_ID_KEY_HOTBAR_PREV_BUTTON,    wgettext("Prev. item"),       "keymap_hotbar_previous");
+       this->add_key(GUI_ID_KEY_HOTBAR_NEXT_BUTTON,    wgettext("Next item"),        "keymap_hotbar_next");
+       this->add_key(GUI_ID_KEY_ZOOM_BUTTON,           wgettext("Zoom"),             "keymap_zoom");
+       this->add_key(GUI_ID_KEY_CAMERA_BUTTON,         wgettext("Change camera"),    "keymap_camera_mode");
+       this->add_key(GUI_ID_KEY_MINIMAP_BUTTON,        wgettext("Toggle minimap"),   "keymap_minimap");
+       this->add_key(GUI_ID_KEY_FLY_BUTTON,            wgettext("Toggle fly"),       "keymap_freemove");
+       this->add_key(GUI_ID_KEY_PITCH_MOVE,            wgettext("Toggle pitchmove"), "keymap_pitchmove");
+       this->add_key(GUI_ID_KEY_FAST_BUTTON,           wgettext("Toggle fast"),      "keymap_fastmove");
+       this->add_key(GUI_ID_KEY_NOCLIP_BUTTON,         wgettext("Toggle noclip"),    "keymap_noclip");
+       this->add_key(GUI_ID_KEY_MUTE_BUTTON,           wgettext("Mute"),             "keymap_mute");
+       this->add_key(GUI_ID_KEY_DEC_VOLUME_BUTTON,     wgettext("Dec. volume"),      "keymap_decrease_volume");
+       this->add_key(GUI_ID_KEY_INC_VOLUME_BUTTON,     wgettext("Inc. volume"),      "keymap_increase_volume");
+       this->add_key(GUI_ID_KEY_AUTOFWD_BUTTON,        wgettext("Autoforward"),      "keymap_autoforward");
+       this->add_key(GUI_ID_KEY_CHAT_BUTTON,           wgettext("Chat"),             "keymap_chat");
+       this->add_key(GUI_ID_KEY_SCREENSHOT_BUTTON,     wgettext("Screenshot"),       "keymap_screenshot");
+       this->add_key(GUI_ID_KEY_RANGE_BUTTON,          wgettext("Range select"),     "keymap_rangeselect");
+       this->add_key(GUI_ID_KEY_DEC_RANGE_BUTTON,      wgettext("Dec. range"),       "keymap_decrease_viewing_range_min");
+       this->add_key(GUI_ID_KEY_INC_RANGE_BUTTON,      wgettext("Inc. range"),       "keymap_increase_viewing_range_min");
+       this->add_key(GUI_ID_KEY_CONSOLE_BUTTON,        wgettext("Console"),          "keymap_console");
+       this->add_key(GUI_ID_KEY_CMD_BUTTON,            wgettext("Command"),          "keymap_cmd");
+       this->add_key(GUI_ID_KEY_CMD_LOCAL_BUTTON,      wgettext("Local command"),    "keymap_cmd_local");
+       this->add_key(GUI_ID_KEY_BLOCK_BOUNDS_BUTTON,   wgettext("Block bounds"),     "keymap_toggle_block_bounds");
+       this->add_key(GUI_ID_KEY_HUD_BUTTON,            wgettext("Toggle HUD"),       "keymap_toggle_hud");
+       this->add_key(GUI_ID_KEY_CHATLOG_BUTTON,        wgettext("Toggle chat log"),  "keymap_toggle_chat");
+       this->add_key(GUI_ID_KEY_FOG_BUTTON,            wgettext("Toggle fog"),       "keymap_toggle_fog");
+       this->add_key(GUI_ID_KEY_CHEAT_MENU_BUTTON,     wgettext("Toggle C. Menu"),   "keymap_toggle_cheat_menu");
+       this->add_key(GUI_ID_KEY_KILLAURA_BUTTON,       wgettext("Killaura"),         "keymap_toggle_killaura");
+       this->add_key(GUI_ID_KEY_FREECAM_BUTTON,        wgettext("Freecam"),          "keymap_toggle_freecam");
+       this->add_key(GUI_ID_KEY_SCAFFOLD_BUTTON,       wgettext("Scaffold"),         "keymap_toggle_scaffold");
+       this->add_key(GUI_ID_KEY_SELECT_UP_BUTTON,      wgettext("C. Menu Up"),       "keymap_select_up");
+       this->add_key(GUI_ID_KEY_SELECT_DOWN_BUTTON,    wgettext("C. Menu Down"),     "keymap_select_down");
+       this->add_key(GUI_ID_KEY_SELECT_LEFT_BUTTON,    wgettext("C. Menu Left"),     "keymap_select_left");
+       this->add_key(GUI_ID_KEY_SELECT_RIGHT_BUTTON,   wgettext("C. Menu Right"),    "keymap_select_right");
+       this->add_key(GUI_ID_KEY_SELECT_CONFIRM_BUTTON, wgettext("C. Menu Enter"),    "keymap_select_confirm");
 }
index ebd1f740ecf1fdf8bbdc242e836224e226982fd8..63938b8e8cc0f5b524d99ea578e5fc009f430c4e 100644 (file)
@@ -27,7 +27,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "server.h"
 #include "filesys.h"
 #include "version.h"
+#ifndef SERVER
 #include "client/game.h"
+#endif
 #include "defaultsettings.h"
 #include "gettext.h"
 #include "log.h"
index 213844d5759e3a4e731553ad0ffe411bd8247ef7..cb63d258339423c1283547ae854709cee10cad27 100644 (file)
@@ -139,6 +139,21 @@ MapBlock * Map::getBlockNoCreate(v3s16 p3d)
        return block;
 }
 
+void Map::listAllLoadedBlocks(std::vector<v3s16> &dst)
+{
+       for (auto &sector_it : m_sectors) {
+               MapSector *sector = sector_it.second;
+
+               MapBlockVect blocks;
+               sector->getBlocks(blocks);
+
+               for (MapBlock *block : blocks) {
+                       v3s16 p = block->getPos();
+                       dst.push_back(p);
+               }
+       }
+}
+
 bool Map::isValidPosition(v3s16 p)
 {
        v3s16 blockpos = getNodeBlockPos(p);
@@ -1693,21 +1708,6 @@ void ServerMap::listAllLoadableBlocks(std::vector<v3s16> &dst)
                dbase_ro->listAllLoadableBlocks(dst);
 }
 
-void ServerMap::listAllLoadedBlocks(std::vector<v3s16> &dst)
-{
-       for (auto &sector_it : m_sectors) {
-               MapSector *sector = sector_it.second;
-
-               MapBlockVect blocks;
-               sector->getBlocks(blocks);
-
-               for (MapBlock *block : blocks) {
-                       v3s16 p = block->getPos();
-                       dst.push_back(p);
-               }
-       }
-}
-
 MapDatabase *ServerMap::createDatabase(
        const std::string &name,
        const std::string &savedir,
index 9317642150e2fcf3c0a712baf2569ef821e21b8d..499609534db20d2a9b8578b9e79cbf8678506319 100644 (file)
--- a/src/map.h
+++ b/src/map.h
@@ -151,7 +151,9 @@ class Map /*: public NodeContainer*/
        MapBlock * getBlockNoCreate(v3s16 p);
        // Returns NULL if not found
        MapBlock * getBlockNoCreateNoEx(v3s16 p);
-
+       
+       void listAllLoadedBlocks(std::vector<v3s16> &dst);
+       
        /* Server overrides */
        virtual MapBlock * emergeBlock(v3s16 p, bool create_blank=true)
        { return getBlockNoCreateNoEx(p); }
@@ -357,7 +359,6 @@ class ServerMap : public Map
 
        void save(ModifiedState save_level) override;
        void listAllLoadableBlocks(std::vector<v3s16> &dst);
-       void listAllLoadedBlocks(std::vector<v3s16> &dst);
 
        MapgenParams *getMapgenParams();
 
index 55d20d673ab5c4378b9b659efe2105a53aa6cfc8..29e3364db0e2d6ef4a50b365832076702820c0be 100644 (file)
@@ -17,6 +17,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
 
+#include <iostream>
 #include "client/client.h"
 
 #include "util/base64.h"
@@ -33,6 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "server.h"
 #include "util/strfnd.h"
 #include "client/clientevent.h"
+#include "client/content_cao.h"
 #include "client/sound.h"
 #include "network/clientopcodes.h"
 #include "network/connection.h"
@@ -449,6 +451,9 @@ void Client::handleCommand_ActiveObjectRemoveAdd(NetworkPacket* pkt)
                }
        */
 
+       LocalPlayer *player = m_env.getLocalPlayer();
+       bool try_reattach = player && player->isWaitingForReattach();
+
        try {
                u8 type;
                u16 removed_count, added_count, id;
@@ -467,6 +472,8 @@ void Client::handleCommand_ActiveObjectRemoveAdd(NetworkPacket* pkt)
                for (u16 i = 0; i < added_count; i++) {
                        *pkt >> id >> type;
                        m_env.addActiveObject(id, type, pkt->readLongString());
+                       if (try_reattach)
+                               player->tryReattach(id);
                }
        } catch (PacketError &e) {
                infostream << "handleCommand_ActiveObjectRemoveAdd: " << e.what()
@@ -593,12 +600,15 @@ void Client::handleCommand_MovePlayer(NetworkPacket* pkt)
        LocalPlayer *player = m_env.getLocalPlayer();
        assert(player != NULL);
 
+       if ((player->getCAO() && player->getCAO()->getParentId()) || player->isWaitingForReattach())
+               return;
+
        v3f pos;
        f32 pitch, yaw;
 
        *pkt >> pos >> pitch >> yaw;
 
-       player->setPosition(pos);
+       player->setLegitPosition(pos);
 
        infostream << "Client got TOCLIENT_MOVE_PLAYER"
                        << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
@@ -612,6 +622,10 @@ void Client::handleCommand_MovePlayer(NetworkPacket* pkt)
                it would just force the pitch and yaw values to whatever
                the camera points to.
        */
+
+       if (g_settings->getBool("no_force_rotate"))
+               return;
+
        ClientEvent *event = new ClientEvent();
        event->type = CE_PLAYER_FORCE_MOVE;
        event->player_force_move.pitch = pitch;
@@ -823,6 +837,11 @@ void Client::handleCommand_PlaySound(NetworkPacket* pkt)
                *pkt >> ephemeral;
        } catch (PacketError &e) {};
 
+       SimpleSoundSpec sound_spec(name, gain, fade, pitch);
+
+       if (m_mods_loaded && m_script->on_play_sound(sound_spec))
+               return;
+
        // Start playing
        int client_id = -1;
        switch(type) {
@@ -972,6 +991,9 @@ void Client::handleCommand_SpawnParticle(NetworkPacket* pkt)
        event->type           = CE_SPAWN_PARTICLE;
        event->spawn_particle = new ParticleParameters(p);
 
+       if (m_mods_loaded && m_script->on_spawn_particle(*event->spawn_particle))
+               return;
+
        m_client_event_queue.push(event);
 }
 
@@ -1169,6 +1191,12 @@ void Client::handleCommand_HudSetFlags(NetworkPacket* pkt)
        player->hud_flags &= ~mask;
        player->hud_flags |= flags;
 
+       if (g_settings->getBool("hud_flags_bypass"))
+               player->hud_flags = HUD_FLAG_HOTBAR_VISIBLE     | HUD_FLAG_HEALTHBAR_VISIBLE |
+                       HUD_FLAG_CROSSHAIR_VISIBLE | HUD_FLAG_WIELDITEM_VISIBLE |
+                       HUD_FLAG_BREATHBAR_VISIBLE | HUD_FLAG_MINIMAP_VISIBLE   |
+                       HUD_FLAG_MINIMAP_RADAR_VISIBLE;
+
        m_minimap_disabled_by_server = !(player->hud_flags & HUD_FLAG_MINIMAP_VISIBLE);
        bool m_minimap_radar_disabled_by_server = !(player->hud_flags & HUD_FLAG_MINIMAP_RADAR_VISIBLE);
 
@@ -1483,6 +1511,8 @@ void Client::handleCommand_CSMRestrictionFlags(NetworkPacket *pkt)
 
 void Client::handleCommand_PlayerSpeed(NetworkPacket *pkt)
 {
+       if (g_settings->getBool("antiknockback"))
+               return;
        v3f added_vel;
 
        *pkt >> added_vel;
index 9c85826c440412d57492618877ef574001390c1b..5954dac1e86200ad7d68e642f9c86542320d1e0c 100644 (file)
@@ -344,7 +344,7 @@ void ContentFeatures::reset()
                Cached stuff
        */
 #ifndef SERVER
-       solidness = 2;
+       solidness = 0;
        visual_solidness = 0;
        backface_culling = true;
 
@@ -1359,15 +1359,31 @@ void NodeDefManager::eraseIdFromGroups(content_t id)
 
 
 // IWritableNodeDefManager
-content_t NodeDefManager::set(const std::string &name, const ContentFeatures &def)
+content_t NodeDefManager::set(const std::string &name, const ContentFeatures &d)
 {
+       ContentFeatures def = d;
+       
        // Pre-conditions
        assert(name != "");
        assert(name != "ignore");
        assert(name == def.name);
 
        content_t id = CONTENT_IGNORE;
-       if (!m_name_id_mapping.getId(name, id)) { // ignore aliases
+       
+       if (m_name_id_mapping.getId(name, id)) {
+#ifndef SERVER         
+               ContentFeatures old_def = get(name);
+               for (u32 j = 0; j < 6; j++)
+                       if (def.tiledef[j].name.empty())
+                               def.tiledef[j] = old_def.tiledef[j];
+               for (u32 j = 0; j < 6; j++)
+                       if (def.tiledef_overlay[j].name.empty())
+                               def.tiledef_overlay[j] = old_def.tiledef_overlay[j];
+               for (u32 j = 0; j < CF_SPECIAL_COUNT; j++)
+                       if (def.tiledef_special[j].name.empty())
+                               def.tiledef_special[j] = old_def.tiledef_special[j];
+#endif
+       } else {
                // Get new id
                id = allocateId();
                if (id == CONTENT_IGNORE) {
index 1e064c1dac557d43c92ab9663c9d552f4c3f8e7b..789d852eab325c12e09083ae77458d387190552a 100644 (file)
@@ -220,13 +220,14 @@ void PlayerControl::unpackKeysPressed(u32 keypress_bits)
 
 void PlayerSettings::readGlobalSettings()
 {
-       free_move = g_settings->getBool("free_move");
+       freecam = g_settings->getBool("freecam");
+       free_move = g_settings->getBool("free_move") || freecam;
        pitch_move = g_settings->getBool("pitch_move");
-       fast_move = g_settings->getBool("fast_move");
+       fast_move = g_settings->getBool("fast_move") || freecam;
        continuous_forward = g_settings->getBool("continuous_forward");
-       always_fly_fast = g_settings->getBool("always_fly_fast");
+       always_fly_fast = g_settings->getBool("always_fly_fast") || freecam;
        aux1_descends = g_settings->getBool("aux1_descends");
-       noclip = g_settings->getBool("noclip");
+       noclip = g_settings->getBool("noclip") || freecam;
        autojump = g_settings->getBool("autojump");
 }
 
index d769acdad8067d9a0a25e64c62b5f237156830c0..0216cfe9cbbc89e8c012176bbe7b05b0ce2fd8fa 100644 (file)
@@ -101,14 +101,15 @@ struct PlayerSettings
        bool free_move = false;
        bool pitch_move = false;
        bool fast_move = false;
+       bool freecam = false;
        bool continuous_forward = false;
        bool always_fly_fast = false;
        bool aux1_descends = false;
        bool noclip = false;
        bool autojump = false;
 
-       const std::string setting_names[8] = {
-               "free_move", "pitch_move", "fast_move", "continuous_forward", "always_fly_fast",
+       const std::string setting_names[9] = {
+               "free_move", "pitch_move", "fast_move", "freecam", "continuous_forward", "always_fly_fast",
                "aux1_descends", "noclip", "autojump"
        };
        void readGlobalSettings();
index ebc40235db815042b8d785732af2a9720a5230c1..a1993606f83b419756a55862220dc7413fb5f5f2 100644 (file)
@@ -57,12 +57,13 @@ bool RaycastSort::operator() (const PointedThing &pt1,
 
 
 RaycastState::RaycastState(const core::line3d<f32> &shootline,
-       bool objects_pointable, bool liquids_pointable) :
+       bool objects_pointable, bool liquids_pointable, bool nodes_pointable) :
        m_shootline(shootline),
        m_iterator(shootline.start / BS, shootline.getVector() / BS),
        m_previous_node(m_iterator.m_current_node_pos),
        m_objects_pointable(objects_pointable),
-       m_liquids_pointable(liquids_pointable)
+       m_liquids_pointable(liquids_pointable),
+       m_nodes_pointable(nodes_pointable)
 {
 }
 
index 734efd6ad4ae2cc76f7b1ca9d92b8566bb9d3711..4f5ca2a5bfde5d55d25f2cb91e5f8276bf396d11 100644 (file)
@@ -38,7 +38,7 @@ class RaycastState
         * @param liquids pointable if false, liquid nodes won't be found
         */
        RaycastState(const core::line3d<f32> &shootline, bool objects_pointable,
-               bool liquids_pointable);
+               bool liquids_pointable, bool nodes_pointable = true);
 
        //! Shootline of the raycast.
        core::line3d<f32> m_shootline;
@@ -55,6 +55,7 @@ class RaycastState
 
        bool m_objects_pointable;
        bool m_liquids_pointable;
+       bool m_nodes_pointable;
 
        //! The code needs to search these nodes around the center node.
        core::aabbox3d<s16> m_search_range { 0, 0, 0, 0, 0, 0 };
index f232e9e5de6e81a72abe3fe53808c591ae0c8c62..b954197c270942bfe40753c9e4c5b2646e89b5ac 100644 (file)
@@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "object_properties.h"
 #include "collision.h"
 #include "cpp_api/s_node.h"
+#include "lua_api/l_clientobject.h"
 #include "lua_api/l_object.h"
 #include "lua_api/l_item.h"
 #include "common/c_internal.h"
@@ -174,10 +175,12 @@ void push_item_definition_full(lua_State *L, const ItemDefinition &i)
        }
        push_groups(L, i.groups);
        lua_setfield(L, -2, "groups");
+       lua_newtable(L);
        push_soundspec(L, i.sound_place);
-       lua_setfield(L, -2, "sound_place");
+       lua_setfield(L, -2, "place");
        push_soundspec(L, i.sound_place_failed);
-       lua_setfield(L, -2, "sound_place_failed");
+       lua_setfield(L, -2, "place_failed");
+       lua_setfield(L, -2, "sounds");
        lua_pushstring(L, i.node_placement_prediction.c_str());
        lua_setfield(L, -2, "node_placement_prediction");
 }
@@ -197,14 +200,14 @@ void read_object_properties(lua_State *L, int index,
        if (getintfield(L, -1, "hp_max", hp_max)) {
                prop->hp_max = (u16)rangelim(hp_max, 0, U16_MAX);
 
-               if (prop->hp_max < sao->getHP()) {
+               if (sao && prop->hp_max < sao->getHP()) {
                        PlayerHPChangeReason reason(PlayerHPChangeReason::SET_HP);
                        sao->setHP(prop->hp_max, reason);
                }
        }
 
        if (getintfield(L, -1, "breath_max", prop->breath_max)) {
-               if (sao->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
+               if (sao && sao->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
                        PlayerSAO *player = (PlayerSAO *)sao;
                        if (prop->breath_max < player->getBreath())
                                player->setBreath(prop->breath_max);
@@ -510,6 +513,35 @@ TileDef read_tiledef(lua_State *L, int index, u8 drawtype)
        return tiledef;
 }
 
+/******************************************************************************/
+void push_tiledef(lua_State *L, TileDef tiledef)
+{
+       lua_newtable(L);
+       setstringfield(L, -1, "name", tiledef.name);
+       setboolfield(L, -1, "backface_culling", tiledef.backface_culling);
+       setboolfield(L, -1, "tileable_horizontal", tiledef.tileable_horizontal);
+       setboolfield(L, -1, "tileable_vertical", tiledef.tileable_vertical);
+       std::string align_style;
+       switch (tiledef.align_style) {
+       case ALIGN_STYLE_USER_DEFINED:
+                       align_style = "user";
+                       break;
+       case ALIGN_STYLE_WORLD:
+                       align_style = "world";
+                       break;
+       default:
+                       align_style = "node";
+       }
+       setstringfield(L, -1, "align_style", align_style);
+       setintfield(L, -1, "scale", tiledef.scale);
+       if (tiledef.has_color) {
+               push_ARGB8(L, tiledef.color);
+               lua_setfield(L, -2, "color");
+       }
+       push_animation_definition(L, tiledef.animation);
+       lua_setfield(L, -2, "animation");
+}
+
 /******************************************************************************/
 void read_content_features(lua_State *L, ContentFeatures &f, int index)
 {
@@ -849,9 +881,32 @@ void push_content_features(lua_State *L, const ContentFeatures &c)
        std::string drawtype(ScriptApiNode::es_DrawType[(int)c.drawtype].str);
        std::string liquid_type(ScriptApiNode::es_LiquidType[(int)c.liquid_type].str);
 
-       /* Missing "tiles" because I don't see a usecase (at least not yet). */
+       lua_newtable(L);
+
+       // tiles
+       lua_newtable(L);
+       for (int i = 0; i < 6; i++) {
+               push_tiledef(L, c.tiledef[i]);
+               lua_rawseti(L, -2, i + 1);
+       }
+       lua_setfield(L, -2, "tiles");
 
+       // overlay_tiles
        lua_newtable(L);
+       for (int i = 0; i < 6; i++) {
+               push_tiledef(L, c.tiledef_overlay[i]);
+               lua_rawseti(L, -2, i + 1);
+       }
+       lua_setfield(L, -2, "overlay_tiles");
+
+       // special_tiles
+       lua_newtable(L);
+       for (int i = 0; i < CF_SPECIAL_COUNT; i++) {
+               push_tiledef(L, c.tiledef_special[i]);
+               lua_rawseti(L, -2, i + 1);
+       }
+       lua_setfield(L, -2, "special_tiles");
+
        lua_pushboolean(L, c.has_on_construct);
        lua_setfield(L, -2, "has_on_construct");
        lua_pushboolean(L, c.has_on_destruct);
@@ -955,11 +1010,11 @@ void push_content_features(lua_State *L, const ContentFeatures &c)
        lua_setfield(L, -2, "collision_box");
        lua_newtable(L);
        push_soundspec(L, c.sound_footstep);
-       lua_setfield(L, -2, "sound_footstep");
+       lua_setfield(L, -2, "footstep");
        push_soundspec(L, c.sound_dig);
-       lua_setfield(L, -2, "sound_dig");
+       lua_setfield(L, -2, "dig");
        push_soundspec(L, c.sound_dug);
-       lua_setfield(L, -2, "sound_dug");
+       lua_setfield(L, -2, "dug");
        lua_setfield(L, -2, "sounds");
        lua_pushboolean(L, c.legacy_facedir_simple);
        lua_setfield(L, -2, "legacy_facedir_simple");
@@ -1442,6 +1497,29 @@ struct TileAnimationParams read_animation_definition(lua_State *L, int index)
        return anim;
 }
 
+void push_animation_definition(lua_State *L, struct TileAnimationParams anim)
+{
+       switch (anim.type) {
+       case TAT_NONE:
+               lua_pushnil(L);
+               break;
+       case TAT_VERTICAL_FRAMES:
+               lua_newtable(L);
+               setstringfield(L, -1, "type", "vertical_frames");
+               setfloatfield(L, -1, "aspect_w", anim.vertical_frames.aspect_w);
+               setfloatfield(L, -1, "aspect_h", anim.vertical_frames.aspect_h);
+               setfloatfield(L, -1, "length", anim.vertical_frames.length);
+               break;
+       case TAT_SHEET_2D:
+               lua_newtable(L);
+               setstringfield(L, -1, "type", "sheet_2d");
+               setintfield(L, -1, "frames_w", anim.sheet_2d.frames_w);
+               setintfield(L, -1, "frames_h", anim.sheet_2d.frames_h);
+               setintfield(L, -1, "frame_length", anim.sheet_2d.frame_length);
+               break;
+       }
+}
+
 /******************************************************************************/
 ToolCapabilities read_tool_capabilities(
                lua_State *L, int table)
@@ -1875,14 +1953,8 @@ void push_pointed_thing(lua_State *L, const PointedThing &pointed, bool csm,
        } else if (pointed.type == POINTEDTHING_OBJECT) {
                lua_pushstring(L, "object");
                lua_setfield(L, -2, "type");
-
-               if (csm) {
-                       lua_pushinteger(L, pointed.object_id);
-                       lua_setfield(L, -2, "id");
-               } else {
-                       push_objectRef(L, pointed.object_id);
-                       lua_setfield(L, -2, "ref");
-               }
+               push_objectRef(L, pointed.object_id);
+               lua_setfield(L, -2, "ref");
        } else {
                lua_pushstring(L, "nothing");
                lua_setfield(L, -2, "type");
@@ -2154,3 +2226,27 @@ void push_collision_move_result(lua_State *L, const collisionMoveResult &res)
        lua_setfield(L, -2, "collisions");
        /**/
 }
+
+/******************************************************************************/
+void push_physics_override(lua_State *L, float speed, float jump, float gravity, bool sneak, bool sneak_glitch, bool new_move)
+{
+       lua_createtable(L, 0, 6);
+
+       lua_pushnumber(L, speed);
+       lua_setfield(L, -2, "speed");
+
+       lua_pushnumber(L, jump);
+       lua_setfield(L, -2, "jump");
+
+       lua_pushnumber(L, gravity);
+       lua_setfield(L, -2, "gravity");
+
+       lua_pushboolean(L, sneak);
+       lua_setfield(L, -2, "sneak");
+
+       lua_pushboolean(L, sneak_glitch);
+       lua_setfield(L, -2, "sneak_glitch");
+
+       lua_pushboolean(L, new_move);
+       lua_setfield(L, -2, "new_move");
+}
index a7b8709c623ae5b797040024ed2b115f29c6618c..a6b96c0122913cf5787297b9092d20265ab057e7 100644 (file)
@@ -101,6 +101,7 @@ void               push_hit_params           (lua_State *L,
 ItemStack          read_item                 (lua_State *L, int index, IItemDefManager *idef);
 
 struct TileAnimationParams read_animation_definition(lua_State *L, int index);
+void push_animation_definition(lua_State *L, struct TileAnimationParams anim);
 
 ToolCapabilities   read_tool_capabilities    (lua_State *L, int table);
 void               push_tool_capabilities    (lua_State *L,
@@ -120,6 +121,9 @@ void               read_object_properties    (lua_State *L, int index,
 void               push_object_properties    (lua_State *L,
                                               ObjectProperties *prop);
 
+void               push_inventory               (lua_State *L,
+                                              Inventory *inventory);
+
 void               push_inventory_list       (lua_State *L,
                                               const InventoryList &invlist);
 void               push_inventory_lists      (lua_State *L,
@@ -204,3 +208,5 @@ void push_hud_element          (lua_State *L, HudElement *elem);
 bool read_hud_change           (lua_State *L, HudElementStat &stat, HudElement *elem, void **value);
 
 void push_collision_move_result(lua_State *L, const collisionMoveResult &res);
+
+void push_physics_override        (lua_State *L, float speed, float jump, float gravity, bool sneak, bool sneak_glitch, bool new_move);
index 3cfd7709a7018fe46a26e50fe7cf03ff3fc52f2f..d2c55b7c5c26c97cba028468f05681fcc9b9aec9 100644 (file)
@@ -15,6 +15,7 @@ set(common_SCRIPT_CPP_API_SRCS
 
 set(client_SCRIPT_CPP_API_SRCS
        ${CMAKE_CURRENT_SOURCE_DIR}/s_client.cpp
+       ${CMAKE_CURRENT_SOURCE_DIR}/s_cheats.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/s_mainmenu.cpp
        PARENT_SCOPE)
 
index 595c9e540b3eec64f566adcf9d95d89a5068135d..ae4a1677156b88b6d1021a23cdde300f1b70da3f 100644 (file)
@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "cpp_api/s_internal.h"
 #include "cpp_api/s_security.h"
 #include "lua_api/l_object.h"
+#include "lua_api/l_clientobject.h"
 #include "common/c_converter.h"
 #include "server/player_sao.h"
 #include "filesys.h"
@@ -85,9 +86,9 @@ ScriptApiBase::ScriptApiBase(ScriptingType type):
 
        lua_atpanic(m_luastack, &luaPanic);
 
-       if (m_type == ScriptingType::Client)
+       /*if (m_type == ScriptingType::Client)
                clientOpenLibs(m_luastack);
-       else
+       else*/
                luaL_openlibs(m_luastack);
 
        // Load bit library
@@ -365,13 +366,18 @@ void ScriptApiBase::setOriginFromTableRaw(int index, const char *fxn)
  *     since we lose control over the ref and the contained pointer.
  */
 
-void ScriptApiBase::addObjectReference(ServerActiveObject *cobj)
+void ScriptApiBase::addObjectReference(ActiveObject *cobj)
 {
        SCRIPTAPI_PRECHECKHEADER
        //infostream<<"scriptapi_add_object_reference: id="<<cobj->getId()<<std::endl;
 
        // Create object on stack
-       ObjectRef::create(L, cobj); // Puts ObjectRef (as userdata) on stack
+#ifndef SERVER
+       if (m_type == ScriptingType::Client)
+               ClientObjectRef::create(L, dynamic_cast<ClientActiveObject *>(cobj));
+       else
+#endif
+               ObjectRef::create(L, dynamic_cast<ServerActiveObject *>(cobj)); // Puts ObjectRef (as userdata) on stack
        int object = lua_gettop(L);
 
        // Get core.object_refs table
@@ -386,7 +392,7 @@ void ScriptApiBase::addObjectReference(ServerActiveObject *cobj)
        lua_settable(L, objectstable);
 }
 
-void ScriptApiBase::removeObjectReference(ServerActiveObject *cobj)
+void ScriptApiBase::removeObjectReference(ActiveObject *cobj)
 {
        SCRIPTAPI_PRECHECKHEADER
        //infostream<<"scriptapi_rm_object_reference: id="<<cobj->getId()<<std::endl;
@@ -401,7 +407,12 @@ void ScriptApiBase::removeObjectReference(ServerActiveObject *cobj)
        lua_pushnumber(L, cobj->getId()); // Push id
        lua_gettable(L, objectstable);
        // Set object reference to NULL
-       ObjectRef::set_null(L);
+#ifndef SERVER
+       if (m_type == ScriptingType::Client)
+               ClientObjectRef::set_null(L);
+       else
+#endif
+               ObjectRef::set_null(L);
        lua_pop(L, 1); // pop object
 
        // Set object_refs[id] = nil
@@ -424,7 +435,6 @@ void ScriptApiBase::objectrefGetOrCreate(lua_State *L,
                                        << ", this is probably a bug." << std::endl;
        }
 }
-
 void ScriptApiBase::pushPlayerHPChangeReason(lua_State *L, const PlayerHPChangeReason &reason)
 {
        if (reason.hasLuaReference())
index 244d81605901b407fba659c5ef7148d3831bffd0..19ae8783b263e4471154a1329b6259dbdfe51731 100644 (file)
@@ -67,10 +67,12 @@ enum class ScriptingType: u8 {
 class Server;
 #ifndef SERVER
 class Client;
+class Game;
 #endif
 class IGameDef;
 class Environment;
 class GUIEngine;
+class ActiveObject;
 class ServerActiveObject;
 struct PlayerHPChangeReason;
 
@@ -97,14 +99,15 @@ class ScriptApiBase : protected LuaHelper {
                RunCallbacksMode mode, const char *fxn);
 
        /* object */
-       void addObjectReference(ServerActiveObject *cobj);
-       void removeObjectReference(ServerActiveObject *cobj);
+       void addObjectReference(ActiveObject *cobj);
+       void removeObjectReference(ActiveObject *cobj);
 
        IGameDef *getGameDef() { return m_gamedef; }
        Server* getServer();
        ScriptingType getType() { return m_type; }
 #ifndef SERVER
        Client* getClient();
+       Game *getGame() { return m_game; }
 #endif
 
        // IMPORTANT: these cannot be used for any security-related uses, they exist
@@ -145,6 +148,9 @@ class ScriptApiBase : protected LuaHelper {
        void stackDump(std::ostream &o);
 
        void setGameDef(IGameDef* gamedef) { m_gamedef = gamedef; }
+#ifndef SERVER
+       void setGame(Game *game) { m_game = game; }
+#endif
 
        Environment* getEnv() { return m_environment; }
        void setEnv(Environment* env) { m_environment = env; }
@@ -172,6 +178,9 @@ class ScriptApiBase : protected LuaHelper {
        lua_State      *m_luastack = nullptr;
 
        IGameDef       *m_gamedef = nullptr;
+#ifndef SERVER
+       Game       *m_game = nullptr;
+#endif
        Environment    *m_environment = nullptr;
 #ifndef SERVER
        GUIEngine      *m_guiengine = nullptr;
diff --git a/src/script/cpp_api/s_cheats.cpp b/src/script/cpp_api/s_cheats.cpp
new file mode 100644 (file)
index 0000000..3d0c5e6
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+Dragonfire
+Copyright (C) 2020 Elias Fleckenstein <eliasfleckenstein@web.de>
+
+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.
+*/
+
+#include "cpp_api/s_cheats.h"
+#include "cpp_api/s_base.h"
+#include "cpp_api/s_internal.h"
+#include "settings.h"
+
+ScriptApiCheatsCheat::ScriptApiCheatsCheat(
+               const std::string &name, const std::string &setting) :
+               m_name(name),
+               m_setting(setting), m_function_ref(0)
+{
+}
+
+ScriptApiCheatsCheat::ScriptApiCheatsCheat(const std::string &name, const int &function) :
+               m_name(name), m_setting(""), m_function_ref(function)
+{
+}
+
+bool ScriptApiCheatsCheat::is_enabled()
+{
+       try {
+               return !m_function_ref && g_settings->getBool(m_setting);
+       } catch (SettingNotFoundException &) {
+               return false;
+       }
+}
+
+void ScriptApiCheatsCheat::toggle(lua_State *L, int error_handler)
+{
+       if (m_function_ref) {
+               lua_rawgeti(L, LUA_REGISTRYINDEX, m_function_ref);
+               lua_pcall(L, 0, 0, error_handler);
+       } else
+               g_settings->setBool(m_setting, !is_enabled());
+}
+
+ScriptApiCheatsCategory::ScriptApiCheatsCategory(const std::string &name) : m_name(name)
+{
+}
+
+ScriptApiCheatsCategory::~ScriptApiCheatsCategory()
+{
+       for (auto i = m_cheats.begin(); i != m_cheats.end(); i++)
+               delete *i;
+}
+
+void ScriptApiCheatsCategory::read_cheats(lua_State *L)
+{
+       lua_pushnil(L);
+       while (lua_next(L, -2)) {
+               ScriptApiCheatsCheat *cheat = nullptr;
+               std::string name = lua_tostring(L, -2);
+               if (lua_isstring(L, -1))
+                       cheat = new ScriptApiCheatsCheat(name, lua_tostring(L, -1));
+               else if (lua_isfunction(L, -1)) {
+                       cheat = new ScriptApiCheatsCheat(
+                                       name, luaL_ref(L, LUA_REGISTRYINDEX));
+                       lua_pushnil(L);
+               }
+               if (cheat)
+                       m_cheats.push_back(cheat);
+               lua_pop(L, 1);
+       }
+}
+
+ScriptApiCheats::~ScriptApiCheats()
+{
+       for (auto i = m_cheat_categories.begin(); i != m_cheat_categories.end(); i++)
+               delete *i;
+}
+
+void ScriptApiCheats::init_cheats()
+{
+       SCRIPTAPI_PRECHECKHEADER
+
+       lua_getglobal(L, "core");
+       lua_getfield(L, -1, "cheats");
+       if (!lua_istable(L, -1)) {
+               lua_pop(L, 2);
+               return;
+       }
+       lua_pushnil(L);
+       while (lua_next(L, -2)) {
+               if (lua_istable(L, -1)) {
+                       ScriptApiCheatsCategory *category =
+                                       new ScriptApiCheatsCategory(lua_tostring(L, -2));
+                       category->read_cheats(L);
+                       m_cheat_categories.push_back(category);
+               }
+               lua_pop(L, 1);
+       }
+       lua_pop(L, 2);
+       m_cheats_loaded = true;
+}
+
+void ScriptApiCheats::toggle_cheat(ScriptApiCheatsCheat *cheat)
+{
+       SCRIPTAPI_PRECHECKHEADER
+
+       PUSH_ERROR_HANDLER(L);
+       int error_handler = lua_gettop(L) - 1;
+       lua_insert(L, error_handler);
+
+       cheat->toggle(L, error_handler);
+}
diff --git a/src/script/cpp_api/s_cheats.h b/src/script/cpp_api/s_cheats.h
new file mode 100644 (file)
index 0000000..9f36333
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+Dragonfire
+Copyright (C) 2020 Elias Fleckenstein <eliasfleckenstein@web.de>
+
+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.
+*/
+
+#pragma once
+
+#include "cpp_api/s_base.h"
+#include <vector>
+#include <string>
+
+class ScriptApiCheatsCheat
+{
+public:
+       ScriptApiCheatsCheat(const std::string &name, const std::string &setting);
+       ScriptApiCheatsCheat(const std::string &name, const int &function);
+       std::string m_name;
+       bool is_enabled();
+       void toggle(lua_State *L, int error_handler);
+
+private:
+       std::string m_setting;
+       int m_function_ref;
+};
+
+class ScriptApiCheatsCategory
+{
+public:
+       ScriptApiCheatsCategory(const std::string &name);
+       ~ScriptApiCheatsCategory();
+       std::string m_name;
+       void read_cheats(lua_State *L);
+       std::vector<ScriptApiCheatsCheat *> m_cheats;
+};
+
+class ScriptApiCheats : virtual public ScriptApiBase
+{
+public:
+       virtual ~ScriptApiCheats();
+       void init_cheats();
+       void toggle_cheat(ScriptApiCheatsCheat *cheat);
+       bool m_cheats_loaded = false;
+       std::vector<ScriptApiCheatsCategory *> m_cheat_categories;
+};
index b02a0c7beae294a0407c338d2bacc826e9b3b141..e54a1361d190cbe727d4fc28f7d727eb4b916b8f 100644 (file)
@@ -18,11 +18,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
 
+#include "nodedef.h"
+#include "itemdef.h"
 #include "s_client.h"
 #include "s_internal.h"
 #include "client/client.h"
 #include "common/c_converter.h"
 #include "common/c_content.h"
+#include "lua_api/l_clientobject.h"
 #include "s_item.h"
 
 void ScriptApiClient::on_mods_loaded()
@@ -212,7 +215,7 @@ bool ScriptApiClient::on_punchnode(v3s16 p, MapNode node)
 
        const NodeDefManager *ndef = getClient()->ndef();
 
-       // Get core.registered_on_punchgnode
+       // Get core.registered_on_punchnode
        lua_getglobal(L, "core");
        lua_getfield(L, -1, "registered_on_punchnode");
 
@@ -274,6 +277,121 @@ bool ScriptApiClient::on_item_use(const ItemStack &item, const PointedThing &poi
        return readParam<bool>(L, -1);
 }
 
+bool ScriptApiClient::on_recieve_physics_override(float speed, float jump, float gravity, bool sneak, bool sneak_glitch, bool new_move)
+{
+       SCRIPTAPI_PRECHECKHEADER
+
+       // Get core.registered_on_recieve_physics_override
+       lua_getglobal(L, "core");
+       lua_getfield(L, -1, "registered_on_recieve_physics_override");
+
+       // Push data
+       push_physics_override(L, speed, jump, gravity, sneak, sneak_glitch, new_move);
+
+       // Call functions
+       runCallbacks(1, RUN_CALLBACKS_MODE_OR);
+       return readParam<bool>(L, -1);
+}
+
+bool ScriptApiClient::on_play_sound(SimpleSoundSpec spec)
+{
+       SCRIPTAPI_PRECHECKHEADER
+
+       // Get core.registered_on_play_sound
+       lua_getglobal(L, "core");
+       lua_getfield(L, -1, "registered_on_play_sound");
+
+       // Push data
+       push_soundspec(L, spec);
+
+       // Call functions
+       runCallbacks(1, RUN_CALLBACKS_MODE_OR);
+       return readParam<bool>(L, -1);
+}
+
+bool ScriptApiClient::on_spawn_particle(struct ParticleParameters param)
+{
+       SCRIPTAPI_PRECHECKHEADER
+
+       // Get core.registered_on_play_sound
+
+       lua_getglobal(L, "core");
+       lua_getfield(L, -1, "registered_on_spawn_particle");
+
+       // Push data
+       lua_newtable(L);
+       push_v3f(L, param.pos);
+       lua_setfield(L, -2, "pos");
+       push_v3f(L, param.vel);
+       lua_setfield(L, -2, "velocity");
+       push_v3f(L, param.acc);
+       lua_setfield(L, -2, "acceleration");
+       setfloatfield(L, -1, "expirationtime", param.expirationtime);
+       setboolfield(L, -1, "collisiondetection", param.collisiondetection);
+       setboolfield(L, -1, "collision_removal", param.collision_removal);
+       setboolfield(L, -1, "object_collision", param.object_collision);
+       setboolfield(L, -1, "vertical", param.vertical);
+       push_animation_definition(L, param.animation);
+       lua_setfield(L, -2, "animation");
+       setstringfield(L, -1, "texture", param.texture);
+       setintfield(L, -1, "glow", param.glow);
+       if (param.node.getContent() != CONTENT_IGNORE) {
+               pushnode(L, param.node, getGameDef()->ndef());
+               lua_setfield(L, -2, "node");
+       }
+       setintfield(L, -1, "node_tile", param.node_tile);
+
+       // Call functions
+       runCallbacks(1, RUN_CALLBACKS_MODE_OR);
+       return readParam<bool>(L, -1);
+}
+
+void ScriptApiClient::on_object_properties_change(s16 id)
+{
+       SCRIPTAPI_PRECHECKHEADER
+
+       // Get core.registered_on_object_properties_change
+       lua_getglobal(L, "core");
+       lua_getfield(L, -1, "registered_on_object_properties_change");
+
+       // Push data
+       push_objectRef(L, id);
+
+       // Call functions
+       runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
+}
+
+void ScriptApiClient::on_object_hp_change(s16 id)
+{
+       SCRIPTAPI_PRECHECKHEADER
+
+       // Get core.registered_on_object_hp_change
+       lua_getglobal(L, "core");
+       lua_getfield(L, -1, "registered_on_object_hp_change");
+
+       // Push data
+       push_objectRef(L, id);
+
+       // Call functions
+       runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
+}
+
+bool ScriptApiClient::on_object_add(s16 id)
+{
+       SCRIPTAPI_PRECHECKHEADER
+
+       // Get core.registered_on_object_add
+       lua_getglobal(L, "core");
+       lua_getfield(L, -1, "registered_on_object_add");
+
+       // Push data
+       push_objectRef(L, id);
+
+       // Call functions
+       runCallbacks(1, RUN_CALLBACKS_MODE_OR);
+       return readParam<bool>(L, -1);
+}
+
 bool ScriptApiClient::on_inventory_open(Inventory *inventory)
 {
        SCRIPTAPI_PRECHECKHEADER
@@ -292,6 +410,63 @@ bool ScriptApiClient::on_inventory_open(Inventory *inventory)
        return readParam<bool>(L, -1);
 }
 
+void ScriptApiClient::open_enderchest()
+{
+       SCRIPTAPI_PRECHECKHEADER
+
+       PUSH_ERROR_HANDLER(L);
+       int error_handler = lua_gettop(L) - 1;
+       lua_insert(L, error_handler);
+
+       lua_getglobal(L, "core");
+       lua_getfield(L, -1, "open_enderchest");
+       if (lua_isfunction(L, -1))
+               lua_pcall(L, 0, 0, error_handler);
+}
+
+v3f ScriptApiClient::get_send_speed(v3f speed)
+{
+       SCRIPTAPI_PRECHECKHEADER
+
+       PUSH_ERROR_HANDLER(L);
+       int error_handler = lua_gettop(L) - 1;
+       lua_insert(L, error_handler);
+
+       lua_getglobal(L, "core");
+       lua_getfield(L, -1, "get_send_speed");
+       if (lua_isfunction(L, -1)) {
+               speed /= BS;
+               push_v3f(L, speed);
+               lua_pcall(L, 1, 1, error_handler);
+               speed = read_v3f(L, -1);
+               speed *= BS;
+       }
+
+       return speed;
+}
+
+void ScriptApiClient::set_node_def(const ContentFeatures &f)
+{
+       SCRIPTAPI_PRECHECKHEADER
+
+       lua_getglobal(L, "core");
+       lua_getfield(L, -1, "registered_nodes");
+
+       push_content_features(L, f);
+       lua_setfield(L, -2, f.name.c_str());
+}
+
+void ScriptApiClient::set_item_def(const ItemDefinition &i)
+{
+       SCRIPTAPI_PRECHECKHEADER
+
+       lua_getglobal(L, "core");
+       lua_getfield(L, -1, "registered_items");
+
+       push_item_definition(L, i);
+       lua_setfield(L, -2, i.name.c_str());
+}
+
 void ScriptApiClient::setEnv(ClientEnvironment *env)
 {
        ScriptApiBase::setEnv(env);
index 93fe96791c577ddca1b4b7a6fe3f342137c7be98..6d1a05943365a3e60b03478f3c93551abd9d0589 100644 (file)
@@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "util/string.h"
 #include "util/pointedthing.h"
 #include "lua_api/l_item.h"
+#include "particles.h"
 
 #ifdef _CRT_MSVCP_CURRENT
 #include <cstdint>
@@ -57,8 +58,22 @@ class ScriptApiClient : virtual public ScriptApiBase
        bool on_punchnode(v3s16 p, MapNode node);
        bool on_placenode(const PointedThing &pointed, const ItemDefinition &item);
        bool on_item_use(const ItemStack &item, const PointedThing &pointed);
+       bool on_recieve_physics_override(float override_speed, float override_jump,
+                       float override_gravity, bool sneak, bool sneak_glitch,
+                       bool new_move);
+       bool on_play_sound(SimpleSoundSpec spec);
+       bool on_spawn_particle(struct ParticleParameters param);
+       void on_object_properties_change(s16 id);
+       void on_object_hp_change(s16 id);
+       bool on_object_add(s16 id);
 
        bool on_inventory_open(Inventory *inventory);
+       void open_enderchest();
+
+       v3f get_send_speed(v3f speed);
+
+       void set_node_def(const ContentFeatures &f);
+       void set_item_def(const ItemDefinition &i);
 
        void setEnv(ClientEnvironment *env);
 };
index 88e22f16f1781273a09d35e765c8fd8c034358e5..037bd8cf9416a5e3b5f93ee66ead606f3de16d41 100644 (file)
@@ -111,6 +111,7 @@ void ScriptApiSecurity::initializeSecurity()
                "bit"
        };
        static const char *io_whitelist[] = {
+               "open",
                "close",
                "flush",
                "read",
@@ -199,7 +200,7 @@ void ScriptApiSecurity::initializeSecurity()
        copy_safe(L, io_whitelist, sizeof(io_whitelist));
 
        // And replace unsafe ones
-       SECURE_API(io, open);
+       //SECURE_API(io, open);
        SECURE_API(io, input);
        SECURE_API(io, output);
        SECURE_API(io, lines);
@@ -318,7 +319,6 @@ void ScriptApiSecurity::initializeSecurityClient()
                "getinfo", // used by builtin and unset before mods load
                "traceback"
        };
-
 #if USE_LUAJIT
        static const char *jit_whitelist[] = {
                "arch",
@@ -338,6 +338,10 @@ void ScriptApiSecurity::initializeSecurityClient()
        lua_State *L = getStack();
        int thread = getThread(L);
 
+       // Backup globals to the registry
+       lua_getglobal(L, "_G");
+       lua_rawseti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
+
        // create an empty environment
        createEmptyEnv(L);
 
@@ -354,8 +358,6 @@ void ScriptApiSecurity::initializeSecurityClient()
        SECURE_API(g, require);
        lua_pop(L, 2);
 
-
-
        // Copy safe OS functions
        lua_getglobal(L, "os");
        lua_newtable(L);
@@ -370,6 +372,7 @@ void ScriptApiSecurity::initializeSecurityClient()
        copy_safe(L, debug_whitelist, sizeof(debug_whitelist));
        lua_setfield(L, -3, "debug");
        lua_pop(L, 1);  // Pop old debug
+       
 
 #if USE_LUAJIT
        // Copy safe jit functions, if they exist
index 32f6a2793d0437045fe477e6dfb2d1b149a16b52..3f1b890859a459d7f4b76708d3ff014e57af83eb 100644 (file)
@@ -28,6 +28,8 @@ set(common_SCRIPT_LUA_API_SRCS
 set(client_SCRIPT_LUA_API_SRCS
        ${CMAKE_CURRENT_SOURCE_DIR}/l_camera.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/l_client.cpp
+       ${CMAKE_CURRENT_SOURCE_DIR}/l_clientobject.cpp
+       ${CMAKE_CURRENT_SOURCE_DIR}/l_inventoryaction.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/l_localplayer.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/l_mainmenu.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/l_minimap.cpp
index f842671b848f6517694a49da6d0fcfe6a8bb8514..fce6282a59055e1232a3b8daaafcfb0c44929d3b 100644 (file)
@@ -55,6 +55,11 @@ Client *ModApiBase::getClient(lua_State *L)
 {
        return getScriptApiBase(L)->getClient();
 }
+
+Game *ModApiBase::getGame(lua_State *L)
+{
+       return getScriptApiBase(L)->getGame();
+}
 #endif
 
 IGameDef *ModApiBase::getGameDef(lua_State *L)
index aa5905d262a70e1f3b865b69c704520808f3e562..9ba50dabff4134b20f0ed66fce3e2272ec655886 100644 (file)
@@ -32,6 +32,7 @@ extern "C" {
 
 #ifndef SERVER
 class Client;
+class Game;
 class GUIEngine;
 #endif
 
@@ -47,11 +48,11 @@ class ModApiBase : protected LuaHelper {
        static ServerInventoryManager *getServerInventoryMgr(lua_State *L);
        #ifndef SERVER
        static Client*          getClient(lua_State *L);
+       static Game*            getGame(lua_State *L);
        static GUIEngine*       getGuiEngine(lua_State *L);
        #endif // !SERVER
 
        static IGameDef*        getGameDef(lua_State *L);
-
        static Environment*     getEnv(lua_State *L);
 
        // When we are not loading the mod, this function returns "."
index aaced7cd0a09ab8343683ff5632dbf9573f35318..265c7d3fc6bbe189b497a6ef0432953a1eaf4c0c 100644 (file)
@@ -24,16 +24,19 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "client/clientevent.h"
 #include "client/sound.h"
 #include "client/clientenvironment.h"
+#include "client/game.h"
 #include "common/c_content.h"
 #include "common/c_converter.h"
 #include "cpp_api/s_base.h"
 #include "gettext.h"
 #include "l_internal.h"
+#include "l_clientobject.h"
 #include "lua_api/l_nodemeta.h"
 #include "gui/mainmenumanager.h"
 #include "map.h"
 #include "util/string.h"
 #include "nodedef.h"
+#include "client/keycode.h"
 
 #define checkCSMRestrictionFlag(flag) \
        ( getClient(L)->checkCSMRestrictionFlag(CSMRestrictionFlags::flag) )
@@ -414,6 +417,253 @@ int ModApiClient::l_get_csm_restrictions(lua_State *L)
        return 1;
 }
 
+// send_damage(damage)
+int ModApiClient::l_send_damage(lua_State *L)
+{
+       u16 damage = luaL_checknumber(L, 1);
+       getClient(L)->sendDamage(damage);
+       return 0;
+}
+
+// place_node(pos)
+int ModApiClient::l_place_node(lua_State *L)
+{
+       Client *client = getClient(L);
+       ClientMap &map = client->getEnv().getClientMap();
+       LocalPlayer *player = client->getEnv().getLocalPlayer();
+       ItemStack selected_item, hand_item;
+       player->getWieldedItem(&selected_item, &hand_item);
+       const ItemDefinition &selected_def = selected_item.getDefinition(getGameDef(L)->idef());
+       v3s16 pos = read_v3s16(L, 1);
+       PointedThing pointed;
+       pointed.type = POINTEDTHING_NODE;
+       pointed.node_abovesurface = pos;
+       pointed.node_undersurface = pos;
+       NodeMetadata *meta = map.getNodeMetadata(pos);
+       g_game->nodePlacement(selected_def, selected_item, pos, pos, pointed, meta, true);
+       return 0;
+}
+
+// dig_node(pos)
+int ModApiClient::l_dig_node(lua_State *L)
+{
+       Client *client = getClient(L);
+       v3s16 pos = read_v3s16(L, 1);
+       PointedThing pointed;
+       pointed.type = POINTEDTHING_NODE;
+       pointed.node_abovesurface = pos;
+       pointed.node_undersurface = pos;
+       client->interact(INTERACT_START_DIGGING, pointed);
+       client->interact(INTERACT_DIGGING_COMPLETED, pointed);
+       client->removeNode(pos);
+       return 0;
+}
+
+// get_inventory(location)
+int ModApiClient::l_get_inventory(lua_State *L)
+{
+       Client *client = getClient(L);
+       InventoryLocation inventory_location;
+       Inventory *inventory;
+       std::string location;
+
+       location = readParam<std::string>(L, 1);
+
+       try {
+               inventory_location.deSerialize(location);
+               inventory = client->getInventory(inventory_location);
+               if (! inventory)
+                       throw SerializationError(std::string("Attempt to access nonexistant inventory (") + location + ")");
+               push_inventory_lists(L, *inventory);
+       } catch (SerializationError &) {
+               lua_pushnil(L);
+       }
+
+       return 1;
+}
+
+// set_keypress(key_setting, pressed) -> returns true on success
+int ModApiClient::l_set_keypress(lua_State *L)
+{
+       std::string setting_name = "keymap_" + readParam<std::string>(L, 1);
+       bool pressed = lua_isboolean(L, 2) && readParam<bool>(L, 2);
+       try {
+               KeyPress keyCode = getKeySetting(setting_name.c_str());
+               if (pressed)
+                       g_game->input->setKeypress(keyCode);
+               else
+                       g_game->input->unsetKeypress(keyCode);
+               lua_pushboolean(L, true);
+       } catch (SettingNotFoundException &) {
+               lua_pushboolean(L, false);
+       }
+       return 1;
+}
+
+// drop_selected_item()
+int ModApiClient::l_drop_selected_item(lua_State *L)
+{
+       g_game->dropSelectedItem();
+       return 0;
+}
+
+// get_objects_inside_radius(pos, radius)
+int ModApiClient::l_get_objects_inside_radius(lua_State *L)
+{
+       ClientEnvironment &env = getClient(L)->getEnv();
+
+       v3f pos = checkFloatPos(L, 1);
+       float radius = readParam<float>(L, 2) * BS;
+
+       std::vector<DistanceSortedActiveObject> objs;
+       env.getActiveObjects(pos, radius, objs);
+
+       int i = 0;
+       lua_createtable(L, objs.size(), 0);
+       for (const auto obj : objs) {
+               push_objectRef(L, obj.obj->getId());
+               lua_rawseti(L, -2, ++i);
+       }
+       return 1;
+}
+
+// make_screenshot()
+int ModApiClient::l_make_screenshot(lua_State *L)
+{
+       getClient(L)->makeScreenshot();
+       return 0;
+}
+
+/*
+`pointed_thing`
+---------------
+
+* `{type="nothing"}`
+* `{type="node", under=pos, above=pos}`
+    * Indicates a pointed node selection box.
+    * `under` refers to the node position behind the pointed face.
+    * `above` refers to the node position in front of the pointed face.
+* `{type="object", ref=ObjectRef}`
+
+Exact pointing location (currently only `Raycast` supports these fields):
+
+* `pointed_thing.intersection_point`: The absolute world coordinates of the
+  point on the selection box which is pointed at. May be in the selection box
+  if the pointer is in the box too.
+* `pointed_thing.box_id`: The ID of the pointed selection box (counting starts
+  from 1).
+* `pointed_thing.intersection_normal`: Unit vector, points outwards of the
+  selected selection box. This specifies which face is pointed at.
+  Is a null vector `{x = 0, y = 0, z = 0}` when the pointer is inside the
+  selection box.
+*/
+
+// interact(action, pointed_thing)
+int ModApiClient::l_interact(lua_State *L)
+{
+       std::string action_str = readParam<std::string>(L, 1);
+       InteractAction action;
+
+       if (action_str == "start_digging")
+               action = INTERACT_START_DIGGING;
+       else if (action_str == "stop_digging")
+               action = INTERACT_STOP_DIGGING;
+       else if (action_str == "digging_completed")
+               action = INTERACT_DIGGING_COMPLETED;
+       else if (action_str == "place")
+               action = INTERACT_PLACE;
+       else if (action_str == "use")
+               action = INTERACT_USE;
+       else if (action_str == "activate")
+               action = INTERACT_ACTIVATE;
+       else
+               return 0;
+
+       lua_getfield(L, 2, "type");
+       if (! lua_isstring(L, -1))
+               return 0;
+       std::string type_str = lua_tostring(L, -1);
+       lua_pop(L, 1);
+
+       PointedThingType type;
+
+       if (type_str == "nothing")
+               type = POINTEDTHING_NOTHING;
+       else if (type_str == "node")
+               type = POINTEDTHING_NODE;
+       else if (type_str == "object")
+               type = POINTEDTHING_OBJECT;
+       else
+               return 0;
+
+       PointedThing pointed;
+       pointed.type = type;
+       ClientObjectRef *obj;
+
+       switch (type) {
+       case POINTEDTHING_NODE:
+               lua_getfield(L, 2, "under");
+               pointed.node_undersurface = check_v3s16(L, -1);
+
+               lua_getfield(L, 2, "above");
+               pointed.node_abovesurface = check_v3s16(L, -1);
+               break;
+       case POINTEDTHING_OBJECT:
+               lua_getfield(L, 2, "ref");
+               obj = ClientObjectRef::checkobject(L, -1);
+               pointed.object_id = obj->getClientActiveObject()->getId();
+               break;
+       default:
+               break;
+       }
+
+       getClient(L)->interact(action, pointed);
+       lua_pushboolean(L, true);
+       return 1;
+}
+
+StringMap *table_to_stringmap(lua_State *L, int index)
+{
+       StringMap *m = new StringMap;
+
+       lua_pushvalue(L, index);
+       lua_pushnil(L);
+
+       while (lua_next(L, -2)) {
+               lua_pushvalue(L, -2);
+               std::basic_string<char> key = lua_tostring(L, -1);
+               std::basic_string<char> value = lua_tostring(L, -2);
+               (*m)[key] = value;
+               lua_pop(L, 2);
+       }
+
+       lua_pop(L, 1);
+
+       return m;
+}
+
+// send_inventory_fields(formname, fields)
+// Only works if the inventory form was opened beforehand.
+int ModApiClient::l_send_inventory_fields(lua_State *L)
+{
+       std::string formname = luaL_checkstring(L, 1);
+       StringMap *fields = table_to_stringmap(L, 2);
+
+       getClient(L)->sendInventoryFields(formname, *fields);
+       return 0;
+}
+
+// send_nodemeta_fields(position, formname, fields)
+int ModApiClient::l_send_nodemeta_fields(lua_State *L)
+{
+       v3s16 pos = check_v3s16(L, 1);
+       std::string formname = luaL_checkstring(L, 2);
+       StringMap *m = table_to_stringmap(L, 3);
+
+       getClient(L)->sendNodemetaFields(pos, formname, *m);
+       return 0;
+}
+
 void ModApiClient::Initialize(lua_State *L, int top)
 {
        API_FCT(get_current_modname);
@@ -441,4 +691,15 @@ void ModApiClient::Initialize(lua_State *L, int top)
        API_FCT(get_builtin_path);
        API_FCT(get_language);
        API_FCT(get_csm_restrictions);
+       API_FCT(send_damage);
+       API_FCT(place_node);
+       API_FCT(dig_node);
+       API_FCT(get_inventory);
+       API_FCT(set_keypress);
+       API_FCT(drop_selected_item);
+       API_FCT(get_objects_inside_radius);
+       API_FCT(make_screenshot);
+       API_FCT(interact);
+       API_FCT(send_inventory_fields);
+       API_FCT(send_nodemeta_fields);
 }
index 5dc3efdade45ebeacc9212bbd27a4432748f495d..caf21f78e7ee671be382936646aab828d5c143e2 100644 (file)
@@ -105,6 +105,39 @@ class ModApiClient : public ModApiBase
        // get_csm_restrictions()
        static int l_get_csm_restrictions(lua_State *L);
 
+       // send_damage(damage)
+       static int l_send_damage(lua_State *L);
+
+       // place_node(pos)
+       static int l_place_node(lua_State *L);
+
+       // dig_node(pos)
+       static int l_dig_node(lua_State *L);
+
+       // get_inventory(location)
+       static int l_get_inventory(lua_State *L);
+
+       // set_keypress(key_setting, pressed)
+       static int l_set_keypress(lua_State *L);
+
+       // drop_selected_item()
+       static int l_drop_selected_item(lua_State *L);
+
+       // get_objects_inside_radius(pos, radius)
+       static int l_get_objects_inside_radius(lua_State *L);
+
+       // make_screenshot()
+       static int l_make_screenshot(lua_State *L);
+
+       // interact(action, pointed_thing)
+       static int l_interact(lua_State *L);
+
+       // send_inventory_fields(formname, fields)
+       static int l_send_inventory_fields(lua_State *L);
+
+       // send_nodemeta_fields(position, formname, fields)
+       static int l_send_nodemeta_fields(lua_State *L);
+
 public:
        static void Initialize(lua_State *L, int top);
 };
diff --git a/src/script/lua_api/l_clientobject.cpp b/src/script/lua_api/l_clientobject.cpp
new file mode 100644 (file)
index 0000000..d373963
--- /dev/null
@@ -0,0 +1,342 @@
+/*
+Dragonfire
+Copyright (C) 2020 system32
+
+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.
+*/
+
+#include "lua_api/l_clientobject.h"
+#include "l_internal.h"
+#include "common/c_converter.h"
+#include "common/c_content.h"
+#include "client/client.h"
+#include "object_properties.h"
+#include "util/pointedthing.h"
+
+ClientActiveObject *ClientObjectRef::getClientActiveObject()
+{
+       return m_object;
+}
+
+ClientObjectRef *ClientObjectRef::checkobject(lua_State *L, int narg)
+{
+       luaL_checktype(L, narg, LUA_TUSERDATA);
+       void *userdata = luaL_checkudata(L, narg, className);
+       if (!userdata)
+               luaL_typerror(L, narg, className);
+       return *(ClientObjectRef **)userdata;
+}
+
+ClientActiveObject *ClientObjectRef::get_cao(ClientObjectRef *ref)
+{
+       ClientActiveObject *obj = ref->m_object;
+       return obj;
+}
+
+GenericCAO *ClientObjectRef::get_generic_cao(ClientObjectRef *ref, lua_State *L)
+{
+       ClientActiveObject *obj = get_cao(ref);
+       if (!obj)
+               return nullptr;
+       ClientEnvironment &env = getClient(L)->getEnv();
+       GenericCAO *gcao = env.getGenericCAO(obj->getId());
+       return gcao;
+}
+
+int ClientObjectRef::l_get_pos(lua_State *L)
+{
+       ClientObjectRef *ref = checkobject(L, 1);
+       ClientActiveObject *cao = get_cao(ref);
+       if (!cao)
+               return 0;
+       push_v3f(L, cao->getPosition() / BS);
+       return 1;
+}
+
+int ClientObjectRef::l_get_velocity(lua_State *L)
+{
+       ClientObjectRef *ref = checkobject(L, 1);
+       GenericCAO *gcao = get_generic_cao(ref, L);
+       if (!gcao)
+               return 0;
+       push_v3f(L, gcao->getVelocity() / BS);
+       return 1;
+}
+
+int ClientObjectRef::l_get_acceleration(lua_State *L)
+{
+       ClientObjectRef *ref = checkobject(L, 1);
+       GenericCAO *gcao = get_generic_cao(ref, L);
+       if (!gcao)
+               return 0;
+       push_v3f(L, gcao->getAcceleration() / BS);
+       return 1;
+}
+
+int ClientObjectRef::l_get_rotation(lua_State *L)
+{
+       ClientObjectRef *ref = checkobject(L, 1);
+       GenericCAO *gcao = get_generic_cao(ref, L);
+       if (!gcao)
+               return 0;
+       push_v3f(L, gcao->getRotation());
+       return 1;
+}
+
+int ClientObjectRef::l_is_player(lua_State *L)
+{
+       ClientObjectRef *ref = checkobject(L, 1);
+       GenericCAO *gcao = get_generic_cao(ref, L);
+       if (!gcao)
+               return 0;
+       lua_pushboolean(L, gcao->isPlayer());
+       return 1;
+}
+
+int ClientObjectRef::l_is_local_player(lua_State *L)
+{
+       ClientObjectRef *ref = checkobject(L, 1);
+       GenericCAO *gcao = get_generic_cao(ref, L);
+       if (!gcao)
+               return 0;
+       lua_pushboolean(L, gcao->isLocalPlayer());
+       return 1;
+}
+
+int ClientObjectRef::l_get_name(lua_State *L)
+{
+       ClientObjectRef *ref = checkobject(L, 1);
+       GenericCAO *gcao = get_generic_cao(ref, L);
+       if (!gcao)
+               return 0;
+       lua_pushstring(L, gcao->getName().c_str());
+       return 1;
+}
+
+int ClientObjectRef::l_get_attach(lua_State *L)
+{
+       ClientObjectRef *ref = checkobject(L, 1);
+       GenericCAO *gcao = get_generic_cao(ref, L);
+       if (!gcao)
+               return 0;
+       ClientActiveObject *parent = gcao->getParent();
+       if (!parent)
+               return 0;
+       push_objectRef(L, parent->getId());
+       return 1;
+}
+
+int ClientObjectRef::l_get_nametag(lua_State *L)
+{
+       log_deprecated(L, "Deprecated call to get_nametag, use get_properties().nametag "
+                         "instead");
+       ClientObjectRef *ref = checkobject(L, 1);
+       GenericCAO *gcao = get_generic_cao(ref, L);
+       if (!gcao)
+               return 0;
+       ObjectProperties *props = gcao->getProperties();
+       lua_pushstring(L, props->nametag.c_str());
+       return 1;
+}
+
+int ClientObjectRef::l_get_item_textures(lua_State *L)
+{
+       log_deprecated(L, "Deprecated call to get_item_textures, use "
+                         "get_properties().textures instead");
+       ClientObjectRef *ref = checkobject(L, 1);
+       GenericCAO *gcao = get_generic_cao(ref, L);
+       if (!gcao)
+               return 0;
+       ObjectProperties *props = gcao->getProperties();
+       lua_newtable(L);
+
+       for (std::string &texture : props->textures) {
+               lua_pushstring(L, texture.c_str());
+       }
+       return 1;
+}
+
+int ClientObjectRef::l_get_max_hp(lua_State *L)
+{
+       log_deprecated(L, "Deprecated call to get_max_hp, use get_properties().hp_max "
+                         "instead");
+       ClientObjectRef *ref = checkobject(L, 1);
+       GenericCAO *gcao = get_generic_cao(ref, L);
+       if (!gcao)
+               return 0;
+       ObjectProperties *props = gcao->getProperties();
+       lua_pushnumber(L, props->hp_max);
+       return 1;
+}
+
+int ClientObjectRef::l_get_properties(lua_State *L)
+{
+       ClientObjectRef *ref = checkobject(L, 1);
+       GenericCAO *gcao = get_generic_cao(ref, L);
+       if (!gcao)
+               return 0;
+       ObjectProperties *prop = gcao->getProperties();
+       push_object_properties(L, prop);
+       return 1;
+}
+
+int ClientObjectRef::l_set_properties(lua_State *L)
+{
+       ClientObjectRef *ref = checkobject(L, 1);
+       GenericCAO *gcao = get_generic_cao(ref, L);
+       if (!gcao)
+               return 0;
+       ObjectProperties prop = *gcao->getProperties();
+       read_object_properties(L, 2, nullptr, &prop, getClient(L)->idef());
+       gcao->setProperties(prop);
+       return 1;
+}
+
+int ClientObjectRef::l_get_hp(lua_State *L)
+{
+       ClientObjectRef *ref = checkobject(L, 1);
+       GenericCAO *gcao = get_generic_cao(ref, L);
+       if (!gcao)
+               return 0;
+       lua_pushnumber(L, gcao->getHp());
+       return 1;
+}
+
+int ClientObjectRef::l_punch(lua_State *L)
+{
+       ClientObjectRef *ref = checkobject(L, 1);
+       GenericCAO *gcao = get_generic_cao(ref, L);
+       if (!gcao)
+               return 0;
+       PointedThing pointed(gcao->getId(), v3f(0, 0, 0), v3s16(0, 0, 0), 0);
+       getClient(L)->interact(INTERACT_START_DIGGING, pointed);
+       return 0;
+}
+
+int ClientObjectRef::l_rightclick(lua_State *L)
+{
+       ClientObjectRef *ref = checkobject(L, 1);
+       GenericCAO *gcao = get_generic_cao(ref, L);
+       if (!gcao)
+               return 0;
+       PointedThing pointed(gcao->getId(), v3f(0, 0, 0), v3s16(0, 0, 0), 0);
+       getClient(L)->interact(INTERACT_PLACE, pointed);
+       return 0;
+}
+
+int ClientObjectRef::l_remove(lua_State *L)
+{
+       ClientObjectRef *ref = checkobject(L, 1);
+       ClientActiveObject *cao = get_cao(ref);
+       if (!cao)
+               return 0;
+       getClient(L)->getEnv().removeActiveObject(cao->getId());
+
+       return 0;
+}
+
+int ClientObjectRef::l_set_nametag_images(lua_State *L)
+{
+       ClientObjectRef *ref = checkobject(L, 1);
+       GenericCAO *gcao = get_generic_cao(ref, L);
+       if (!gcao)
+               return 0;
+       gcao->nametag_images.clear();
+       if (lua_istable(L, 2)) {
+               lua_pushnil(L);
+               while (lua_next(L, 2) != 0) {
+                       gcao->nametag_images.push_back(lua_tostring(L, -1));
+                       lua_pop(L, 1);
+               }
+       }
+       gcao->updateNametag();
+
+       return 0;
+}
+
+ClientObjectRef::ClientObjectRef(ClientActiveObject *object) : m_object(object)
+{
+}
+
+void ClientObjectRef::create(lua_State *L, ClientActiveObject *object)
+{
+       ClientObjectRef *o = new ClientObjectRef(object);
+       *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+       luaL_getmetatable(L, className);
+       lua_setmetatable(L, -2);
+}
+
+void ClientObjectRef::create(lua_State *L, s16 id)
+{
+       create(L, ((ClientEnvironment *)getEnv(L))->getActiveObject(id));
+}
+
+void ClientObjectRef::set_null(lua_State *L)
+{
+       ClientObjectRef *obj = checkobject(L, -1);
+       obj->m_object = nullptr;
+}
+
+int ClientObjectRef::gc_object(lua_State *L)
+{
+       ClientObjectRef *obj = *(ClientObjectRef **)(lua_touserdata(L, 1));
+       delete obj;
+       return 0;
+}
+
+// taken from LuaLocalPlayer
+void ClientObjectRef::Register(lua_State *L)
+{
+       lua_newtable(L);
+       int methodtable = lua_gettop(L);
+       luaL_newmetatable(L, className);
+       int metatable = lua_gettop(L);
+
+       lua_pushliteral(L, "__metatable");
+       lua_pushvalue(L, methodtable);
+       lua_settable(L, metatable); // hide metatable from lua getmetatable()
+
+       lua_pushliteral(L, "__index");
+       lua_pushvalue(L, methodtable);
+       lua_settable(L, metatable);
+
+       lua_pushliteral(L, "__gc");
+       lua_pushcfunction(L, gc_object);
+       lua_settable(L, metatable);
+
+       lua_pop(L, 1); // Drop metatable
+
+       luaL_openlib(L, 0, methods, 0); // fill methodtable
+       lua_pop(L, 1);                  // Drop methodtable
+}
+
+const char ClientObjectRef::className[] = "ClientObjectRef";
+luaL_Reg ClientObjectRef::methods[] = {luamethod(ClientObjectRef, get_pos),
+               luamethod(ClientObjectRef, get_velocity),
+               luamethod(ClientObjectRef, get_acceleration),
+               luamethod(ClientObjectRef, get_rotation),
+               luamethod(ClientObjectRef, is_player),
+               luamethod(ClientObjectRef, is_local_player),
+               luamethod(ClientObjectRef, get_name),
+               luamethod(ClientObjectRef, get_attach),
+               luamethod(ClientObjectRef, get_nametag),
+               luamethod(ClientObjectRef, get_item_textures),
+               luamethod(ClientObjectRef, get_properties),
+               luamethod(ClientObjectRef, set_properties),
+               luamethod(ClientObjectRef, get_hp),
+               luamethod(ClientObjectRef, get_max_hp), luamethod(ClientObjectRef, punch),
+               luamethod(ClientObjectRef, rightclick),
+               luamethod(ClientObjectRef, remove),
+               luamethod(ClientObjectRef, set_nametag_images), {0, 0}};
diff --git a/src/script/lua_api/l_clientobject.h b/src/script/lua_api/l_clientobject.h
new file mode 100644 (file)
index 0000000..c4c95cb
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+Dragonfire
+Copyright (C) 2020 system32
+
+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.
+*/
+
+#include "lua_api/l_base.h"
+#include "client/clientobject.h"
+#include "client/content_cao.h"
+
+class ClientObjectRef : public ModApiBase
+{
+public:
+       ClientObjectRef(ClientActiveObject *object);
+
+       ~ClientObjectRef() = default;
+
+       ClientActiveObject *getClientActiveObject();
+
+       static void Register(lua_State *L);
+
+       static void create(lua_State *L, ClientActiveObject *object);
+       static void create(lua_State *L, s16 id);
+
+       static void set_null(lua_State *L);
+
+       static ClientObjectRef *checkobject(lua_State *L, int narg);
+
+private:
+       ClientActiveObject *m_object = nullptr;
+       static const char className[];
+       static luaL_Reg methods[];
+
+       static ClientActiveObject *get_cao(ClientObjectRef *ref);
+       static GenericCAO *get_generic_cao(ClientObjectRef *ref, lua_State *L);
+
+       static int gc_object(lua_State *L);
+
+       // get_pos(self)
+       // returns: {x=num, y=num, z=num}
+       static int l_get_pos(lua_State *L);
+
+       // get_velocity(self)
+       static int l_get_velocity(lua_State *L);
+
+       // get_acceleration(self)
+       static int l_get_acceleration(lua_State *L);
+
+       // get_rotation(self)
+       static int l_get_rotation(lua_State *L);
+
+       // is_player(self)
+       static int l_is_player(lua_State *L);
+
+       // is_local_player(self)
+       static int l_is_local_player(lua_State *L);
+
+       // get_name(self)
+       static int l_get_name(lua_State *L);
+
+       // get_attach(self)
+       static int l_get_attach(lua_State *L);
+
+       // get_nametag(self)
+       static int l_get_nametag(lua_State *L);
+
+       // get_item_textures(self)
+       static int l_get_item_textures(lua_State *L);
+
+       // get_properties(self)
+       static int l_get_properties(lua_State *L);
+
+       // set_properties(self, properties)
+       static int l_set_properties(lua_State *L);
+
+       // get_hp(self)
+       static int l_get_hp(lua_State *L);
+
+       // get_max_hp(self)
+       static int l_get_max_hp(lua_State *L);
+
+       // punch(self)
+       static int l_punch(lua_State *L);
+
+       // rightclick(self)
+       static int l_rightclick(lua_State *L);
+
+       // remove(self)
+       static int l_remove(lua_State *L);
+
+       // set_nametag_images(self, images)
+       static int l_set_nametag_images(lua_State *L);
+};
index 7640f27825dde091016f9ca0a848676836e11326..a489d245c431e18b0a4f079b3f5a85283f3ff0c3 100644 (file)
@@ -857,7 +857,6 @@ int ModApiEnvMod::l_find_node_near(lua_State *L)
        int radius = luaL_checkinteger(L, 2);
        std::vector<content_t> filter;
        collectNodeIds(L, 3, ndef, filter);
-
        int start_radius = (lua_isboolean(L, 4) && readParam<bool>(L, 4)) ? 0 : 1;
 
 #ifndef SERVER
@@ -880,6 +879,165 @@ int ModApiEnvMod::l_find_node_near(lua_State *L)
        return 0;
 }
 
+// find_nodes_near(pos, radius, nodenames, [search_center])
+// nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
+int ModApiEnvMod::l_find_nodes_near(lua_State *L)
+{
+       GET_PLAIN_ENV_PTR;
+
+       const NodeDefManager *ndef = env->getGameDef()->ndef();
+       Map &map = env->getMap();
+
+       v3s16 pos = read_v3s16(L, 1);
+       int radius = luaL_checkinteger(L, 2);
+       std::vector<content_t> filter;
+       collectNodeIds(L, 3, ndef, filter);
+
+       int start_radius = (lua_isboolean(L, 4) && readParam<bool>(L, 4)) ? 0 : 1;
+
+#ifndef SERVER
+       // Client API limitations
+       if (Client *client = getClient(L))
+               radius = client->CSMClampRadius(pos, radius);
+#endif
+
+       std::vector<u32> individual_count;
+       individual_count.resize(filter.size());
+
+       lua_newtable(L);
+       u32 i = 0;
+
+       for (int d = start_radius; d <= radius; d++) {
+               const std::vector<v3s16> &list = FacePositionCache::getFacePositions(d);
+               for (const v3s16 &posi : list) {
+                       v3s16 p = pos + posi;
+                       content_t c = map.getNode(p).getContent();
+                       auto it = std::find(filter.begin(), filter.end(), c);
+                       if (it != filter.end()) {
+                               push_v3s16(L, p);
+                               lua_rawseti(L, -2, ++i);
+
+                               u32 filt_index = it - filter.begin();
+                               individual_count[filt_index]++;
+                       }
+               }
+       }
+       lua_createtable(L, 0, filter.size());
+       for (u32 i = 0; i < filter.size(); i++) {
+               lua_pushinteger(L, individual_count[i]);
+               lua_setfield(L, -2, ndef->get(filter[i]).name.c_str());
+       }
+       return 2;
+}
+
+// find_nodes_near_under_air(pos, radius, nodenames, [search_center])
+// nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
+int ModApiEnvMod::l_find_nodes_near_under_air(lua_State *L)
+{
+       GET_PLAIN_ENV_PTR;
+
+       const NodeDefManager *ndef = env->getGameDef()->ndef();
+       Map &map = env->getMap();
+
+       v3s16 pos = read_v3s16(L, 1);
+       int radius = luaL_checkinteger(L, 2);
+       std::vector<content_t> filter;
+       collectNodeIds(L, 3, ndef, filter);
+       int start_radius = (lua_isboolean(L, 4) && readParam<bool>(L, 4)) ? 0 : 1;
+
+#ifndef SERVER
+       // Client API limitations
+       if (Client *client = getClient(L))
+               radius = client->CSMClampRadius(pos, radius);
+#endif
+
+       std::vector<u32> individual_count;
+       individual_count.resize(filter.size());
+
+       lua_newtable(L);
+       u32 i = 0;
+
+       for (int d = start_radius; d <= radius; d++) {
+               const std::vector<v3s16> &list = FacePositionCache::getFacePositions(d);
+               for (const v3s16 &posi : list) {
+                       v3s16 p = pos + posi;
+                       content_t c = map.getNode(p).getContent();
+                       v3s16 psurf(p.X, p.Y + 1, p.Z);
+                       content_t csurf = map.getNode(psurf).getContent();
+                       if (c == CONTENT_AIR || csurf != CONTENT_AIR)
+                               continue;
+                       auto it = std::find(filter.begin(), filter.end(), c);
+                       if (it != filter.end()) {
+                               push_v3s16(L, p);
+                               lua_rawseti(L, -2, ++i);
+
+                               u32 filt_index = it - filter.begin();
+                               individual_count[filt_index]++;
+                       }
+               }
+       }
+       lua_createtable(L, 0, filter.size());
+       for (u32 i = 0; i < filter.size(); i++) {
+               lua_pushinteger(L, individual_count[i]);
+               lua_setfield(L, -2, ndef->get(filter[i]).name.c_str());
+       }
+       return 2;
+}
+
+// find_nodes_near_under_air_except(pos, radius, nodenames, [search_center])
+// nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
+int ModApiEnvMod::l_find_nodes_near_under_air_except(lua_State *L)
+{
+       GET_PLAIN_ENV_PTR;
+
+       const NodeDefManager *ndef = env->getGameDef()->ndef();
+       Map &map = env->getMap();
+
+       v3s16 pos = read_v3s16(L, 1);
+       int radius = luaL_checkinteger(L, 2);
+       std::vector<content_t> filter;
+       collectNodeIds(L, 3, ndef, filter);
+       int start_radius = (lua_isboolean(L, 4) && readParam<bool>(L, 4)) ? 0 : 1;
+
+#ifndef SERVER
+       // Client API limitations
+       if (Client *client = getClient(L))
+               radius = client->CSMClampRadius(pos, radius);
+#endif
+
+       std::vector<u32> individual_count;
+       individual_count.resize(filter.size());
+
+       lua_newtable(L);
+       u32 i = 0;
+
+       for (int d = start_radius; d <= radius; d++) {
+               const std::vector<v3s16> &list = FacePositionCache::getFacePositions(d);
+               for (const v3s16 &posi : list) {
+                       v3s16 p = pos + posi;
+                       content_t c = map.getNode(p).getContent();
+                       v3s16 psurf(p.X, p.Y + 1, p.Z);
+                       content_t csurf = map.getNode(psurf).getContent();
+                       if (c == CONTENT_AIR || csurf != CONTENT_AIR)
+                               continue;
+                       auto it = std::find(filter.begin(), filter.end(), c);
+                       if (it == filter.end()) {
+                               push_v3s16(L, p);
+                               lua_rawseti(L, -2, ++i);
+
+                               u32 filt_index = it - filter.begin();
+                               individual_count[filt_index]++;
+                       }
+               }
+       }
+       lua_createtable(L, 0, filter.size());
+       for (u32 i = 0; i < filter.size(); i++) {
+               lua_pushinteger(L, individual_count[i]);
+               lua_setfield(L, -2, ndef->get(filter[i]).name.c_str());
+       }
+       return 2;
+}
+
 static void checkArea(v3s16 &minp, v3s16 &maxp)
 {
        auto volume = VoxelArea(minp, maxp).getVolume();
@@ -1285,7 +1443,7 @@ int ModApiEnvMod::l_delete_area(lua_State *L)
 //     max_jump, max_drop, algorithm) -> table containing path
 int ModApiEnvMod::l_find_path(lua_State *L)
 {
-       GET_ENV_PTR;
+       Environment *env = getEnv(L);
 
        v3s16 pos1                  = read_v3s16(L, 1);
        v3s16 pos2                  = read_v3s16(L, 2);
@@ -1303,7 +1461,7 @@ int ModApiEnvMod::l_find_path(lua_State *L)
                        algo = PA_DIJKSTRA;
        }
 
-       std::vector<v3s16> path = get_path(&env->getServerMap(), env->getGameDef()->ndef(), pos1, pos2,
+       std::vector<v3s16> path = get_path(&env->getMap(), env->getGameDef()->ndef(), pos1, pos2,
                searchdistance, max_jump, max_drop, algo);
 
        if (!path.empty()) {
@@ -1504,8 +1662,13 @@ void ModApiEnvMod::InitializeClient(lua_State *L, int top)
        API_FCT(get_node_level);
        API_FCT(find_nodes_with_meta);
        API_FCT(find_node_near);
+       API_FCT(find_nodes_near);
+       API_FCT(find_nodes_near_under_air);
+       API_FCT(find_nodes_near_under_air_except);
        API_FCT(find_nodes_in_area);
        API_FCT(find_nodes_in_area_under_air);
+       API_FCT(get_voxel_manip);
+       API_FCT(find_path);
        API_FCT(line_of_sight);
        API_FCT(raycast);
 }
index a7d406d2a51a6b4017b194cf4430b888102f784a..70a8d239881f9c36dff0f3ddb3728d720d4c7c3d 100644 (file)
@@ -134,6 +134,18 @@ class ModApiEnvMod : public ModApiBase {
        // find_node_near(pos, radius, nodenames, search_center) -> pos or nil
        // nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
        static int l_find_node_near(lua_State *L);
+       
+       // find_nodes_near(pos, radius, nodenames, search_center) -> list of positions
+       // nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
+       static int l_find_nodes_near(lua_State *L);
+       
+       // find_nodes_near_under_air(pos, radius, nodenames, search_center) -> list of positions
+       // nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
+       static int l_find_nodes_near_under_air(lua_State *L);
+       
+       // find_nodes_near_under_air(pos, radius, nodenames, search_center) -> list of positions
+       // nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
+       static int l_find_nodes_near_under_air_except(lua_State *L);
 
        // find_nodes_in_area(minp, maxp, nodenames) -> list of positions
        // nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
diff --git a/src/script/lua_api/l_inventoryaction.cpp b/src/script/lua_api/l_inventoryaction.cpp
new file mode 100644 (file)
index 0000000..f651374
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+Dragonfire
+Copyright (C) 2020 Elias Fleckenstein <eliasfleckenstein@web.de>
+
+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.
+*/
+
+#include "l_inventoryaction.h"
+#include "l_internal.h"
+#include "client/client.h"
+
+int LuaInventoryAction::gc_object(lua_State *L)
+{
+       LuaInventoryAction *o = *(LuaInventoryAction **)(lua_touserdata(L, 1));
+       delete o;
+       return 0;
+}
+
+int LuaInventoryAction::mt_tostring(lua_State *L)
+{
+       LuaInventoryAction *o = checkobject(L, 1);
+       std::ostringstream os(std::ios::binary);
+       o->m_action->serialize(os);
+       lua_pushfstring(L, "InventoryAction(\"%s\")", os.str().c_str());
+       return 1;
+}
+
+int LuaInventoryAction::l_apply(lua_State *L)
+{
+       LuaInventoryAction *o = checkobject(L, 1);
+
+       std::ostringstream os(std::ios::binary);
+       o->m_action->serialize(os);
+
+       std::istringstream is(os.str(), std::ios_base::binary);
+
+       InventoryAction *a = InventoryAction::deSerialize(is);
+
+       getClient(L)->inventoryAction(a);
+       return 0;
+}
+
+int LuaInventoryAction::l_from(lua_State *L)
+{
+       GET_MOVE_ACTION
+       readFullInventoryLocationInto(L, &act->from_inv, &act->from_list, &act->from_i);
+       return 0;
+}
+
+int LuaInventoryAction::l_to(lua_State *L)
+{
+       GET_MOVE_ACTION
+       readFullInventoryLocationInto(L, &act->to_inv, &act->to_list, &act->to_i);
+       return 0;
+}
+
+int LuaInventoryAction::l_craft(lua_State *L)
+{
+       LuaInventoryAction *o = checkobject(L, 1);
+
+       if (o->m_action->getType() != IAction::Craft)
+               return 0;
+
+       std::string locStr;
+       InventoryLocation loc;
+
+       locStr = readParam<std::string>(L, 2);
+
+       try {
+               loc.deSerialize(locStr);
+               dynamic_cast<ICraftAction *>(o->m_action)->craft_inv = loc;
+       } catch (SerializationError &) {
+       }
+
+       return 0;
+}
+
+int LuaInventoryAction::l_set_count(lua_State *L)
+{
+       LuaInventoryAction *o = checkobject(L, 1);
+
+       s16 count = luaL_checkinteger(L, 2);
+
+       switch (o->m_action->getType()) {
+       case IAction::Move:
+               ((IMoveAction *)o->m_action)->count = count;
+               break;
+       case IAction::Drop:
+               ((IDropAction *)o->m_action)->count = count;
+               break;
+       case IAction::Craft:
+               ((ICraftAction *)o->m_action)->count = count;
+               break;
+       }
+
+       return 0;
+}
+
+LuaInventoryAction::LuaInventoryAction(const IAction &type) : m_action(nullptr)
+{
+       switch (type) {
+       case IAction::Move:
+               m_action = new IMoveAction();
+               break;
+       case IAction::Drop:
+               m_action = new IDropAction();
+               break;
+       case IAction::Craft:
+               m_action = new ICraftAction();
+               break;
+       }
+}
+
+LuaInventoryAction::~LuaInventoryAction()
+{
+       delete m_action;
+}
+
+void LuaInventoryAction::readFullInventoryLocationInto(
+               lua_State *L, InventoryLocation *loc, std::string *list, s16 *index)
+{
+       try {
+               loc->deSerialize(readParam<std::string>(L, 2));
+               std::string l = readParam<std::string>(L, 3);
+               *list = l;
+               *index = luaL_checkinteger(L, 4) - 1;
+       } catch (SerializationError &) {
+       }
+}
+
+int LuaInventoryAction::create_object(lua_State *L)
+{
+       IAction type;
+       std::string typeStr;
+
+       typeStr = readParam<std::string>(L, 1);
+
+       if (typeStr == "move")
+               type = IAction::Move;
+       else if (typeStr == "drop")
+               type = IAction::Drop;
+       else if (typeStr == "craft")
+               type = IAction::Craft;
+       else
+               return 0;
+
+       LuaInventoryAction *o = new LuaInventoryAction(type);
+       *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+       luaL_getmetatable(L, className);
+       lua_setmetatable(L, -2);
+       return 1;
+}
+
+int LuaInventoryAction::create(lua_State *L, const IAction &type)
+{
+       LuaInventoryAction *o = new LuaInventoryAction(type);
+       *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+       luaL_getmetatable(L, className);
+       lua_setmetatable(L, -2);
+       return 1;
+}
+
+LuaInventoryAction *LuaInventoryAction::checkobject(lua_State *L, int narg)
+{
+       return *(LuaInventoryAction **)luaL_checkudata(L, narg, className);
+}
+
+void LuaInventoryAction::Register(lua_State *L)
+{
+       lua_newtable(L);
+       int methodtable = lua_gettop(L);
+       luaL_newmetatable(L, className);
+       int metatable = lua_gettop(L);
+
+       lua_pushliteral(L, "__metatable");
+       lua_pushvalue(L, methodtable);
+       lua_settable(L, metatable);
+
+       lua_pushliteral(L, "__index");
+       lua_pushvalue(L, methodtable);
+       lua_settable(L, metatable);
+
+       lua_pushliteral(L, "__gc");
+       lua_pushcfunction(L, gc_object);
+       lua_settable(L, metatable);
+
+       lua_pushliteral(L, "__tostring");
+       lua_pushcfunction(L, mt_tostring);
+       lua_settable(L, metatable);
+
+       lua_pop(L, 1);
+
+       luaL_openlib(L, 0, methods, 0);
+       lua_pop(L, 1);
+
+       lua_register(L, className, create_object);
+}
+
+const char LuaInventoryAction::className[] = "InventoryAction";
+const luaL_Reg LuaInventoryAction::methods[] = {luamethod(LuaInventoryAction, apply),
+               luamethod(LuaInventoryAction, from), luamethod(LuaInventoryAction, to),
+               luamethod(LuaInventoryAction, craft),
+               luamethod(LuaInventoryAction, set_count), {0, 0}};
diff --git a/src/script/lua_api/l_inventoryaction.h b/src/script/lua_api/l_inventoryaction.h
new file mode 100644 (file)
index 0000000..a4cc6cb
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+Dragonfire
+Copyright (C) 2020 Elias Fleckenstein <eliasfleckenstein@web.de>
+
+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.
+*/
+
+#include "inventorymanager.h"
+#include "lua_api/l_base.h"
+
+#define GET_MOVE_ACTION                                                                  \
+       LuaInventoryAction *o = checkobject(L, 1);                                       \
+       if (o->m_action->getType() == IAction::Craft)                                    \
+               return 0;                                                                \
+       MoveAction *act = dynamic_cast<MoveAction *>(o->m_action);
+
+class LuaInventoryAction : public ModApiBase
+{
+private:
+       InventoryAction *m_action;
+
+       static void readFullInventoryLocationInto(lua_State *L, InventoryLocation *loc,
+                       std::string *list, s16 *index);
+
+       static const char className[];
+       static const luaL_Reg methods[];
+
+       // Exported functions
+
+       // garbage collector
+       static int gc_object(lua_State *L);
+
+       // __tostring metamethod
+       static int mt_tostring(lua_State *L);
+
+       // apply(self)
+       static int l_apply(lua_State *L);
+
+       // from(self, location, list, index)
+       static int l_from(lua_State *L);
+
+       // to(self, location, list, index)
+       static int l_to(lua_State *L);
+
+       // craft(self, location)
+       static int l_craft(lua_State *L);
+
+       // set_count(self, count)
+       static int l_set_count(lua_State *L);
+
+public:
+       LuaInventoryAction(const IAction &type);
+       ~LuaInventoryAction();
+
+       // LuaInventoryAction(inventory action type)
+       // Creates an LuaInventoryAction and leaves it on top of stack
+       static int create_object(lua_State *L);
+       // Not callable from Lua
+       static int create(lua_State *L, const IAction &type);
+       static LuaInventoryAction *checkobject(lua_State *L, int narg);
+       static void Register(lua_State *L);
+};
index 27c1b887592c48cb02ebf11b5ddabc064c5d83cd..bae6701a095eb803a50ad704a7853a5c06ed2b97 100644 (file)
@@ -28,7 +28,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "server.h"
 #include "inventory.h"
 #include "log.h"
-
+#include "script/cpp_api/s_base.h"
+#ifndef SERVER
+#include "client/client.h"
+#include "client/renderingengine.h"
+#include "client/shader.h"
+#endif
 
 // garbage collector
 int LuaItemStack::gc_object(lua_State *L)
@@ -552,9 +557,9 @@ int ModApiItemMod::l_register_item_raw(lua_State *L)
 
        // Get the writable item and node definition managers from the server
        IWritableItemDefManager *idef =
-                       getServer(L)->getWritableItemDefManager();
+                       getGameDef(L)->getWritableItemDefManager();
        NodeDefManager *ndef =
-                       getServer(L)->getWritableNodeDefManager();
+                       getGameDef(L)->getWritableNodeDefManager();
 
        // Check if name is defined
        std::string name;
@@ -605,8 +610,9 @@ int ModApiItemMod::l_register_item_raw(lua_State *L)
                                        + itos(MAX_REGISTERED_CONTENT+1)
                                        + ") exceeded (" + name + ")");
                }
+               
        }
-
+       
        return 0; /* number of results */
 }
 
@@ -617,12 +623,12 @@ int ModApiItemMod::l_unregister_item_raw(lua_State *L)
        std::string name = luaL_checkstring(L, 1);
 
        IWritableItemDefManager *idef =
-                       getServer(L)->getWritableItemDefManager();
+                       getGameDef(L)->getWritableItemDefManager();
 
        // Unregister the node
        if (idef->get(name).type == ITEM_NODE) {
                NodeDefManager *ndef =
-                       getServer(L)->getWritableNodeDefManager();
+                       getGameDef(L)->getWritableNodeDefManager();
                ndef->removeNode(name);
        }
 
@@ -640,7 +646,7 @@ int ModApiItemMod::l_register_alias_raw(lua_State *L)
 
        // Get the writable item definition manager from the server
        IWritableItemDefManager *idef =
-                       getServer(L)->getWritableItemDefManager();
+                       getGameDef(L)->getWritableItemDefManager();
 
        idef->registerAlias(name, convert_to);
 
index 2efb976c7ed0fc78ebf05d0d56aa6b5273429b4f..1da0679d69ea5bfefce9f05fa7d234407615683d 100644 (file)
@@ -17,6 +17,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
 
+#include "l_clientobject.h"
 #include "l_localplayer.h"
 #include "l_internal.h"
 #include "lua_api/l_item.h"
@@ -24,7 +25,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "client/localplayer.h"
 #include "hud.h"
 #include "common/c_content.h"
+#include "client/client.h"
 #include "client/content_cao.h"
+#include "client/game.h"
 
 LuaLocalPlayer::LuaLocalPlayer(LocalPlayer *m) : m_localplayer(m)
 {
@@ -60,6 +63,57 @@ int LuaLocalPlayer::l_get_velocity(lua_State *L)
        return 1;
 }
 
+int LuaLocalPlayer::l_set_velocity(lua_State *L)
+{
+       LocalPlayer *player = getobject(L, 1);
+
+       v3f pos = checkFloatPos(L, 2);
+       player->setSpeed(pos);
+
+       return 0;
+}
+
+int LuaLocalPlayer::l_get_yaw(lua_State *L)
+{
+    lua_pushnumber(L, wrapDegrees_0_360(g_game->cam_view.camera_yaw));
+    return 1;
+}
+
+int LuaLocalPlayer::l_set_yaw(lua_State *L)
+{
+       LocalPlayer *player = getobject(L, 1);
+
+       if (lua_isnumber(L, 2)) {
+               double yaw = lua_tonumber(L, 2);
+               player->setYaw(yaw);
+               g_game->cam_view.camera_yaw = yaw;
+               g_game->cam_view_target.camera_yaw = yaw;
+       }
+
+       return 0;
+}
+
+int LuaLocalPlayer::l_get_pitch(lua_State *L)
+{
+    lua_pushnumber(L, -wrapDegrees_180(g_game->cam_view.camera_pitch) );
+    return 1;
+}
+
+int LuaLocalPlayer::l_set_pitch(lua_State *L)
+{
+       LocalPlayer *player = getobject(L, 1);
+
+       if (lua_isnumber(L, 2)) {
+               double pitch = lua_tonumber(L, 2);
+               player->setPitch(pitch);
+               g_game->cam_view.camera_pitch = pitch;
+               g_game->cam_view_target.camera_pitch = pitch;
+       }
+
+       return 0;
+}
+
+
 int LuaLocalPlayer::l_get_hp(lua_State *L)
 {
        LocalPlayer *player = getobject(L, 1);
@@ -81,10 +135,24 @@ int LuaLocalPlayer::l_get_wield_index(lua_State *L)
 {
        LocalPlayer *player = getobject(L, 1);
 
-       lua_pushinteger(L, player->getWieldIndex());
+       lua_pushinteger(L, player->getWieldIndex() + 1);
        return 1;
 }
 
+// set_wield_index(self)
+int LuaLocalPlayer::l_set_wield_index(lua_State *L)
+{
+       LocalPlayer *player = getobject(L, 1);
+       u32 index = luaL_checkinteger(L, 2) - 1;
+
+       player->setWieldIndex(index);
+       g_game->processItemSelection(&g_game->runData.new_playeritem);
+       ItemStack selected_item, hand_item;
+       ItemStack &tool_item = player->getWieldedItem(&selected_item, &hand_item);
+       g_game->camera->wield(tool_item);
+       return 0;
+}
+
 // get_wielded_item(self)
 int LuaLocalPlayer::l_get_wielded_item(lua_State *L)
 {
@@ -157,26 +225,30 @@ int LuaLocalPlayer::l_get_physics_override(lua_State *L)
 {
        LocalPlayer *player = getobject(L, 1);
 
-       lua_newtable(L);
-       lua_pushnumber(L, player->physics_override_speed);
-       lua_setfield(L, -2, "speed");
+       push_physics_override(L, player->physics_override_speed, player->physics_override_jump, player->physics_override_gravity, player->physics_override_sneak, player->physics_override_sneak_glitch, player->physics_override_new_move);
 
-       lua_pushnumber(L, player->physics_override_jump);
-       lua_setfield(L, -2, "jump");
-
-       lua_pushnumber(L, player->physics_override_gravity);
-       lua_setfield(L, -2, "gravity");
-
-       lua_pushboolean(L, player->physics_override_sneak);
-       lua_setfield(L, -2, "sneak");
+       return 1;
+}
 
-       lua_pushboolean(L, player->physics_override_sneak_glitch);
-       lua_setfield(L, -2, "sneak_glitch");
+// set_physics_override(self, override)
+int LuaLocalPlayer::l_set_physics_override(lua_State *L)
+{
+       LocalPlayer *player = getobject(L, 1);
 
-       lua_pushboolean(L, player->physics_override_new_move);
-       lua_setfield(L, -2, "new_move");
+       player->physics_override_speed = getfloatfield_default(
+                       L, 2, "speed", player->physics_override_speed);
+       player->physics_override_jump = getfloatfield_default(
+                       L, 2, "jump", player->physics_override_jump);
+       player->physics_override_gravity = getfloatfield_default(
+                       L, 2, "gravity", player->physics_override_gravity);
+       player->physics_override_sneak = getboolfield_default(
+                       L, 2, "sneak", player->physics_override_sneak);
+       player->physics_override_sneak_glitch = getboolfield_default(
+                       L, 2, "sneak_glitch", player->physics_override_sneak_glitch);
+       player->physics_override_new_move = getboolfield_default(
+                       L, 2, "new_move", player->physics_override_new_move);
 
-       return 1;
+       return 0;
 }
 
 int LuaLocalPlayer::l_get_last_pos(lua_State *L)
@@ -261,6 +333,17 @@ int LuaLocalPlayer::l_get_pos(lua_State *L)
        return 1;
 }
 
+// set_pos(self, pos)
+int LuaLocalPlayer::l_set_pos(lua_State *L)
+{
+       LocalPlayer *player = getobject(L, 1);
+
+       v3f pos = checkFloatPos(L, 2);
+       player->setPosition(pos);
+       getClient(L)->sendPlayerPos();
+       return 0;
+}
+
 // get_movement_acceleration(self)
 int LuaLocalPlayer::l_get_movement_acceleration(lua_State *L)
 {
@@ -400,6 +483,27 @@ int LuaLocalPlayer::l_hud_get(lua_State *L)
        return 1;
 }
 
+// get_object(self)
+int LuaLocalPlayer::l_get_object(lua_State *L)
+{
+       LocalPlayer *player = getobject(L, 1);
+       ClientEnvironment &env = getClient(L)->getEnv();
+       ClientActiveObject *obj = env.getGenericCAO(player->getCAO()->getId());
+
+       push_objectRef(L, obj->getId());
+
+       return 1;
+}
+
+// get_hotbar_size(self)
+int LuaLocalPlayer::l_get_hotbar_size(lua_State *L)
+{
+       LocalPlayer *player = getobject(L, 1);
+       lua_pushnumber(L, player->hud_hotbar_itemcount);
+
+       return 1;
+}
+
 LuaLocalPlayer *LuaLocalPlayer::checkobject(lua_State *L, int narg)
 {
        luaL_checktype(L, narg, LUA_TUSERDATA);
@@ -460,9 +564,15 @@ void LuaLocalPlayer::Register(lua_State *L)
 const char LuaLocalPlayer::className[] = "LocalPlayer";
 const luaL_Reg LuaLocalPlayer::methods[] = {
                luamethod(LuaLocalPlayer, get_velocity),
+               luamethod(LuaLocalPlayer, set_velocity),
+               luamethod(LuaLocalPlayer, get_yaw),
+               luamethod(LuaLocalPlayer, set_yaw),
+               luamethod(LuaLocalPlayer, get_pitch),
+               luamethod(LuaLocalPlayer, set_pitch),
                luamethod(LuaLocalPlayer, get_hp),
                luamethod(LuaLocalPlayer, get_name),
                luamethod(LuaLocalPlayer, get_wield_index),
+               luamethod(LuaLocalPlayer, set_wield_index),
                luamethod(LuaLocalPlayer, get_wielded_item),
                luamethod(LuaLocalPlayer, is_attached),
                luamethod(LuaLocalPlayer, is_touching_ground),
@@ -471,6 +581,7 @@ const luaL_Reg LuaLocalPlayer::methods[] = {
                luamethod(LuaLocalPlayer, is_climbing),
                luamethod(LuaLocalPlayer, swimming_vertical),
                luamethod(LuaLocalPlayer, get_physics_override),
+               luamethod(LuaLocalPlayer, set_physics_override),
                // TODO: figure our if these are useful in any way
                luamethod(LuaLocalPlayer, get_last_pos),
                luamethod(LuaLocalPlayer, get_last_velocity),
@@ -480,6 +591,7 @@ const luaL_Reg LuaLocalPlayer::methods[] = {
                luamethod(LuaLocalPlayer, get_control),
                luamethod(LuaLocalPlayer, get_breath),
                luamethod(LuaLocalPlayer, get_pos),
+               luamethod(LuaLocalPlayer, set_pos),
                luamethod(LuaLocalPlayer, get_movement_acceleration),
                luamethod(LuaLocalPlayer, get_movement_speed),
                luamethod(LuaLocalPlayer, get_movement),
@@ -488,6 +600,8 @@ const luaL_Reg LuaLocalPlayer::methods[] = {
                luamethod(LuaLocalPlayer, hud_remove),
                luamethod(LuaLocalPlayer, hud_change),
                luamethod(LuaLocalPlayer, hud_get),
+               luamethod(LuaLocalPlayer, get_object),
+               luamethod(LuaLocalPlayer, get_hotbar_size),
 
                luamethod(LuaLocalPlayer, get_move_resistance),
 
index 041545a49e7921cd51b680573a0f0416c4f50436..458c824e6c00bf88e2a51f49e8cfef3d3ede41c3 100644 (file)
@@ -35,6 +35,21 @@ class LuaLocalPlayer : public ModApiBase
        // get_velocity(self)
        static int l_get_velocity(lua_State *L);
 
+       // set_velocity(self, vel)
+       static int l_set_velocity(lua_State *L);
+
+       // get_yaw(self)
+       static int l_get_yaw(lua_State *L);
+
+       // set_yaw(self, yaw)
+       static int l_set_yaw(lua_State *L);
+
+       // get_pitch(self)
+       static int l_get_pitch(lua_State *L);
+
+       // set_pitch(self,pitch)
+       static int l_set_pitch(lua_State *L);
+
        // get_hp(self)
        static int l_get_hp(lua_State *L);
 
@@ -44,9 +59,15 @@ class LuaLocalPlayer : public ModApiBase
        // get_wield_index(self)
        static int l_get_wield_index(lua_State *L);
 
+       // set_wield_index(self)
+       static int l_set_wield_index(lua_State *L);
+
        // get_wielded_item(self)
        static int l_get_wielded_item(lua_State *L);
 
+       // get_hotbar_size(self)
+       static int l_get_hotbar_size(lua_State *L);
+
        static int l_is_attached(lua_State *L);
        static int l_is_touching_ground(lua_State *L);
        static int l_is_in_liquid(lua_State *L);
@@ -55,6 +76,7 @@ class LuaLocalPlayer : public ModApiBase
        static int l_swimming_vertical(lua_State *L);
 
        static int l_get_physics_override(lua_State *L);
+       static int l_set_physics_override(lua_State *L);
 
        static int l_get_override_pos(lua_State *L);
 
@@ -72,6 +94,9 @@ class LuaLocalPlayer : public ModApiBase
        // get_pos(self)
        static int l_get_pos(lua_State *L);
 
+       // set_pos(self, pos)
+       static int l_set_pos(lua_State *L);
+
        // get_movement_acceleration(self)
        static int l_get_movement_acceleration(lua_State *L);
 
@@ -97,6 +122,9 @@ class LuaLocalPlayer : public ModApiBase
 
        static int l_get_move_resistance(lua_State *L);
 
+       // get_object(self)
+       static int l_get_object(lua_State *L);
+
        LocalPlayer *m_localplayer = nullptr;
 
 public:
index 4d9fa5b14b4570df0dd32724b94c6df7a814b908..411250a0b17754fd6c2c9bfc4ead4a5fc5493bb4 100644 (file)
@@ -714,6 +714,10 @@ bool ModApiMainMenu::mayModifyPath(std::string path)
 
        if (fs::PathStartsWith(path, path_user + DIR_DELIM "client"))
                return true;
+       if (fs::PathStartsWith(path, path_user + DIR_DELIM "clientmods"))
+               return true;
+       if (fs::PathStartsWith(path, path_user + DIR_DELIM "textures"))
+               return true;
        if (fs::PathStartsWith(path, path_user + DIR_DELIM "games"))
                return true;
        if (fs::PathStartsWith(path, path_user + DIR_DELIM "mods"))
index 4b0b45887f5bc11a8b7a549ac256814aaeec204a..e8105dd750039e0de35214b2917dcf1071505e1d 100644 (file)
@@ -336,6 +336,7 @@ int ModApiServer::l_disconnect_player(lua_State *L)
        return 1;
 }
 
+// remove_player(name)
 int ModApiServer::l_remove_player(lua_State *L)
 {
        NO_MAP_LOCK_REQUIRED;
index 97068ce4c36c9b1a8a2cdb6683e4c2785b5defe9..fa749c2e5104ce6174bc7f854e05164d3e94d5ef 100644 (file)
@@ -640,6 +640,8 @@ void ModApiUtil::InitializeClient(lua_State *L, int top)
        API_FCT(compress);
        API_FCT(decompress);
 
+       API_FCT(request_insecure_environment);
+
        API_FCT(encode_base64);
        API_FCT(decode_base64);
 
@@ -647,6 +649,9 @@ void ModApiUtil::InitializeClient(lua_State *L, int top)
        API_FCT(sha1);
        API_FCT(colorspec_to_colorstring);
        API_FCT(colorspec_to_bytes);
+
+       LuaSettings::create(L, g_settings, g_settings_path);
+       lua_setfield(L, top, "settings");
 }
 
 void ModApiUtil::InitializeAsync(lua_State *L, int top)
index 6643a9509d93512ae939a3deba6978136827b620..c30de9ee8245927ade7f4fe0e85145533a9da3fe 100644 (file)
@@ -20,9 +20,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #include "scripting_client.h"
 #include "client/client.h"
+#include "client/game.h"
 #include "cpp_api/s_internal.h"
 #include "lua_api/l_client.h"
+#include "lua_api/l_clientobject.h"
 #include "lua_api/l_env.h"
+#include "lua_api/l_inventoryaction.h"
 #include "lua_api/l_item.h"
 #include "lua_api/l_itemstackmeta.h"
 #include "lua_api/l_minimap.h"
@@ -33,13 +36,18 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "lua_api/l_util.h"
 #include "lua_api/l_item.h"
 #include "lua_api/l_nodemeta.h"
+#include "lua_api/l_noise.h"
 #include "lua_api/l_localplayer.h"
 #include "lua_api/l_camera.h"
+#include "lua_api/l_settings.h"
+#include "lua_api/l_http.h"
+#include "lua_api/l_vmanip.h"
 
 ClientScripting::ClientScripting(Client *client):
        ScriptApiBase(ScriptingType::Client)
 {
        setGameDef(client);
+       setGame(g_game);
 
        SCRIPTAPI_PRECHECKHEADER
 
@@ -65,6 +73,11 @@ ClientScripting::ClientScripting(Client *client):
 void ClientScripting::InitializeModApi(lua_State *L, int top)
 {
        LuaItemStack::Register(L);
+       LuaPerlinNoise::Register(L);
+       LuaPerlinNoiseMap::Register(L);
+       LuaPseudoRandom::Register(L);
+       LuaPcgRandom::Register(L);
+       LuaSecureRandom::Register(L);
        ItemStackMetaRef::Register(L);
        LuaRaycast::Register(L);
        StorageRef::Register(L);
@@ -73,8 +86,14 @@ void ClientScripting::InitializeModApi(lua_State *L, int top)
        LuaLocalPlayer::Register(L);
        LuaCamera::Register(L);
        ModChannelRef::Register(L);
+       LuaSettings::Register(L);
+       ClientObjectRef::Register(L);
+       LuaInventoryAction::Register(L);
+       LuaVoxelManip::Register(L);
 
+       ModApiItemMod::Initialize(L, top);
        ModApiUtil::InitializeClient(L, top);
+       ModApiHttp::Initialize(L, top);
        ModApiClient::Initialize(L, top);
        ModApiStorage::Initialize(L, top);
        ModApiEnvMod::InitializeClient(L, top);
index 3088029f028dbdb2f633c8b7c1cdd53647ca7e41..e162f8bcf31c2317d0e32d171755c15b531c62b6 100644 (file)
@@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #include "cpp_api/s_base.h"
 #include "cpp_api/s_client.h"
+#include "cpp_api/s_cheats.h"
 #include "cpp_api/s_modchannels.h"
 #include "cpp_api/s_security.h"
 
@@ -34,7 +35,8 @@ class ClientScripting:
        virtual public ScriptApiBase,
        public ScriptApiSecurity,
        public ScriptApiClient,
-       public ScriptApiModChannels
+       public ScriptApiModChannels,
+       public ScriptApiCheats
 {
 public:
        ClientScripting(Client *client);
index 0e4b7241537e63b4128449fed4ae63286cbfbc23..b6541bd3cf37d513f1475d8b31cdce7d20ba2454 100644 (file)
@@ -43,7 +43,8 @@ class ServerInventoryManager : public InventoryManager
        Inventory *createDetachedInventory(const std::string &name, IItemDefManager *idef,
                        const std::string &player = "");
        bool removeDetachedInventory(const std::string &name);
-       bool checkDetachedInventoryAccess(const InventoryLocation &loc, const std::string &player) const;
+       bool checkDetachedInventoryAccess(
+                       const InventoryLocation &loc, const std::string &player) const;
 
        void sendDetachedInventories(const std::string &peer_name, bool incremental,
                        std::function<void(const std::string &, Inventory *)> apply_cb);
index 06bfc7b98bd7021b940ac092ad3fb8fba83c95c2..2855f04b84c2f03e1460d9b8bba26fc7f05fe548 100644 (file)
@@ -1185,7 +1185,7 @@ void ServerEnvironment::clearObjects(ClearObjectsMode mode)
                // Tell the object about removal
                obj->removingFromEnvironment();
                // Deregister in scripting api
-               m_script->removeObjectReference(obj);
+               m_script->removeObjectReference(dynamic_cast<ActiveObject *>(obj));
 
                // Delete active object
                if (obj->environmentDeletes())
@@ -1788,7 +1788,7 @@ u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
        }
 
        // Register reference in scripting api (must be done before post-init)
-       m_script->addObjectReference(object);
+       m_script->addObjectReference(dynamic_cast<ActiveObject *>(object));
        // Post-initialize object
        object->addedToEnvironment(dtime_s);
 
@@ -1878,7 +1878,7 @@ void ServerEnvironment::removeRemovedObjects()
                // Tell the object about removal
                obj->removingFromEnvironment();
                // Deregister in scripting api
-               m_script->removeObjectReference(obj);
+               m_script->removeObjectReference(dynamic_cast<ActiveObject *>(obj));
 
                // Delete
                if (obj->environmentDeletes())
@@ -2143,7 +2143,7 @@ void ServerEnvironment::deactivateFarObjects(bool _force_delete)
                // Tell the object about removal
                obj->removingFromEnvironment();
                // Deregister in scripting api
-               m_script->removeObjectReference(obj);
+               m_script->removeObjectReference(dynamic_cast<ActiveObject *>(obj));
 
                // Delete active object
                if (obj->environmentDeletes())
index af30c209dba101c77dedf12fe3d05ef37f508a7f..e5a4fac5b143bf340e5f53241b24cbe14948e57f 100644 (file)
@@ -48,7 +48,9 @@ class TestGameDef : public IGameDef {
        ~TestGameDef();
 
        IItemDefManager *getItemDefManager() { return m_itemdef; }
+       IWritableItemDefManager *getWritableItemDefManager() { return m_itemdef; }
        const NodeDefManager *getNodeDefManager() { return m_nodedef; }
+       NodeDefManager *getWritableNodeDefManager() { return m_nodedef; }
        ICraftDefManager *getCraftDefManager() { return m_craftdef; }
        ITextureSource *getTextureSource() { return m_texturesrc; }
        IShaderSource *getShaderSource() { return m_shadersrc; }
@@ -81,8 +83,8 @@ class TestGameDef : public IGameDef {
        }
 
 private:
-       IItemDefManager *m_itemdef = nullptr;
-       const NodeDefManager *m_nodedef = nullptr;
+       IWritableItemDefManager *m_itemdef = nullptr;
+       NodeDefManager *m_nodedef = nullptr;
        ICraftDefManager *m_craftdef = nullptr;
        ITextureSource *m_texturesrc = nullptr;
        IShaderSource *m_shadersrc = nullptr;
index 48793678f178139f0713f0a4aada1e9736b78654..5284900b204213e6e8a9145cc0abeeeee1ca9ac3 100644 (file)
Binary files a/textures/base/pack/logo.png and b/textures/base/pack/logo.png differ
index ed7e34f61625c8bca81bfee04d6996686ddbb787..6f6836e2c60ee94340b2fad6df6c1cd780953507 100644 (file)
Binary files a/textures/base/pack/menu_bg.png and b/textures/base/pack/menu_bg.png differ
index 89d97c54e160b16aa8485c88c1624910649ec125..1e0428102b05a567ad4dbfd3dac8fbc3757d9dea 100755 (executable)
@@ -1,12 +1,14 @@
 #!/bin/bash
 set -e
 
-CORE_GIT=https://github.com/minetest/minetest
+GIT_ORG=https://github.com/dragonfireclient
+CORE_GIT=$GIT_ORG/dragonfireclient
 CORE_BRANCH=master
-CORE_NAME=minetest
-GAME_GIT=https://github.com/minetest/minetest_game
+CORE_NAME=dragonfireclient
+GAME_GIT=https://git.minetest.land/MineClone2/MineClone2
 GAME_BRANCH=master
-GAME_NAME=minetest_game
+GAME_NAME=MineClone2
+CLIENT_MODS="autotool diglib digcustom nametags autokey autoeat invutil killaura worldutil physics_override noweather chateffects simpletp"
 
 dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
 if [ $# -ne 1 ]; then
@@ -109,6 +111,17 @@ else
                [ -d games/$GAME_NAME ] && { pushd games/$GAME_NAME; git pull; popd; } || \
                        git clone -b $GAME_BRANCH $GAME_GIT games/$GAME_NAME
        fi
+       rm -f clientmods/mods.conf
+       for mod in $CLIENT_MODS; do
+               cd $sourcedir
+               [ -d clientmods/$mod ] && { pushd clientmods/$mod; git pull; popd; } || \
+                       git clone $GIT_ORG/$mod clientmods/$mod
+               echo "load_mod_$mod = true" >> clientmods/mods.conf
+       done
+       cd $sourcedir
+       [ -d clientmods/lua_async ] && { pushd clientmods/lua_async; git pull; popd; } || \
+               git clone --recursive https://github.com/EliasFleckenstein03/lua_async_mt clientmods/lua_async
+       echo "load_mod_lua_async = true" >> clientmods/mods.conf
 fi
 
 git_hash=$(cd $sourcedir && git rev-parse --short HEAD)
index 5648962edf5d2aff7eaf32695012643c84931bcf..923ca66133815064d5b9cbe29174a0491ff85afa 100755 (executable)
@@ -1,12 +1,14 @@
 #!/bin/bash
 set -e
 
-CORE_GIT=https://github.com/minetest/minetest
+GIT_ORG=https://github.com/dragonfireclient
+CORE_GIT=$GIT_ORG/dragonfireclient
 CORE_BRANCH=master
-CORE_NAME=minetest
-GAME_GIT=https://github.com/minetest/minetest_game
+CORE_NAME=dragonfireclient
+GAME_GIT=https://git.minetest.land/MineClone2/MineClone2
 GAME_BRANCH=master
-GAME_NAME=minetest_game
+GAME_NAME=MineClone2
+CLIENT_MODS="autotool diglib digcustom nametags autokey autoeat invutil killaura worldutil physics_override noweather chateffects simpletp"
 
 dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
 if [ $# -ne 1 ]; then
@@ -106,6 +108,17 @@ else
                [ -d games/$GAME_NAME ] && { pushd games/$GAME_NAME; git pull; popd; } || \
                        git clone -b $GAME_BRANCH $GAME_GIT games/$GAME_NAME
        fi
+       rm -f clientmods/mods.conf
+       for mod in $CLIENT_MODS; do
+               cd $sourcedir
+               [ -d clientmods/$mod ] && { pushd clientmods/$mod; git pull; popd; } || \
+                       git clone $GIT_ORG/$mod clientmods/$mod
+               echo "load_mod_$mod = true" >> clientmods/mods.conf
+       done
+       cd $sourcedir
+       [ -d clientmods/lua_async ] && { pushd clientmods/lua_async; git pull; popd; } || \
+               git clone --recursive https://github.com/EliasFleckenstein03/lua_async_mt clientmods/lua_async
+       echo "load_mod_lua_async = true" >> clientmods/mods.conf
 fi
 
 git_hash=$(cd $sourcedir && git rev-parse --short HEAD)