]> git.lizzy.rs Git - dragonfireclient.git/commitdiff
Merge branch 'master' of https://github.com/minetest/minetest
authorElias Fleckenstein <eliasfleckenstein@web.de>
Tue, 7 Jun 2022 01:19:05 +0000 (03:19 +0200)
committerElias Fleckenstein <eliasfleckenstein@web.de>
Tue, 7 Jun 2022 01:19:05 +0000 (03:19 +0200)
49 files changed:
.github/ISSUE_TEMPLATE/bug_report.md
LICENSE.txt
android/app/src/main/AndroidManifest.xml
android/app/src/main/java/net/minetest/minetest/GameActivity.java
android/app/src/main/res/xml/filepaths.xml [new file with mode: 0644]
builtin/common/misc_helpers.lua
builtin/mainmenu/common.lua
builtin/mainmenu/dlg_contentstore.lua
builtin/mainmenu/dlg_delete_content.lua
builtin/mainmenu/dlg_delete_world.lua
builtin/mainmenu/dlg_register.lua [new file with mode: 0644]
builtin/mainmenu/init.lua
builtin/mainmenu/tab_about.lua
builtin/mainmenu/tab_online.lua
builtin/mainmenu/tab_settings.lua
builtin/settingtypes.txt
doc/lua_api.txt
doc/menu_lua_api.txt
src/client/client.cpp
src/client/client.h
src/client/clientlauncher.cpp
src/client/clientmap.cpp
src/client/clientmap.h
src/client/game.cpp
src/client/localplayer.cpp
src/client/localplayer.h
src/defaultsettings.cpp
src/gameparams.h
src/gui/CMakeLists.txt
src/gui/guiConfirmRegistration.cpp [deleted file]
src/gui/guiConfirmRegistration.h [deleted file]
src/gui/guiMainMenu.h
src/mapgen/mapgen.cpp
src/network/clientpackethandler.cpp
src/noise.cpp
src/porting_android.cpp
src/porting_android.h
src/script/lua_api/l_item.cpp
src/script/lua_api/l_item.h
src/script/lua_api/l_mainmenu.cpp
src/script/lua_api/l_mainmenu.h
src/script/lua_api/l_util.cpp
src/script/lua_api/l_util.h
src/serverenvironment.cpp
src/tool.cpp
src/tool.h
src/unittest/test_noise.cpp
src/util/string.cpp
textures/base/pack/server_favorite_delete.png [new file with mode: 0644]

index b6f351c1570e9ad5204584b0257e440cf0f5339a..7cf34bd4a0413a38babafc600b12a7ab7f186f8e 100644 (file)
@@ -8,8 +8,8 @@ assignees: ''
 
 ##### Minetest version
 <!--
