From b72932b445a0d0fa547eb75e363d2e3cc1c9250a Mon Sep 17 00:00:00 2001 From: Zughy <63455151+Zughy@users.noreply.github.com> Date: Fri, 3 Jun 2022 12:08:58 +0200 Subject: [PATCH 01/16] Docs: remove unimplemented `preserve` field in crafting recipes --- doc/lua_api.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 15a067a5e..43748dfba 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -1779,7 +1779,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: From 6d163b72dc777c6dfc62175c7af231cd62e5c2c7 Mon Sep 17 00:00:00 2001 From: ROllerozxa Date: Fri, 3 Jun 2022 21:46:37 +0200 Subject: [PATCH 02/16] Rework main menu confirmation dialogs (#12356) --- builtin/mainmenu/common.lua | 8 ++++++++ builtin/mainmenu/dlg_contentstore.lua | 10 ++++------ builtin/mainmenu/dlg_delete_content.lua | 13 ++++--------- builtin/mainmenu/dlg_delete_world.lua | 12 ++++-------- 4 files changed, 20 insertions(+), 23 deletions(-) diff --git a/builtin/mainmenu/common.lua b/builtin/mainmenu/common.lua index 8db8bb8d1..dcccb2b2a 100644 --- a/builtin/mainmenu/common.lua +++ b/builtin/mainmenu/common.lua @@ -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 diff --git a/builtin/mainmenu/dlg_contentstore.lua b/builtin/mainmenu/dlg_contentstore.lua index 16ab1c3a7..11eaceac3 100644 --- a/builtin/mainmenu/dlg_contentstore.lua +++ b/builtin/mainmenu/dlg_contentstore.lua @@ -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) diff --git a/builtin/mainmenu/dlg_delete_content.lua b/builtin/mainmenu/dlg_delete_content.lua index a24171541..4463825f7 100644 --- a/builtin/mainmenu/dlg_delete_content.lua +++ b/builtin/mainmenu/dlg_delete_content.lua @@ -18,15 +18,10 @@ -------------------------------------------------------------------------------- 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 -------------------------------------------------------------------------------- diff --git a/builtin/mainmenu/dlg_delete_world.lua b/builtin/mainmenu/dlg_delete_world.lua index 33e7bc945..67c0612bd 100644 --- a/builtin/mainmenu/dlg_delete_world.lua +++ b/builtin/mainmenu/dlg_delete_world.lua @@ -17,14 +17,10 @@ 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) From 6a6b579c5472065dd4ba8edcebe120b4b1c9198e Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Fri, 3 Jun 2022 19:47:04 +0000 Subject: [PATCH 03/16] Add helper functions to make tool usable n times (#12047) --- doc/lua_api.txt | 12 ++++++++++++ src/script/lua_api/l_item.cpp | 22 +++++++++++++++++++++- src/script/lua_api/l_item.h | 11 ++++++++++- src/script/lua_api/l_util.cpp | 12 ++++++++++++ src/script/lua_api/l_util.h | 3 +++ src/tool.cpp | 2 +- src/tool.h | 1 + 7 files changed, 60 insertions(+), 3 deletions(-) diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 43748dfba..8a8030394 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -3590,6 +3590,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: @@ -6525,7 +6531,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 diff --git a/src/script/lua_api/l_item.cpp b/src/script/lua_api/l_item.cpp index 27c1b8875..13d046d00 100644 --- a/src/script/lua_api/l_item.cpp +++ b/src/script/lua_api/l_item.cpp @@ -343,7 +343,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) @@ -357,6 +357,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(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) @@ -532,6 +551,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), diff --git a/src/script/lua_api/l_item.h b/src/script/lua_api/l_item.h index 180975061..a392555d2 100644 --- a/src/script/lua_api/l_item.h +++ b/src/script/lua_api/l_item.h @@ -108,11 +108,20 @@ private: 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); diff --git a/src/script/lua_api/l_util.cpp b/src/script/lua_api/l_util.cpp index 97068ce4c..f774daf97 100644 --- a/src/script/lua_api/l_util.cpp +++ b/src/script/lua_api/l_util.cpp @@ -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(L, 1); + u16 initial_wear = readParam(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); diff --git a/src/script/lua_api/l_util.h b/src/script/lua_api/l_util.h index cc5563577..ec86c6632 100644 --- a/src/script/lua_api/l_util.h +++ b/src/script/lua_api/l_util.h @@ -50,6 +50,9 @@ private: // 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); diff --git a/src/tool.cpp b/src/tool.cpp index 075c6b3c5..821ddf07d 100644 --- a/src/tool.cpp +++ b/src/tool.cpp @@ -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 diff --git a/src/tool.h b/src/tool.h index 8409f59af..c2444a834 100644 --- a/src/tool.h +++ b/src/tool.h @@ -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); From 5f3af7d18b528e502e2cf09e0f46cc892df98dd4 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sat, 21 May 2022 19:27:35 +0200 Subject: [PATCH 04/16] Remove obsolete eye_height related workaround This was added a long time ago in 42bbd5c9ae06a8d8ffb7915599097ead6f848755 and meant to fix prevent the view becoming black when jumping into a ceiling, this no longer happens today. --- src/client/localplayer.cpp | 23 +---------------------- src/client/localplayer.h | 1 - 2 files changed, 1 insertion(+), 23 deletions(-) diff --git a/src/client/localplayer.cpp b/src/client/localplayer.cpp index 279efafe9..79fe2cb11 100644 --- a/src/client/localplayer.cpp +++ b/src/client/localplayer.cpp @@ -426,16 +426,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 */ @@ -696,8 +686,7 @@ v3s16 LocalPlayer::getLightPosition() const 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 @@ -1025,16 +1014,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 */ diff --git a/src/client/localplayer.h b/src/client/localplayer.h index 3d0072fc1..650a01574 100644 --- a/src/client/localplayer.h +++ b/src/client/localplayer.h @@ -199,7 +199,6 @@ private: 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; From 575caa8015fe420ce5e709d6c137036dfc0262ef Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sat, 21 May 2022 20:29:44 +0200 Subject: [PATCH 05/16] Properly keep noclip state in Game and ClientMap --- src/client/clientmap.cpp | 24 ++++++++++-------------- src/client/clientmap.h | 6 ++++-- src/client/game.cpp | 10 +++++++++- 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/client/clientmap.cpp b/src/client/clientmap.cpp index 98e3f40d3..38ba1daad 100644 --- a/src/client/clientmap.cpp +++ b/src/client/clientmap.cpp @@ -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")) { + if (m_control.allow_noclip) { 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") && - m_client->checkLocalPrivilege("noclip")) && - 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) { 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(); diff --git a/src/client/clientmap.h b/src/client/clientmap.h index 823870c68..8c45b5382 100644 --- a/src/client/clientmap.h +++ b/src/client/clientmap.h @@ -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; }; diff --git a/src/client/game.cpp b/src/client/game.cpp index f93bd34a3..d6e0cc8b8 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -1743,6 +1743,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); @@ -1757,6 +1759,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, @@ -3762,7 +3767,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) { + // 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")) { direct_brightness = time_brightness; sunlight_seen = true; } else { From 8e5bd82c4d19c405fbb4f2592bf91ad8b110294b Mon Sep 17 00:00:00 2001 From: JosiahWI <41302989+JosiahWI@users.noreply.github.com> Date: Fri, 3 Jun 2022 19:51:58 -0500 Subject: [PATCH 06/16] fix integer overflow in mapgen (#11641) * fix integer overflow in mapgen Some calculations involving the magic seed had overflow because the result of an intermediate arithmetic step could not fit in an s32. By making the magic seed unsigned, the other operand in the equation will be cast to unsigned, and possibly other operands or intermediate operands. This will result in unexpected behavior if an operand is negative, which is technically possible, but logically should not happen. * comment noise2d bitshift While working through the code I was momentarily concerned that the right bitshift in noise2d could fill ones in some cases. It turns out that with signed integers, this is indeed true, but this one is shifting an unsigned integer, so the behavior is as expected. I put a comment here to clarify this, in case someone else wonders the same thing down the line. * noise2d and noise3d unittests I have added 3 tests each for noise2d and noise3d, testing all zero inputs, a very large seed (case which caused UB in the old implementation) and some fun primes I picked for no particular reason. This should be sufficient to demonstrate that the behavior of the new implementation has not changed. I used uniform initialization because it is a good feature of C++11. Please do not explode. * uncomment the noise2d bitshift This reverts commit 583b77ee9f1ad6bb77340ebb5ba51eb9a88ff51c. It's a well-defined language semantic; it doesn't need to be commented. * code cleanliness --- src/mapgen/mapgen.cpp | 3 ++- src/noise.cpp | 3 ++- src/unittest/test_noise.cpp | 54 +++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/src/mapgen/mapgen.cpp b/src/mapgen/mapgen.cpp index d767bd264..1f2ac491e 100644 --- a/src/mapgen/mapgen.cpp +++ b/src/mapgen/mapgen.cpp @@ -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); } diff --git a/src/noise.cpp b/src/noise.cpp index 2f4de6855..d98d4dafb 100644 --- a/src/noise.cpp +++ b/src/noise.cpp @@ -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, diff --git a/src/unittest/test_noise.cpp b/src/unittest/test_noise.cpp index 421f3b66e..12b155f46 100644 --- a/src/unittest/test_noise.cpp +++ b/src/unittest/test_noise.cpp @@ -30,8 +30,14 @@ public: 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); From e82985c0a1b5d828cb0cbb4d76cdf7085dfec682 Mon Sep 17 00:00:00 2001 From: Lars Mueller Date: Fri, 3 Jun 2022 13:09:03 +0200 Subject: [PATCH 07/16] Document itemstrings with metadata --- doc/lua_api.txt | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 8a8030394..1efa5678e 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -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: - [[ ]] +1. Full item identifier ("item name") +2. Optional amount +3. Optional wear value +4. Optional item metadata + +Syntax: + + [[ [ ]]] 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 From 1f39948bc3341af99a1a2dfc39e4b4164ab56f4c Mon Sep 17 00:00:00 2001 From: savilli <78875209+savilli@users.noreply.github.com> Date: Sun, 5 Jun 2022 16:20:29 +0300 Subject: [PATCH 08/16] Fix BSD iconv declaration --- src/util/string.cpp | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/util/string.cpp b/src/util/string.cpp index b805b2f78..d70c26015 100644 --- a/src/util/string.cpp +++ b/src/util/string.cpp @@ -39,16 +39,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #endif -#ifdef __NetBSD__ - #include - #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; From 21323ef1ff02dd714330a8c9d8235f047e1dacf8 Mon Sep 17 00:00:00 2001 From: ROllerozxa Date: Sun, 5 Jun 2022 15:20:39 +0200 Subject: [PATCH 09/16] Hide "Autosave Screen Size" on Android --- builtin/mainmenu/tab_settings.lua | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/builtin/mainmenu/tab_settings.lua b/builtin/mainmenu/tab_settings.lua index 880978800..8307ca7e2 100644 --- a/builtin/mainmenu/tab_settings.lua +++ b/builtin/mainmenu/tab_settings.lua @@ -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 From 03d86ea0b4900cd0394649597d278d465512d629 Mon Sep 17 00:00:00 2001 From: rubenwardy Date: Sun, 5 Jun 2022 16:47:38 +0100 Subject: [PATCH 10/16] Add register dialog to separate login/register (#12185) New users find Minetest's account system confusing. This change moves username/password to a new dialog, with login and register buttons added to the Join Game tab. The old registration confirmation dialog is removed in favour of the new dialog. Fixes #8138 --- LICENSE.txt | 6 + builtin/mainmenu/dlg_register.lua | 123 ++++++++ builtin/mainmenu/init.lua | 2 + builtin/mainmenu/tab_online.lua | 57 +++- builtin/settingtypes.txt | 6 +- src/client/client.cpp | 22 +- src/client/client.h | 8 +- src/client/clientlauncher.cpp | 1 + src/client/game.cpp | 34 +-- src/defaultsettings.cpp | 2 +- src/gameparams.h | 11 +- src/gui/CMakeLists.txt | 1 - src/gui/guiConfirmRegistration.cpp | 266 ------------------ src/gui/guiConfirmRegistration.h | 65 ----- src/gui/guiMainMenu.h | 3 + src/network/clientpackethandler.cpp | 19 +- src/script/lua_api/l_mainmenu.cpp | 8 + textures/base/pack/server_favorite_delete.png | Bin 0 -> 748 bytes 18 files changed, 232 insertions(+), 402 deletions(-) create mode 100644 builtin/mainmenu/dlg_register.lua delete mode 100644 src/gui/guiConfirmRegistration.cpp delete mode 100644 src/gui/guiConfirmRegistration.h create mode 100644 textures/base/pack/server_favorite_delete.png diff --git a/LICENSE.txt b/LICENSE.txt index 6eae833d5..1f2c6c38d 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -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 ------------------------------- diff --git a/builtin/mainmenu/dlg_register.lua b/builtin/mainmenu/dlg_register.lua new file mode 100644 index 000000000..a7658249c --- /dev/null +++ b/builtin/mainmenu/dlg_register.lua @@ -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 diff --git a/builtin/mainmenu/init.lua b/builtin/mainmenu/init.lua index 8e716c2eb..d073f5a57 100644 --- a/builtin/mainmenu/init.lua +++ b/builtin/mainmenu/init.lua @@ -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 = {} diff --git a/builtin/mainmenu/tab_online.lua b/builtin/mainmenu/tab_online.lua index fb7409864..a8e1eb2ef 100644 --- a/builtin/mainmenu/tab_online.lua +++ b/builtin/mainmenu/tab_online.lua @@ -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 diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt index 3f6f6c9fc..5b5146522 100644 --- a/builtin/settingtypes.txt +++ b/builtin/settingtypes.txt @@ -1033,9 +1033,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] diff --git a/src/client/client.cpp b/src/client/client.cpp index 93a403e81..d81ee434e 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -100,7 +100,8 @@ Client::Client( MtEventManager *event, RenderingEngine *rendering_engine, bool ipv6, - GameUI *game_ui + GameUI *game_ui, + ELoginRegister allow_login_or_register ): m_tsrc(tsrc), m_shsrc(shsrc), @@ -124,7 +125,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)); @@ -396,10 +398,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) { @@ -1078,18 +1076,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; diff --git a/src/client/client.h b/src/client/client.h index cb1227768..f01510ddb 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -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 #define CLIENT_CHAT_MESSAGE_LIMIT_PER_10S 10.0f @@ -127,7 +128,8 @@ public: MtEventManager *event, RenderingEngine *rendering_engine, bool ipv6, - GameUI *game_ui + GameUI *game_ui, + ELoginRegister allow_login_or_register ); ~Client(); @@ -347,8 +349,7 @@ public: 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(); @@ -460,7 +461,6 @@ private: 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 &blocks); void sendGotBlocks(const std::vector &blocks); diff --git a/src/client/clientlauncher.cpp b/src/client/clientlauncher.cpp index 54c561d11..60c9525f3 100644 --- a/src/client/clientlauncher.cpp +++ b/src/client/clientlauncher.cpp @@ -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; diff --git a/src/client/game.cpp b/src/client/game.cpp index d6e0cc8b8..441054631 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -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" @@ -1480,7 +1479,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()); @@ -1543,28 +1543,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 diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index 0087f8d48..b320e499e 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -64,7 +64,7 @@ void set_default_settings() settings->setDefault("enable_client_modding", "false"); 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"); // Keymap diff --git a/src/gameparams.h b/src/gameparams.h index 70b0ffcde..b138f8771 100644 --- a/src/gameparams.h +++ b/src/gameparams.h @@ -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; }; diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 513b13e8e..4434b14a0 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -11,7 +11,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 index c5aa9c85e..000000000 --- a/src/gui/guiConfirmRegistration.cpp +++ /dev/null @@ -1,266 +0,0 @@ -/* -Minetest -Copyright (C) 2018 srifqi, Muhammad Rifqi Priyo Susanto - - -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 -#include -#include -#include -#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( - 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 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 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 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 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 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 index fb2157756..000000000 --- a/src/gui/guiConfirmRegistration.h +++ /dev/null @@ -1,65 +0,0 @@ -/* -Minetest -Copyright (C) 2018 srifqi, Muhammad Rifqi Priyo Susanto - - -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 - -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; -}; diff --git a/src/gui/guiMainMenu.h b/src/gui/guiMainMenu.h index 1dca8bf2d..9b8ff383c 100644 --- a/src/gui/guiMainMenu.h +++ b/src/gui/guiMainMenu.h @@ -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 #include @@ -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; }; diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index 55d20d673..78ace6a81 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -101,11 +101,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); } diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp index 4d9fa5b14..f7b2393fb 100644 --- a/src/script/lua_api/l_mainmenu.cpp +++ b/src/script/lua_api/l_mainmenu.cpp @@ -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"); diff --git a/textures/base/pack/server_favorite_delete.png b/textures/base/pack/server_favorite_delete.png new file mode 100644 index 0000000000000000000000000000000000000000..e35c6aaf05f7ee2f176f98d57441a1c3885170b7 GIT binary patch literal 748 zcmVxFe<%$Yj8k0%#L?^QAE|7fM+{2(~)|aZ(E2|Np(d%xPWWFe{8pKW7?{UxrK1a zmV2gXTHUjf-v9u=l6leq0H|qPxsZ0(tBb;)fXbtUzK3whfpF8OhyMTo-nNtJ00930 z0MVX+=>Py}008L;2cln9=mrI2004sk0E7Slpa1}^006cC0J(o^!k2o+gK)>FgUpY2 z%(9Emhjh=qlF*xf)R%qLn10ozh1SfR*r$ivtBTvLjN7=C+_I0}-m2fYk>9zJ;lh~W zz?SC8o#)P<=@=2|9~J2$7wIG!=_MNM*{AHPx#O>|ODQvd-00|g2Y6crjDA0Q(tD=;xLI6XZ;LP<+h zSz26NU2SuBeU6oupP;0tsjhSRK^Y!@n`TF|$`}_U<{{Fw5 zCYt~N0MSWAK~xwSRl#Q?LSYyN;5%g%GLlVY%icSyVcl;YE6N_(l&$gG9i8*VbpcS& z^ftgyv^lAOs`EZGbS||OQ0V$val+uBEUUTfdp8Vub(A%xva^ll)_edxBNOwK7p6Wg zd{d*t^=MxD&RkKR`IAm(E(a=s>apbK3FV1zuTgIaH1@%p#3AL83+;u-sR`cSMJNv} zfUf2EHh#TF*&uWsr)NjI`#Y2n@y9e2JLqp}o!O@N2~FwZxVsoA>s)7eS^=imH*DK9Z19?OM0000 Date: Sun, 5 Jun 2022 16:58:48 +0200 Subject: [PATCH 11/16] Improve LBMManager::applyLBMs() code Fixes a possible bug for lbms on content ID zero and removes unsafe casts. --- src/serverenvironment.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/serverenvironment.cpp b/src/serverenvironment.cpp index 06bfc7b98..39cd7aa64 100644 --- a/src/serverenvironment.cpp +++ b/src/serverenvironment.cpp @@ -258,23 +258,22 @@ void LBMManager::applyLBMs(ServerEnvironment *env, MapBlock *block, u32 stamp) v3s16 pos; MapNode n; content_t c; - lbm_lookup_map::const_iterator it = getLBMsIntroducedAfter(stamp); + 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 *lbm_list = nullptr; + content_t previous_c = CONTENT_IGNORE; + const std::vector *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, nullptr); c = n.getContent(); // If content_t are not matching perform an LBM lookup if (previous_c != c) { - lbm_list = (std::vector *) - it->second.lookup(c); + lbm_list = it->second.lookup(c); previous_c = c; } From 4baf56520d61e22687b563d403f5d873251e135f Mon Sep 17 00:00:00 2001 From: rubenwardy Date: Sun, 5 Jun 2022 17:42:09 +0100 Subject: [PATCH 12/16] Android: Add support for sharing debug.txt (#12370) --- android/app/src/main/AndroidManifest.xml | 13 +++++++++++- .../net/minetest/minetest/GameActivity.java | 21 +++++++++++++++++++ android/app/src/main/res/xml/filepaths.xml | 3 +++ builtin/mainmenu/tab_about.lua | 9 +++++++- doc/menu_lua_api.txt | 2 ++ src/porting_android.cpp | 12 +++++++++++ src/porting_android.h | 7 +++++++ src/script/lua_api/l_mainmenu.cpp | 14 +++++++++++++ src/script/lua_api/l_mainmenu.h | 2 ++ 9 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 android/app/src/main/res/xml/filepaths.xml diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 6ea677cb9..11c868622 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -59,6 +59,17 @@ android:name=".UnzipService" android:enabled="true" android:exported="false" /> - + + + + + + diff --git a/android/app/src/main/java/net/minetest/minetest/GameActivity.java b/android/app/src/main/java/net/minetest/minetest/GameActivity.java index eeb90ea7f..f5e9fd6d0 100644 --- a/android/app/src/main/java/net/minetest/minetest/GameActivity.java +++ b/android/app/src/main/java/net/minetest/minetest/GameActivity.java @@ -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 index 000000000..2fff06908 --- /dev/null +++ b/android/app/src/main/res/xml/filepaths.xml @@ -0,0 +1,3 @@ + + + diff --git a/builtin/mainmenu/tab_about.lua b/builtin/mainmenu/tab_about.lua index ba258fd2d..8e6155ea1 100644 --- a/builtin/mainmenu/tab_about.lua +++ b/builtin/mainmenu/tab_about.lua @@ -128,7 +128,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.") .. "]" @@ -142,6 +144,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 diff --git a/doc/menu_lua_api.txt b/doc/menu_lua_api.txt index 68e7b4b9d..63e229135 100644 --- a/doc/menu_lua_api.txt +++ b/doc/menu_lua_api.txt @@ -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 diff --git a/src/porting_android.cpp b/src/porting_android.cpp index c71fe5ad8..83b590b99 100644 --- a/src/porting_android.cpp +++ b/src/porting_android.cpp @@ -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, diff --git a/src/porting_android.h b/src/porting_android.h index 239815922..265825fbd 100644 --- a/src/porting_android.h +++ b/src/porting_android.h @@ -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 diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp index f7b2393fb..4a847ed6d 100644 --- a/src/script/lua_api/l_mainmenu.cpp +++ b/src/script/lua_api/l_mainmenu.cpp @@ -876,6 +876,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) { @@ -941,6 +954,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); } diff --git a/src/script/lua_api/l_mainmenu.h b/src/script/lua_api/l_mainmenu.h index 781185425..6ceff6dd7 100644 --- a/src/script/lua_api/l_mainmenu.h +++ b/src/script/lua_api/l_mainmenu.h @@ -152,6 +152,8 @@ private: 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); From 14c283a623a1c9c0015f04865655df7a225bedf9 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sun, 5 Jun 2022 18:59:53 +0200 Subject: [PATCH 13/16] Fix crash in commit a69b7abe00fb818fd88f3cd04e7f9997ffd21072 --- src/serverenvironment.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/serverenvironment.cpp b/src/serverenvironment.cpp index 39cd7aa64..8989fb05f 100644 --- a/src/serverenvironment.cpp +++ b/src/serverenvironment.cpp @@ -258,6 +258,7 @@ void LBMManager::applyLBMs(ServerEnvironment *env, MapBlock *block, u32 stamp) v3s16 pos; MapNode n; content_t c; + 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 @@ -268,7 +269,7 @@ void LBMManager::applyLBMs(ServerEnvironment *env, MapBlock *block, u32 stamp) 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->getNodeNoCheck(pos, nullptr); + n = block->getNodeNoCheck(pos, &pos_valid); c = n.getContent(); // If content_t are not matching perform an LBM lookup From 381f84ee2788eb462999701e902bd22271cfcb2e Mon Sep 17 00:00:00 2001 From: Zughy <63455151+Zughy@users.noreply.github.com> Date: Sun, 5 Jun 2022 22:12:39 +0200 Subject: [PATCH 14/16] Bug report template: ask contributors to provide a code snippet (#12405) --- .github/ISSUE_TEMPLATE/bug_report.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index b6f351c15..7cf34bd4a 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -8,8 +8,8 @@ assignees: '' ##### Minetest version ``` @@ -29,4 +29,4 @@ OpenGL version: ##### Steps to reproduce - + From 951604e29ff9d4b796003264574e06031c014a3f Mon Sep 17 00:00:00 2001 From: paradust7 <102263465+paradust7@users.noreply.github.com> Date: Mon, 6 Jun 2022 03:05:42 +0000 Subject: [PATCH 15/16] Remove invalid fps_max on Mac --- src/defaultsettings.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index b320e499e..d35000814 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -456,7 +456,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 From edc7df54801ab3bf30f96ac5aad6ce11a102f6b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20M=C3=BCller?= <34514239+appgurueu@users.noreply.github.com> Date: Mon, 6 Jun 2022 18:32:28 +0200 Subject: [PATCH 16/16] core.formspec_escape: Restore backwards compat Support numbers as arguments by using `string.gsub(text, ...)` instead of `text:gsub(...)` which will coerce `text` to a string --- builtin/common/misc_helpers.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/common/misc_helpers.lua b/builtin/common/misc_helpers.lua index d2356b505..467f18804 100644 --- a/builtin/common/misc_helpers.lua +++ b/builtin/common/misc_helpers.lua @@ -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