From 0534d696f70cdb60254a0943a305ca0895c1a5bb Mon Sep 17 00:00:00 2001 From: MoNTE48 Date: Thu, 15 Jul 2021 22:01:11 +0200 Subject: [PATCH] Merge MultiCraft Legacy changes --- README.md | 4 +- build/macOS/Podfile | 0 builtin/game/falling.lua | 6 +- builtin/game/item.lua | 5 + builtin/mainmenu/dlg_settings_advanced.lua | 4 + builtin/mainmenu/tab_credits.lua | 5 +- src/client/game.cpp | 20 +++- src/client/inputhandler.cpp | 17 +-- src/client/renderingengine.cpp | 36 ++++--- src/defaultsettings.cpp | 116 +++++++++++---------- src/gui/guiSkin.cpp | 2 +- src/gui/touchscreengui.cpp | 2 +- src/porting_android.cpp | 33 +----- src/porting_android.h | 1 - src/serverlist.cpp | 4 +- textures/base/pack/bg.png | Bin 8482 -> 1346 bytes 16 files changed, 129 insertions(+), 126 deletions(-) mode change 100755 => 100644 build/macOS/Podfile diff --git a/README.md b/README.md index 3a33bb4b8..318dd35c8 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,14 @@ MultiCraft Open Source ====================== -![Build Status](https://github.com/MultiCraft/MultiCraft5.3/workflows/build/badge.svg) +![Build Status](https://github.com/MultiCraft/MultiCraft2/workflows/build/badge.svg) [![License](https://img.shields.io/badge/license-LGPLv3.0%2B-blue.svg)](https://www.gnu.org/licenses/lgpl-3.0.en.html) MultiCraft Open Source is a free open-source voxel game engine with easy modding and game creation. MultiCraft is based on the Minetest project, which is developed by a [number of contributors](https://github.com/minetest/minetest/graphs/contributors). -Copyright © 2014-2020 Maksim Gamarnik [MoNTE48] & MultiCraft Development Team. +Copyright © 2014-2021 Maksim Gamarnik [MoNTE48] & MultiCraft Development Team. Table of Contents ------------------ diff --git a/build/macOS/Podfile b/build/macOS/Podfile old mode 100755 new mode 100644 diff --git a/builtin/game/falling.lua b/builtin/game/falling.lua index cc15b5542..bd1fe8c89 100644 --- a/builtin/game/falling.lua +++ b/builtin/game/falling.lua @@ -390,7 +390,11 @@ core.register_entity(":__builtin:falling_node", { -- Drop node if does not fall within 5 seconds self.timer = self.timer + dtime if self.timer > 5 then - core.add_item(pos, self.node) + -- Add dropped items + local drops = core.get_node_drops(self.node, "") + for _, dropped_item in pairs(drops) do + core.add_item(pos, dropped_item) + end self.object:remove() return end diff --git a/builtin/game/item.lua b/builtin/game/item.lua index 074eb4ffc..cf8f7751f 100644 --- a/builtin/game/item.lua +++ b/builtin/game/item.lua @@ -633,6 +633,11 @@ end function core.item_eat(hp_change, replace_with_item, poison) return function(itemstack, user, pointed_thing) -- closure if user then + if user:is_player() and pointed_thing.type == "object" then + pointed_thing.ref:right_click(user) + return user:get_wielded_item() + end + return core.do_item_eat(hp_change, replace_with_item, itemstack, user, pointed_thing, poison) end end diff --git a/builtin/mainmenu/dlg_settings_advanced.lua b/builtin/mainmenu/dlg_settings_advanced.lua index d5989591d..390d249d5 100644 --- a/builtin/mainmenu/dlg_settings_advanced.lua +++ b/builtin/mainmenu/dlg_settings_advanced.lua @@ -31,6 +31,10 @@ end -- returns error message, or nil local function parse_setting_line(settings, line, read_all, base_level, allow_secure) + + -- strip carriage returns (CR, /r) + line = line:gsub("\r", "") + -- comment local comment = line:match("^#" .. CHAR_CLASSES.SPACE .. "*(.*)$") if comment then diff --git a/builtin/mainmenu/tab_credits.lua b/builtin/mainmenu/tab_credits.lua index e2c302699..77b5e6350 100644 --- a/builtin/mainmenu/tab_credits.lua +++ b/builtin/mainmenu/tab_credits.lua @@ -22,9 +22,10 @@ local multicraft_developers = { "Bektur Mambetov (ubulem) ", "Alexander Zavrin (Ransom.00)", "luk3yx", - "An0n3m0us", - "Jean-Patrick Guerrero (kilbith) ", + "Nathan Salapat (NathanS21) ", "Vitaliy Lobachevskiy (numberZero) ", + "Jean-Patrick Guerrero (kilbith) ", + "An0n3m0us", "sfan5 ", "Stuart Jones (stujones11) ", "And other people who helped make the world better!" diff --git a/src/client/game.cpp b/src/client/game.cpp index 9247f8701..abb44ed77 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -1898,6 +1898,11 @@ void Game::processKeyInput() showPauseMenu(); } } else if (wasKeyDown(KeyType::CHAT)) { +#if defined(__ANDROID__) || defined(__IOS__) + if (isKeyDown(KeyType::SNEAK)) + m_game_ui->toggleChat(); + else + #endif openConsole(0.2, L""); } else if (wasKeyDown(KeyType::CMD)) { openConsole(0.2, L"/"); @@ -1911,6 +1916,11 @@ void Game::processKeyInput() } else if (wasKeyDown(KeyType::FREEMOVE)) { toggleFreeMove(); } else if (wasKeyDown(KeyType::JUMP)) { +#if defined(__ANDROID__) || defined(__IOS__) + if (isKeyDown(KeyType::SNEAK) && client->checkPrivilege("fly")) + toggleFast(); + else + #endif toggleFreeMoveAlt(); } else if (wasKeyDown(KeyType::PITCHMOVE)) { togglePitchMove(); @@ -2548,7 +2558,11 @@ inline void Game::step(f32 *dtime) #if defined(__ANDROID__) || defined(__IOS__) if (g_menumgr.pausesGame()) { runData.pause_game_timer += *dtime; - if (runData.pause_game_timer > 120.f) { + float disconnect_time = 180.0f; +#ifdef __IOS__ + disconnect_time = simple_singleplayer_mode ? 60.0f : 120.0f; +#endif + if (runData.pause_game_timer > disconnect_time) { g_gamecallback->disconnect(); return; } @@ -4423,7 +4437,7 @@ void the_game(bool *kill, } #if defined(__ANDROID__) || defined(__IOS__) -void external_pause_game() +extern "C" void external_pause_game() { if (!g_game) return; @@ -4432,7 +4446,7 @@ void external_pause_game() #endif #ifdef __IOS__ -void external_statustext(const char *text, float duration) +extern "C" void external_statustext(const char *text, float duration) { if (!g_game) return; diff --git a/src/client/inputhandler.cpp b/src/client/inputhandler.cpp index be60e5e56..81bb01c7e 100644 --- a/src/client/inputhandler.cpp +++ b/src/client/inputhandler.cpp @@ -31,8 +31,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "porting_ios.h" #endif -#if defined(__ANDROID__) || defined(__IOS__) -extern void external_pause_game(); +#if defined(__IOS__) +extern "C" void external_pause_game(); #endif void KeyCache::populate_nonchanging() @@ -118,7 +118,7 @@ bool MyEventReceiver::OnEvent(const SEvent &event) if (isMenuActive()) { #ifdef HAVE_TOUCHSCREENGUI if (m_touchscreengui) { - m_touchscreengui->Toggle(false); + m_touchscreengui->hide(); } #endif return g_menumgr.preprocessEvent(event); @@ -154,16 +154,9 @@ bool MyEventReceiver::OnEvent(const SEvent &event) #ifdef __IOS__ } else if (event.EventType == irr::EET_APPLICATION_EVENT) { int AppEvent = event.ApplicationEvent.EventType; - if (AppEvent == irr::EAET_DID_PAUSE) { + ioswrap_events(AppEvent); + if (AppEvent == irr::EAET_WILL_PAUSE) external_pause_game(); -#ifdef ADS - ads_set_paused(true); -#endif - } -#ifdef ADS - if (AppEvent == irr::EAET_DID_RESUME) - ads_set_paused(false); -#endif return true; #endif diff --git a/src/client/renderingengine.cpp b/src/client/renderingengine.cpp index 1e5074820..2f2fb704c 100644 --- a/src/client/renderingengine.cpp +++ b/src/client/renderingengine.cpp @@ -56,6 +56,10 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "filesys.h" #endif +#ifdef __ANDROID__ +#include "defaultsettings.h" +#endif + RenderingEngine *RenderingEngine::s_singleton = nullptr; @@ -85,16 +89,15 @@ RenderingEngine::RenderingEngine(IEventReceiver *receiver) { sanity_check(!s_singleton); -#ifdef __ANDROID__ - // Set correct resolution - g_settings->setU16("screen_w", porting::getDisplaySize().X); - g_settings->setU16("screen_h", porting::getDisplaySize().Y); -#endif - // Resolution selection bool fullscreen = g_settings->getBool("fullscreen"); +#if defined(__ANDROID__) || defined(__IOS__) + u16 screen_w = 0; + u16 screen_h = 0; + #else u16 screen_w = g_settings->getU16("screen_w"); u16 screen_h = g_settings->getU16("screen_h"); + #endif // bpp, fsaa, vsync bool vsync = g_settings->getBool("vsync"); @@ -155,13 +158,17 @@ RenderingEngine::RenderingEngine(IEventReceiver *receiver) m_device->getGUIEnvironment()->setSkin(skin); skin->drop(); -#ifdef __IOS__ - if (device) { - CIrrDeviceiOS* dev = (CIrrDeviceiOS*) device; - porting::setViewController(dev->getViewController()); -#ifdef ADS - ads_startup(dev->getViewController()); +#ifdef __ANDROID__ + // Apply settings according to screen size + // We can get real screen size only after device initialization finished + if (m_device) + set_default_settings(); #endif + +#ifdef __IOS__ + if (m_device) { + CIrrDeviceiOS* dev = (CIrrDeviceiOS*) m_device; + porting::setViewController(dev->getViewController()); } #endif } @@ -815,6 +822,9 @@ float RenderingEngine::getDisplayDensity() v2u32 RenderingEngine::getDisplaySize() { - return porting::getDisplaySize(); + const RenderingEngine *engine = RenderingEngine::get_instance(); + if (engine == nullptr) + return v2u32(0, 0); + return engine->getWindowSize(); } #endif // __ANDROID__/__IOS__ diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index 15a52eb3b..dc62d0bea 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -23,10 +23,13 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "filesys.h" #include "config.h" #include "constants.h" -#include "porting.h" #include "mapgen/mapgen.h" // Mapgen::setDefaultSettings #include "util/string.h" +#ifdef __ANDROID__ +#include "client/renderingengine.h" +#endif + #ifdef __APPLE__ #ifdef __IOS__ #import "SDVersion.h" @@ -37,7 +40,9 @@ with this program; if not, write to the Free Software Foundation, Inc., void set_default_settings() { - Settings *settings = Settings::createLayer(SL_DEFAULTS); + Settings *settings = Settings::getLayer(SL_DEFAULTS); + if (settings == nullptr) + settings = Settings::createLayer(SL_DEFAULTS); // Client and server settings->setDefault("language", ""); @@ -242,7 +247,7 @@ void set_default_settings() settings->setDefault("show_entity_selectionbox", "false"); settings->setDefault("texture_clean_transparent", "false"); settings->setDefault("texture_min_size", "0"); - settings->setDefault("ambient_occlusion_gamma", "1.8"); + settings->setDefault("ambient_occlusion_gamma", "2.2"); #if ENABLE_GLES settings->setDefault("enable_shaders", "false"); #else @@ -250,7 +255,7 @@ void set_default_settings() #endif settings->setDefault("enable_particles", "true"); settings->setDefault("arm_inertia", "false"); - settings->setDefault("show_nametag_backgrounds", "true"); + settings->setDefault("show_nametag_backgrounds", "false"); settings->setDefault("enable_minimap", "true"); settings->setDefault("minimap_shape_round", "true"); @@ -398,7 +403,7 @@ void set_default_settings() settings->setDefault("kick_msg_crash", "This server has experienced an internal error. You will now be disconnected."); settings->setDefault("ask_reconnect_on_crash", "false"); - settings->setDefault("chat_message_format", "<@name> @message"); + settings->setDefault("chat_message_format", "@name: @message"); settings->setDefault("profiler_print_interval", "0"); settings->setDefault("active_object_send_range_blocks", "8"); settings->setDefault("active_block_range", "4"); @@ -485,7 +490,6 @@ void set_default_settings() // Altered settings for macOS #if defined(__MACH__) && defined(__APPLE__) && !defined(__IOS__) settings->setDefault("keymap_sneak", "KEY_SHIFT"); - settings->setDefault("keymap_toggle_debug", "KEY_KEY_V"); settings->setDefault("keymap_camera_mode", "KEY_KEY_C"); settings->setDefault("vsync", "true"); @@ -502,8 +506,6 @@ void set_default_settings() // Mobile Platform #if defined(__ANDROID__) || defined(__IOS__) - settings->setDefault("screen_w", "0"); - settings->setDefault("screen_h", "0"); settings->setDefault("fullscreen", "true"); settings->setDefault("touchtarget", "true"); settings->setDefault("TMPFolder", porting::path_cache); @@ -531,10 +533,8 @@ void set_default_settings() if (memoryMax < 2) { // minimal settings for less than 2GB RAM #elif __IOS__ - if (iOS_ver < 11.0) { - // minimal settings for legacy 32-bit devices - settings->setDefault("enable_minimap", "false"); - settings->setDefault("enable_clouds", "false"); + if (false) { + // obsolete #endif settings->setDefault("client_unload_unused_data_timeout", "60"); settings->setDefault("client_mapblock_limit", "50"); @@ -593,10 +593,7 @@ void set_default_settings() settings->setDefault("viewing_range", "80"); settings->setDefault("max_block_generate_distance", "5"); -#ifdef __ANDROID__ - settings->setDefault("video_driver", "ogles2"); - settings->setDefault("enable_shaders", "true"); -#elif __IOS__ +#ifdef __IOS__ if (@available(iOS 13, *)) { #endif // enable visual shader effects @@ -608,44 +605,50 @@ void set_default_settings() #endif } + std::string font_small = std::to_string(TTF_DEFAULT_FONT_SIZE - 1); + // Android Settings #ifdef __ANDROID__ - settings->setDefault("video_driver", "ogles1"); - settings->setDefault("enable_shaders", "false"); + // Switch to olges2 with shaders on powerful Android devices + if (memoryMax >= 6) { + settings->setDefault("video_driver", "ogles2"); + settings->setDefault("enable_shaders", "true"); + } else { + settings->setDefault("video_driver", "ogles1"); + settings->setDefault("enable_shaders", "false"); + } settings->setDefault("debug_log_level", "error"); - // Apply settings according to screen size - float x_inches = (float) porting::getDisplaySize().X / - (160.f * porting::getDisplayDensity()); - - std::string font_size_str_small = std::to_string(TTF_DEFAULT_FONT_SIZE - 1); - - if (x_inches <= 3.7) { - // small 4" phones - settings->setDefault("hud_scaling", "0.55"); - settings->setDefault("font_size", font_size_str_small); - settings->setDefault("mouse_sensitivity", "0.3"); - } else if (x_inches > 3.7 && x_inches <= 4.5) { - // medium phones - settings->setDefault("hud_scaling", "0.6"); - settings->setDefault("font_size", font_size_str_small); - settings->setDefault("selectionbox_width", "6"); - } else if (x_inches > 4.5 && x_inches <= 5.5) { - // large 6" phones - settings->setDefault("hud_scaling", "0.7"); - settings->setDefault("mouse_sensitivity", "0.15"); - settings->setDefault("selectionbox_width", "6"); - } else if (x_inches > 5.5 && x_inches <= 6.5) { - // 7" tablets - settings->setDefault("hud_scaling", "0.9"); - settings->setDefault("selectionbox_width", "6"); + v2u32 window_size = RenderingEngine::getDisplaySize(); + if (window_size.X > 0) { + float x_inches = window_size.X / (160.f * porting::getDisplayDensity()); + if (x_inches <= 3.7) { + // small 4" phones + g_settings->setDefault("hud_scaling", "0.55"); + g_settings->setDefault("font_size", font_small); + g_settings->setDefault("mouse_sensitivity", "0.3"); + } else if (x_inches > 3.7 && x_inches <= 4.5) { + // medium phones + g_settings->setDefault("hud_scaling", "0.6"); + g_settings->setDefault("font_size", font_small); + g_settings->setDefault("selectionbox_width", "6"); + } else if (x_inches > 4.5 && x_inches <= 5.5) { + // large 6" phones + g_settings->setDefault("hud_scaling", "0.7"); + g_settings->setDefault("mouse_sensitivity", "0.15"); + g_settings->setDefault("selectionbox_width", "6"); + } else if (x_inches > 5.5 && x_inches <= 6.5) { + // 7" tablets + g_settings->setDefault("hud_scaling", "0.9"); + g_settings->setDefault("selectionbox_width", "6"); + } } #endif // Android // iOS Settings #ifdef __IOS__ - // Switch to olges2 with shaders on the new iOS version + // Switch to olges2 with shaders in new iOS versions if (@available(iOS 13, *)) { settings->setDefault("video_driver", "ogles2"); settings->setDefault("enable_shaders", "true"); @@ -662,14 +665,17 @@ void set_default_settings() // 4" iPhone and iPod Touch settings->setDefault("hud_scaling", "0.55"); settings->setDefault("mouse_sensitivity", "0.33"); + settings->setDefault("font_size", font_small); } else if SDVersion4and7Inch { // 4.7" iPhone - settings->setDefault("hud_scaling", "0.65"); + settings->setDefault("hud_scaling", "0.6"); settings->setDefault("mouse_sensitivity", "0.27"); + settings->setDefault("font_size", font_small); } else if SDVersion5and5Inch { // 5.5" iPhone Plus - settings->setDefault("hud_scaling", "0.7"); + settings->setDefault("hud_scaling", "0.65"); settings->setDefault("mouse_sensitivity", "0.3"); + settings->setDefault("font_size", font_small); } else if (SDVersion5and8Inch || SDVersion6and1Inch || SDVersion6and5Inch) { // 5.8+" iPhones settings->setDefault("hud_scaling", "0.85"); @@ -687,18 +693,14 @@ void set_default_settings() } // Settings for the Rounded Screen and Home Bar - if (@available(iOS 11, *)) { - UIWindow *window = UIApplication.sharedApplication.windows.firstObject; - int bottomPadding = (int) window.safeAreaInsets.bottom; + UIWindow *window = UIApplication.sharedApplication.windows.firstObject; - if (bottomPadding > 0) { - settings->setDefault("hud_move_upwards", "20"); - if (SDVersioniPhone12Series) - settings->setDefault("round_screen", "75"); - else - settings->setDefault("round_screen", "35"); - } - } + if (window.safeAreaInsets.bottom > 0) { + settings->setDefault("hud_move_upwards", "20"); + if (SDVersioniPhone12Series) + settings->setDefault("round_screen", "75"); + else + settings->setDefault("round_screen", "35"); #endif // iOS #endif } diff --git a/src/gui/guiSkin.cpp b/src/gui/guiSkin.cpp index e09209bd9..8892a00b4 100644 --- a/src/gui/guiSkin.cpp +++ b/src/gui/guiSkin.cpp @@ -29,7 +29,7 @@ GUISkin::GUISkin(EGUI_SKIN_TYPE type, video::IVideoDriver* driver) { Colors[EGDC_3D_DARK_SHADOW] = video::SColor(101,50,50,50); Colors[EGDC_3D_SHADOW] = video::SColor(101,130,130,130); - Colors[EGDC_3D_FACE] = video::SColor(220,100,100,100); + Colors[EGDC_3D_FACE] = video::SColor(101,210,210,210); Colors[EGDC_3D_HIGH_LIGHT] = video::SColor(101,255,255,255); Colors[EGDC_3D_LIGHT] = video::SColor(101,210,210,210); Colors[EGDC_ACTIVE_BORDER] = video::SColor(101,16,14,115); diff --git a/src/gui/touchscreengui.cpp b/src/gui/touchscreengui.cpp index edbda8df1..316b592b2 100644 --- a/src/gui/touchscreengui.cpp +++ b/src/gui/touchscreengui.cpp @@ -1249,7 +1249,7 @@ void TouchScreenGUI::Toggle(bool visible) button.guibutton->setVisible(visible); } - if (m_joystick_btn_off->guibutton) + if (m_joystick_btn_off != nullptr && m_joystick_btn_off->guibutton) m_joystick_btn_off->guibutton->setVisible(visible); // clear all active buttons diff --git a/src/porting_android.cpp b/src/porting_android.cpp index b646855b4..fba251e6b 100644 --- a/src/porting_android.cpp +++ b/src/porting_android.cpp @@ -38,7 +38,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #endif extern int main(int argc, char *argv[]); -extern void external_pause_game(); +extern "C" void external_pause_game(); void android_main(android_app *app) { @@ -310,7 +310,7 @@ void notifyExitGame() "notifyExitGame", "()V"); FATAL_ERROR_IF(notifyExit == nullptr, - "porting::notifyExit unable to find java getDensity method"); + "porting::notifyExit unable to find java notifyExit method"); jnienv->CallVoidMethod(app_global->activity->clazz, notifyExit); } @@ -333,34 +333,5 @@ float getDisplayDensity() } return value; } - -v2u32 getDisplaySize() -{ - static bool firstrun = true; - static v2u32 retval; - - if (firstrun) { - jmethodID getDisplayWidth = jnienv->GetMethodID(nativeActivity, - "getDisplayWidth", "()I"); - - FATAL_ERROR_IF(getDisplayWidth == nullptr, - "porting::getDisplayWidth unable to find java getDisplayWidth method"); - - retval.X = jnienv->CallIntMethod(app_global->activity->clazz, - getDisplayWidth); - - jmethodID getDisplayHeight = jnienv->GetMethodID(nativeActivity, - "getDisplayHeight", "()I"); - - FATAL_ERROR_IF(getDisplayHeight == nullptr, - "porting::getDisplayHeight unable to find java getDisplayHeight method"); - - retval.Y = jnienv->CallIntMethod(app_global->activity->clazz, - getDisplayHeight); - - firstrun = false; - } - return retval; -} #endif // ndef SERVER } diff --git a/src/porting_android.h b/src/porting_android.h index 34428271b..bcea5cd8d 100644 --- a/src/porting_android.h +++ b/src/porting_android.h @@ -90,6 +90,5 @@ std::string getInputDialogValue(); #ifndef SERVER float getDisplayDensity(); -v2u32 getDisplaySize(); #endif } diff --git a/src/serverlist.cpp b/src/serverlist.cpp index acf166be3..726b561e0 100644 --- a/src/serverlist.cpp +++ b/src/serverlist.cpp @@ -81,10 +81,10 @@ void sendAnnounce(AnnounceAction action, server["mapgen"] = mg_name; server["privs"] = g_settings->get("default_privs"); server["can_see_far_names"] = g_settings->getS16("player_transfer_distance") <= 0; - server["mods"] = Json::Value(Json::arrayValue); + /*server["mods"] = Json::Value(Json::arrayValue); for (const ModSpec &mod : mods) { server["mods"].append(mod.name); - } + }*/ } else if (action == AA_UPDATE) { if (lag) server["lag"] = lag; diff --git a/textures/base/pack/bg.png b/textures/base/pack/bg.png index 55afbb6f4e16ee5f4d9c8b9483a909457b9c3c3d..209d3019c6f4672badbdbff5b76f4a16db27dbd7 100644 GIT binary patch delta 1339 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 Q(EtDd07*qoM6N<$g3nJ^$^ZZW