-Paste Minetest version between quotes below
-If you are on a devel version, please add git commit hash
+Paste Minetest version between quotes below.
+If you are on a devel version, please add git commit hash.
 You can use `minetest --version` to find it.
 -->
 ```
@@ -29,4 +29,4 @@ OpenGL version:
 <!-- Describe your problem here -->
 
 ##### Steps to reproduce
-<!-- For bug reports or build issues, explain how the problem happened -->
+<!-- Explain how the problem has happened, providing a minimal test (i.e. a code snippet reduced to the bone) where possible -->
index 41d58901e397a09472e8ef97449542c112bd4133..565ba8bad0f13e6c76293d512e2c57f8053319d0 100644 (file)
@@ -67,6 +67,12 @@ appgurueu:
 erlehmann, Warr1024, rollerozxa:
   textures/base/pack/no_screenshot.png
 
+kilbith:
+  textures/base/pack/server_favorite.png
+
+SmallJoker
+  textures/base/pack/server_favorite_delete.png (based on server_favorite.png)
+
 License of Minetest source code
 -------------------------------
 
index 6ea677cb99ab859a0dd62e0e6f04f96067885aa7..11c868622b53599f5d5bf516ba0a69f0c5e15975 100644 (file)
                        android:name=".UnzipService"
                        android:enabled="true"
                        android:exported="false" />
-       </application>
+
+               <provider
+                       android:name="androidx.core.content.FileProvider"
+                       android:authorities="net.minetest.minetest.fileprovider"
+                       android:grantUriPermissions="true"
+                       android:exported="false">
+                       <meta-data
+                               android:name="android.support.FILE_PROVIDER_PATHS"
+                               android:resource="@xml/filepaths" />
+               </provider>
+
+</application>
 
 </manifest>
index eeb90ea7f7e59ebbe59e0a181e1ad578668c0799..f5e9fd6d08a303c653e9fd661f9d609ccc60e0e8 100644 (file)
@@ -26,6 +26,7 @@ import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
 import android.text.InputType;
+import android.util.Log;
 import android.view.KeyEvent;
 import android.view.View;
 import android.view.WindowManager;
@@ -36,7 +37,9 @@ import android.widget.LinearLayout;
 
 import androidx.annotation.Keep;
 import androidx.appcompat.app.AlertDialog;
+import androidx.core.content.FileProvider;
 
+import java.io.File;
 import java.util.Objects;
 
 // Native code finds these methods by name (see porting_android.cpp).
@@ -183,4 +186,22 @@ public class GameActivity extends NativeActivity {
        public String getCachePath() {
                return Utils.getCacheDirectory(this).getAbsolutePath();
        }
+
+       public void shareFile(String path) {
+               File file = new File(path);
+               if (!file.exists()) {
+                       Log.e("GameActivity", "File " + file.getAbsolutePath() + " doesn't exist");
+                       return;
+               }
+
+               Uri fileUri = FileProvider.getUriForFile(this, "net.minetest.minetest.fileprovider", file);
+
+               Intent intent = new Intent(Intent.ACTION_SEND, fileUri);
+               intent.setDataAndType(fileUri, getContentResolver().getType(fileUri));
+               intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+               intent.putExtra(Intent.EXTRA_STREAM, fileUri);
+
+               Intent shareIntent = Intent.createChooser(intent, null);
+               startActivity(shareIntent);
+       }
 }
diff --git a/android/app/src/main/res/xml/filepaths.xml b/android/app/src/main/res/xml/filepaths.xml
new file mode 100644 (file)
index 0000000..2fff069
--- /dev/null
@@ -0,0 +1,3 @@
+<paths>
+       <external-files-path path="Minetest/" name="minetest" />
+</paths>
index f8a905c7bbf6d819e9009022fa9bcb4d2c687245..1043675f67e9247bcaf3f26605ba97001b9d5283 100644 (file)
@@ -254,7 +254,7 @@ local formspec_escapes = {
 }
 function core.formspec_escape(text)
        -- Use explicit character set instead of dot here because it doubles the performance
-       return text and text:gsub("[\\%[%];,]", formspec_escapes)
+       return text and string.gsub(text, "[\\%[%];,]", formspec_escapes)
 end
 
 
index 8db8bb8d17f19c0515d980c71da83c1efc2b7c87..dcccb2b2a9f7bda36abd69a8b703e2980c1589fd 100644 (file)
@@ -242,3 +242,11 @@ function menu_worldmt_legacy(selected)
                end
        end
 end
+
+function confirmation_formspec(message, confirm_id, confirm_label, cancel_id, cancel_label)
+       return "size[10,2.5,true]" ..
+                       "label[0.5,0.5;" .. message .. "]" ..
+                       "style[" .. confirm_id .. ";bgcolor=red]" ..
+                       "button[0.5,1.5;2.5,0.5;" .. confirm_id .. ";" .. confirm_label .. "]" ..
+                       "button[7.0,1.5;2.5,0.5;" .. cancel_id .. ";" .. cancel_label .. "]"
+end
index 924c66400829469b3bbe71d9b234775e4e70ce34..55472891336c8156150e38a88e7ff7949fad1e98 100644 (file)
@@ -488,12 +488,10 @@ local confirm_overwrite = {}
 function confirm_overwrite.get_formspec()
        local package = confirm_overwrite.package
 
-       return "size[11.5,4.5,true]" ..
-                       "label[2,2;" ..
-                       fgettext("\"$1\" already exists. Would you like to overwrite it?", package.name) .. "]"..
-                       "style[install;bgcolor=red]" ..
-                       "button[3.25,3.5;2.5,0.5;install;" .. fgettext("Overwrite") .. "]" ..
-                       "button[5.75,3.5;2.5,0.5;cancel;" .. fgettext("Cancel") .. "]"
+       return confirmation_formspec(
+               fgettext("\"$1\" already exists. Would you like to overwrite it?", package.name),
+               'install', fgettext("Overwrite"),
+               'cancel', fgettext("Cancel"))
 end
 
 function confirm_overwrite.handle_submit(this, fields)
index a24171541e3659e8b134a99a661ec1c670e7be73..4463825f7ff694b69ac662d7405fd73c863f43c1 100644 (file)
 --------------------------------------------------------------------------------
 
 local function delete_content_formspec(dialogdata)
-       local retval =
-               "size[11.5,4.5,true]" ..
-               "label[2,2;" ..
-               fgettext("Are you sure you want to delete \"$1\"?", dialogdata.content.name) .. "]"..
-               "style[dlg_delete_content_confirm;bgcolor=red]" ..
-               "button[3.25,3.5;2.5,0.5;dlg_delete_content_confirm;" .. fgettext("Delete") .. "]" ..
-               "button[5.75,3.5;2.5,0.5;dlg_delete_content_cancel;" .. fgettext("Cancel") .. "]"
-
-       return retval
+       return confirmation_formspec(
+               fgettext("Are you sure you want to delete \"$1\"?", dialogdata.content.name),
+               'dlg_delete_content_confirm', fgettext("Delete"),
+               'dlg_delete_content_cancel', fgettext("Cancel"))
 end
 
 --------------------------------------------------------------------------------
index 33e7bc94548918a4ee6cb879150de5f2eda068ac..67c0612bdac65f8db754fe5ab485af7f1becaa2b 100644 (file)
 
 
 local function delete_world_formspec(dialogdata)
-       local retval =
-               "size[10,2.5,true]" ..
-               "label[0.5,0.5;" ..
-               fgettext("Delete World \"$1\"?", dialogdata.delete_name) .. "]" ..
-               "style[world_delete_confirm;bgcolor=red]" ..
-               "button[0.5,1.5;2.5,0.5;world_delete_confirm;" .. fgettext("Delete") .. "]" ..
-               "button[7.0,1.5;2.5,0.5;world_delete_cancel;" .. fgettext("Cancel") .. "]"
-       return retval
+       return confirmation_formspec(
+               fgettext("Delete World \"$1\"?", dialogdata.delete_name),
+               'world_delete_confirm', fgettext("Delete"),
+               'world_delete_cancel', fgettext("Cancel"))
 end
 
 local function delete_world_buttonhandler(this, fields)
diff --git a/builtin/mainmenu/dlg_register.lua b/builtin/mainmenu/dlg_register.lua
new file mode 100644 (file)
index 0000000..a765824
--- /dev/null
@@ -0,0 +1,123 @@
+--Minetest
+--Copyright (C) 2022 rubenwardy
+--
+--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.
+
+--------------------------------------------------------------------------------
+
+local function register_formspec(dialogdata)
+       local title = fgettext("Joining $1", dialogdata.server and dialogdata.server.name or dialogdata.address)
+       local buttons_y = 4 + 1.3
+       if dialogdata.error then
+               buttons_y = buttons_y + 0.8
+       end
+
+       local retval = {
+               "formspec_version[4]",
+               "size[8,", tostring(buttons_y + 1.175), "]",
+               "set_focus[", (dialogdata.name ~= "" and "password" or "name"), "]",
+               "label[0.375,0.8;", title, "]",
+               "field[0.375,1.575;7.25,0.8;name;", core.formspec_escape(fgettext("Name")), ";",
+                               core.formspec_escape(dialogdata.name), "]",
+               "pwdfield[0.375,2.875;7.25,0.8;password;", core.formspec_escape(fgettext("Password")), "]",
+               "pwdfield[0.375,4.175;7.25,0.8;password_2;", core.formspec_escape(fgettext("Confirm Password")), "]"
+       }
+
+       if dialogdata.error then
+               table.insert_all(retval, {
+                       "box[0.375,", tostring(buttons_y - 0.9), ";7.25,0.6;darkred]",
+                       "label[0.625,", tostring(buttons_y - 0.6), ";", core.formspec_escape(dialogdata.error), "]",
+               })
+       end
+
+       table.insert_all(retval, {
+               "container[0.375,", tostring(buttons_y), "]",
+               "button[0,0;2.5,0.8;dlg_register_confirm;", fgettext("Register"), "]",
+               "button[4.75,0;2.5,0.8;dlg_register_cancel;", fgettext("Cancel"), "]",
+               "container_end[]",
+       })
+
+       return table.concat(retval, "")
+end
+
+--------------------------------------------------------------------------------
+local function register_buttonhandler(this, fields)
+       this.data.name = fields.name
+       this.data.error = nil
+
+       if fields.dlg_register_confirm or fields.key_enter then
+               if fields.name == "" then
+                       this.data.error = fgettext("Missing name")
+                       return true
+               end
+               if fields.password ~= fields.password_2 then
+                       this.data.error = fgettext("Passwords do not match")
+                       return true
+               end
+
+               gamedata.playername = fields.name
+               gamedata.password   = fields.password
+               gamedata.address    = this.data.address
+               gamedata.port       = this.data.port
+               gamedata.allow_login_or_register = "register"
+               gamedata.selected_world = 0
+
+               assert(gamedata.address and gamedata.port)
+
+               local server = this.data.server
+               if server then
+                       serverlistmgr.add_favorite(server)
+                       gamedata.servername        = server.name
+                       gamedata.serverdescription = server.description
+               else
+                       gamedata.servername        = ""
+                       gamedata.serverdescription = ""
+
+                       serverlistmgr.add_favorite({
+                               address = gamedata.address,
+                               port = gamedata.port,
+                       })
+               end
+
+               core.settings:set("name", fields.name)
+               core.settings:set("address",     gamedata.address)
+               core.settings:set("remote_port", gamedata.port)
+
+               core.start()
+       end
+
+       if fields["dlg_register_cancel"] then
+               this:delete()
+               return true
+       end
+
+       return false
+end
+
+--------------------------------------------------------------------------------
+function create_register_dialog(address, port, server)
+       assert(address)
+       assert(type(port) == "number")
+
+       local retval = dialog_create("dlg_register",
+                       register_formspec,
+                       register_buttonhandler,
+                       nil)
+       retval.data.address = address
+       retval.data.port = port
+       retval.data.server = server
+       retval.data.name = core.settings:get("name") or ""
+       return retval
+end
index 94345467734943b5f10134224ea317d3b81817f0..2ffae74b5847477d62b2dceb5bab59e5ad891d38 100644 (file)
@@ -17,6 +17,7 @@
 
 mt_color_grey  = "#AAAAAA"
 mt_color_blue  = "#6389FF"
+mt_color_lightblue  = "#99CCFF"
 mt_color_green = "#72FF63"
 mt_color_dark_green = "#25C191"
 mt_color_orange  = "#FF8800"
@@ -43,6 +44,7 @@ dofile(menupath .. DIR_DELIM .. "dlg_contentstore.lua")
 dofile(menupath .. DIR_DELIM .. "dlg_create_world.lua")
 dofile(menupath .. DIR_DELIM .. "dlg_delete_content.lua")
 dofile(menupath .. DIR_DELIM .. "dlg_delete_world.lua")
+dofile(menupath .. DIR_DELIM .. "dlg_register.lua")
 dofile(menupath .. DIR_DELIM .. "dlg_rename_modpack.lua")
 
 local tabs = {}
index 3336786ba4ea9e56d4cafbf29a4eda18d632da28..2a2ed7bc43542e11d7ad85a42a5a13251e3b9455 100644 (file)
@@ -140,7 +140,9 @@ return {
                        fgettext("Active renderer:") .. "\n" ..
                        core.formspec_escape(core.get_screen_info().render_info) .. "]"
 
-               if PLATFORM ~= "Android" then
+               if PLATFORM == "Android" then
+                       fs = fs .. "button[0,4;3.5,1;share_debug;" .. fgettext("Share debug log") .. "]"
+               else
                        fs = fs .. "tooltip[userdata;" ..
                                        fgettext("Opens the directory that contains user-provided worlds, games, mods,\n" ..
                                                        "and texture packs in a file manager / explorer.") .. "]"
@@ -154,6 +156,11 @@ return {
                        core.open_url("https://www.minetest.net")
                end
 
+               if fields.share_debug then
+                       local path = core.get_user_path() .. DIR_DELIM .. "debug.txt"
+                       core.share_file(path)
+               end
+
                if fields.userdata then
                        core.open_dir(core.get_user_path())
                end
index fb7409864fa526b839353fce2d5bf5dd2851f45c..a8e1eb2ef422ff39ec36c22373c2954267d19914 100644 (file)
@@ -87,27 +87,34 @@ local function get_formspec(tabview, name, tabdata)
                "field[4.25,0.5;1.25,0.75;te_port;;" ..
                        core.formspec_escape(core.settings:get("remote_port")) .. "]" ..
 
-               -- Name / Password
-               "label[0.25,1.55;" .. fgettext("Name") .. "]" ..
-               "label[3,1.55;" .. fgettext("Password") .. "]" ..
-               "field[0.25,1.75;2.75,0.75;te_name;;" ..
-                       core.formspec_escape(core.settings:get("name")) .. "]" ..
-               "pwdfield[3,1.75;2.5,0.75;te_pwd;]" ..
-
                -- Description Background
-               "label[0.25,2.75;" .. fgettext("Server Description") .. "]" ..
-               "box[0.25,3;5.25,2.75;#999999]"..
+               "label[0.25,1.6;" .. fgettext("Server Description") .. "]" ..
+               "box[0.25,1.85;5.25,2.7;#999999]"..
+
+               -- Name / Password
+               "container[0,4.8]" ..
+               "label[0.25,0;" .. fgettext("Name") .. "]" ..
+               "label[3,0;" .. fgettext("Password") .. "]" ..
+               "field[0.25,0.2;2.625,0.75;te_name;;" .. core.formspec_escape(core.settings:get("name")) .. "]" ..
+               "pwdfield[2.875,0.2;2.625,0.75;te_pwd;]" ..
+               "container_end[]" ..
 
                -- Connect
-               "button[3,6;2.5,0.75;btn_mp_connect;" .. fgettext("Connect") .. "]"
+               "button[3,6;2.5,0.75;btn_mp_login;" .. fgettext("Login") .. "]"
+
+       if core.settings:get_bool("enable_split_login_register") then
+               retval = retval .. "button[0.25,6;2.5,0.75;btn_mp_register;" .. fgettext("Register") .. "]"
+       end
 
        if tabdata.selected then
                if gamedata.fav then
-                       retval = retval .. "button[0.25,6;2.5,0.75;btn_delete_favorite;" ..
-                               fgettext("Del. Favorite") .. "]"
+                       retval = retval .. "tooltip[btn_delete_favorite;" .. fgettext("Remove favorite") .. "]"
+                       retval = retval .. "style[btn_delete_favorite;padding=6]"
+                       retval = retval .. "image_button[5,1.3;0.5,0.5;" .. defaulttexturedir ..
+                               "server_favorite_delete.png;btn_delete_favorite;]"
                end
                if gamedata.serverdescription then
-                       retval = retval .. "textarea[0.25,3;5.25,2.75;;;" ..
+                       retval = retval .. "textarea[0.25,1.85;5.2,2.75;;;" ..
                                core.formspec_escape(gamedata.serverdescription) .. "]"
                end
        end
@@ -339,12 +346,15 @@ local function main_button_handler(tabview, fields, name, tabdata)
                return true
        end
 
-       if (fields.btn_mp_connect or fields.key_enter)
+       if (fields.btn_mp_login or fields.key_enter)
                        and fields.te_address ~= "" and fields.te_port then
                gamedata.playername = fields.te_name
                gamedata.password   = fields.te_pwd
                gamedata.address    = fields.te_address
                gamedata.port       = tonumber(fields.te_port)
+
+               local enable_split_login_register = core.settings:get_bool("enable_split_login_register")
+               gamedata.allow_login_or_register = enable_split_login_register and "login" or "any"
                gamedata.selected_world = 0
 
                local idx = core.get_table_index("servers")
@@ -381,6 +391,25 @@ local function main_button_handler(tabview, fields, name, tabdata)
                return true
        end
 
+       if fields.btn_mp_register and fields.te_address ~= "" and fields.te_port then
+               local idx = core.get_table_index("servers")
+               local server = idx and tabdata.lookup[idx]
+               if server and (server.address ~= fields.te_address or server.port ~= tonumber(fields.te_port)) then
+                       server = nil
+               end
+
+               if server and not is_server_protocol_compat_or_error(
+                                       server.proto_min, server.proto_max) then
+                       return true
+               end
+
+               local dlg = create_register_dialog(fields.te_address, tonumber(fields.te_port), server)
+               dlg:set_parent(tabview)
+               tabview:hide()
+               dlg:show()
+               return true
+       end
+
        return false
 end
 
index 880978800b24e4d4468607f94b93f6985978a2fb..8307ca7e24031f67682bf7b9d6369c1e6329c4d5 100644 (file)
@@ -160,7 +160,7 @@ local function formspec(tabview, name, tabdata)
                                .. getSettingIndex.NodeHighlighting() .. "]" ..
                "dropdown[0.25,3.6;3.5;dd_leaves_style;" .. dd_options.leaves[1] .. ";"
                                .. getSettingIndex.Leaves() .. "]" ..
-               "box[4,0;3.75,4.5;#999999]" ..
+               "box[4,0;3.75,4.9;#999999]" ..
                "label[4.25,0.1;" .. fgettext("Texturing:") .. "]" ..
                "dropdown[4.25,0.55;3.5;dd_filters;" .. dd_options.filters[1] .. ";"
                                .. getSettingIndex.Filter() .. "]" ..
@@ -169,9 +169,6 @@ local function formspec(tabview, name, tabdata)
                "label[4.25,2.15;" .. fgettext("Antialiasing:") .. "]" ..
                "dropdown[4.25,2.6;3.5;dd_antialiasing;" .. dd_options.antialiasing[1] .. ";"
                                .. getSettingIndex.Antialiasing() .. "]" ..
-               "label[4.25,3.45;" .. fgettext("Screen:") .. "]" ..
-               "checkbox[4.25,3.6;cb_autosave_screensize;" .. fgettext("Autosave Screen Size") .. ";"
-                               .. dump(core.settings:get_bool("autosave_screensize")) .. "]" ..
                "box[8,0;3.75,4.5;#999999]"
 
        local video_driver = core.settings:get("video_driver")
@@ -203,10 +200,15 @@ local function formspec(tabview, name, tabdata)
 
        if core.settings:get("touchscreen_threshold") ~= nil then
                tab_string = tab_string ..
-                       "label[4.3,4.2;" .. fgettext("Touchthreshold: (px)") .. "]" ..
-                       "dropdown[4.25,4.65;3.5;dd_touchthreshold;0,10,20,30,40,50;" ..
+                       "label[4.25,3.5;" .. fgettext("Touch threshold (px):") .. "]" ..
+                       "dropdown[4.25,3.95;3.5;dd_touchthreshold;0,10,20,30,40,50;" ..
                        ((tonumber(core.settings:get("touchscreen_threshold")) / 10) + 1) ..
-                       "]box[4.0,4.5;3.75,1.0;#999999]"
+                       "]"
+       else
+               tab_string = tab_string ..
+                       "label[4.25,3.65;" .. fgettext("Screen:") .. "]" ..
+                       "checkbox[4.25,3.9;cb_autosave_screensize;" .. fgettext("Autosave Screen Size") .. ";"
+                                       .. dump(core.settings:get_bool("autosave_screensize")) .. "]"
        end
 
        if shaders_enabled then
index a6a2b9c7763ecd4224326117fde3866df801ad08..0bed1071cdb7e3a79b5d3c4a97be48d72a5a75a6 100644 (file)
@@ -1045,9 +1045,9 @@ serverlist_file (Serverlist file) string favoriteservers.json
 #    0 to disable queueing and -1 to make the queue size unlimited.
 max_out_chat_queue_size (Maximum size of the out chat queue) int 20
 
-#    Enable register confirmation when connecting to server.
-#    If disabled, new account will be registered automatically.
-enable_register_confirmation (Enable register confirmation) bool true
+#    If enabled, account registration is separate from login in the UI.
+#    If disabled, new accounts will be registered automatically when logging in.
+enable_split_login_register (Enable split login/register) bool true
 
 [*Advanced]
 
index d277429b3f32998b85b5e4b67372b247f9e63712..1d8de7ed9d71609391919bb45f4c2a9847e73182 100644 (file)
@@ -1673,10 +1673,16 @@ these formats.
 ### Serialized
 
 This is called "stackstring" or "itemstring". It is a simple string with
-1-3 components: the full item identifier, an optional amount and an optional
-wear value. Syntax:
+1-4 components:
 
-    <identifier> [<amount>[ <wear>]]
+1. Full item identifier ("item name")
+2. Optional amount
+3. Optional wear value
+4. Optional item metadata
+
+Syntax:
+
+    <identifier> [<amount>[ <wear>[ <metadata>]]]
 
 Examples:
 
@@ -1684,6 +1690,26 @@ Examples:
 * `"default:dirt 5"`: 5 dirt
 * `"default:pick_stone"`: a new stone pickaxe
 * `"default:pick_wood 1 21323"`: a wooden pickaxe, ca. 1/3 worn out
+* `[[default:pick_wood 1 21323 "\u0001description\u0002My worn out pick\u0003"]]`:
+  * a wooden pickaxe from the `default` mod,
+  * amount must be 1 (pickaxe is a tool), ca. 1/3 worn out (it's a tool),
+  * with the `description` field set to `"My worn out pick"` in its metadata
+* `[[default:dirt 5 0 "\u0001description\u0002Special dirt\u0003"]]`:
+  * analogeous to the above example
+  * note how the wear is set to `0` as dirt is not a tool
+
+You should ideally use the `ItemStack` format to build complex item strings
+(especially if they use item metadata)
+without relying on the serialization format. Example:
+
+    local stack = ItemStack("default:pick_wood")
+    stack:set_wear(21323)
+    stack:get_meta():set_string("description", "My worn out pick")
+    local itemstring = stack:to_string()
+
+Additionally the methods `minetest.itemstring_with_palette(item, palette_index)`
+and `minetest.itemstring_with_color(item, colorstring)` may be used to create
+item strings encoding color information in their metadata.
 
 ### Table format
 
@@ -1779,7 +1805,6 @@ An example: Make meat soup from any meat, any water and any bowl:
             {"group:water"},
             {"group:bowl"},
         },
-        -- preserve = {"group:bowl"}, -- Not implemented yet (TODO)
     }
 
 Another example: Make red wool from white wool and red dye:
@@ -3593,6 +3618,12 @@ Helper functions
 * `minetest.pointed_thing_to_face_pos(placer, pointed_thing)`: returns a
   position.
     * returns the exact position on the surface of a pointed node
+* `minetest.get_tool_wear_after_use(uses [, initial_wear])`
+    * Simulates a tool being used once and returns the added wear,
+      such that, if only this function is used to calculate wear,
+      the tool will break exactly after `uses` times of uses
+    * `uses`: Number of times the tool can be used
+    * `initial_wear`: The initial wear the tool starts with (default: 0)
 * `minetest.get_dig_params(groups, tool_capabilities [, wear])`:
     Simulates an item that digs a node.
     Returns a table with the following fields:
@@ -6528,7 +6559,13 @@ an itemstring, a table or `nil`.
   or those of the hand if none are defined for this item type
 * `add_wear(amount)`
     * Increases wear by `amount` if the item is a tool, otherwise does nothing
+    * Valid `amount` range is [0,65536]
     * `amount`: number, integer
+* `add_wear_by_uses(max_uses)`
+    * Increases wear in such a way that, if only this function is called,
+      the item breaks after `max_uses` times
+    * Valid `max_uses` range is [0,65536]
+    * Does nothing if item is not a tool or if `max_uses` is 0
 * `add_item(item)`: returns leftover `ItemStack`
     * Put some item or stack onto this stack
 * `item_fits(item)`: returns `true` if item or stack can be fully added to
index 68e7b4b9de018edb3bdff85149b3cd74211320ed..63e229135394403ff94ee71cbed1a3f54cc8ea2b 100644 (file)
@@ -46,6 +46,8 @@ core.open_url(url)
 core.open_dir(path)
 ^ opens the path in the system file browser/explorer, returns false on failure.
 ^ Must be an existing directory.
+core.share_file(path)
+^ Android only. Shares file using the share popup
 core.get_version() (possible in async calls)
 ^ returns current core version
 
index 5e31387ab02fc0be00b3d3fdebed552a106b94a3..7337229fbd71394b120940db04f97a7208689218 100644 (file)
@@ -101,7 +101,8 @@ Client::Client(
                MtEventManager *event,
                RenderingEngine *rendering_engine,
                bool ipv6,
-               GameUI *game_ui
+               GameUI *game_ui,
+               ELoginRegister allow_login_or_register
 ):
        m_mesh_update_thread(this),
        m_tsrc(tsrc),
@@ -125,7 +126,8 @@ Client::Client(
        m_media_downloader(new ClientMediaDownloader()),
        m_state(LC_Created),
        m_game_ui(game_ui),
-       m_modchannel_mgr(new ModChannelMgr())
+       m_modchannel_mgr(new ModChannelMgr()),
+       m_allow_login_or_register(allow_login_or_register)
 {
        // Add local player
        m_env.setLocalPlayer(new LocalPlayer(this, playername));
@@ -399,10 +401,6 @@ void Client::step(float dtime)
                initial_step = false;
        }
        else if(m_state == LC_Created) {
-               if (m_is_registration_confirmation_state) {
-                       // Waiting confirmation
-                       return;
-               }
                float &counter = m_connection_reinit_timer;
                counter -= dtime;
                if(counter <= 0.0) {
@@ -1081,18 +1079,6 @@ void Client::sendInit(const std::string &playerName)
        Send(&pkt);
 }
 
-void Client::promptConfirmRegistration(AuthMechanism chosen_auth_mechanism)
-{
-       m_chosen_auth_mech = chosen_auth_mechanism;
-       m_is_registration_confirmation_state = true;
-}
-
-void Client::confirmRegistration()
-{
-       m_is_registration_confirmation_state = false;
-       startAuth(m_chosen_auth_mech);
-}
-
 void Client::startAuth(AuthMechanism chosen_auth_mechanism)
 {
        m_chosen_auth_mech = chosen_auth_mechanism;
index d49f2f9ada7392fe9426da50f89c05ba6c838d87..c1b8cfbaa0727c48e47e776cb190e438e6bdb40e 100644 (file)
@@ -37,6 +37,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "mesh_generator_thread.h"
 #include "network/address.h"
 #include "network/peerhandler.h"
+#include "gameparams.h"
 #include <fstream>
 
 #define CLIENT_CHAT_MESSAGE_LIMIT_PER_10S 10.0f
@@ -126,7 +127,8 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
                        MtEventManager *event,
                        RenderingEngine *rendering_engine,
                        bool ipv6,
-                       GameUI *game_ui
+                       GameUI *game_ui,
+                       ELoginRegister allow_login_or_register
        );
 
        ~Client();
@@ -348,8 +350,7 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
        u16 getProtoVersion()
        { return m_proto_ver; }
 
-       void confirmRegistration();
-       bool m_is_registration_confirmation_state = false;
+       ELoginRegister m_allow_login_or_register = ELoginRegister::Any;
        bool m_simple_singleplayer_mode;
 
        float mediaReceiveProgress();
@@ -467,7 +468,6 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
        static AuthMechanism choseAuthMech(const u32 mechs);
 
        void sendInit(const std::string &playerName);
-       void promptConfirmRegistration(AuthMechanism chosen_auth_mechanism);
        void startAuth(AuthMechanism chosen_auth_mechanism);
        void sendDeletedBlocks(std::vector<v3s16> &blocks);
        void sendGotBlocks(const std::vector<v3s16> &blocks);
index 54c561d11ecccfe738ec50b0764cfb6dbaf6b395..60c9525f332cdc6ec96cb18311b8c5d4a60c67a3 100644 (file)
@@ -451,6 +451,7 @@ bool ClientLauncher::launch_game(std::string &error_message,
                start_data.name = menudata.name;
                start_data.password = menudata.password;
                start_data.address = std::move(menudata.address);
+               start_data.allow_login_or_register = menudata.allow_login_or_register;
                server_name = menudata.servername;
                server_description = menudata.serverdescription;
 
index 85b765709ebff6581ce8385b0df0758e984d4fed..3a89b88038b638058d44935eb2334448d7cd1ac9 100644 (file)
@@ -219,13 +219,11 @@ void ClientMap::updateDrawList()
        // Number of blocks occlusion culled
        u32 blocks_occlusion_culled = 0;
 
-       // No occlusion culling when free_move is on and camera is
-       // inside ground
+       // 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")) || g_settings->getBool("freecam")) {
+       if (m_control.allow_noclip || g_settings->getBool("freecam")) {
                MapNode n = getNode(cam_pos_nodes);
-               if (n.getContent() == CONTENT_IGNORE ||
-                               m_nodedef->get(n).solidness == 2)
+               if (n.getContent() == CONTENT_IGNORE || m_nodedef->get(n).solidness == 2)
                        occlusion_culling_enabled = false;
        }
 
@@ -678,19 +676,17 @@ void ClientMap::renderPostFx(CameraMode cam_mode)
 
        MapNode n = getNode(floatToInt(m_camera_position, BS));
 
-       // - If the player is in a solid node, make everything black.
-       // - If the player is in liquid, draw a semi-transparent overlay.
-       // - 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") || g_settings->getBool("freecam")) &&
-                       (m_client->checkLocalPrivilege("noclip") || g_settings->getBool("freecam"))) &&
-                       cam_mode == CAMERA_MODE_FIRST)
-       {
+
+       // If the camera is in a solid node, make everything black.
+       // (first person mode only)
+       if (features.solidness == 2 && cam_mode == CAMERA_MODE_FIRST &&
+               !(m_control.allow_noclip || g_settings->getBool("freecam"))) {
                post_effect_color = video::SColor(255, 0, 0, 0);
        }
-       if (post_effect_color.getAlpha() != 0)
-       {
+
+       if (post_effect_color.getAlpha() != 0) {
                // Draw a full-screen rectangle
                video::IVideoDriver* driver = SceneManager->getVideoDriver();
                v2u32 ss = driver->getScreenSize();
index 823870c6860d699a3623a0b45c1f7d4de0851a67..8c45b538276215a4d70120dbfe049d8258f7060b 100644 (file)
@@ -27,10 +27,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 struct MapDrawControl
 {
-       // Overrides limits by drawing everything
-       bool range_all = false;
        // Wanted drawing range
        float wanted_range = 0.0f;
+       // Overrides limits by drawing everything
+       bool range_all = false;
+       // Allow rendering out of bounds
+       bool allow_noclip = false;
        // show a wire frame for debugging
        bool show_wireframe = false;
 };
index e439d0e32da366d7a056fa93b977c8fd34591a68..888191f4a406ad39ddf7402e0474bea7783d0b64 100644 (file)
@@ -43,7 +43,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "gameparams.h"
 #include "gettext.h"
 #include "gui/guiChatConsole.h"
-#include "gui/guiConfirmRegistration.h"
 #include "gui/guiFormSpecMenu.h"
 #include "gui/guiKeyChangeMenu.h"
 #include "gui/guiPasswordChange.h"
@@ -675,7 +674,8 @@ bool Game::connectToServer(const GameStartData &start_data,
                                start_data.password, start_data.address,
                                *draw_control, texture_src, shader_src,
                                itemdef_manager, nodedef_manager, sound, eventmgr,
-                               m_rendering_engine, connect_address.isIPv6(), m_game_ui.get());
+                               m_rendering_engine, connect_address.isIPv6(), m_game_ui.get(),
+                               start_data.allow_login_or_register);
                client->migrateModStorage();
        } catch (const BaseException &e) {
                *error_message = fmtgettext("Error creating client: %s", e.what());
@@ -738,28 +738,16 @@ bool Game::connectToServer(const GameStartData &start_data,
                                break;
                        }
 
-                       if (client->m_is_registration_confirmation_state) {
-                               if (registration_confirmation_shown) {
-                                       // Keep drawing the GUI
-                                       m_rendering_engine->draw_menu_scene(guienv, dtime, true);
-                               } else {
-                                       registration_confirmation_shown = true;
-                                       (new GUIConfirmRegistration(guienv, guienv->getRootGUIElement(), -1,
-                                                  &g_menumgr, client, start_data.name, start_data.password,
-                                                  connection_aborted, texture_src))->drop();
-                               }
-                       } else {
-                               wait_time += dtime;
-                               // Only time out if we aren't waiting for the server we started
-                               if (!start_data.address.empty() && wait_time > 10) {
-                                       *error_message = gettext("Connection timed out.");
-                                       errorstream << *error_message << std::endl;
-                                       break;
-                               }
-
-                               // Update status
-                               showOverlayMessage(N_("Connecting to server..."), dtime, 20);
+                       wait_time += dtime;
+                       // Only time out if we aren't waiting for the server we started
+                       if (!start_data.address.empty() && wait_time > 10) {
+                               *error_message = gettext("Connection timed out.");
+                               errorstream << *error_message << std::endl;
+                               break;
                        }
+
+                       // Update status
+                       showOverlayMessage(N_("Connecting to server..."), dtime, 20);
                }
        } catch (con::PeerNotFoundException &e) {
                // TODO: Should something be done here? At least an info/error
@@ -938,6 +926,8 @@ void Game::processQueues()
 void Game::updateDebugState()
 {
        LocalPlayer *player = client->getEnv().getLocalPlayer();
+
+       // debug UI and wireframe
        bool has_debug = client->checkPrivilege("debug");
        bool has_basic_debug = has_debug || (player->hud_flags & HUD_FLAG_BASIC_DEBUG);
 
@@ -952,6 +942,9 @@ void Game::updateDebugState()
                hud->disableBlockBounds();
        if (!has_debug)
                draw_control->show_wireframe = false;
+
+       // noclip
+       draw_control->allow_noclip = m_cache_enable_noclip && client->checkPrivilege("noclip");
 }
 
 void Game::updateProfilers(const RunStats &stats, const FpsControl &draw_times,
@@ -3047,7 +3040,10 @@ 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) || g_settings->getBool("freecam")) {
+       // When in noclip mode force same sky brightness as above ground so you
+       // can see properly
+       if ((draw_control->allow_noclip && m_cache_enable_free_move &&
+               client->checkPrivilege("fly")) || g_settings->getBool("freecam")) {
                direct_brightness = time_brightness;
                sunlight_seen = true;
        } else {
index c4d9b98457d6c10574b5e7aec07e964c2db52d60..aeccc5c7dc4de54531d0fdede13567ad1089865e 100644 (file)
@@ -450,16 +450,6 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
                camera_impact = getSpeed().Y * -1;
        }
 
-       {
-               camera_barely_in_ceiling = false;
-               v3s16 camera_np = floatToInt(getEyePosition(), BS);
-               MapNode n = map->getNode(camera_np);
-               if (n.getContent() != CONTENT_IGNORE) {
-                       if (nodemgr->get(n).walkable && nodemgr->get(n).solidness == 2)
-                               camera_barely_in_ceiling = true;
-               }
-       }
-
        /*
                Check properties of the node on which the player is standing
        */
@@ -730,8 +720,7 @@ v3f LocalPlayer::getSendSpeed()
 
 v3f LocalPlayer::getEyeOffset() const
 {
-       float eye_height = camera_barely_in_ceiling ? m_eye_height - 0.125f : m_eye_height;
-       return v3f(0.0f, BS * eye_height, 0.0f);
+       return v3f(0.0f, BS * m_eye_height, 0.0f);
 }
 
 ClientActiveObject *LocalPlayer::getParent() const
@@ -1071,16 +1060,6 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
                camera_impact = getSpeed().Y * -1.0f;
        }
 
-       {
-               camera_barely_in_ceiling = false;
-               v3s16 camera_np = floatToInt(getEyePosition(), BS);
-               MapNode n = map->getNode(camera_np);
-               if (n.getContent() != CONTENT_IGNORE) {
-                       if (nodemgr->get(n).walkable && nodemgr->get(n).solidness == 2)
-                               camera_barely_in_ceiling = true;
-               }
-       }
-
        /*
                Update the node last under the player
        */
index ebc67c4f8c7849844375ca3bacbb60cb3fcb146a..271589c592b58210f3a3a1a2ed46e65cb927eff8 100644 (file)
@@ -237,7 +237,6 @@ class LocalPlayer : public Player
        u16 m_breath = PLAYER_MAX_BREATH_DEFAULT;
        f32 m_yaw = 0.0f;
        f32 m_pitch = 0.0f;
-       bool camera_barely_in_ceiling = false;
        aabb3f m_collisionbox = aabb3f(-BS * 0.30f, 0.0f, -BS * 0.30f, BS * 0.30f,
                BS * 1.75f, BS * 0.30f);
        float m_eye_height = 1.625f;
index 9224d99ed0d5cb24b531b7c1e1f53096787699fe..c3fe0203875a825559e964e88e41ca286991701b 100644 (file)
@@ -64,7 +64,7 @@ void set_default_settings()
        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("enable_split_login_register", "true");
        settings->setDefault("chat_weblink_color", "#8888FF");
 
        // Cheat Menu
@@ -526,7 +526,6 @@ void set_default_settings()
        // Altered settings for macOS
 #if defined(__MACH__) && defined(__APPLE__)
        settings->setDefault("keymap_sneak", "KEY_SHIFT");
-       settings->setDefault("fps_max", "0");
 #endif
 
 #ifdef HAVE_TOUCHSCREENGUI
index 70b0ffcde407de2410509d7be2a4030775a73696..b138f8771c93ce7183d3f44ae80c1d7acdaec253 100644 (file)
@@ -20,8 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #pragma once
 
 #include "irrlichttypes.h"
-
-struct SubgameSpec;
+#include "content/subgames.h"
 
 // Information provided from "main"
 struct GameParams
@@ -34,6 +33,12 @@ struct GameParams
        bool is_dedicated_server;
 };
 
+enum class ELoginRegister {
+       Any = 0,
+       Login,
+       Register
+};
+
 // Information processed by main menu
 struct GameStartData : GameParams
 {
@@ -46,6 +51,8 @@ struct GameStartData : GameParams
        std::string address;
        bool local_server;
 
+       ELoginRegister allow_login_or_register = ELoginRegister::Any;
+
        // "world_path" must be kept in sync!
        WorldSpec world_spec;
 };
index a5f25c0f3ec511129af6549ccfbad02bd18d83c2..87110d2cd0d586348d81fb8adf9e953792d5c8d5 100644 (file)
@@ -12,7 +12,6 @@ set(gui_SRCS
        ${CMAKE_CURRENT_SOURCE_DIR}/guiButtonImage.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/guiButtonItemImage.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/guiChatConsole.cpp
-       ${CMAKE_CURRENT_SOURCE_DIR}/guiConfirmRegistration.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/guiEditBox.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/guiEditBoxWithScrollbar.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/guiEngine.cpp
diff --git a/src/gui/guiConfirmRegistration.cpp b/src/gui/guiConfirmRegistration.cpp
deleted file mode 100644 (file)
index c5aa9c8..0000000
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
-Minetest
-Copyright (C) 2018 srifqi, Muhammad Rifqi Priyo Susanto
-               <muhammadrifqipriyosusanto@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.
-*/
-
-#include "guiConfirmRegistration.h"
-#include "client/client.h"
-#include "guiButton.h"
-#include <IGUICheckBox.h>
-#include <IGUIButton.h>
-#include <IGUIStaticText.h>
-#include <IGUIFont.h>
-#include "guiEditBoxWithScrollbar.h"
-#include "porting.h"
-
-#ifdef HAVE_TOUCHSCREENGUI
-       #include "client/renderingengine.h"
-#endif
-
-#include "gettext.h"
-
-// Continuing from guiPasswordChange.cpp
-const int ID_confirmPassword = 262;
-const int ID_confirm = 263;
-const int ID_intotext = 264;
-const int ID_cancel = 265;
-const int ID_message = 266;
-
-GUIConfirmRegistration::GUIConfirmRegistration(gui::IGUIEnvironment *env,
-               gui::IGUIElement *parent, s32 id, IMenuManager *menumgr, Client *client,
-               const std::string &playername, const std::string &password,
-               bool *aborted, ISimpleTextureSource *tsrc) :
-               GUIModalMenu(env, parent, id, menumgr),
-               m_client(client), m_playername(playername), m_password(password),
-               m_aborted(aborted), m_tsrc(tsrc)
-{
-#ifdef HAVE_TOUCHSCREENGUI
-       m_touchscreen_visible = false;
-#endif
-}
-
-void GUIConfirmRegistration::regenerateGui(v2u32 screensize)
-{
-       acceptInput();
-       removeAllChildren();
-
-       /*
-               Calculate new sizes and positions
-       */
-#ifdef HAVE_TOUCHSCREENGUI
-       const float s = m_gui_scale * RenderingEngine::getDisplayDensity() / 2;
-#else
-       const float s = m_gui_scale;
-#endif
-       DesiredRect = core::rect<s32>(
-               screensize.X / 2 - 600 * s / 2,
-               screensize.Y / 2 - 360 * s / 2,
-               screensize.X / 2 + 600 * s / 2,
-               screensize.Y / 2 + 360 * s / 2
-       );
-       recalculateAbsolutePosition(false);
-
-       v2s32 size = DesiredRect.getSize();
-       v2s32 topleft_client(0, 0);
-
-       const wchar_t *text;
-
-       /*
-               Add stuff
-       */
-       s32 ypos = 30 * s;
-       {
-               core::rect<s32> rect2(0, 0, 540 * s, 180 * s);
-               rect2 += topleft_client + v2s32(30 * s, ypos);
-               static const std::string info_text_template = strgettext(
-                               "You are about to join this server with the name \"%s\" for the "
-                               "first time.\n"
-                               "If you proceed, a new account using your credentials will be "
-                               "created on this server.\n"
-                               "Please retype your password and click 'Register and Join' to "
-                               "confirm account creation, or click 'Cancel' to abort.");
-               char info_text_buf[1024];
-               porting::mt_snprintf(info_text_buf, sizeof(info_text_buf),
-                               info_text_template.c_str(), m_playername.c_str());
-
-               std::wstring info_text_w = utf8_to_wide(info_text_buf);
-               gui::IGUIEditBox *e = new GUIEditBoxWithScrollBar(info_text_w.c_str(),
-                               true, Environment, this, ID_intotext, rect2, false, true);
-               e->drop();
-               e->setMultiLine(true);
-               e->setWordWrap(true);
-               e->setTextAlignment(gui::EGUIA_UPPERLEFT, gui::EGUIA_CENTER);
-       }
-
-       ypos += 200 * s;
-       {
-               core::rect<s32> rect2(0, 0, 540 * s, 30 * s);
-               rect2 += topleft_client + v2s32(30 * s, ypos);
-               gui::IGUIEditBox *e = Environment->addEditBox(m_pass_confirm.c_str(),
-                               rect2, true, this, ID_confirmPassword);
-               e->setPasswordBox(true);
-               Environment->setFocus(e);
-       }
-
-       ypos += 50 * s;
-       {
-               core::rect<s32> rect2(0, 0, 230 * s, 35 * s);
-               rect2 = rect2 + v2s32(size.X / 2 - 220 * s, ypos);
-               text = wgettext("Register and Join");
-               GUIButton::addButton(Environment, rect2, m_tsrc, this, ID_confirm, text);
-               delete[] text;
-       }
-       {
-               core::rect<s32> rect2(0, 0, 120 * s, 35 * s);
-               rect2 = rect2 + v2s32(size.X / 2 + 70 * s, ypos);
-               text = wgettext("Cancel");
-               GUIButton::addButton(Environment, rect2, m_tsrc, this, ID_cancel, text);
-               delete[] text;
-       }
-       {
-               core::rect<s32> rect2(0, 0, 500 * s, 40 * s);
-               rect2 += topleft_client + v2s32(30 * s, ypos + 40 * s);
-               text = wgettext("Passwords do not match!");
-               IGUIElement *e = Environment->addStaticText(
-                               text, rect2, false, true, this, ID_message);
-               e->setVisible(false);
-               delete[] text;
-       }
-}
-
-void GUIConfirmRegistration::drawMenu()
-{
-       gui::IGUISkin *skin = Environment->getSkin();
-       if (!skin)
-               return;
-       video::IVideoDriver *driver = Environment->getVideoDriver();
-
-       video::SColor bgcolor(140, 0, 0, 0);
-       driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);
-
-       gui::IGUIElement::draw();
-#ifdef __ANDROID__
-       getAndroidUIInput();
-#endif
-}
-
-void GUIConfirmRegistration::closeMenu(bool goNext)
-{
-       if (goNext) {
-               m_client->confirmRegistration();
-       } else {
-               *m_aborted = true;
-               infostream << "Connect aborted [Escape]" << std::endl;
-       }
-       quitMenu();
-}
-
-void GUIConfirmRegistration::acceptInput()
-{
-       gui::IGUIElement *e;
-       e = getElementFromId(ID_confirmPassword);
-       if (e)
-               m_pass_confirm = e->getText();
-}
-
-bool GUIConfirmRegistration::processInput()
-{
-       if (utf8_to_wide(m_password) != m_pass_confirm) {
-               gui::IGUIElement *e = getElementFromId(ID_message);
-               if (e)
-                       e->setVisible(true);
-               return false;
-       }
-       return true;
-}
-
-bool GUIConfirmRegistration::OnEvent(const SEvent &event)
-{
-       if (event.EventType == EET_KEY_INPUT_EVENT) {
-               // clang-format off
-               if ((event.KeyInput.Key == KEY_ESCAPE ||
-                               event.KeyInput.Key == KEY_CANCEL) &&
-                               event.KeyInput.PressedDown) {
-                       closeMenu(false);
-                       return true;
-               }
-               // clang-format on
-               if (event.KeyInput.Key == KEY_RETURN && event.KeyInput.PressedDown) {
-                       acceptInput();
-                       if (processInput())
-                               closeMenu(true);
-                       return true;
-               }
-       }
-
-       if (event.EventType != EET_GUI_EVENT)
-               return Parent ? Parent->OnEvent(event) : false;
-
-       if (event.GUIEvent.EventType == gui::EGET_ELEMENT_FOCUS_LOST && isVisible()) {
-               if (!canTakeFocus(event.GUIEvent.Element)) {
-                       infostream << "GUIConfirmRegistration: Not allowing focus change."
-                               << std::endl;
-                       // Returning true disables focus change
-                       return true;
-               }
-       } else if (event.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED) {
-               switch (event.GUIEvent.Caller->getID()) {
-               case ID_confirm:
-                       acceptInput();
-                       if (processInput())
-                               closeMenu(true);
-                       return true;
-               case ID_cancel:
-                       closeMenu(false);
-                       return true;
-               }
-       } else if (event.GUIEvent.EventType == gui::EGET_EDITBOX_ENTER) {
-               switch (event.GUIEvent.Caller->getID()) {
-               case ID_confirmPassword:
-                       acceptInput();
-                       if (processInput())
-                               closeMenu(true);
-                       return true;
-               }
-       }
-
-       return false;
-}
-
-#ifdef __ANDROID__
-bool GUIConfirmRegistration::getAndroidUIInput()
-{
-       if (!hasAndroidUIInput() || m_jni_field_name != "password")
-               return false;
-
-       // still waiting
-       if (porting::getInputDialogState() == -1)
-               return true;
-
-       m_jni_field_name.clear();
-
-       gui::IGUIElement *e = getElementFromId(ID_confirmPassword);
-
-       if (!e || e->getType() != irr::gui::EGUIET_EDIT_BOX)
-               return false;
-
-       std::string text = porting::getInputDialogValue();
-       e->setText(utf8_to_wide(text).c_str());
-       return false;
-}
-#endif
diff --git a/src/gui/guiConfirmRegistration.h b/src/gui/guiConfirmRegistration.h
deleted file mode 100644 (file)
index fb21577..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
-Minetest
-Copyright (C) 2018 srifqi, Muhammad Rifqi Priyo Susanto
-               <muhammadrifqipriyosusanto@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.
-*/
-
-#pragma once
-
-#include "irrlichttypes_extrabloated.h"
-#include "modalMenu.h"
-#include <string>
-
-class Client;
-class ISimpleTextureSource;
-
-class GUIConfirmRegistration : public GUIModalMenu
-{
-public:
-       GUIConfirmRegistration(gui::IGUIEnvironment *env, gui::IGUIElement *parent,
-                       s32 id, IMenuManager *menumgr, Client *client,
-                       const std::string &playername, const std::string &password,
-                       bool *aborted, ISimpleTextureSource *tsrc);
-       /*
-               Remove and re-add (or reposition) stuff
-       */
-       void regenerateGui(v2u32 screensize);
-
-       void drawMenu();
-
-       void closeMenu(bool goNext);
-
-       void acceptInput();
-
-       bool processInput();
-
-       bool OnEvent(const SEvent &event);
-#ifdef __ANDROID__
-       bool getAndroidUIInput();
-#endif
-
-private:
-       std::wstring getLabelByID(s32 id) { return L""; }
-       std::string getNameByID(s32 id) { return "password"; }
-
-       Client *m_client = nullptr;
-       const std::string &m_playername;
-       const std::string &m_password;
-       bool *m_aborted = nullptr;
-       std::wstring m_pass_confirm = L"";
-       ISimpleTextureSource *m_tsrc;
-};
index 1dca8bf2d295863c3c8993f15afc08b6894611ce..9b8ff383c592a0642c29c4426ea04551e7addbe3 100644 (file)
@@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #pragma once
 
 #include "irrlichttypes_extrabloated.h"
+#include "gameparams.h"
 #include <string>
 #include <list>
 
@@ -50,5 +51,7 @@ struct MainMenuData {
        // Data to be passed to the script
        MainMenuDataForScript script_data;
 
+       ELoginRegister allow_login_or_register = ELoginRegister::Any;
+
        MainMenuData() = default;
 };
index d767bd264dd350b8741842581ed4719ada575e64..1f2ac491e952331e41aac3249760d5d18be5c3f7 100644 (file)
@@ -238,7 +238,8 @@ u32 Mapgen::getBlockSeed(v3s16 p, s32 seed)
 
 u32 Mapgen::getBlockSeed2(v3s16 p, s32 seed)
 {
-       u32 n = 1619 * p.X + 31337 * p.Y + 52591 * p.Z + 1013 * seed;
+       // Multiply by unsigned number to avoid signed overflow (UB)
+       u32 n = 1619U * p.X + 31337U * p.Y + 52591U * p.Z + 1013U * seed;
        n = (n >> 13) ^ n;
        return (n * (n * n * 60493 + 19990303) + 1376312589);
 }
index 29e3364db0e2d6ef4a50b365832076702820c0be..1f17470af99f409c38b6026761af67821d7b90ed 100644 (file)
@@ -103,11 +103,20 @@ void Client::handleCommand_Hello(NetworkPacket* pkt)
 
        // Authenticate using that method, or abort if there wasn't any method found
        if (chosen_auth_mechanism != AUTH_MECHANISM_NONE) {
-               if (chosen_auth_mechanism == AUTH_MECHANISM_FIRST_SRP &&
-                               !m_simple_singleplayer_mode &&
-                               !getServerAddress().isLocalhost() &&
-                               g_settings->getBool("enable_register_confirmation")) {
-                       promptConfirmRegistration(chosen_auth_mechanism);
+               bool is_register = chosen_auth_mechanism == AUTH_MECHANISM_FIRST_SRP;
+               ELoginRegister mode = is_register ? ELoginRegister::Register : ELoginRegister::Login;
+               if (m_allow_login_or_register != ELoginRegister::Any &&
+                               m_allow_login_or_register != mode) {
+                       m_chosen_auth_mech = AUTH_MECHANISM_NONE;
+                       m_access_denied = true;
+                       if (m_allow_login_or_register == ELoginRegister::Login) {
+                               m_access_denied_reason =
+                                               gettext("Name is not registered. To create an account on this server, click 'Register'");
+                       } else {
+                               m_access_denied_reason =
+                                               gettext("Name is taken. Please choose another name");
+                       }
+                       m_con->Disconnect();
                } else {
                        startAuth(chosen_auth_mechanism);
                }
index 2f4de6855ac0afb1331c9a818f3519fdc1b18cea..d98d4dafb01186efc558c8e517f42be8e8b35da2 100644 (file)
@@ -35,7 +35,8 @@
 #define NOISE_MAGIC_X    1619
 #define NOISE_MAGIC_Y    31337
 #define NOISE_MAGIC_Z    52591
-#define NOISE_MAGIC_SEED 1013
+// Unsigned magic seed prevents undefined behavior.
+#define NOISE_MAGIC_SEED 1013U
 
 typedef float (*Interp2dFxn)(
                float v00, float v10, float v01, float v11,
index c71fe5ad88e1c733de7a9a7afceee4d7163139db..83b590b99d016d76d8f86074726466005f15968f 100644 (file)
@@ -213,6 +213,18 @@ void openURIAndroid(const std::string &url)
        jnienv->CallVoidMethod(app_global->activity->clazz, url_open, jurl);
 }
 
+void shareFileAndroid(const std::string &path)
+{
+       jmethodID url_open = jnienv->GetMethodID(nativeActivity, "shareFile",
+                       "(Ljava/lang/String;)V");
+
+       FATAL_ERROR_IF(url_open == nullptr,
+                       "porting::shareFileAndroid unable to find java openURI method");
+
+       jstring jurl = jnienv->NewStringUTF(path.c_str());
+       jnienv->CallVoidMethod(app_global->activity->clazz, url_open, jurl);
+}
+
 int getInputDialogState()
 {
        jmethodID dialogstate = jnienv->GetMethodID(nativeActivity,
index 23981592265f50b5da30dff92c3febb4d1d7b97e..265825fbd8960f9e3fb88aa698bdbff2155c41dd 100644 (file)
@@ -60,6 +60,13 @@ void showInputDialog(const std::string &acceptButton,
 
 void openURIAndroid(const std::string &url);
 
+/**
+ * Opens a share intent to the file at path
+ *
+ * @param path
+ */
+void shareFileAndroid(const std::string &path);
+
 /**
  * WORKAROUND for not working callbacks from java -> c++
  * get current state of input dialog
index bae6701a095eb803a50ad704a7853a5c06ed2b97..160bb4e83597fdb20e05be8f620ab1783f6f6926 100644 (file)
@@ -348,7 +348,7 @@ int LuaItemStack::l_get_tool_capabilities(lua_State *L)
 }
 
 // add_wear(self, amount) -> true/false
-// The range for "amount" is [0,65535]. Wear is only added if the item
+// The range for "amount" is [0,65536]. Wear is only added if the item
 // is a tool. Adding wear might destroy the item.
 // Returns true if the item is (or was) a tool.
 int LuaItemStack::l_add_wear(lua_State *L)
@@ -362,6 +362,25 @@ int LuaItemStack::l_add_wear(lua_State *L)
        return 1;
 }
 
+// add_wear_by_uses(self, max_uses) -> true/false
+// The range for "max_uses" is [0,65536].
+// Adds wear to the item in such a way that, if
+// only this function is called to add wear, the item
+// will be destroyed exactly after `max_uses` times of calling it.
+// No-op if `max_uses` is 0 or item is not a tool.
+// Returns true if the item is (or was) a tool.
+int LuaItemStack::l_add_wear_by_uses(lua_State *L)
+{
+       NO_MAP_LOCK_REQUIRED;
+       LuaItemStack *o = checkobject(L, 1);
+       ItemStack &item = o->m_stack;
+       u32 max_uses = readParam<int>(L, 2);
+       u32 add_wear = calculateResultWear(max_uses, item.wear);
+       bool result = item.addWear(add_wear, getGameDef(L)->idef());
+       lua_pushboolean(L, result);
+       return 1;
+}
+
 // add_item(self, itemstack or itemstring or table or nil) -> itemstack
 // Returns leftover item stack
 int LuaItemStack::l_add_item(lua_State *L)
@@ -537,6 +556,7 @@ const luaL_Reg LuaItemStack::methods[] = {
        luamethod(LuaItemStack, get_definition),
        luamethod(LuaItemStack, get_tool_capabilities),
        luamethod(LuaItemStack, add_wear),
+       luamethod(LuaItemStack, add_wear_by_uses),
        luamethod(LuaItemStack, add_item),
        luamethod(LuaItemStack, item_fits),
        luamethod(LuaItemStack, take_item),
index 180975061317225a04929fcc97d271dbbc1b1265..a392555d2c4beae7b0bda7a7eb9ed9d416f65a23 100644 (file)
@@ -108,11 +108,20 @@ class LuaItemStack : public ModApiBase {
        static int l_get_tool_capabilities(lua_State *L);
 
        // add_wear(self, amount) -> true/false
-       // The range for "amount" is [0,65535]. Wear is only added if the item
+       // The range for "amount" is [0,65536]. Wear is only added if the item
        // is a tool. Adding wear might destroy the item.
        // Returns true if the item is (or was) a tool.
        static int l_add_wear(lua_State *L);
 
+       // add_wear_by_uses(self, max_uses) -> true/false
+       // The range for "max_uses" is [0,65536].
+       // Adds wear to the item in such a way that, if
+       // only this function is called to add wear, the item
+       // will be destroyed exactly after `max_uses` times of calling it.
+       // No-op if `max_uses` is 0 or item is not a tool.
+       // Returns true if the item is (or was) a tool.
+       static int l_add_wear_by_uses(lua_State *L);
+
        // add_item(self, itemstack or itemstring or table or nil) -> itemstack
        // Returns leftover item stack
        static int l_add_item(lua_State *L);
index 411250a0b17754fd6c2c9bfc4ead4a5fc5493bb4..c1530f0d3cec51c534683ac06c7e14ee03873c49 100644 (file)
@@ -139,6 +139,14 @@ int ModApiMainMenu::l_start(lua_State *L)
                data->password = getTextData(L,"password");
                data->address  = getTextData(L,"address");
                data->port     = getTextData(L,"port");
+
+               const auto val = getTextData(L, "allow_login_or_register");
+               if (val == "login")
+                       data->allow_login_or_register = ELoginRegister::Login;
+               else if (val == "register")
+                       data->allow_login_or_register = ELoginRegister::Register;
+               else
+                       data->allow_login_or_register = ELoginRegister::Any;
        }
        data->serverdescription = getTextData(L,"serverdescription");
        data->servername        = getTextData(L,"servername");
@@ -872,6 +880,19 @@ int ModApiMainMenu::l_open_dir(lua_State *L)
        return 1;
 }
 
+/******************************************************************************/
+int ModApiMainMenu::l_share_file(lua_State *L)
+{
+#ifdef __ANDROID__
+       std::string path = luaL_checkstring(L, 1);
+       porting::shareFileAndroid(path);
+       lua_pushboolean(L, true);
+#else
+       lua_pushboolean(L, false);
+#endif
+       return 1;
+}
+
 /******************************************************************************/
 int ModApiMainMenu::l_do_async_callback(lua_State *L)
 {
@@ -937,6 +958,7 @@ void ModApiMainMenu::Initialize(lua_State *L, int top)
        API_FCT(get_max_supp_proto);
        API_FCT(open_url);
        API_FCT(open_dir);
+       API_FCT(share_file);
        API_FCT(do_async_callback);
 }
 
index 781185425196b7f9931f0c4d3f46a10d2de739e4..6ceff6dd7df203741327ac55f100f56a85324fdc 100644 (file)
@@ -152,6 +152,8 @@ class ModApiMainMenu: public ModApiBase
 
        static int l_open_dir(lua_State *L);
 
+       static int l_share_file(lua_State *L);
+
 
        // async
        static int l_do_async_callback(lua_State *L);
index fa749c2e5104ce6174bc7f854e05164d3e94d5ef..44973f96829de8dd0055c1252bee0cd70faf3673 100644 (file)
@@ -159,6 +159,17 @@ int ModApiUtil::l_write_json(lua_State *L)
        return 1;
 }
 
+// get_tool_wear_after_use(uses[, initial_wear])
+int ModApiUtil::l_get_tool_wear_after_use(lua_State *L)
+{
+       NO_MAP_LOCK_REQUIRED;
+       u32 uses = readParam<int>(L, 1);
+       u16 initial_wear = readParam<int>(L, 2, 0);
+       u16 wear = calculateResultWear(uses, initial_wear);
+       lua_pushnumber(L, wear);
+       return 1;
+}
+
 // get_dig_params(groups, tool_capabilities[, wear])
 int ModApiUtil::l_get_dig_params(lua_State *L)
 {
@@ -586,6 +597,7 @@ void ModApiUtil::Initialize(lua_State *L, int top)
        API_FCT(parse_json);
        API_FCT(write_json);
 
+       API_FCT(get_tool_wear_after_use);
        API_FCT(get_dig_params);
        API_FCT(get_hit_params);
 
index cc55635776bddb00f03b0e0e43ba3c20ebb24a93..ec86c663229736ff0cac5c608d2c696ef3b635bf 100644 (file)
@@ -50,6 +50,9 @@ class ModApiUtil : public ModApiBase
        // write_json(data[, styled])
        static int l_write_json(lua_State *L);
 
+       // get_tool_wear_after_use(uses[, initial_wear])
+       static int l_get_tool_wear_after_use(lua_State *L);
+
        // get_dig_params(groups, tool_capabilities[, wear])
        static int l_get_dig_params(lua_State *L);
 
index 2855f04b84c2f03e1460d9b8bba26fc7f05fe548..9da5f98bd73e64fc03e13e62ab797912eb44c56a 100644 (file)
@@ -258,23 +258,23 @@ void LBMManager::applyLBMs(ServerEnvironment *env, MapBlock *block, u32 stamp)
        v3s16 pos;
        MapNode n;
        content_t c;
-       lbm_lookup_map::const_iterator it = getLBMsIntroducedAfter(stamp);
+       bool pos_valid; // dummy, we know it's valid
+       auto it = getLBMsIntroducedAfter(stamp);
        for (; it != m_lbm_lookup.end(); ++it) {
                // Cache previous version to speedup lookup which has a very high performance
                // penalty on each call
-               content_t previous_c{};
-               std::vector<LoadingBlockModifierDef *> *lbm_list = nullptr;
+               content_t previous_c = CONTENT_IGNORE;
+               const std::vector<LoadingBlockModifierDef *> *lbm_list = nullptr;
 
                for (pos.X = 0; pos.X < MAP_BLOCKSIZE; pos.X++)
                        for (pos.Y = 0; pos.Y < MAP_BLOCKSIZE; pos.Y++)
                                for (pos.Z = 0; pos.Z < MAP_BLOCKSIZE; pos.Z++) {
-                                       n = block->getNodeNoEx(pos);
+                                       n = block->getNodeNoCheck(pos, &pos_valid);
                                        c = n.getContent();
 
                                        // If content_t are not matching perform an LBM lookup
                                        if (previous_c != c) {
-                                               lbm_list = (std::vector<LoadingBlockModifierDef *> *)
-                                                       it->second.lookup(c);
+                                               lbm_list = it->second.lookup(c);
                                                previous_c = c;
                                        }
 
index 075c6b3c5ff13f8bb5e5ada473d85d7c8e80f7ca..821ddf07d6b9a9289dc5f5eee086a2f99c399d9d 100644 (file)
@@ -183,7 +183,7 @@ void ToolCapabilities::deserializeJson(std::istream &is)
        }
 }
 
-static u32 calculateResultWear(const u32 uses, const u16 initial_wear)
+u32 calculateResultWear(const u32 uses, const u16 initial_wear)
 {
        if (uses == 0) {
                // Trivial case: Infinite uses
index 8409f59afcd234da41fb2b2b58bdd0b7738abde3..c2444a834c0100eee6b91cdbb40cd4fece03ead8 100644 (file)
@@ -142,4 +142,5 @@ PunchDamageResult getPunchDamage(
                u16 initial_wear = 0
 );
 
+u32 calculateResultWear(const u32 uses, const u16 initial_wear);
 f32 getToolRange(const ItemDefinition &def_selected, const ItemDefinition &def_hand);
index 421f3b66e5c29442b1841c7ef049336f225dbb00..12b155f46c1f0ba714af2571a82d76ddc12628bc 100644 (file)
@@ -30,8 +30,14 @@ class TestNoise : public TestBase {
 
        void runTests(IGameDef *gamedef);
 
+       void testNoise2dAtOriginWithZeroSeed();
+       void testNoise2dWithMaxSeed();
+       void testNoise2dWithFunPrimes();
        void testNoise2dPoint();
        void testNoise2dBulk();
+       void testNoise3dAtOriginWithZeroSeed();
+       void testNoise3dWithMaxSeed();
+       void testNoise3dWithFunPrimes();
        void testNoise3dPoint();
        void testNoise3dBulk();
        void testNoiseInvalidParams();
@@ -44,8 +50,14 @@ static TestNoise g_test_instance;
 
 void TestNoise::runTests(IGameDef *gamedef)
 {
+       TEST(testNoise2dAtOriginWithZeroSeed);
+       TEST(testNoise2dWithMaxSeed);
+       TEST(testNoise2dWithFunPrimes);
        TEST(testNoise2dPoint);
        TEST(testNoise2dBulk);
+       TEST(testNoise3dAtOriginWithZeroSeed);
+       TEST(testNoise3dWithMaxSeed);
+       TEST(testNoise3dWithFunPrimes);
        TEST(testNoise3dPoint);
        TEST(testNoise3dBulk);
        TEST(testNoiseInvalidParams);
@@ -53,6 +65,27 @@ void TestNoise::runTests(IGameDef *gamedef)
 
 ////////////////////////////////////////////////////////////////////////////////
 
+void TestNoise::testNoise2dAtOriginWithZeroSeed()
+{
+       float actual{ noise2d(0, 0, 0) };
+       constexpr float expected{ -0.281791f };
+       UASSERT(std::fabs(actual - expected) <= 0.00001);
+}
+
+void TestNoise::testNoise2dWithMaxSeed()
+{
+       float actual{ noise2d(4096, 4096, 2147483647) };
+       constexpr float expected{ 0.950606f };
+       UASSERT(std::fabs(actual - expected) <= 0.00001);
+}
+
+void TestNoise::testNoise2dWithFunPrimes()
+{
+       float actual{ noise2d(-3947, -2333, 7027) };
+       constexpr float expected{ -0.294907f };
+       UASSERT(std::fabs(actual - expected) <= 0.00001);
+}
+
 void TestNoise::testNoise2dPoint()
 {
        NoiseParams np_normal(20, 40, v3f(50, 50, 50), 9,  5, 0.6, 2.0);
@@ -79,6 +112,27 @@ void TestNoise::testNoise2dBulk()
        }
 }
 
+void TestNoise::testNoise3dAtOriginWithZeroSeed()
+{
+       float actual{ noise2d(0, 0, 0) };
+       constexpr float expected{ -0.281791f };
+       UASSERT(std::fabs(actual - expected) <= 0.00001);
+}
+
+void TestNoise::testNoise3dWithMaxSeed()
+{
+       float actual{ noise3d(4096, 4096, 4096, 2147483647) };
+       constexpr float expected{ -0.775243f };
+       UASSERT(std::fabs(actual - expected) <= 0.00001);
+}
+
+void TestNoise::testNoise3dWithFunPrimes()
+{
+       float actual{ noise2d(3903, -1723, 7411) };
+       constexpr float expected{ 0.989124f };
+       UASSERT(std::fabs(actual - expected) <= 0.00001);
+}
+
 void TestNoise::testNoise3dPoint()
 {
        NoiseParams np_normal(20, 40, v3f(50, 50, 50), 9,  5, 0.6, 2.0);
index b805b2f78c19b28be4420b6784ea63f7d18aabdd..d70c26015deee23a960e86c76940e6f095dd9817 100644 (file)
@@ -39,16 +39,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
        #include <windows.h>
 #endif
 
-#ifdef __NetBSD__
-       #include <sys/param.h>
-       #if __NetBSD_Version__ <= 999001500
-               #define BSD_ICONV_USED
-       #endif
-#elif defined(_ICONV_H_) && (defined(__FreeBSD__) || defined(__OpenBSD__) || \
-       defined(__DragonFly__))
-       #define BSD_ICONV_USED
-#endif
-
 #ifndef _WIN32
 
 static bool convert(const char *to, const char *from, char *outbuf,
@@ -56,11 +46,7 @@ static bool convert(const char *to, const char *from, char *outbuf,
 {
        iconv_t cd = iconv_open(to, from);
 
-#ifdef BSD_ICONV_USED
-       const char *inbuf_ptr = inbuf;
-#else
        char *inbuf_ptr = inbuf;
-#endif
        char *outbuf_ptr = outbuf;
 
        size_t *inbuf_left_ptr = &inbuf_size;
diff --git a/textures/base/pack/server_favorite_delete.png b/textures/base/pack/server_favorite_delete.png
new file mode 100644 (file)
index 0000000..e35c6aa
Binary files /dev/null and b/textures/base/pack/server_favorite_delete.png differ