From 2e567b7d40ef99e48fb6acc5adef42c986720943 Mon Sep 17 00:00:00 2001 From: Gregor Parzefall Date: Mon, 19 Aug 2024 16:00:24 +0200 Subject: [PATCH 01/67] Replace removed rare_controls.png in Devtest /test_formspec removed by 013c6ee1663f2bdd93a6d30690a96a5914dc27dc / #14918 --- games/devtest/mods/testformspec/formspec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/games/devtest/mods/testformspec/formspec.lua b/games/devtest/mods/testformspec/formspec.lua index 99ee691f1..8d0b759f5 100644 --- a/games/devtest/mods/testformspec/formspec.lua +++ b/games/devtest/mods/testformspec/formspec.lua @@ -66,7 +66,7 @@ local inv_style_fs = [[ -- Some textures from textures/base/pack and Devtest, with many different sizes -- and aspect ratios. -local image_column = "image,0=logo.png,1=rare_controls.png,2=checkbox_16.png," .. +local image_column = "image,0=logo.png,1=crack_anylength.png^[invert:rgb,2=checkbox_16.png," .. "3=checkbox_32.png,4=checkbox_64.png,5=default_lava.png," .. "6=progress_bar.png,7=progress_bar_bg.png" local words = { From 88397c2908ce2ab53adf107f0653600def2296b5 Mon Sep 17 00:00:00 2001 From: Gregor Parzefall Date: Mon, 19 Aug 2024 16:06:26 +0200 Subject: [PATCH 02/67] TouchScreenGUI: Don't release pointers when toggling grid menu --- src/gui/touchcontrols.cpp | 38 ++++++++++++-------------------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/src/gui/touchcontrols.cpp b/src/gui/touchcontrols.cpp index 1e4f8a99b..7d7cd6e09 100644 --- a/src/gui/touchcontrols.cpp +++ b/src/gui/touchcontrols.cpp @@ -477,16 +477,13 @@ void TouchControls::handleReleaseEvent(size_t pointer_id) m_pointer_downpos.erase(pointer_id); m_pointer_pos.erase(pointer_id); - if (m_overflow_open) { - buttons_handleRelease(m_overflow_buttons, pointer_id, m_device->getVideoDriver(), - m_receiver, m_texturesource); - return; - } - // handle buttons if (buttons_handleRelease(m_buttons, pointer_id, m_device->getVideoDriver(), m_receiver, m_texturesource)) return; + if (buttons_handleRelease(m_overflow_buttons, pointer_id, m_device->getVideoDriver(), + m_receiver, m_texturesource)) + return; if (m_has_move_id && pointer_id == m_move_id) { // handle the point used for moving view @@ -513,9 +510,7 @@ void TouchControls::handleReleaseEvent(size_t pointer_id) m_joystick_status_aux1 = false; applyJoystickStatus(); - m_joystick_btn_off->setVisible(true); - m_joystick_btn_bg->setVisible(false); - m_joystick_btn_center->setVisible(false); + updateVisibility(); } else { infostream << "TouchControls::translateEvent released unknown button: " << pointer_id << std::endl; @@ -572,9 +567,6 @@ void TouchControls::translateEvent(const SEvent &event) toggleOverflowMenu(); // refresh since visibility of buttons has changed element = m_guienv->getRootGUIElement()->getElementFromPoint(touch_pos); - // restore after releaseAll in toggleOverflowMenu - m_pointer_downpos[pointer_id] = touch_pos; - m_pointer_pos[pointer_id] = touch_pos; // continue processing, but avoid accidentally placing a node // when closing the overflow menu prevent_short_tap = true; @@ -600,9 +592,7 @@ void TouchControls::translateEvent(const SEvent &event) m_joystick_id = pointer_id; m_joystick_has_really_moved = false; - m_joystick_btn_off->setVisible(false); - m_joystick_btn_bg->setVisible(true); - m_joystick_btn_center->setVisible(true); + updateVisibility(); // If it's a fixed joystick, don't move the joystick "button". if (!m_fixed_joystick) @@ -633,9 +623,6 @@ void TouchControls::translateEvent(const SEvent &event) } else { assert(event.TouchInput.Event == ETIE_MOVED); - if (m_overflow_open) - return; - if (!(m_has_joystick_id && m_fixed_joystick) && m_pointer_pos[event.TouchInput.ID] == touch_pos) return; @@ -721,13 +708,9 @@ void TouchControls::applyJoystickStatus() void TouchControls::step(float dtime) { - if (m_overflow_open) { - buttons_step(m_overflow_buttons, dtime, m_device->getVideoDriver(), m_receiver, m_texturesource); - return; - } - // simulate keyboard repeats buttons_step(m_buttons, dtime, m_device->getVideoDriver(), m_receiver, m_texturesource); + buttons_step(m_overflow_buttons, dtime, m_device->getVideoDriver(), m_receiver, m_texturesource); // joystick applyJoystickStatus(); @@ -774,7 +757,6 @@ void TouchControls::setVisible(bool visible) return; m_visible = visible; - // order matters if (!visible) { releaseAll(); m_overflow_open = false; @@ -784,7 +766,8 @@ void TouchControls::setVisible(bool visible) void TouchControls::toggleOverflowMenu() { - releaseAll(); // must be done first + // no releaseAll here so that you can e.g. continue holding the joystick + // while the overflow menu is open m_overflow_open = !m_overflow_open; updateVisibility(); } @@ -795,7 +778,10 @@ void TouchControls::updateVisibility() for (auto &button : m_buttons) button.gui_button->setVisible(regular_visible); m_overflow_btn->setVisible(regular_visible); - m_joystick_btn_off->setVisible(regular_visible); + + m_joystick_btn_off->setVisible(regular_visible && !m_has_joystick_id); + m_joystick_btn_bg->setVisible(regular_visible && m_has_joystick_id); + m_joystick_btn_center->setVisible(regular_visible && m_has_joystick_id); bool overflow_visible = m_visible && m_overflow_open; m_overflow_bg->setVisible(overflow_visible); From 08de047033da30255faf6685059c96a1c31d8bb1 Mon Sep 17 00:00:00 2001 From: Gregor Parzefall Date: Wed, 21 Aug 2024 13:04:51 +0200 Subject: [PATCH 03/67] TouchScreenGUI: Show status text above grid menu --- src/client/gameui.cpp | 28 ++++++++++++++++++++-------- src/gui/touchcontrols.cpp | 4 ++++ src/gui/touchcontrols.h | 5 +++++ 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/client/gameui.cpp b/src/client/gameui.cpp index 7631f9c78..41071ef66 100644 --- a/src/client/gameui.cpp +++ b/src/client/gameui.cpp @@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "gui/mainmenumanager.h" #include "gui/guiChatConsole.h" #include "gui/guiFormSpecMenu.h" +#include "gui/touchcontrols.h" #include "util/enriched_string.h" #include "util/pointedthing.h" #include "client.h" @@ -191,16 +192,27 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_ } } - setStaticText(m_guitext_status, m_statustext.c_str()); - m_guitext_status->setVisible(!m_statustext.empty()); + IGUIStaticText *guitext_status; + bool overriden = g_touchcontrols && g_touchcontrols->isStatusTextOverriden(); + if (overriden) { + guitext_status = g_touchcontrols->getStatusText(); + m_guitext_status->setVisible(false); + } else { + guitext_status = m_guitext_status; + if (g_touchcontrols) + g_touchcontrols->getStatusText()->setVisible(false); + } + + setStaticText(guitext_status, m_statustext.c_str()); + guitext_status->setVisible(!m_statustext.empty()); if (!m_statustext.empty()) { - s32 status_width = m_guitext_status->getTextWidth(); - s32 status_height = m_guitext_status->getTextHeight(); - s32 status_y = screensize.Y - 150; + s32 status_width = guitext_status->getTextWidth(); + s32 status_height = guitext_status->getTextHeight(); + s32 status_y = screensize.Y - (overriden ? 15 : 150); s32 status_x = (screensize.X - status_width) / 2; - m_guitext_status->setRelativePosition(core::rect(status_x , + guitext_status->setRelativePosition(core::rect(status_x , status_y - status_height, status_x + status_width, status_y)); // Fade out @@ -208,8 +220,8 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_ final_color.setAlpha(0); video::SColor fade_color = m_statustext_initial_color.getInterpolated_quadratic( m_statustext_initial_color, final_color, m_statustext_time / statustext_time_max); - m_guitext_status->setOverrideColor(fade_color); - m_guitext_status->enableOverrideColor(true); + guitext_status->setOverrideColor(fade_color); + guitext_status->enableOverrideColor(true); } // Hide chat when disabled by server or when console is visible diff --git a/src/gui/touchcontrols.cpp b/src/gui/touchcontrols.cpp index 7d7cd6e09..4a673ccf3 100644 --- a/src/gui/touchcontrols.cpp +++ b/src/gui/touchcontrols.cpp @@ -412,6 +412,10 @@ TouchControls::TouchControls(IrrlichtDevice *device, ISimpleTextureSource *tsrc) pos.X += spacing.X; } + + m_status_text = grab_gui_element( + m_guienv->addStaticText(L"", recti(), false, false)); + m_status_text->setVisible(false); } void TouchControls::addButton(std::vector &buttons, touch_gui_button_id id, diff --git a/src/gui/touchcontrols.h b/src/gui/touchcontrols.h index 0a86fe34e..102c85f09 100644 --- a/src/gui/touchcontrols.h +++ b/src/gui/touchcontrols.h @@ -177,6 +177,9 @@ public: void registerHotbarRect(u16 index, const recti &rect); std::optional getHotbarSelection(); + bool isStatusTextOverriden() { return m_overflow_open; } + IGUIStaticText *getStatusText() { return m_status_text.get(); } + private: IrrlichtDevice *m_device = nullptr; IGUIEnvironment *m_guienv = nullptr; @@ -235,6 +238,8 @@ private: std::vector> m_overflow_button_titles; std::vector m_overflow_button_rects; + std::shared_ptr m_status_text; + void toggleOverflowMenu(); void updateVisibility(); void releaseAll(); From 83498463336b56a7ad5440060f7daa7723e04246 Mon Sep 17 00:00:00 2001 From: grorp Date: Wed, 4 Sep 2024 15:18:45 +0200 Subject: [PATCH 04/67] TouchControls: Fix setUseCrosshair not being called (#15100) --- src/client/game.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/client/game.cpp b/src/client/game.cpp index 0a9b4ec58..7213faafa 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -1510,10 +1510,6 @@ bool Game::createClient(const GameStartData &start_data) client->getScript()->on_camera_ready(camera); client->setCamera(camera); - if (g_touchcontrols) { - g_touchcontrols->setUseCrosshair(!isTouchCrosshairDisabled()); - } - /* Clouds */ if (m_cache_enable_clouds) @@ -1578,8 +1574,10 @@ bool Game::initGui() gui_chat_console = new GUIChatConsole(guienv, guienv->getRootGUIElement(), -1, chat_backend, client, &g_menumgr); - if (g_settings->getBool("touch_controls")) + if (g_settings->getBool("touch_controls")) { g_touchcontrols = new TouchControls(device, texture_src); + g_touchcontrols->setUseCrosshair(!isTouchCrosshairDisabled()); + } return true; } From 074700b35eab0d0a3fe57e959889b92aa97ae157 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20M=C3=BCller?= <34514239+appgurueu@users.noreply.github.com> Date: Wed, 4 Sep 2024 15:19:00 +0200 Subject: [PATCH 05/67] Remove no* prefixes from settingtypes possible flags (#15111) --- builtin/settingtypes.txt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt index d03634506..54a639a89 100644 --- a/builtin/settingtypes.txt +++ b/builtin/settingtypes.txt @@ -1027,7 +1027,7 @@ mapgen_limit (Map generation limit) int 31007 0 31007 # Global map generation attributes. # In Mapgen v6 the 'decorations' flag controls all decorations except trees # and jungle grass, in all other mapgens this flag controls all decorations. -mg_flags (Mapgen flags) flags caves,dungeons,light,decorations,biomes,ores caves,dungeons,light,decorations,biomes,ores,nocaves,nodungeons,nolight,nodecorations,nobiomes,noores +mg_flags (Mapgen flags) flags caves,dungeons,light,decorations,biomes,ores caves,dungeons,light,decorations,biomes,ores [*Biome API] @@ -1046,7 +1046,7 @@ mg_biome_np_humidity_blend (Humidity blend noise) noise_params_2d 0, 1.5, (8, 8, [*Mapgen V5] # Map generation attributes specific to Mapgen v5. -mgv5_spflags (Mapgen V5 specific flags) flags caverns caverns,nocaverns +mgv5_spflags (Mapgen V5 specific flags) flags caverns caverns # Controls width of tunnels, a smaller value creates wider tunnels. # Value >= 10.0 completely disables generation of tunnels and avoids the @@ -1120,7 +1120,7 @@ mgv5_np_dungeons (Dungeon noise) noise_params_3d 0.9, 0.5, (500, 500, 500), 0, 2 # When the 'snowbiomes' flag is enabled jungles are automatically enabled and # the 'jungles' flag is ignored. # The 'temples' flag disables generation of desert temples. Normal dungeons will appear instead. -mgv6_spflags (Mapgen V6 specific flags) flags jungles,biomeblend,mudflow,snowbiomes,noflat,trees,temples jungles,biomeblend,mudflow,snowbiomes,flat,trees,temples,nojungles,nobiomeblend,nomudflow,nosnowbiomes,noflat,notrees,notemples +mgv6_spflags (Mapgen V6 specific flags) flags jungles,biomeblend,mudflow,snowbiomes,noflat,trees,temples jungles,biomeblend,mudflow,snowbiomes,flat,trees,temples # Deserts occur when np_biome exceeds this value. # When the 'snowbiomes' flag is enabled, this is ignored. @@ -1176,7 +1176,7 @@ mgv6_np_apple_trees (Apple trees noise) noise_params_2d 0, 1, (100, 100, 100), 3 # 'ridges': Rivers. # 'floatlands': Floating land masses in the atmosphere. # 'caverns': Giant caves deep underground. -mgv7_spflags (Mapgen V7 specific flags) flags mountains,ridges,nofloatlands,caverns mountains,ridges,floatlands,caverns,nomountains,noridges,nofloatlands,nocaverns +mgv7_spflags (Mapgen V7 specific flags) flags mountains,ridges,nofloatlands,caverns mountains,ridges,floatlands,caverns # Y of mountain density gradient zero level. Used to shift mountains vertically. mgv7_mount_zero_level (Mountain zero level) int 0 -31000 31000 @@ -1310,7 +1310,7 @@ mgv7_np_dungeons (Dungeon noise) noise_params_3d 0.9, 0.5, (500, 500, 500), 0, 2 [*Mapgen Carpathian] # Map generation attributes specific to Mapgen Carpathian. -mgcarpathian_spflags (Mapgen Carpathian specific flags) flags caverns,norivers caverns,rivers,nocaverns,norivers +mgcarpathian_spflags (Mapgen Carpathian specific flags) flags caverns,norivers caverns,rivers # Defines the base ground level. mgcarpathian_base_level (Base ground level) float 12.0 @@ -1419,7 +1419,7 @@ mgcarpathian_np_dungeons (Dungeon noise) noise_params_3d 0.9, 0.5, (500, 500, 50 # Map generation attributes specific to Mapgen Flat. # Occasional lakes and hills can be added to the flat world. -mgflat_spflags (Mapgen Flat specific flags) flags nolakes,nohills,nocaverns lakes,hills,caverns,nolakes,nohills,nocaverns +mgflat_spflags (Mapgen Flat specific flags) flags nolakes,nohills,nocaverns lakes,hills,caverns # Y of flat ground. mgflat_ground_level (Ground level) int 8 -31000 31000 @@ -1503,7 +1503,7 @@ mgflat_np_dungeons (Dungeon noise) noise_params_3d 0.9, 0.5, (500, 500, 500), 0, # Map generation attributes specific to Mapgen Fractal. # 'terrain' enables the generation of non-fractal terrain: # ocean, islands and underground. -mgfractal_spflags (Mapgen Fractal specific flags) flags terrain terrain,noterrain +mgfractal_spflags (Mapgen Fractal specific flags) flags terrain terrain # Controls width of tunnels, a smaller value creates wider tunnels. # Value >= 10.0 completely disables generation of tunnels and avoids the @@ -1637,7 +1637,7 @@ mgfractal_np_dungeons (Dungeon noise) noise_params_3d 0.9, 0.5, (500, 500, 500), # 'vary_river_depth': If enabled, low humidity and high heat causes rivers # to become shallower and occasionally dry. # 'altitude_dry': Reduces humidity with altitude. -mgvalleys_spflags (Mapgen Valleys specific flags) flags altitude_chill,humid_rivers,vary_river_depth,altitude_dry altitude_chill,humid_rivers,vary_river_depth,altitude_dry,noaltitude_chill,nohumid_rivers,novary_river_depth,noaltitude_dry +mgvalleys_spflags (Mapgen Valleys specific flags) flags altitude_chill,humid_rivers,vary_river_depth,altitude_dry altitude_chill,humid_rivers,vary_river_depth,altitude_dry # The vertical distance over which heat drops by 20 if 'altitude_chill' is # enabled. Also, the vertical distance over which humidity drops by 10 if From 486dc3288d7b8e8c55bbc20dea11fef32fd7119b Mon Sep 17 00:00:00 2001 From: red-001 Date: Wed, 4 Sep 2024 14:20:39 +0100 Subject: [PATCH 06/67] VoxelManipulator code cleanup (#15114) * Cache node in voxel area index when possible The index function according to the MSVC profiler actually takes up a significant time slice (around ~5% of total time for the process) during normal game-play. Might not be accurate but still good to not recalculate it twice. * Remove `setNodeNoRef` from VM * VM: remove old commented out print statement --- src/unittest/test_voxelmanipulator.cpp | 2 +- src/voxel.h | 33 ++++++++++++-------------- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/src/unittest/test_voxelmanipulator.cpp b/src/unittest/test_voxelmanipulator.cpp index acc2707e7..6ea0ca9af 100644 --- a/src/unittest/test_voxelmanipulator.cpp +++ b/src/unittest/test_voxelmanipulator.cpp @@ -87,7 +87,7 @@ void TestVoxelManipulator::testVoxelManipulator(const NodeDefManager *nodedef) v.print(infostream, nodedef); infostream << "*** Setting (-1,0,-1)=2 ***" << std::endl; - v.setNodeNoRef(v3s16(-1,0,-1), MapNode(t_CONTENT_GRASS)); + v.setNode(v3s16(-1,0,-1), MapNode(t_CONTENT_GRASS)); v.print(infostream, nodedef); UASSERT(v.getNode(v3s16(-1,0,-1)).getContent() == t_CONTENT_GRASS); diff --git a/src/voxel.h b/src/voxel.h index 286e09abe..882a59b77 100644 --- a/src/voxel.h +++ b/src/voxel.h @@ -392,36 +392,36 @@ public: VoxelArea voxel_area(p); addArea(voxel_area); - if (m_flags[m_area.index(p)] & VOXELFLAG_NO_DATA) { - /*dstream<<"EXCEPT: VoxelManipulator::getNode(): " - <<"p=("< Date: Fri, 6 Sep 2024 11:30:10 +0200 Subject: [PATCH 07/67] Refactor "Cavegen y biome check" --- src/mapgen/cavegen.cpp | 16 +++++----------- src/mapgen/mapgen.cpp | 15 ++------------- src/mapgen/mg_biome.cpp | 35 ++++++++++++----------------------- src/mapgen/mg_biome.h | 14 ++++++++++---- 4 files changed, 29 insertions(+), 51 deletions(-) diff --git a/src/mapgen/cavegen.cpp b/src/mapgen/cavegen.cpp index 47272142f..e6ab66980 100644 --- a/src/mapgen/cavegen.cpp +++ b/src/mapgen/cavegen.cpp @@ -82,8 +82,6 @@ void CavesNoiseIntersection::generateCaves(MMVManip *vm, const v3s16 &em = vm->m_area.getExtent(); u32 index2d = 0; // Biomemap index - s16 *biome_transitions = m_bmgn->getBiomeTransitions(); - for (s16 z = nmin.Z; z <= nmax.Z; z++) for (s16 x = nmin.X; x <= nmax.X; x++, index2d++) { bool column_is_open = false; // Is column open to overground @@ -101,8 +99,7 @@ void CavesNoiseIntersection::generateCaves(MMVManip *vm, u16 depth_riverbed = biome->depth_riverbed; u16 nplaced = 0; - int cur_biome_depth = 0; - s16 biome_y_min = biome_transitions[cur_biome_depth]; + s16 biome_y_min = m_bmgn->getNextTransitionY(nmax.Y); // Don't excavate the overgenerated stone at nmax.Y + 1, // this creates a 'roof' over the tunnel, preventing light in @@ -114,15 +111,12 @@ void CavesNoiseIntersection::generateCaves(MMVManip *vm, // We need this check to make sure that biomes don't generate too far down if (y < biome_y_min) { biome = m_bmgn->getBiomeAtIndex(index2d, v3s16(x, y, z)); + biome_y_min = m_bmgn->getNextTransitionY(y); - // Finding the height of the next biome - // On first iteration this may loop a couple times after than it should just run once - while (y < biome_y_min) { - biome_y_min = biome_transitions[++cur_biome_depth]; + if (x == nmin.X && z == nmin.Z && false) { + dstream << "cavegen: biome at " << y << " is " << biome->name + << ", next at " << biome_y_min << std::endl; } - - /*if (x == nmin.X && z == nmin.Z) - printf("Cave: check @ %i -> %s -> again at %i\n", y, biome->name.c_str(), biome_y_min);*/ } content_t c = vm->m_data[vi].getContent(); diff --git a/src/mapgen/mapgen.cpp b/src/mapgen/mapgen.cpp index 80ffebc9e..0b821e02e 100644 --- a/src/mapgen/mapgen.cpp +++ b/src/mapgen/mapgen.cpp @@ -649,8 +649,6 @@ void MapgenBasic::generateBiomes() noise_filler_depth->perlinMap2D(node_min.X, node_min.Z); - s16 *biome_transitions = biomegen->getBiomeTransitions(); - for (s16 z = node_min.Z; z <= node_max.Z; z++) for (s16 x = node_min.X; x <= node_max.X; x++, index++) { Biome *biome = NULL; @@ -661,8 +659,7 @@ void MapgenBasic::generateBiomes() u16 depth_riverbed = 0; u32 vi = vm->m_area.index(x, node_max.Y, z); - int cur_biome_depth = 0; - s16 biome_y_min = biome_transitions[cur_biome_depth]; + s16 biome_y_min = biomegen->getNextTransitionY(node_max.Y); // Check node at base of mapchunk above, either a node of a previously // generated mapchunk or if not, a node of overgenerated base terrain. @@ -695,15 +692,7 @@ void MapgenBasic::generateBiomes() if (!biome || y < biome_y_min) { // (Re)calculate biome biome = biomegen->getBiomeAtIndex(index, v3s16(x, y, z)); - - // Finding the height of the next biome - // On first iteration this may loop a couple times after than it should just run once - while (y < biome_y_min) { - biome_y_min = biome_transitions[++cur_biome_depth]; - } - - /*if (x == node_min.X && z == node_min.Z) - printf("Map: check @ %i -> %s -> again at %i\n", y, biome->name.c_str(), biome_y_min);*/ + biome_y_min = biomegen->getNextTransitionY(y); } // Add biome to biomemap at first stone surface detected diff --git a/src/mapgen/mg_biome.cpp b/src/mapgen/mg_biome.cpp index 83ecbd691..b270a5413 100644 --- a/src/mapgen/mg_biome.cpp +++ b/src/mapgen/mg_biome.cpp @@ -149,47 +149,36 @@ BiomeGenOriginal::BiomeGenOriginal(BiomeManager *biomemgr, // is disabled. memset(biomemap, 0, sizeof(biome_t) * m_csize.X * m_csize.Z); - // Calculating the bounding position of each biome so we know when we might switch - // First gathering all heights where we might switch - std::vector temp_transition_heights; - temp_transition_heights.reserve(m_bmgr->getNumObjects() * 2); + // Calculate cache of Y transition points + std::vector values; + values.reserve(m_bmgr->getNumObjects() * 2); for (size_t i = 0; i < m_bmgr->getNumObjects(); i++) { Biome *b = (Biome *)m_bmgr->getRaw(i); - temp_transition_heights.push_back(b->max_pos.Y); - temp_transition_heights.push_back(b->min_pos.Y); + values.push_back(b->max_pos.Y); + values.push_back(b->min_pos.Y); } - // Sorting the biome transition points - std::sort(temp_transition_heights.begin(), temp_transition_heights.end(), std::greater()); + std::sort(values.begin(), values.end(), std::greater<>()); + values.erase(std::unique(values.begin(), values.end()), values.end()); - // Getting rid of duplicate biome transition points - s16 last = temp_transition_heights[0]; - size_t out_pos = 1; - for (size_t i = 1; i < temp_transition_heights.size(); i++){ - if (temp_transition_heights[i] != last) { - last = temp_transition_heights[i]; - temp_transition_heights[out_pos++] = last; - } - } - - biome_transitions = new s16[out_pos]; - memcpy(biome_transitions, temp_transition_heights.data(), sizeof(s16) * out_pos); + m_transitions_y = std::move(values); } BiomeGenOriginal::~BiomeGenOriginal() { delete []biomemap; - delete []biome_transitions; delete noise_heat; delete noise_humidity; delete noise_heat_blend; delete noise_humidity_blend; } -s16* BiomeGenOriginal::getBiomeTransitions() const +s16 BiomeGenOriginal::getNextTransitionY(s16 y) const { - return biome_transitions; + // Find first value that is less than y using binary search + auto it = std::lower_bound(m_transitions_y.begin(), m_transitions_y.end(), y, std::greater_equal<>()); + return (it == m_transitions_y.end()) ? S16_MIN : *it; } BiomeGen *BiomeGenOriginal::clone(BiomeManager *biomemgr) const diff --git a/src/mapgen/mg_biome.h b/src/mapgen/mg_biome.h index 567a0fe81..389b36ee9 100644 --- a/src/mapgen/mg_biome.h +++ b/src/mapgen/mg_biome.h @@ -128,11 +128,14 @@ public: // Same as above, but uses a raw numeric index correlating to the (x,z) position. virtual Biome *getBiomeAtIndex(size_t index, v3s16 pos) const = 0; - virtual s16 *getBiomeTransitions() const = 0; + // Returns the next lower y position at which the biome could change. + // You can use this to optimize calls to getBiomeAtIndex(). + virtual s16 getNextTransitionY(s16 y) const { + return y == S16_MIN ? y : (y - 1); + }; // Result of calcBiomes bulk computation. biome_t *biomemap = nullptr; - s16 *biome_transitions = nullptr; protected: BiomeManager *m_bmgr = nullptr; @@ -167,7 +170,7 @@ struct BiomeParamsOriginal : public BiomeParams { NoiseParams np_humidity_blend; }; -class BiomeGenOriginal : public BiomeGen { +class BiomeGenOriginal final : public BiomeGen { public: BiomeGenOriginal(BiomeManager *biomemgr, const BiomeParamsOriginal *params, v3s16 chunksize); @@ -189,7 +192,7 @@ public: Biome *getBiomeAtIndex(size_t index, v3s16 pos) const; Biome *calcBiomeFromNoise(float heat, float humidity, v3s16 pos) const; - s16 *getBiomeTransitions() const; + s16 getNextTransitionY(s16 y) const; float *heatmap; float *humidmap; @@ -201,6 +204,9 @@ private: Noise *noise_humidity; Noise *noise_heat_blend; Noise *noise_humidity_blend; + + // ordered descending + std::vector m_transitions_y; }; From 4fd744cdf6ef100cbcdaf6f55eca2af624fd9d84 Mon Sep 17 00:00:00 2001 From: sfence Date: Fri, 6 Sep 2024 11:30:27 +0200 Subject: [PATCH 08/67] Generate Minetest.app on macOS 12, so at least macOS 12 will be supported --- .github/workflows/macos.yml | 4 ++-- src/util/numeric.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 34556ce8c..e193c828d 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -29,8 +29,8 @@ on: jobs: build: - # use macOS 13 since it's the last one that still runs on x86 - runs-on: macos-13 + # use lowest possible macOS running on x86_64 to support more users + runs-on: macos-12 steps: - uses: actions/checkout@v4 - name: Install deps diff --git a/src/util/numeric.h b/src/util/numeric.h index cfe0317a1..758b55968 100644 --- a/src/util/numeric.h +++ b/src/util/numeric.h @@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "SColor.h" #include #include +#include #define rangelim(d, min, max) ((d) < (min) ? (min) : ((d) > (max) ? (max) : (d))) #define myfloor(x) ((x) < 0.0 ? (int)(x) - 1 : (int)(x)) From 197d09cc534b61b01384ef5c97c05035a323e4d7 Mon Sep 17 00:00:00 2001 From: red-001 Date: Mon, 2 Sep 2024 05:56:53 +0100 Subject: [PATCH 09/67] SRP switch to porting randomness source --- src/util/srp.cpp | 70 +++++------------------------------------------- 1 file changed, 7 insertions(+), 63 deletions(-) diff --git a/src/util/srp.cpp b/src/util/srp.cpp index 56b2aa763..3c7b6de36 100644 --- a/src/util/srp.cpp +++ b/src/util/srp.cpp @@ -51,6 +51,7 @@ #endif #include "my_sha256.h" +#include "porting.h" #include "srp.h" //#define CSRP_USE_SHA1 @@ -70,12 +71,6 @@ printf("\n"); }*/ -static int g_initialized = 0; - -#define RAND_BUFF_MAX 128 -static unsigned int g_rand_idx; -static unsigned char g_rand_buff[RAND_BUFF_MAX]; - void *(*srp_alloc)(size_t) = &malloc; void *(*srp_realloc)(void *, size_t) = &realloc; void (*srp_free)(void *) = &free; @@ -521,52 +516,15 @@ static SRP_Result calculate_H_AMK(SRP_HashAlgorithm alg, unsigned char *dest, return SRP_OK; } -static SRP_Result fill_buff() -{ - g_rand_idx = 0; - -#ifdef WIN32 - HCRYPTPROV wctx; -#else - FILE *fp = 0; -#endif - -#ifdef WIN32 - - if (!CryptAcquireContext(&wctx, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) - return SRP_ERR; - if (!CryptGenRandom(wctx, sizeof(g_rand_buff), (BYTE *)g_rand_buff)) return SRP_ERR; - if (!CryptReleaseContext(wctx, 0)) return SRP_ERR; - -#else - fp = fopen("/dev/urandom", "r"); - - if (!fp) return SRP_ERR; - - if (fread(g_rand_buff, sizeof(g_rand_buff), 1, fp) != 1) { fclose(fp); return SRP_ERR; } - if (fclose(fp)) return SRP_ERR; -#endif - return SRP_OK; -} - static SRP_Result mpz_fill_random(mpz_t num) { - // was call: BN_rand(num, 256, -1, 0); - if (RAND_BUFF_MAX - g_rand_idx < 32) - if (fill_buff() != SRP_OK) return SRP_ERR; - mpz_from_bin((const unsigned char *)(&g_rand_buff[g_rand_idx]), 32, num); - g_rand_idx += 32; + unsigned char random_buf[32]; + if (!porting::secure_rand_fill_buf(random_buf, sizeof(random_buf))) + return SRP_ERR; + mpz_from_bin(random_buf, sizeof(random_buf), num); return SRP_OK; } -static SRP_Result init_random() -{ - if (g_initialized) return SRP_OK; - SRP_Result ret = fill_buff(); - g_initialized = (ret == SRP_OK); - return ret; -} - #define srp_dbg_num(num, text) ; /*void srp_dbg_num(mpz_t num, char * prevtext) { @@ -600,18 +558,13 @@ SRP_Result srp_create_salted_verification_key( SRP_HashAlgorithm alg, if (!ng) goto error_and_exit; - if (init_random() != SRP_OK) /* Only happens once */ - goto error_and_exit; - if (*bytes_s == NULL) { size_t size_to_fill = 16; *len_s = size_to_fill; - if (RAND_BUFF_MAX - g_rand_idx < size_to_fill) - if (fill_buff() != SRP_OK) goto error_and_exit; *bytes_s = (unsigned char *)srp_alloc(size_to_fill); if (!*bytes_s) goto error_and_exit; - memcpy(*bytes_s, &g_rand_buff[g_rand_idx], size_to_fill); - g_rand_idx += size_to_fill; + if (!porting::secure_rand_fill_buf(*bytes_s, size_to_fill)) + goto error_and_exit; } if (!calculate_x( @@ -677,12 +630,6 @@ struct SRPVerifier *srp_verifier_new(SRP_HashAlgorithm alg, if (!ver) goto cleanup_and_exit; - if (init_random() != SRP_OK) { /* Only happens once */ - srp_free(ver); - ver = 0; - goto cleanup_and_exit; - } - ver->username = (char *)srp_alloc(ulen); ver->hash_alg = alg; ver->ng = ng; @@ -824,9 +771,6 @@ struct SRPUser *srp_user_new(SRP_HashAlgorithm alg, SRP_NGType ng_type, if (!usr) goto err_exit; - if (init_random() != SRP_OK) /* Only happens once */ - goto err_exit; - usr->hash_alg = alg; usr->ng = new_ng(ng_type, n_hex, g_hex); From 1527cdf6a478d9daa8d9bcab0f5a642d03e0e4cf Mon Sep 17 00:00:00 2001 From: red-001 Date: Mon, 2 Sep 2024 05:58:45 +0100 Subject: [PATCH 10/67] SRP remove custom memory allocator --- src/util/srp.cpp | 92 ++++++++++++++++++++---------------------------- src/util/srp.h | 9 ----- 2 files changed, 39 insertions(+), 62 deletions(-) diff --git a/src/util/srp.cpp b/src/util/srp.cpp index 3c7b6de36..b1dfa76a4 100644 --- a/src/util/srp.cpp +++ b/src/util/srp.cpp @@ -71,20 +71,6 @@ printf("\n"); }*/ -void *(*srp_alloc)(size_t) = &malloc; -void *(*srp_realloc)(void *, size_t) = &realloc; -void (*srp_free)(void *) = &free; - -void srp_set_memory_functions( - void *(*new_srp_alloc)(size_t), - void *(*new_srp_realloc)(void *, size_t), - void (*new_srp_free)(void *)) -{ - srp_alloc = new_srp_alloc; - srp_realloc = new_srp_realloc; - srp_free = new_srp_free; -} - typedef struct { mpz_t N; mpz_t g; @@ -184,13 +170,13 @@ static void delete_ng(NGConstant *ng) if (ng) { mpz_clear(ng->N); mpz_clear(ng->g); - srp_free(ng); + free(ng); } } static NGConstant *new_ng(SRP_NGType ng_type, const char *n_hex, const char *g_hex) { - NGConstant *ng = (NGConstant *)srp_alloc(sizeof(NGConstant)); + NGConstant *ng = (NGConstant *)malloc(sizeof(NGConstant)); if (!ng) return 0; @@ -397,17 +383,17 @@ static SRP_Result H_nn( size_t len_n1 = mpz_num_bytes(n1); size_t len_n2 = mpz_num_bytes(n2); size_t nbytes = len_N + len_N; - unsigned char *bin = (unsigned char *)srp_alloc(nbytes); + unsigned char *bin = (unsigned char *)malloc(nbytes); if (!bin) return SRP_ERR; if (len_n1 > len_N || len_n2 > len_N) { - srp_free(bin); + free(bin); return SRP_ERR; } memset(bin, 0, nbytes); mpz_to_bin(n1, bin + (len_N - len_n1)); mpz_to_bin(n2, bin + (len_N + len_N - len_n2)); hash(alg, bin, nbytes, buff); - srp_free(bin); + free(bin); mpz_from_bin(buff, hash_length(alg), result); return SRP_OK; } @@ -417,12 +403,12 @@ static SRP_Result H_ns(mpz_t result, SRP_HashAlgorithm alg, const unsigned char { unsigned char buff[CSRP_MAX_HASH]; size_t nbytes = len_n + len_bytes; - unsigned char *bin = (unsigned char *)srp_alloc(nbytes); + unsigned char *bin = (unsigned char *)malloc(nbytes); if (!bin) return SRP_ERR; memcpy(bin, n, len_n); memcpy(bin + len_n, bytes, len_bytes); hash(alg, bin, nbytes, buff); - srp_free(bin); + free(bin); mpz_from_bin(buff, hash_length(alg), result); return SRP_OK; } @@ -449,22 +435,22 @@ static int calculate_x(mpz_t result, SRP_HashAlgorithm alg, const unsigned char static SRP_Result update_hash_n(SRP_HashAlgorithm alg, HashCTX *ctx, const mpz_t n) { size_t len = mpz_num_bytes(n); - unsigned char *n_bytes = (unsigned char *)srp_alloc(len); + unsigned char *n_bytes = (unsigned char *)malloc(len); if (!n_bytes) return SRP_ERR; mpz_to_bin(n, n_bytes); hash_update(alg, ctx, n_bytes, len); - srp_free(n_bytes); + free(n_bytes); return SRP_OK; } static SRP_Result hash_num(SRP_HashAlgorithm alg, const mpz_t n, unsigned char *dest) { int nbytes = mpz_num_bytes(n); - unsigned char *bin = (unsigned char *)srp_alloc(nbytes); + unsigned char *bin = (unsigned char *)malloc(nbytes); if (!bin) return SRP_ERR; mpz_to_bin(n, bin); hash(alg, bin, nbytes, dest); - srp_free(bin); + free(bin); return SRP_OK; } @@ -529,10 +515,10 @@ static SRP_Result mpz_fill_random(mpz_t num) /*void srp_dbg_num(mpz_t num, char * prevtext) { int len_num = mpz_num_bytes(num); - char *bytes_num = (char*) srp_alloc(len_num); + char *bytes_num = (char*) malloc(len_num); mpz_to_bin(num, (unsigned char *) bytes_num); srp_dbg_data(bytes_num, len_num, prevtext); - srp_free(bytes_num); + free(bytes_num); }*/ @@ -561,7 +547,7 @@ SRP_Result srp_create_salted_verification_key( SRP_HashAlgorithm alg, if (*bytes_s == NULL) { size_t size_to_fill = 16; *len_s = size_to_fill; - *bytes_s = (unsigned char *)srp_alloc(size_to_fill); + *bytes_s = (unsigned char *)malloc(size_to_fill); if (!*bytes_s) goto error_and_exit; if (!porting::secure_rand_fill_buf(*bytes_s, size_to_fill)) goto error_and_exit; @@ -577,7 +563,7 @@ SRP_Result srp_create_salted_verification_key( SRP_HashAlgorithm alg, *len_v = mpz_num_bytes(v); - *bytes_v = (unsigned char *)srp_alloc(*len_v); + *bytes_v = (unsigned char *)malloc(*len_v); if (!*bytes_v) goto error_and_exit; @@ -626,16 +612,16 @@ struct SRPVerifier *srp_verifier_new(SRP_HashAlgorithm alg, if (!ng) goto cleanup_and_exit; - ver = (struct SRPVerifier *)srp_alloc(sizeof(struct SRPVerifier)); + ver = (struct SRPVerifier *)malloc(sizeof(struct SRPVerifier)); if (!ver) goto cleanup_and_exit; - ver->username = (char *)srp_alloc(ulen); + ver->username = (char *)malloc(ulen); ver->hash_alg = alg; ver->ng = ng; if (!ver->username) { - srp_free(ver); + free(ver); ver = 0; goto cleanup_and_exit; } @@ -680,7 +666,7 @@ struct SRPVerifier *srp_verifier_new(SRP_HashAlgorithm alg, } *len_B = mpz_num_bytes(B); - *bytes_B = (unsigned char *)srp_alloc(*len_B); + *bytes_B = (unsigned char *)malloc(*len_B); if (!*bytes_B) { *len_B = 0; @@ -691,7 +677,7 @@ struct SRPVerifier *srp_verifier_new(SRP_HashAlgorithm alg, ver->bytes_B = *bytes_B; } else { - srp_free(ver); + free(ver); ver = 0; } @@ -708,8 +694,8 @@ cleanup_and_exit: mpz_clear(tmp3); return ver; ver_cleanup_and_exit: - srp_free(ver->username); - srp_free(ver); + free(ver->username); + free(ver); ver = 0; goto cleanup_and_exit; } @@ -718,10 +704,10 @@ void srp_verifier_delete(struct SRPVerifier *ver) { if (ver) { delete_ng(ver->ng); - srp_free(ver->username); - srp_free(ver->bytes_B); + free(ver->username); + free(ver->bytes_B); memset(ver, 0, sizeof(*ver)); - srp_free(ver); + free(ver); } } @@ -765,7 +751,7 @@ struct SRPUser *srp_user_new(SRP_HashAlgorithm alg, SRP_NGType ng_type, const unsigned char *bytes_password, size_t len_password, const char *n_hex, const char *g_hex) { - struct SRPUser *usr = (struct SRPUser *)srp_alloc(sizeof(struct SRPUser)); + struct SRPUser *usr = (struct SRPUser *)malloc(sizeof(struct SRPUser)); size_t ulen = strlen(username) + 1; size_t uvlen = strlen(username_for_verifier) + 1; @@ -780,9 +766,9 @@ struct SRPUser *srp_user_new(SRP_HashAlgorithm alg, SRP_NGType ng_type, if (!usr->ng) goto err_exit; - usr->username = (char *)srp_alloc(ulen); - usr->username_verifier = (char *)srp_alloc(uvlen); - usr->password = (unsigned char *)srp_alloc(len_password); + usr->username = (char *)malloc(ulen); + usr->username_verifier = (char *)malloc(uvlen); + usr->password = (unsigned char *)malloc(len_password); usr->password_len = len_password; if (!usr->username || !usr->password || !usr->username_verifier) goto err_exit; @@ -803,13 +789,13 @@ err_exit: mpz_clear(usr->A); mpz_clear(usr->S); delete_ng(usr->ng); - srp_free(usr->username); - srp_free(usr->username_verifier); + free(usr->username); + free(usr->username_verifier); if (usr->password) { memset(usr->password, 0, usr->password_len); - srp_free(usr->password); + free(usr->password); } - srp_free(usr); + free(usr); } return 0; @@ -826,14 +812,14 @@ void srp_user_delete(struct SRPUser *usr) memset(usr->password, 0, usr->password_len); - srp_free(usr->username); - srp_free(usr->username_verifier); - srp_free(usr->password); + free(usr->username); + free(usr->username_verifier); + free(usr->password); - if (usr->bytes_A) srp_free(usr->bytes_A); + if (usr->bytes_A) free(usr->bytes_A); memset(usr, 0, sizeof(*usr)); - srp_free(usr); + free(usr); } } @@ -872,7 +858,7 @@ SRP_Result srp_user_start_authentication(struct SRPUser *usr, char **username, mpz_powm(usr->A, usr->ng->g, usr->a, usr->ng->N); *len_A = mpz_num_bytes(usr->A); - *bytes_A = (unsigned char *)srp_alloc(*len_A); + *bytes_A = (unsigned char *)malloc(*len_A); if (!*bytes_A) goto error_and_exit; diff --git a/src/util/srp.h b/src/util/srp.h index ac66dc936..fc4d2dc89 100644 --- a/src/util/srp.h +++ b/src/util/srp.h @@ -79,15 +79,6 @@ typedef enum { SRP_OK, } SRP_Result; -/* Sets the memory functions used by srp. - * Note: this doesn't set the memory functions used by gmp, - * but it is supported to have different functions for srp and gmp. - * Don't call this after you have already allocated srp structures. - */ -void srp_set_memory_functions( - void *(*new_srp_alloc) (size_t), - void *(*new_srp_realloc) (void *, size_t), - void (*new_srp_free) (void *)); /* Out: bytes_v, len_v * From 041d67cecad21b8cea26b74d8d0faaf0f58b138b Mon Sep 17 00:00:00 2001 From: grorp Date: Fri, 6 Sep 2024 12:11:03 +0200 Subject: [PATCH 11/67] Improve formspec scaling (#14840) --- builtin/fstk/buttonbar.lua | 7 +- builtin/fstk/tabview.lua | 22 +++- builtin/mainmenu/init.lua | 9 +- builtin/mainmenu/tab_local.lua | 10 +- doc/lua_api.md | 4 +- doc/menu_lua_api.md | 4 +- games/devtest/mods/testfullscreenfs/init.lua | 59 ++++++++-- src/clientdynamicinfo.cpp | 20 ++-- src/clientdynamicinfo.h | 2 +- src/gui/guiFormSpecMenu.cpp | 118 +++++++++++-------- src/gui/guiFormSpecMenu.h | 8 ++ 11 files changed, 176 insertions(+), 87 deletions(-) diff --git a/builtin/fstk/buttonbar.lua b/builtin/fstk/buttonbar.lua index 64ac37f03..e53814751 100644 --- a/builtin/fstk/buttonbar.lua +++ b/builtin/fstk/buttonbar.lua @@ -28,10 +28,8 @@ local function buttonbar_formspec(self) end local formspec = { - "style_type[box;noclip=true]", string.format("box[%f,%f;%f,%f;%s]", self.pos.x, self.pos.y, self.size.x, self.size.y, self.bgcolor), - "style_type[box;noclip=false]", } local btn_size = self.size.y - 2*BASE_SPACING @@ -71,7 +69,7 @@ local function buttonbar_formspec(self) y = self.pos.y + BASE_SPACING, } - table.insert(formspec, string.format("image_button[%f,%f;%f,%f;%s;%s;%s;true;false]tooltip[%s;%s]", + table.insert(formspec, string.format("image_button[%f,%f;%f,%f;%s;%s;%s;false;false]tooltip[%s;%s]", btn_pos.x, btn_pos.y, btn_size, btn_size, btn.image, btn.name, btn.caption, btn.name, btn.tooltip)) end @@ -86,9 +84,6 @@ local function buttonbar_formspec(self) y = self.pos.y + BASE_SPACING, } - table.insert(formspec, string.format("style[%s,%s;noclip=true]", - self.btn_prev_name, self.btn_next_name)) - table.insert(formspec, string.format("button[%f,%f;%f,%f;%s;<]", btn_prev_pos.x, btn_prev_pos.y, get_scroll_btn_width(), btn_size, self.btn_prev_name)) diff --git a/builtin/fstk/tabview.lua b/builtin/fstk/tabview.lua index f09c4df2d..9f8889143 100644 --- a/builtin/fstk/tabview.lua +++ b/builtin/fstk/tabview.lua @@ -66,11 +66,22 @@ local function get_formspec(self) local content, prepend = tab.get_formspec(self, tab.name, tab.tabdata, tab.tabsize) - local tsize = tab.tabsize or { width = self.width, height = self.height } + local ENABLE_TOUCH = core.settings:get_bool("enable_touch") + + local orig_tsize = tab.tabsize or { width = self.width, height = self.height } + local tsize = { width = orig_tsize.width, height = orig_tsize.height } + tsize.height = tsize.height + + TABHEADER_H -- tabheader included in formspec size + + (ENABLE_TOUCH and GAMEBAR_OFFSET_TOUCH or GAMEBAR_OFFSET_DESKTOP) + + GAMEBAR_H -- gamebar included in formspec size + if self.parent == nil and not prepend then prepend = string.format("size[%f,%f,%s]", tsize.width, tsize.height, dump(self.fixed_size)) + local anchor_pos = TABHEADER_H + orig_tsize.height / 2 + prepend = prepend .. ("anchor[0.5,%f]"):format(anchor_pos / tsize.height) + if tab.formspec_version then prepend = ("formspec_version[%d]"):format(tab.formspec_version) .. prepend end @@ -78,12 +89,15 @@ local function get_formspec(self) local end_button_size = 0.75 - local tab_header_size = { width = tsize.width, height = 0.85 } + local tab_header_size = { width = tsize.width, height = TABHEADER_H } if self.end_button then tab_header_size.width = tab_header_size.width - end_button_size - 0.1 end - local formspec = (prepend or "") .. self:tab_header(tab_header_size) .. content + local formspec = (prepend or "") + formspec = formspec .. ("bgcolor[;neither]container[0,%f]box[0,0;%f,%f;#0000008C]"):format( + TABHEADER_H, orig_tsize.width, orig_tsize.height) + formspec = formspec .. self:tab_header(tab_header_size) .. content if self.end_button then formspec = formspec .. @@ -98,6 +112,8 @@ local function get_formspec(self) self.end_button.name) end + formspec = formspec .. "container_end[]" + return formspec end diff --git a/builtin/mainmenu/init.lua b/builtin/mainmenu/init.lua index 41885e298..dd35334c2 100644 --- a/builtin/mainmenu/init.lua +++ b/builtin/mainmenu/init.lua @@ -23,6 +23,13 @@ mt_color_dark_green = "#25C191" mt_color_orange = "#FF8800" mt_color_red = "#FF3300" +MAIN_TAB_W = 15.5 +MAIN_TAB_H = 7.1 +TABHEADER_H = 0.85 +GAMEBAR_H = 1.25 +GAMEBAR_OFFSET_DESKTOP = 0.375 +GAMEBAR_OFFSET_TOUCH = 0.15 + local menupath = core.get_mainmenu_path() local basepath = core.get_builtin_path() defaulttexturedir = core.get_texturepath_share() .. DIR_DELIM .. "base" .. @@ -89,7 +96,7 @@ local function init_globals() mm_game_theme.set_engine() -- This is just a fallback. -- Create main tabview - local tv_main = tabview_create("maintab", {x = 15.5, y = 7.1}, {x = 0, y = 0}) + local tv_main = tabview_create("maintab", {x = MAIN_TAB_W, y = MAIN_TAB_H}, {x = 0, y = 0}) tv_main:set_autosave_tab(true) tv_main:add(tabs.local_game) diff --git a/builtin/mainmenu/tab_local.lua b/builtin/mainmenu/tab_local.lua index 7f46be213..f0a7255d7 100644 --- a/builtin/mainmenu/tab_local.lua +++ b/builtin/mainmenu/tab_local.lua @@ -92,10 +92,16 @@ function singleplayer_refresh_gamebar() end end + local ENABLE_TOUCH = core.settings:get_bool("enable_touch") + + local gamebar_pos_y = MAIN_TAB_H + + TABHEADER_H -- tabheader included in formspec size + + (ENABLE_TOUCH and GAMEBAR_OFFSET_TOUCH or GAMEBAR_OFFSET_DESKTOP) + local btnbar = buttonbar_create( "game_button_bar", - core.settings:get_bool("touch_gui") and {x = 0, y = 7.25} or {x = 0, y = 7.475}, - {x = 15.5, y = 1.25}, + {x = 0, y = gamebar_pos_y}, + {x = MAIN_TAB_W, y = GAMEBAR_H}, "#000000", game_buttonbar_button_handler) diff --git a/doc/lua_api.md b/doc/lua_api.md index 6989f3483..ea728cfbe 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -5580,8 +5580,8 @@ Utilities }, -- Estimated maximum formspec size before Minetest will start shrinking the - -- formspec to fit. For a fullscreen formspec, use a size 10-20% larger than - -- this and `padding[-0.01,-0.01]`. + -- formspec to fit. For a fullscreen formspec, use this formspec size and + -- `padding[0,0]`. `bgcolor[;true]` is also recommended. max_formspec_size = { x = 20, y = 11.25 diff --git a/doc/menu_lua_api.md b/doc/menu_lua_api.md index df14b859d..be63af904 100644 --- a/doc/menu_lua_api.md +++ b/doc/menu_lua_api.md @@ -253,8 +253,8 @@ GUI }, -- Estimated maximum formspec size before Minetest will start shrinking the - -- formspec to fit. For a fullscreen formspec, use a size 10-20% larger than - -- this and `padding[-0.01,-0.01]`. + -- formspec to fit. For a fullscreen formspec, use this formspec size and + -- `padding[0,0]`. `bgcolor[;true]` is also recommended. max_formspec_size = { x = 20, y = 11.25 diff --git a/games/devtest/mods/testfullscreenfs/init.lua b/games/devtest/mods/testfullscreenfs/init.lua index e1af3ae33..7abc7f817 100644 --- a/games/devtest/mods/testfullscreenfs/init.lua +++ b/games/devtest/mods/testfullscreenfs/init.lua @@ -1,18 +1,30 @@ -local function show_fullscreen_fs(name) - local window = minetest.get_player_window_information(name) - if not window then - return false, "Unable to get window info" - end +local function window_info_equal(a, b) + return + -- size + a.size.x == b.size.x and a.size.y == b.size.y and + -- real_gui_scaling, real_hud_scaling + a.real_gui_scaling == b.real_gui_scaling and + a.real_hud_scaling == b.real_hud_scaling and + -- max_formspec_size + a.max_formspec_size.x == b.max_formspec_size.x and + a.max_formspec_size.y == b.max_formspec_size.y and + -- touch_controls + a.touch_controls == b.touch_controls +end +local last_window_info = {} + +local function show_fullscreen_fs(name, window) print(dump(window)) - local size = { x = window.max_formspec_size.x * 1.1, y = window.max_formspec_size.y * 1.1 } + local size = window.max_formspec_size local touch_text = window.touch_controls and "Touch controls enabled" or "Touch controls disabled" local fs = { "formspec_version[4]", ("size[%f,%f]"):format(size.x, size.y), - "padding[-0.01,-0.01]", + "padding[0,0]", + "bgcolor[;true]", ("button[%f,%f;1,1;%s;%s]"):format(0, 0, "tl", "TL"), ("button[%f,%f;1,1;%s;%s]"):format(size.x - 1, 0, "tr", "TR"), ("button[%f,%f;1,1;%s;%s]"):format(size.x - 1, size.y - 1, "br", "BR"), @@ -23,10 +35,37 @@ local function show_fullscreen_fs(name) } minetest.show_formspec(name, "testfullscreenfs:fs", table.concat(fs)) - return true, ("Calculated size of %f, %f"):format(size.x, size.y) + minetest.chat_send_player(name, ("Calculated size of %f, %f"):format(size.x, size.y)) + last_window_info[name] = window end - minetest.register_chatcommand("testfullscreenfs", { - func = show_fullscreen_fs, + func = function(name) + local window = minetest.get_player_window_information(name) + if not window then + return false, "Unable to get window info" + end + + show_fullscreen_fs(name, window) + return true + end, }) + +minetest.register_globalstep(function() + for name, last_window in pairs(last_window_info) do + local window = minetest.get_player_window_information(name) + if window and not window_info_equal(last_window, window) then + show_fullscreen_fs(name, window) + end + end +end) + +minetest.register_on_player_receive_fields(function(player, formname, fields) + if formname == "testfullscreenfs:fs" and fields.quit then + last_window_info[player:get_player_name()] = nil + end +end) + +minetest.register_on_leaveplayer(function(player) + last_window_info[player:get_player_name()] = nil +end) diff --git a/src/clientdynamicinfo.cpp b/src/clientdynamicinfo.cpp index c206018f3..12bc23abd 100644 --- a/src/clientdynamicinfo.cpp +++ b/src/clientdynamicinfo.cpp @@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "settings.h" #include "client/renderingengine.h" +#include "gui/guiFormSpecMenu.h" #include "gui/touchcontrols.h" ClientDynamicInfo ClientDynamicInfo::getCurrent() @@ -37,19 +38,22 @@ ClientDynamicInfo ClientDynamicInfo::getCurrent() return { screen_size, real_gui_scaling, real_hud_scaling, - ClientDynamicInfo::calculateMaxFSSize(screen_size, gui_scaling), + ClientDynamicInfo::calculateMaxFSSize(screen_size, density, gui_scaling), touch_controls }; } -v2f32 ClientDynamicInfo::calculateMaxFSSize(v2u32 render_target_size, f32 gui_scaling) +v2f32 ClientDynamicInfo::calculateMaxFSSize(v2u32 render_target_size, f32 density, f32 gui_scaling) { - f32 factor = (g_settings->getBool("touch_gui") ? 10 : 15) / gui_scaling; - f32 ratio = (f32)render_target_size.X / (f32)render_target_size.Y; - if (ratio < 1) - return { factor, factor / ratio }; - else - return { factor * ratio, factor }; + // must stay in sync with GUIFormSpecMenu::calculateImgsize + + const double screen_dpi = density * 96; + + // assume padding[0,0] since max_formspec_size is used for fullscreen formspecs + double prefer_imgsize = GUIFormSpecMenu::getImgsize(render_target_size, + screen_dpi, gui_scaling); + return v2f32(render_target_size.X / prefer_imgsize, + render_target_size.Y / prefer_imgsize); } #endif diff --git a/src/clientdynamicinfo.h b/src/clientdynamicinfo.h index 39faeeecc..c43fcb8d8 100644 --- a/src/clientdynamicinfo.h +++ b/src/clientdynamicinfo.h @@ -42,6 +42,6 @@ public: static ClientDynamicInfo getCurrent(); private: - static v2f32 calculateMaxFSSize(v2u32 render_target_size, f32 gui_scaling); + static v2f32 calculateMaxFSSize(v2u32 render_target_size, f32 density, f32 gui_scaling); #endif }; diff --git a/src/gui/guiFormSpecMenu.cpp b/src/gui/guiFormSpecMenu.cpp index 8b572276c..0371c26f3 100644 --- a/src/gui/guiFormSpecMenu.cpp +++ b/src/gui/guiFormSpecMenu.cpp @@ -3133,58 +3133,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize) offset = v2s32(0,0); } - const double gui_scaling = g_settings->getFloat("gui_scaling", 0.5f, 42.0f); - const double screen_dpi = RenderingEngine::getDisplayDensity() * 96; - - double use_imgsize; - if (m_lock) { - // In fixed-size mode, inventory image size - // is 0.53 inch multiplied by the gui_scaling - // config parameter. This magic size is chosen - // to make the main menu (15.5 inventory images - // wide, including border) just fit into the - // default window (800 pixels wide) at 96 DPI - // and default scaling (1.00). - use_imgsize = 0.5555 * screen_dpi * gui_scaling; - } else { - // Variables for the maximum imgsize that can fit in the screen. - double fitx_imgsize; - double fity_imgsize; - - v2f padded_screensize( - mydata.screensize.X * (1.0f - mydata.padding.X * 2.0f), - mydata.screensize.Y * (1.0f - mydata.padding.Y * 2.0f) - ); - - if (mydata.real_coordinates) { - fitx_imgsize = padded_screensize.X / mydata.invsize.X; - fity_imgsize = padded_screensize.Y / mydata.invsize.Y; - } else { - // The maximum imgsize in the old coordinate system also needs to - // factor in padding and spacing along with 0.1 inventory slot spare - // and help text space, hence the magic numbers. - fitx_imgsize = padded_screensize.X / - ((5.0 / 4.0) * (0.5 + mydata.invsize.X)); - fity_imgsize = padded_screensize.Y / - ((15.0 / 13.0) * (0.85 + mydata.invsize.Y)); - } - - s32 min_screen_dim = std::min(padded_screensize.X, padded_screensize.Y); - - double prefer_imgsize; - if (g_settings->getBool("touch_gui")) { - // The preferred imgsize should be larger to accommodate the - // smaller screensize. - prefer_imgsize = min_screen_dim / 10 * gui_scaling; - } else { - // Desktop computers have more space, so try to fit 15 coordinates. - prefer_imgsize = min_screen_dim / 15 * gui_scaling; - } - // Try to use the preferred imgsize, but if that's bigger than the maximum - // size, use the maximum size. - use_imgsize = std::min(prefer_imgsize, - std::min(fitx_imgsize, fity_imgsize)); - } + double use_imgsize = calculateImgsize(mydata); // Everything else is scaled in proportion to the // inventory image size. The inventory slot spacing @@ -5072,3 +5021,68 @@ std::array GUIFormSpecMenu::getStyleForElement return ret; } + +double GUIFormSpecMenu::getFixedImgsize(double screen_dpi, double gui_scaling) +{ + // In fixed-size mode, inventory image size + // is 0.53 inch multiplied by the gui_scaling + // config parameter. This magic size is chosen + // to make the main menu (15.5 inventory images + // wide, including border) just fit into the + // default window (800 pixels wide) at 96 DPI + // and default scaling (1.00). + return 0.5555 * screen_dpi * gui_scaling; +} + +double GUIFormSpecMenu::getImgsize(v2u32 avail_screensize, double screen_dpi, double gui_scaling) +{ + double fixed_imgsize = getFixedImgsize(screen_dpi, gui_scaling); + + s32 min_screen_dim = std::min(avail_screensize.X, avail_screensize.Y); + double prefer_imgsize = min_screen_dim / 15 * gui_scaling; + // Use the available space more effectively on small windows/screens. + // This is especially important for mobile platforms. + prefer_imgsize = std::max(prefer_imgsize, fixed_imgsize); + return prefer_imgsize; +} + +double GUIFormSpecMenu::calculateImgsize(const parserData &data) +{ + // must stay in sync with ClientDynamicInfo::calculateMaxFSSize + + const double screen_dpi = RenderingEngine::getDisplayDensity() * 96; + const double gui_scaling = g_settings->getFloat("gui_scaling", 0.5f, 42.0f); + + // Fixed-size mode + if (m_lock) + return getFixedImgsize(screen_dpi, gui_scaling); + + // Variables for the maximum imgsize that can fit in the screen. + double fitx_imgsize; + double fity_imgsize; + + v2f padded_screensize( + data.screensize.X * (1.0f - data.padding.X * 2.0f), + data.screensize.Y * (1.0f - data.padding.Y * 2.0f) + ); + + if (data.real_coordinates) { + fitx_imgsize = padded_screensize.X / data.invsize.X; + fity_imgsize = padded_screensize.Y / data.invsize.Y; + } else { + // The maximum imgsize in the old coordinate system also needs to + // factor in padding and spacing along with 0.1 inventory slot spare + // and help text space, hence the magic numbers. + fitx_imgsize = padded_screensize.X / + ((5.0 / 4.0) * (0.5 + data.invsize.X)); + fity_imgsize = padded_screensize.Y / + ((15.0 / 13.0) * (0.85 + data.invsize.Y)); + } + + double prefer_imgsize = getImgsize(v2u32(padded_screensize.X, padded_screensize.Y), + screen_dpi, gui_scaling); + + // Try to use the preferred imgsize, but if that's bigger than the maximum + // size, use the maximum size. + return std::min(prefer_imgsize, std::min(fitx_imgsize, fity_imgsize)); +} diff --git a/src/gui/guiFormSpecMenu.h b/src/gui/guiFormSpecMenu.h index 12add12e6..7c4be4301 100644 --- a/src/gui/guiFormSpecMenu.h +++ b/src/gui/guiFormSpecMenu.h @@ -296,6 +296,11 @@ public: void getAndroidUIInput(); #endif + // Returns the fixed formspec coordinate size for the given parameters. + static double getFixedImgsize(double screen_dpi, double gui_scaling); + // Returns the preferred non-fixed formspec coordinate size for the given parameters. + static double getImgsize(v2u32 avail_screensize, double screen_dpi, double gui_scaling); + protected: v2s32 getBasePos() const { @@ -514,6 +519,9 @@ private: // used by getAbsoluteRect s32 m_tabheader_upper_edge = 0; + + // Determines the size (in pixels) of formspec coordinate units. + double calculateImgsize(const parserData &data); }; class FormspecFormSource: public IFormSource From 9e5d6bc16290aadc30e46e21255495cab800cf34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20M=C3=BCller?= <34514239+appgurueu@users.noreply.github.com> Date: Fri, 6 Sep 2024 12:11:16 +0200 Subject: [PATCH 12/67] Fix upright sprite entities not animating --- src/client/content_cao.cpp | 10 ++++++++++ src/client/mesh.cpp | 10 +--------- src/client/mesh.h | 7 ------- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/client/content_cao.cpp b/src/client/content_cao.cpp index 563fe0abd..72f24dfca 100644 --- a/src/client/content_cao.cpp +++ b/src/client/content_cao.cpp @@ -1264,6 +1264,16 @@ void GenericCAO::step(float dtime, ClientEnvironment *env) } } +static void setMeshBufferTextureCoords(scene::IMeshBuffer *buf, const v2f *uv, u32 count) +{ + assert(buf->getVertexType() == video::EVT_STANDARD); + assert(buf->getVertexCount() == count); + auto *vertices = static_cast(buf->getVertices()); + for (u32 i = 0; i < count; i++) + vertices[i].TCoords = uv[i]; + buf->setDirty(scene::EBT_VERTEX); +} + void GenericCAO::updateTexturePos() { if(m_spritenode) diff --git a/src/client/mesh.cpp b/src/client/mesh.cpp index 711712c33..6196e04d4 100644 --- a/src/client/mesh.cpp +++ b/src/client/mesh.cpp @@ -18,6 +18,7 @@ with this program; if not, write to the Free Software Foundation, Inc., */ #include "mesh.h" +#include "S3DVertex.h" #include "debug.h" #include "log.h" #include @@ -197,15 +198,6 @@ void setMeshColor(scene::IMesh *mesh, const video::SColor &color) setMeshBufferColor(mesh->getMeshBuffer(j), color); } -void setMeshBufferTextureCoords(scene::IMeshBuffer *buf, const v2f *uv, u32 count) -{ - const u32 stride = getVertexPitchFromType(buf->getVertexType()); - assert(buf->getVertexCount() >= count); - u8 *vertices = (u8 *) buf->getVertices(); - for (u32 i = 0; i < count; i++) - ((video::S3DVertex*) (vertices + i * stride))->TCoords = uv[i]; -} - template static void applyToMesh(scene::IMesh *mesh, const F &fn) { diff --git a/src/client/mesh.h b/src/client/mesh.h index 106787af3..35d3886aa 100644 --- a/src/client/mesh.h +++ b/src/client/mesh.h @@ -59,13 +59,6 @@ void setMeshBufferColor(scene::IMeshBuffer *buf, const video::SColor &color); */ void setMeshColor(scene::IMesh *mesh, const video::SColor &color); - -/* - Sets texture coords for vertices in the mesh buffer. - `uv[]` must have `count` elements -*/ -void setMeshBufferTextureCoords(scene::IMeshBuffer *buf, const v2f *uv, u32 count); - /* Set a constant color for an animated mesh */ From e90ef85e7d8c9497585f1c413686a9f74da565e5 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Fri, 6 Sep 2024 10:32:05 +0200 Subject: [PATCH 13/67] Fix texture matrix handling in our shaders --- client/shaders/object_shader/opengl_vertex.glsl | 2 +- irr/src/OpenGL/Driver.cpp | 7 +++++-- src/client/shader.cpp | 5 +++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/client/shaders/object_shader/opengl_vertex.glsl b/client/shaders/object_shader/opengl_vertex.glsl index d5a434da5..65acba92a 100644 --- a/client/shaders/object_shader/opengl_vertex.glsl +++ b/client/shaders/object_shader/opengl_vertex.glsl @@ -91,7 +91,7 @@ float directional_ambient(vec3 normal) void main(void) { - varTexCoord = (mTexture * inTexCoord0).st; + varTexCoord = (mTexture * vec4(inTexCoord0.xy, 1.0, 1.0)).st; gl_Position = mWorldViewProj * inVertexPosition; vPosition = gl_Position.xyz; diff --git a/irr/src/OpenGL/Driver.cpp b/irr/src/OpenGL/Driver.cpp index 46aa36d5c..3a921d104 100644 --- a/irr/src/OpenGL/Driver.cpp +++ b/irr/src/OpenGL/Driver.cpp @@ -1096,8 +1096,11 @@ void COpenGL3DriverBase::setMaterial(const SMaterial &material) OverrideMaterial.apply(Material); for (u32 i = 0; i < Feature.MaxTextureUnits; ++i) { - CacheHandler->getTextureCache().set(i, material.getTexture(i)); - setTransform((E_TRANSFORMATION_STATE)(ETS_TEXTURE_0 + i), material.getTextureMatrix(i)); + auto *texture = material.getTexture(i); + CacheHandler->getTextureCache().set(i, texture); + if (texture) { + setTransform((E_TRANSFORMATION_STATE)(ETS_TEXTURE_0 + i), material.getTextureMatrix(i)); + } } } diff --git a/src/client/shader.cpp b/src/client/shader.cpp index dae53ff96..242fda81c 100644 --- a/src/client/shader.cpp +++ b/src/client/shader.cpp @@ -249,7 +249,7 @@ public: m_world_view_proj.set(worldViewProj, services); if (driver->getDriverType() == video::EDT_OGLES2 || driver->getDriverType() == video::EDT_OPENGL3) { - core::matrix4 texture = driver->getTransform(video::ETS_TEXTURE_0); + auto &texture = driver->getTransform(video::ETS_TEXTURE_0); m_world_view.set(worldView, services); m_texture.set(texture, services); } @@ -573,6 +573,7 @@ ShaderInfo ShaderSource::generateShader(const std::string &name, } else { shaders_header << "#version 100\n"; } + // cf. EVertexAttributes.h for the predefined ones vertex_header = R"( precision mediump float; @@ -582,7 +583,7 @@ ShaderInfo ShaderSource::generateShader(const std::string &name, attribute highp vec4 inVertexPosition; attribute lowp vec4 inVertexColor; - attribute mediump vec4 inTexCoord0; + attribute mediump vec2 inTexCoord0; attribute mediump vec3 inVertexNormal; attribute mediump vec4 inVertexTangent; attribute mediump vec4 inVertexBinormal; From 275bef06337b48b56af111d00a0df5d00287f512 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Fri, 6 Sep 2024 11:02:26 +0200 Subject: [PATCH 14/67] Remove unused leftovers from normal mapping --- src/client/mapblock_mesh.cpp | 8 -------- src/client/texturesource.cpp | 23 ----------------------- src/client/texturesource.h | 2 -- src/client/tile.h | 4 ---- src/client/wieldmesh.cpp | 14 -------------- src/nodedef.cpp | 9 +-------- 6 files changed, 1 insertion(+), 59 deletions(-) diff --git a/src/client/mapblock_mesh.cpp b/src/client/mapblock_mesh.cpp index 5b47a32ff..32d559149 100644 --- a/src/client/mapblock_mesh.cpp +++ b/src/client/mapblock_mesh.cpp @@ -746,9 +746,6 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs material.MaterialType = m_shdrsrc->getShaderInfo( p.layer.shader_id).material; p.layer.applyMaterialOptionsWithShaders(material); - if (p.layer.normal_texture) - material.setTexture(1, p.layer.normal_texture); - material.setTexture(2, p.layer.flags_texture); } else { p.layer.applyMaterialOptions(material); } @@ -858,11 +855,6 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack, const FrameSpec &frame = (*tile.frames)[frameno]; buf->getMaterial().setTexture(0, frame.texture); - if (m_enable_shaders) { - if (frame.normal_texture) - buf->getMaterial().setTexture(1, frame.normal_texture); - buf->getMaterial().setTexture(2, frame.flags_texture); - } } // Day-night transition diff --git a/src/client/texturesource.cpp b/src/client/texturesource.cpp index a4222f414..f18fa6cbf 100644 --- a/src/client/texturesource.cpp +++ b/src/client/texturesource.cpp @@ -137,7 +137,6 @@ public: video::ITexture* getNormalTexture(const std::string &name); video::SColor getTextureAverageColor(const std::string &name); - video::ITexture *getShaderFlagsTexture(bool normamap_present); private: @@ -541,25 +540,3 @@ video::SColor TextureSource::getTextureAverageColor(const std::string &name) return c; } - - -video::ITexture *TextureSource::getShaderFlagsTexture(bool normalmap_present) -{ - std::string tname = "__shaderFlagsTexture"; - tname += normalmap_present ? "1" : "0"; - - if (isKnownSourceImage(tname)) { - return getTexture(tname); - } - - video::IVideoDriver *driver = RenderingEngine::get_video_driver(); - video::IImage *flags_image = driver->createImage( - video::ECF_A8R8G8B8, core::dimension2d(1, 1)); - sanity_check(flags_image); - video::SColor c(255, normalmap_present ? 255 : 0, 0, 0); - flags_image->setPixel(0, 0, c); - insertSourceImage(tname, flags_image); - flags_image->drop(); - return getTexture(tname); - -} diff --git a/src/client/texturesource.h b/src/client/texturesource.h index d4880ed4c..324c58e4f 100644 --- a/src/client/texturesource.h +++ b/src/client/texturesource.h @@ -71,7 +71,6 @@ public: virtual bool isKnownSourceImage(const std::string &name)=0; virtual video::ITexture* getNormalTexture(const std::string &name)=0; virtual video::SColor getTextureAverageColor(const std::string &name)=0; - virtual video::ITexture *getShaderFlagsTexture(bool normalmap_present)=0; }; class IWritableTextureSource : public ITextureSource @@ -93,7 +92,6 @@ public: virtual void rebuildImagesAndTextures()=0; virtual video::ITexture* getNormalTexture(const std::string &name)=0; virtual video::SColor getTextureAverageColor(const std::string &name)=0; - virtual video::ITexture *getShaderFlagsTexture(bool normalmap_present)=0; }; IWritableTextureSource *createTextureSource(); diff --git a/src/client/tile.h b/src/client/tile.h index d761eefdd..f41b127bf 100644 --- a/src/client/tile.h +++ b/src/client/tile.h @@ -62,8 +62,6 @@ struct FrameSpec u32 texture_id = 0; video::ITexture *texture = nullptr; - video::ITexture *normal_texture = nullptr; - video::ITexture *flags_texture = nullptr; }; #define MAX_TILE_LAYERS 2 @@ -114,8 +112,6 @@ struct TileLayer // Ordered for size, please do not reorder video::ITexture *texture = nullptr; - video::ITexture *normal_texture = nullptr; - video::ITexture *flags_texture = nullptr; u32 shader_id = 0; diff --git a/src/client/wieldmesh.cpp b/src/client/wieldmesh.cpp index 66f89efb1..148130606 100644 --- a/src/client/wieldmesh.cpp +++ b/src/client/wieldmesh.cpp @@ -306,9 +306,6 @@ void WieldMeshSceneNode::setExtruded(const std::string &imagename, }); // mipmaps cause "thin black line" artifacts material.UseMipMaps = false; - if (m_enable_shaders) { - material.setTexture(2, tsrc->getShaderFlagsTexture(false)); - } } } @@ -343,7 +340,6 @@ static scene::SMesh *createSpecialNodeMesh(Client *client, MapNode n, if (p.layer.material_flags & MATERIAL_FLAG_ANIMATION) { const FrameSpec &frame = (*p.layer.frames)[0]; p.layer.texture = frame.texture; - p.layer.normal_texture = frame.normal_texture; } for (video::S3DVertex &v : p.vertices) { v.Color.setAlpha(255); @@ -772,16 +768,6 @@ void postProcessNodeMesh(scene::SMesh *mesh, const ContentFeatures &f, } else { material.setTexture(0, layer->texture); } - if (use_shaders) { - if (layer->normal_texture) { - if (layer->animation_frame_count > 1) { - const FrameSpec &animation_frame = (*layer->frames)[0]; - material.setTexture(1, animation_frame.normal_texture); - } else - material.setTexture(1, layer->normal_texture); - } - material.setTexture(2, layer->flags_texture); - } if (apply_scale && tile->world_aligned) { u32 n = buf->getVertexCount(); diff --git a/src/nodedef.cpp b/src/nodedef.cpp index 2914cc3aa..811753c89 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -712,8 +712,6 @@ static void fillTileAttribs(ITextureSource *tsrc, TileLayer *layer, if (!tile.world_aligned) layer->scale = 1; - layer->flags_texture = tsrc->getShaderFlagsTexture(layer->normal_texture ? true : false); - // Material flags layer->material_flags = 0; if (backface_culling) @@ -753,18 +751,13 @@ static void fillTileAttribs(ITextureSource *tsrc, TileLayer *layer, std::ostringstream os(std::ios::binary); for (int i = 0; i < frame_count; i++) { - FrameSpec frame; - os.str(""); os << tiledef.name; tiledef.animation.getTextureModifer(os, layer->texture->getOriginalSize(), i); + FrameSpec &frame = (*layer->frames)[i]; frame.texture = tsrc->getTextureForMesh(os.str(), &frame.texture_id); - if (layer->normal_texture) - frame.normal_texture = tsrc->getNormalTexture(os.str()); - frame.flags_texture = layer->flags_texture; - (*layer->frames)[i] = frame; } } } From 3feec87d5214caad3b782fa9262495a98b3acdc5 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sat, 7 Sep 2024 13:55:33 +0200 Subject: [PATCH 15/67] Count global number of drawcalls too --- irr/include/IVideoDriver.h | 2 ++ irr/src/CNullDriver.cpp | 2 ++ src/client/game.cpp | 5 ++++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/irr/include/IVideoDriver.h b/irr/include/IVideoDriver.h index b3312160c..af8d97fef 100644 --- a/irr/include/IVideoDriver.h +++ b/irr/include/IVideoDriver.h @@ -54,6 +54,8 @@ const c8 *const FogTypeNames[] = { }; struct SFrameStats { + //! Number of draw calls + u32 Drawcalls = 0; //! Count of primitives drawn u32 PrimitivesDrawn = 0; //! Number of hardware buffers uploaded (new or updated) diff --git a/irr/src/CNullDriver.cpp b/irr/src/CNullDriver.cpp index 6f261cef1..91f441a14 100644 --- a/irr/src/CNullDriver.cpp +++ b/irr/src/CNullDriver.cpp @@ -605,6 +605,7 @@ void CNullDriver::drawVertexPrimitiveList(const void *vertices, u32 vertexCount, { if ((iType == EIT_16BIT) && (vertexCount > 65536)) os::Printer::log("Too many vertices for 16bit index type, render artifacts may occur."); + FrameStats.Drawcalls++; FrameStats.PrimitivesDrawn += primitiveCount; } @@ -613,6 +614,7 @@ void CNullDriver::draw2DVertexPrimitiveList(const void *vertices, u32 vertexCoun { if ((iType == EIT_16BIT) && (vertexCount > 65536)) os::Printer::log("Too many vertices for 16bit index type, render artifacts may occur."); + FrameStats.Drawcalls++; FrameStats.PrimitivesDrawn += primitiveCount; } diff --git a/src/client/game.cpp b/src/client/game.cpp index 7213faafa..5855be96f 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -1953,7 +1953,10 @@ void Game::updateProfilers(const RunStats &stats, const FpsControl &draw_times, g_profiler->graphSet("FPS", 1.0f / dtime); auto stats2 = driver->getFrameStats(); - g_profiler->avg("Irr: primitives drawn", stats2.PrimitivesDrawn); + g_profiler->avg("Irr: drawcalls", stats2.Drawcalls); + if (stats2.Drawcalls > 0) + g_profiler->avg("Irr: primitives per drawcall", + stats2.PrimitivesDrawn / float(stats2.Drawcalls)); g_profiler->avg("Irr: buffers uploaded", stats2.HWBuffersUploaded); g_profiler->avg("Irr: buffers uploaded (bytes)", stats2.HWBuffersUploadedSize); } From c8ebc2e5d00a4ba7d502cac38104c1550d9577a6 Mon Sep 17 00:00:00 2001 From: Gregor Parzefall Date: Fri, 6 Sep 2024 21:11:13 +0200 Subject: [PATCH 16/67] Delete Irrlicht CGUISkin --- irr/src/CGUISkin.cpp | 891 ------------------------------------------- irr/src/CGUISkin.h | 233 ----------- 2 files changed, 1124 deletions(-) delete mode 100644 irr/src/CGUISkin.cpp delete mode 100644 irr/src/CGUISkin.h diff --git a/irr/src/CGUISkin.cpp b/irr/src/CGUISkin.cpp deleted file mode 100644 index 84ceaeabf..000000000 --- a/irr/src/CGUISkin.cpp +++ /dev/null @@ -1,891 +0,0 @@ -// Copyright (C) 2002-2012 Nikolaus Gebhardt -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in irrlicht.h - -#include "CGUISkin.h" - -#include "IGUIFont.h" -#include "IGUISpriteBank.h" -#include "IGUIElement.h" -#include "IVideoDriver.h" -#include "IAttributes.h" - -namespace irr -{ -namespace gui -{ - -CGUISkin::CGUISkin(EGUI_SKIN_TYPE type, video::IVideoDriver *driver) : - SpriteBank(0), Driver(driver), Type(type) -{ -#ifdef _DEBUG - setDebugName("CGUISkin"); -#endif - - if ((Type == EGST_WINDOWS_CLASSIC) || (Type == EGST_WINDOWS_METALLIC)) { - 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(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); - Colors[EGDC_ACTIVE_CAPTION] = video::SColor(255, 255, 255, 255); - Colors[EGDC_APP_WORKSPACE] = video::SColor(101, 100, 100, 100); - Colors[EGDC_BUTTON_TEXT] = video::SColor(240, 10, 10, 10); - Colors[EGDC_GRAY_TEXT] = video::SColor(240, 130, 130, 130); - Colors[EGDC_HIGH_LIGHT] = video::SColor(101, 8, 36, 107); - Colors[EGDC_HIGH_LIGHT_TEXT] = video::SColor(240, 255, 255, 255); - Colors[EGDC_INACTIVE_BORDER] = video::SColor(101, 165, 165, 165); - Colors[EGDC_INACTIVE_CAPTION] = video::SColor(255, 30, 30, 30); - Colors[EGDC_TOOLTIP] = video::SColor(200, 0, 0, 0); - Colors[EGDC_TOOLTIP_BACKGROUND] = video::SColor(200, 255, 255, 225); - Colors[EGDC_SCROLLBAR] = video::SColor(101, 230, 230, 230); - Colors[EGDC_WINDOW] = video::SColor(101, 255, 255, 255); - Colors[EGDC_WINDOW_SYMBOL] = video::SColor(200, 10, 10, 10); - Colors[EGDC_ICON] = video::SColor(200, 255, 255, 255); - Colors[EGDC_ICON_HIGH_LIGHT] = video::SColor(200, 8, 36, 107); - Colors[EGDC_GRAY_WINDOW_SYMBOL] = video::SColor(240, 100, 100, 100); - Colors[EGDC_EDITABLE] = video::SColor(255, 255, 255, 255); - Colors[EGDC_GRAY_EDITABLE] = video::SColor(255, 120, 120, 120); - Colors[EGDC_FOCUSED_EDITABLE] = video::SColor(255, 240, 240, 255); - - Sizes[EGDS_SCROLLBAR_SIZE] = 14; - Sizes[EGDS_MENU_HEIGHT] = 30; - Sizes[EGDS_WINDOW_BUTTON_WIDTH] = 15; - Sizes[EGDS_CHECK_BOX_WIDTH] = 18; - Sizes[EGDS_MESSAGE_BOX_WIDTH] = 500; - Sizes[EGDS_MESSAGE_BOX_HEIGHT] = 200; - Sizes[EGDS_BUTTON_WIDTH] = 80; - Sizes[EGDS_BUTTON_HEIGHT] = 30; - - Sizes[EGDS_TEXT_DISTANCE_X] = 2; - Sizes[EGDS_TEXT_DISTANCE_Y] = 0; - - Sizes[EGDS_TITLEBARTEXT_DISTANCE_X] = 2; - Sizes[EGDS_TITLEBARTEXT_DISTANCE_Y] = 0; - } else { - // 0x80a6a8af - Colors[EGDC_3D_DARK_SHADOW] = 0x60767982; - // Colors[EGDC_3D_FACE] = 0xc0c9ccd4; // tab background - Colors[EGDC_3D_FACE] = 0xc0cbd2d9; // tab background - Colors[EGDC_3D_SHADOW] = 0x50e4e8f1; // tab background, and left-top highlight - Colors[EGDC_3D_HIGH_LIGHT] = 0x40c7ccdc; - Colors[EGDC_3D_LIGHT] = 0x802e313a; - Colors[EGDC_ACTIVE_BORDER] = 0x80404040; // window title - Colors[EGDC_ACTIVE_CAPTION] = 0xffd0d0d0; - Colors[EGDC_APP_WORKSPACE] = 0xc0646464; // unused - Colors[EGDC_BUTTON_TEXT] = 0xd0161616; - Colors[EGDC_GRAY_TEXT] = 0x3c141414; - Colors[EGDC_HIGH_LIGHT] = 0x6c606060; - Colors[EGDC_HIGH_LIGHT_TEXT] = 0xd0e0e0e0; - Colors[EGDC_INACTIVE_BORDER] = 0xf0a5a5a5; - Colors[EGDC_INACTIVE_CAPTION] = 0xffd2d2d2; - Colors[EGDC_TOOLTIP] = 0xf00f2033; - Colors[EGDC_TOOLTIP_BACKGROUND] = 0xc0cbd2d9; - Colors[EGDC_SCROLLBAR] = 0xf0e0e0e0; - Colors[EGDC_WINDOW] = 0xf0f0f0f0; - Colors[EGDC_WINDOW_SYMBOL] = 0xd0161616; - Colors[EGDC_ICON] = 0xd0161616; - Colors[EGDC_ICON_HIGH_LIGHT] = 0xd0606060; - Colors[EGDC_GRAY_WINDOW_SYMBOL] = 0x3c101010; - Colors[EGDC_EDITABLE] = 0xf0ffffff; - Colors[EGDC_GRAY_EDITABLE] = 0xf0cccccc; - Colors[EGDC_FOCUSED_EDITABLE] = 0xf0fffff0; - - Sizes[EGDS_SCROLLBAR_SIZE] = 14; - Sizes[EGDS_MENU_HEIGHT] = 48; - Sizes[EGDS_WINDOW_BUTTON_WIDTH] = 15; - Sizes[EGDS_CHECK_BOX_WIDTH] = 18; - Sizes[EGDS_MESSAGE_BOX_WIDTH] = 500; - Sizes[EGDS_MESSAGE_BOX_HEIGHT] = 200; - Sizes[EGDS_BUTTON_WIDTH] = 80; - Sizes[EGDS_BUTTON_HEIGHT] = 30; - - Sizes[EGDS_TEXT_DISTANCE_X] = 3; - Sizes[EGDS_TEXT_DISTANCE_Y] = 2; - - Sizes[EGDS_TITLEBARTEXT_DISTANCE_X] = 3; - Sizes[EGDS_TITLEBARTEXT_DISTANCE_Y] = 2; - } - - Sizes[EGDS_MESSAGE_BOX_GAP_SPACE] = 15; - Sizes[EGDS_MESSAGE_BOX_MIN_TEXT_WIDTH] = 0; - Sizes[EGDS_MESSAGE_BOX_MAX_TEXT_WIDTH] = 500; - Sizes[EGDS_MESSAGE_BOX_MIN_TEXT_HEIGHT] = 0; - Sizes[EGDS_MESSAGE_BOX_MAX_TEXT_HEIGHT] = 99999; - - Sizes[EGDS_BUTTON_PRESSED_IMAGE_OFFSET_X] = 1; - Sizes[EGDS_BUTTON_PRESSED_IMAGE_OFFSET_Y] = 1; - Sizes[EGDS_BUTTON_PRESSED_TEXT_OFFSET_X] = 0; - Sizes[EGDS_BUTTON_PRESSED_TEXT_OFFSET_Y] = 2; - Sizes[EGDS_BUTTON_PRESSED_SPRITE_OFFSET_X] = 0; - Sizes[EGDS_BUTTON_PRESSED_SPRITE_OFFSET_Y] = 0; - - Texts[EGDT_MSG_BOX_OK] = L"OK"; - Texts[EGDT_MSG_BOX_CANCEL] = L"Cancel"; - Texts[EGDT_MSG_BOX_YES] = L"Yes"; - Texts[EGDT_MSG_BOX_NO] = L"No"; - Texts[EGDT_WINDOW_CLOSE] = L"Close"; - Texts[EGDT_WINDOW_RESTORE] = L"Restore"; - Texts[EGDT_WINDOW_MINIMIZE] = L"Minimize"; - Texts[EGDT_WINDOW_MAXIMIZE] = L"Maximize"; - - Icons[EGDI_WINDOW_MAXIMIZE] = 225; - Icons[EGDI_WINDOW_RESTORE] = 226; - Icons[EGDI_WINDOW_CLOSE] = 227; - Icons[EGDI_WINDOW_MINIMIZE] = 228; - Icons[EGDI_CURSOR_UP] = 229; - Icons[EGDI_CURSOR_DOWN] = 230; - Icons[EGDI_CURSOR_LEFT] = 231; - Icons[EGDI_CURSOR_RIGHT] = 232; - Icons[EGDI_MENU_MORE] = 232; - Icons[EGDI_CHECK_BOX_CHECKED] = 233; - Icons[EGDI_DROP_DOWN] = 234; - Icons[EGDI_SMALL_CURSOR_UP] = 235; - Icons[EGDI_SMALL_CURSOR_DOWN] = 236; - Icons[EGDI_RADIO_BUTTON_CHECKED] = 237; - Icons[EGDI_MORE_LEFT] = 238; - Icons[EGDI_MORE_RIGHT] = 239; - Icons[EGDI_MORE_UP] = 240; - Icons[EGDI_MORE_DOWN] = 241; - Icons[EGDI_WINDOW_RESIZE] = 242; - Icons[EGDI_EXPAND] = 243; - Icons[EGDI_COLLAPSE] = 244; - - Icons[EGDI_FILE] = 245; - Icons[EGDI_DIRECTORY] = 246; - - for (u32 i = 0; i < EGDF_COUNT; ++i) - Fonts[i] = 0; - - UseGradient = (Type == EGST_WINDOWS_METALLIC) || (Type == EGST_BURNING_SKIN); -} - -//! destructor -CGUISkin::~CGUISkin() -{ - for (u32 i = 0; i < EGDF_COUNT; ++i) { - if (Fonts[i]) - Fonts[i]->drop(); - } - - if (SpriteBank) - SpriteBank->drop(); -} - -//! returns default color -video::SColor CGUISkin::getColor(EGUI_DEFAULT_COLOR color) const -{ - if ((u32)color < EGDC_COUNT) - return Colors[color]; - else - return video::SColor(); -} - -//! sets a default color -void CGUISkin::setColor(EGUI_DEFAULT_COLOR which, video::SColor newColor) -{ - if ((u32)which < EGDC_COUNT) - Colors[which] = newColor; -} - -//! returns size for the given size type -s32 CGUISkin::getSize(EGUI_DEFAULT_SIZE size) const -{ - if ((u32)size < EGDS_COUNT) - return Sizes[size]; - else - return 0; -} - -//! sets a default size -void CGUISkin::setSize(EGUI_DEFAULT_SIZE which, s32 size) -{ - if ((u32)which < EGDS_COUNT) - Sizes[which] = size; -} - -//! returns the default font -IGUIFont *CGUISkin::getFont(EGUI_DEFAULT_FONT which) const -{ - if (((u32)which < EGDF_COUNT) && Fonts[which]) - return Fonts[which]; - else - return Fonts[EGDF_DEFAULT]; -} - -//! sets a default font -void CGUISkin::setFont(IGUIFont *font, EGUI_DEFAULT_FONT which) -{ - if ((u32)which >= EGDF_COUNT) - return; - - if (font) { - font->grab(); - if (Fonts[which]) - Fonts[which]->drop(); - - Fonts[which] = font; - } -} - -//! gets the sprite bank stored -IGUISpriteBank *CGUISkin::getSpriteBank() const -{ - return SpriteBank; -} - -//! set a new sprite bank or remove one by passing 0 -void CGUISkin::setSpriteBank(IGUISpriteBank *bank) -{ - if (bank) - bank->grab(); - - if (SpriteBank) - SpriteBank->drop(); - - SpriteBank = bank; -} - -//! Returns a default icon -u32 CGUISkin::getIcon(EGUI_DEFAULT_ICON icon) const -{ - if ((u32)icon < EGDI_COUNT) - return Icons[icon]; - else - return 0; -} - -//! Sets a default icon -void CGUISkin::setIcon(EGUI_DEFAULT_ICON icon, u32 index) -{ - if ((u32)icon < EGDI_COUNT) - Icons[icon] = index; -} - -//! Returns a default text. For example for Message box button captions: -//! "OK", "Cancel", "Yes", "No" and so on. -const wchar_t *CGUISkin::getDefaultText(EGUI_DEFAULT_TEXT text) const -{ - if ((u32)text < EGDT_COUNT) - return Texts[text].c_str(); - else - return Texts[0].c_str(); -} - -//! Sets a default text. For example for Message box button captions: -//! "OK", "Cancel", "Yes", "No" and so on. -void CGUISkin::setDefaultText(EGUI_DEFAULT_TEXT which, const wchar_t *newText) -{ - if ((u32)which < EGDT_COUNT) - Texts[which] = newText; -} - -//! draws a standard 3d button pane -/** Used for drawing for example buttons in normal state. -It uses the colors EGDC_3D_DARK_SHADOW, EGDC_3D_HIGH_LIGHT, EGDC_3D_SHADOW and -EGDC_3D_FACE for this. See EGUI_DEFAULT_COLOR for details. -\param rect: Defining area where to draw. -\param clip: Clip area. -\param element: Pointer to the element which wishes to draw this. This parameter -is usually not used by ISkin, but can be used for example by more complex -implementations to find out how to draw the part exactly. */ -void CGUISkin::draw3DButtonPaneStandard(IGUIElement *element, - const core::rect &r, - const core::rect *clip) -{ - if (!Driver) - return; - - core::rect rect = r; - - if (Type == EGST_BURNING_SKIN) { - rect.UpperLeftCorner.X -= 1; - rect.UpperLeftCorner.Y -= 1; - rect.LowerRightCorner.X += 1; - rect.LowerRightCorner.Y += 1; - draw3DSunkenPane(element, - getColor(EGDC_WINDOW).getInterpolated(0xFFFFFFFF, 0.9f), false, true, rect, clip); - return; - } - - Driver->draw2DRectangle(getColor(EGDC_3D_DARK_SHADOW), rect, clip); - - rect.LowerRightCorner.X -= 1; - rect.LowerRightCorner.Y -= 1; - Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), rect, clip); - - rect.UpperLeftCorner.X += 1; - rect.UpperLeftCorner.Y += 1; - Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), rect, clip); - - rect.LowerRightCorner.X -= 1; - rect.LowerRightCorner.Y -= 1; - - if (!UseGradient) { - Driver->draw2DRectangle(getColor(EGDC_3D_FACE), rect, clip); - } else { - const video::SColor c1 = getColor(EGDC_3D_FACE); - const video::SColor c2 = c1.getInterpolated(getColor(EGDC_3D_DARK_SHADOW), 0.4f); - Driver->draw2DRectangle(rect, c1, c1, c2, c2, clip); - } -} - -//! draws a pressed 3d button pane -/** Used for drawing for example buttons in pressed state. -It uses the colors EGDC_3D_DARK_SHADOW, EGDC_3D_HIGH_LIGHT, EGDC_3D_SHADOW and -EGDC_3D_FACE for this. See EGUI_DEFAULT_COLOR for details. -\param rect: Defining area where to draw. -\param clip: Clip area. -\param element: Pointer to the element which wishes to draw this. This parameter -is usually not used by ISkin, but can be used for example by more complex -implementations to find out how to draw the part exactly. */ -void CGUISkin::draw3DButtonPanePressed(IGUIElement *element, - const core::rect &r, - const core::rect *clip) -{ - if (!Driver) - return; - - core::rect rect = r; - Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), rect, clip); - - rect.LowerRightCorner.X -= 1; - rect.LowerRightCorner.Y -= 1; - Driver->draw2DRectangle(getColor(EGDC_3D_DARK_SHADOW), rect, clip); - - rect.UpperLeftCorner.X += 1; - rect.UpperLeftCorner.Y += 1; - Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), rect, clip); - - rect.UpperLeftCorner.X += 1; - rect.UpperLeftCorner.Y += 1; - - if (!UseGradient) { - Driver->draw2DRectangle(getColor(EGDC_3D_FACE), rect, clip); - } else { - const video::SColor c1 = getColor(EGDC_3D_FACE); - const video::SColor c2 = c1.getInterpolated(getColor(EGDC_3D_DARK_SHADOW), 0.4f); - Driver->draw2DRectangle(rect, c1, c1, c2, c2, clip); - } -} - -//! draws a sunken 3d pane -/** Used for drawing the background of edit, combo or check boxes. -\param element: Pointer to the element which wishes to draw this. This parameter -is usually not used by ISkin, but can be used for example by more complex -implementations to find out how to draw the part exactly. -\param bgcolor: Background color. -\param flat: Specifies if the sunken pane should be flat or displayed as sunken -deep into the ground. -\param rect: Defining area where to draw. -\param clip: Clip area. */ -void CGUISkin::draw3DSunkenPane(IGUIElement *element, video::SColor bgcolor, - bool flat, bool fillBackGround, - const core::rect &r, - const core::rect *clip) -{ - if (!Driver) - return; - - core::rect rect = r; - - if (fillBackGround) - Driver->draw2DRectangle(bgcolor, rect, clip); - - if (flat) { - // draw flat sunken pane - - rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + 1; - Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), rect, clip); // top - - ++rect.UpperLeftCorner.Y; - rect.LowerRightCorner.Y = r.LowerRightCorner.Y; - rect.LowerRightCorner.X = rect.UpperLeftCorner.X + 1; - Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), rect, clip); // left - - rect = r; - ++rect.UpperLeftCorner.Y; - rect.UpperLeftCorner.X = rect.LowerRightCorner.X - 1; - Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), rect, clip); // right - - rect = r; - ++rect.UpperLeftCorner.X; - rect.UpperLeftCorner.Y = r.LowerRightCorner.Y - 1; - --rect.LowerRightCorner.X; - Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), rect, clip); // bottom - } else { - // draw deep sunken pane - rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + 1; - Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), rect, clip); // top - ++rect.UpperLeftCorner.X; - ++rect.UpperLeftCorner.Y; - --rect.LowerRightCorner.X; - ++rect.LowerRightCorner.Y; - Driver->draw2DRectangle(getColor(EGDC_3D_DARK_SHADOW), rect, clip); - - rect.UpperLeftCorner.X = r.UpperLeftCorner.X; - rect.UpperLeftCorner.Y = r.UpperLeftCorner.Y + 1; - rect.LowerRightCorner.X = rect.UpperLeftCorner.X + 1; - rect.LowerRightCorner.Y = r.LowerRightCorner.Y; - Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), rect, clip); // left - ++rect.UpperLeftCorner.X; - ++rect.UpperLeftCorner.Y; - ++rect.LowerRightCorner.X; - --rect.LowerRightCorner.Y; - Driver->draw2DRectangle(getColor(EGDC_3D_DARK_SHADOW), rect, clip); - - rect = r; - rect.UpperLeftCorner.X = rect.LowerRightCorner.X - 1; - ++rect.UpperLeftCorner.Y; - Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), rect, clip); // right - --rect.UpperLeftCorner.X; - ++rect.UpperLeftCorner.Y; - --rect.LowerRightCorner.X; - --rect.LowerRightCorner.Y; - Driver->draw2DRectangle(getColor(EGDC_3D_LIGHT), rect, clip); - - rect = r; - ++rect.UpperLeftCorner.X; - rect.UpperLeftCorner.Y = r.LowerRightCorner.Y - 1; - --rect.LowerRightCorner.X; - Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), rect, clip); // bottom - ++rect.UpperLeftCorner.X; - --rect.UpperLeftCorner.Y; - --rect.LowerRightCorner.X; - --rect.LowerRightCorner.Y; - Driver->draw2DRectangle(getColor(EGDC_3D_LIGHT), rect, clip); - } -} - -//! draws a window background -// return where to draw title bar text. -core::rect CGUISkin::draw3DWindowBackground(IGUIElement *element, - bool drawTitleBar, video::SColor titleBarColor, - const core::rect &r, - const core::rect *clip, - core::rect *checkClientArea) -{ - if (!Driver) { - if (checkClientArea) { - *checkClientArea = r; - } - return r; - } - - core::rect rect = r; - - // top border - rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + 1; - if (!checkClientArea) { - Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), rect, clip); - } - - // left border - rect.LowerRightCorner.Y = r.LowerRightCorner.Y; - rect.LowerRightCorner.X = rect.UpperLeftCorner.X + 1; - if (!checkClientArea) { - Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), rect, clip); - } - - // right border dark outer line - rect.UpperLeftCorner.X = r.LowerRightCorner.X - 1; - rect.LowerRightCorner.X = r.LowerRightCorner.X; - rect.UpperLeftCorner.Y = r.UpperLeftCorner.Y; - rect.LowerRightCorner.Y = r.LowerRightCorner.Y; - if (!checkClientArea) { - Driver->draw2DRectangle(getColor(EGDC_3D_DARK_SHADOW), rect, clip); - } - - // right border bright innner line - rect.UpperLeftCorner.X -= 1; - rect.LowerRightCorner.X -= 1; - rect.UpperLeftCorner.Y += 1; - rect.LowerRightCorner.Y -= 1; - if (!checkClientArea) { - Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), rect, clip); - } - - // bottom border dark outer line - rect.UpperLeftCorner.X = r.UpperLeftCorner.X; - rect.UpperLeftCorner.Y = r.LowerRightCorner.Y - 1; - rect.LowerRightCorner.Y = r.LowerRightCorner.Y; - rect.LowerRightCorner.X = r.LowerRightCorner.X; - if (!checkClientArea) { - Driver->draw2DRectangle(getColor(EGDC_3D_DARK_SHADOW), rect, clip); - } - - // bottom border bright inner line - rect.UpperLeftCorner.X += 1; - rect.LowerRightCorner.X -= 1; - rect.UpperLeftCorner.Y -= 1; - rect.LowerRightCorner.Y -= 1; - if (!checkClientArea) { - Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), rect, clip); - } - - // client area for background - rect = r; - rect.UpperLeftCorner.X += 1; - rect.UpperLeftCorner.Y += 1; - rect.LowerRightCorner.X -= 2; - rect.LowerRightCorner.Y -= 2; - if (checkClientArea) { - *checkClientArea = rect; - } - - if (!checkClientArea) { - if (!UseGradient) { - Driver->draw2DRectangle(getColor(EGDC_3D_FACE), rect, clip); - } else if (Type == EGST_BURNING_SKIN) { - const video::SColor c1 = getColor(EGDC_WINDOW).getInterpolated(0xFFFFFFFF, 0.9f); - const video::SColor c2 = getColor(EGDC_WINDOW).getInterpolated(0xFFFFFFFF, 0.8f); - - Driver->draw2DRectangle(rect, c1, c1, c2, c2, clip); - } else { - const video::SColor c2 = getColor(EGDC_3D_SHADOW); - const video::SColor c1 = getColor(EGDC_3D_FACE); - Driver->draw2DRectangle(rect, c1, c1, c1, c2, clip); - } - } - - // title bar - rect = r; - rect.UpperLeftCorner.X += 2; - rect.UpperLeftCorner.Y += 2; - rect.LowerRightCorner.X -= 2; - rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + getSize(EGDS_WINDOW_BUTTON_WIDTH) + 2; - - if (drawTitleBar) { - if (checkClientArea) { - (*checkClientArea).UpperLeftCorner.Y = rect.LowerRightCorner.Y; - } else { - // draw title bar - // if (!UseGradient) - // Driver->draw2DRectangle(titleBarColor, rect, clip); - // else - if (Type == EGST_BURNING_SKIN) { - const video::SColor c = titleBarColor.getInterpolated(video::SColor(titleBarColor.getAlpha(), 255, 255, 255), 0.8f); - Driver->draw2DRectangle(rect, titleBarColor, titleBarColor, c, c, clip); - } else { - const video::SColor c = titleBarColor.getInterpolated(video::SColor(titleBarColor.getAlpha(), 0, 0, 0), 0.2f); - Driver->draw2DRectangle(rect, titleBarColor, c, titleBarColor, c, clip); - } - } - } - - return rect; -} - -//! draws a standard 3d menu pane -/** Used for drawing for menus and context menus. -It uses the colors EGDC_3D_DARK_SHADOW, EGDC_3D_HIGH_LIGHT, EGDC_3D_SHADOW and -EGDC_3D_FACE for this. See EGUI_DEFAULT_COLOR for details. -\param element: Pointer to the element which wishes to draw this. This parameter -is usually not used by ISkin, but can be used for example by more complex -implementations to find out how to draw the part exactly. -\param rect: Defining area where to draw. -\param clip: Clip area. */ -void CGUISkin::draw3DMenuPane(IGUIElement *element, - const core::rect &r, const core::rect *clip) -{ - if (!Driver) - return; - - core::rect rect = r; - - if (Type == EGST_BURNING_SKIN) { - rect.UpperLeftCorner.Y -= 3; - draw3DButtonPaneStandard(element, rect, clip); - return; - } - - // in this skin, this is exactly what non pressed buttons look like, - // so we could simply call - // draw3DButtonPaneStandard(element, rect, clip); - // here. - // but if the skin is transparent, this doesn't look that nice. So - // We draw it a little bit better, with some more draw2DRectangle calls, - // but there aren't that much menus visible anyway. - - rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + 1; - Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), rect, clip); - - rect.LowerRightCorner.Y = r.LowerRightCorner.Y; - rect.LowerRightCorner.X = rect.UpperLeftCorner.X + 1; - Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), rect, clip); - - rect.UpperLeftCorner.X = r.LowerRightCorner.X - 1; - rect.LowerRightCorner.X = r.LowerRightCorner.X; - rect.UpperLeftCorner.Y = r.UpperLeftCorner.Y; - rect.LowerRightCorner.Y = r.LowerRightCorner.Y; - Driver->draw2DRectangle(getColor(EGDC_3D_DARK_SHADOW), rect, clip); - - rect.UpperLeftCorner.X -= 1; - rect.LowerRightCorner.X -= 1; - rect.UpperLeftCorner.Y += 1; - rect.LowerRightCorner.Y -= 1; - Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), rect, clip); - - rect.UpperLeftCorner.X = r.UpperLeftCorner.X; - rect.UpperLeftCorner.Y = r.LowerRightCorner.Y - 1; - rect.LowerRightCorner.Y = r.LowerRightCorner.Y; - rect.LowerRightCorner.X = r.LowerRightCorner.X; - Driver->draw2DRectangle(getColor(EGDC_3D_DARK_SHADOW), rect, clip); - - rect.UpperLeftCorner.X += 1; - rect.LowerRightCorner.X -= 1; - rect.UpperLeftCorner.Y -= 1; - rect.LowerRightCorner.Y -= 1; - Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), rect, clip); - - rect = r; - rect.UpperLeftCorner.X += 1; - rect.UpperLeftCorner.Y += 1; - rect.LowerRightCorner.X -= 2; - rect.LowerRightCorner.Y -= 2; - - if (!UseGradient) - Driver->draw2DRectangle(getColor(EGDC_3D_FACE), rect, clip); - else { - const video::SColor c1 = getColor(EGDC_3D_FACE); - const video::SColor c2 = getColor(EGDC_3D_SHADOW); - Driver->draw2DRectangle(rect, c1, c1, c2, c2, clip); - } -} - -//! draws a standard 3d tool bar -/** Used for drawing for toolbars and menus. -\param element: Pointer to the element which wishes to draw this. This parameter -is usually not used by ISkin, but can be used for example by more complex -implementations to find out how to draw the part exactly. -\param rect: Defining area where to draw. -\param clip: Clip area. */ -void CGUISkin::draw3DToolBar(IGUIElement *element, - const core::rect &r, - const core::rect *clip) -{ - if (!Driver) - return; - - core::rect rect = r; - - rect.UpperLeftCorner.X = r.UpperLeftCorner.X; - rect.UpperLeftCorner.Y = r.LowerRightCorner.Y - 1; - rect.LowerRightCorner.Y = r.LowerRightCorner.Y; - rect.LowerRightCorner.X = r.LowerRightCorner.X; - Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), rect, clip); - - rect = r; - rect.LowerRightCorner.Y -= 1; - - if (!UseGradient) { - Driver->draw2DRectangle(getColor(EGDC_3D_FACE), rect, clip); - } else if (Type == EGST_BURNING_SKIN) { - const video::SColor c1 = 0xF0000000 | getColor(EGDC_3D_FACE).color; - const video::SColor c2 = 0xF0000000 | getColor(EGDC_3D_SHADOW).color; - - rect.LowerRightCorner.Y += 1; - Driver->draw2DRectangle(rect, c1, c2, c1, c2, clip); - } else { - const video::SColor c1 = getColor(EGDC_3D_FACE); - const video::SColor c2 = getColor(EGDC_3D_SHADOW); - Driver->draw2DRectangle(rect, c1, c1, c2, c2, clip); - } -} - -//! draws a tab button -/** Used for drawing for tab buttons on top of tabs. -\param element: Pointer to the element which wishes to draw this. This parameter -is usually not used by ISkin, but can be used for example by more complex -implementations to find out how to draw the part exactly. -\param active: Specifies if the tab is currently active. -\param rect: Defining area where to draw. -\param clip: Clip area. */ -void CGUISkin::draw3DTabButton(IGUIElement *element, bool active, - const core::rect &frameRect, const core::rect *clip, EGUI_ALIGNMENT alignment) -{ - if (!Driver) - return; - - core::rect tr = frameRect; - - if (alignment == EGUIA_UPPERLEFT) { - tr.LowerRightCorner.X -= 2; - tr.LowerRightCorner.Y = tr.UpperLeftCorner.Y + 1; - tr.UpperLeftCorner.X += 1; - Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), tr, clip); - - // draw left highlight - tr = frameRect; - tr.LowerRightCorner.X = tr.UpperLeftCorner.X + 1; - tr.UpperLeftCorner.Y += 1; - Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), tr, clip); - - // draw grey background - tr = frameRect; - tr.UpperLeftCorner.X += 1; - tr.UpperLeftCorner.Y += 1; - tr.LowerRightCorner.X -= 2; - Driver->draw2DRectangle(getColor(EGDC_3D_FACE), tr, clip); - - // draw right middle gray shadow - tr.LowerRightCorner.X += 1; - tr.UpperLeftCorner.X = tr.LowerRightCorner.X - 1; - Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), tr, clip); - - tr.LowerRightCorner.X += 1; - tr.UpperLeftCorner.X += 1; - tr.UpperLeftCorner.Y += 1; - Driver->draw2DRectangle(getColor(EGDC_3D_DARK_SHADOW), tr, clip); - } else { - tr.LowerRightCorner.X -= 2; - tr.UpperLeftCorner.Y = tr.LowerRightCorner.Y - 1; - tr.UpperLeftCorner.X += 1; - Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), tr, clip); - - // draw left highlight - tr = frameRect; - tr.LowerRightCorner.X = tr.UpperLeftCorner.X + 1; - tr.LowerRightCorner.Y -= 1; - Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), tr, clip); - - // draw grey background - tr = frameRect; - tr.UpperLeftCorner.X += 1; - tr.UpperLeftCorner.Y -= 1; - tr.LowerRightCorner.X -= 2; - tr.LowerRightCorner.Y -= 1; - Driver->draw2DRectangle(getColor(EGDC_3D_FACE), tr, clip); - - // draw right middle gray shadow - tr.LowerRightCorner.X += 1; - tr.UpperLeftCorner.X = tr.LowerRightCorner.X - 1; - // tr.LowerRightCorner.Y -= 1; - Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), tr, clip); - - tr.LowerRightCorner.X += 1; - tr.UpperLeftCorner.X += 1; - tr.LowerRightCorner.Y -= 1; - Driver->draw2DRectangle(getColor(EGDC_3D_DARK_SHADOW), tr, clip); - } -} - -//! draws a tab control body -/** \param element: Pointer to the element which wishes to draw this. This parameter -is usually not used by ISkin, but can be used for example by more complex -implementations to find out how to draw the part exactly. -\param border: Specifies if the border should be drawn. -\param background: Specifies if the background should be drawn. -\param rect: Defining area where to draw. -\param clip: Clip area. */ -void CGUISkin::draw3DTabBody(IGUIElement *element, bool border, bool background, - const core::rect &rect, const core::rect *clip, s32 tabHeight, EGUI_ALIGNMENT alignment) -{ - if (!Driver) - return; - - core::rect tr = rect; - - if (tabHeight == -1) - tabHeight = getSize(gui::EGDS_BUTTON_HEIGHT); - - // draw border. - if (border) { - if (alignment == EGUIA_UPPERLEFT) { - // draw left hightlight - tr.UpperLeftCorner.Y += tabHeight + 2; - tr.LowerRightCorner.X = tr.UpperLeftCorner.X + 1; - Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), tr, clip); - - // draw right shadow - tr.UpperLeftCorner.X = rect.LowerRightCorner.X - 1; - tr.LowerRightCorner.X = tr.UpperLeftCorner.X + 1; - Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), tr, clip); - - // draw lower shadow - tr = rect; - tr.UpperLeftCorner.Y = tr.LowerRightCorner.Y - 1; - Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), tr, clip); - } else { - // draw left hightlight - tr.LowerRightCorner.Y -= tabHeight + 2; - tr.LowerRightCorner.X = tr.UpperLeftCorner.X + 1; - Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), tr, clip); - - // draw right shadow - tr.UpperLeftCorner.X = rect.LowerRightCorner.X - 1; - tr.LowerRightCorner.X = tr.UpperLeftCorner.X + 1; - Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), tr, clip); - - // draw lower shadow - tr = rect; - tr.LowerRightCorner.Y = tr.UpperLeftCorner.Y + 1; - Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), tr, clip); - } - } - - if (background) { - if (alignment == EGUIA_UPPERLEFT) { - tr = rect; - tr.UpperLeftCorner.Y += tabHeight + 2; - tr.LowerRightCorner.X -= 1; - tr.UpperLeftCorner.X += 1; - tr.LowerRightCorner.Y -= 1; - } else { - tr = rect; - tr.UpperLeftCorner.X += 1; - tr.UpperLeftCorner.Y -= 1; - tr.LowerRightCorner.X -= 1; - tr.LowerRightCorner.Y -= tabHeight + 2; - // tr.UpperLeftCorner.X += 1; - } - - if (!UseGradient) - Driver->draw2DRectangle(getColor(EGDC_3D_FACE), tr, clip); - else { - video::SColor c1 = getColor(EGDC_3D_FACE); - video::SColor c2 = getColor(EGDC_3D_SHADOW); - Driver->draw2DRectangle(tr, c1, c1, c2, c2, clip); - } - } -} - -//! draws an icon, usually from the skin's sprite bank -/** \param parent: Pointer to the element which wishes to draw this icon. -This parameter is usually not used by IGUISkin, but can be used for example -by more complex implementations to find out how to draw the part exactly. -\param icon: Specifies the icon to be drawn. -\param position: The position to draw the icon -\param starttime: The time at the start of the animation -\param currenttime: The present time, used to calculate the frame number -\param loop: Whether the animation should loop or not -\param clip: Clip area. */ -void CGUISkin::drawIcon(IGUIElement *element, EGUI_DEFAULT_ICON icon, - const core::position2di position, - u32 starttime, u32 currenttime, - bool loop, const core::rect *clip) -{ - if (!SpriteBank) - return; - - bool gray = element && !element->isEnabled(); - SpriteBank->draw2DSprite(Icons[icon], position, clip, - Colors[gray ? EGDC_GRAY_WINDOW_SYMBOL : EGDC_WINDOW_SYMBOL], starttime, currenttime, loop, true); -} - -EGUI_SKIN_TYPE CGUISkin::getType() const -{ - return Type; -} - -//! draws a 2d rectangle. -void CGUISkin::draw2DRectangle(IGUIElement *element, - const video::SColor &color, const core::rect &pos, - const core::rect *clip) -{ - Driver->draw2DRectangle(color, pos, clip); -} - -} // end namespace gui -} // end namespace irr diff --git a/irr/src/CGUISkin.h b/irr/src/CGUISkin.h deleted file mode 100644 index 68eae1c73..000000000 --- a/irr/src/CGUISkin.h +++ /dev/null @@ -1,233 +0,0 @@ -// Copyright (C) 2002-2012 Nikolaus Gebhardt -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in irrlicht.h - -#pragma once - -#include "IGUISkin.h" -#include "irrString.h" - -namespace irr -{ -namespace video -{ -class IVideoDriver; -} -namespace gui -{ - -class CGUISkin : public IGUISkin -{ -public: - CGUISkin(EGUI_SKIN_TYPE type, video::IVideoDriver *driver); - - //! destructor - virtual ~CGUISkin(); - - //! returns display density scaling factor - virtual float getScale() const override { return Scale; } - - //! sets display density scaling factor - virtual void setScale(float scale) override { Scale = scale; } - - //! returns default color - video::SColor getColor(EGUI_DEFAULT_COLOR color) const override; - - //! sets a default color - void setColor(EGUI_DEFAULT_COLOR which, video::SColor newColor) override; - - //! returns size for the given size type - s32 getSize(EGUI_DEFAULT_SIZE size) const override; - - //! sets a default size - void setSize(EGUI_DEFAULT_SIZE which, s32 size) override; - - //! returns the default font - IGUIFont *getFont(EGUI_DEFAULT_FONT which = EGDF_DEFAULT) const override; - - //! sets a default font - void setFont(IGUIFont *font, EGUI_DEFAULT_FONT which = EGDF_DEFAULT) override; - - //! sets the sprite bank used for drawing icons - void setSpriteBank(IGUISpriteBank *bank) override; - - //! gets the sprite bank used for drawing icons - IGUISpriteBank *getSpriteBank() const override; - - //! Returns a default icon - /** Returns the sprite index within the sprite bank */ - u32 getIcon(EGUI_DEFAULT_ICON icon) const override; - - //! Sets a default icon - /** Sets the sprite index used for drawing icons like arrows, - close buttons and ticks in checkboxes - \param icon: Enum specifying which icon to change - \param index: The sprite index used to draw this icon */ - void setIcon(EGUI_DEFAULT_ICON icon, u32 index) override; - - //! Returns a default text. - /** For example for Message box button captions: - "OK", "Cancel", "Yes", "No" and so on. */ - const wchar_t *getDefaultText(EGUI_DEFAULT_TEXT text) const override; - - //! Sets a default text. - /** For example for Message box button captions: - "OK", "Cancel", "Yes", "No" and so on. */ - void setDefaultText(EGUI_DEFAULT_TEXT which, const wchar_t *newText) override; - - //! draws a standard 3d button pane - /** Used for drawing for example buttons in normal state. - It uses the colors EGDC_3D_DARK_SHADOW, EGDC_3D_HIGH_LIGHT, EGDC_3D_SHADOW and - EGDC_3D_FACE for this. See EGUI_DEFAULT_COLOR for details. - \param rect: Defining area where to draw. - \param clip: Clip area. - \param element: Pointer to the element which wishes to draw this. This parameter - is usually not used by ISkin, but can be used for example by more complex - implementations to find out how to draw the part exactly. */ - virtual void draw3DButtonPaneStandard(IGUIElement *element, - const core::rect &rect, - const core::rect *clip = 0) override; - - //! draws a pressed 3d button pane - /** Used for drawing for example buttons in pressed state. - It uses the colors EGDC_3D_DARK_SHADOW, EGDC_3D_HIGH_LIGHT, EGDC_3D_SHADOW and - EGDC_3D_FACE for this. See EGUI_DEFAULT_COLOR for details. - \param rect: Defining area where to draw. - \param clip: Clip area. - \param element: Pointer to the element which wishes to draw this. This parameter - is usually not used by ISkin, but can be used for example by more complex - implementations to find out how to draw the part exactly. */ - virtual void draw3DButtonPanePressed(IGUIElement *element, - const core::rect &rect, - const core::rect *clip = 0) override; - - //! draws a sunken 3d pane - /** Used for drawing the background of edit, combo or check boxes. - \param element: Pointer to the element which wishes to draw this. This parameter - is usually not used by ISkin, but can be used for example by more complex - implementations to find out how to draw the part exactly. - \param bgcolor: Background color. - \param flat: Specifies if the sunken pane should be flat or displayed as sunken - deep into the ground. - \param rect: Defining area where to draw. - \param clip: Clip area. */ - virtual void draw3DSunkenPane(IGUIElement *element, - video::SColor bgcolor, bool flat, - bool fillBackGround, - const core::rect &rect, - const core::rect *clip = 0) override; - - //! draws a window background - /** Used for drawing the background of dialogs and windows. - \param element: Pointer to the element which wishes to draw this. This parameter - is usually not used by ISkin, but can be used for example by more complex - implementations to find out how to draw the part exactly. - \param titleBarColor: Title color. - \param drawTitleBar: True to enable title drawing. - \param rect: Defining area where to draw. - \param clip: Clip area. - \param checkClientArea: When set to non-null the function will not draw anything, - but will instead return the clientArea which can be used for drawing by the calling window. - That is the area without borders and without titlebar. - \return Returns rect where it would be good to draw title bar text. This will - work even when checkClientArea is set to a non-null value.*/ - virtual core::rect draw3DWindowBackground(IGUIElement *element, - bool drawTitleBar, video::SColor titleBarColor, - const core::rect &rect, - const core::rect *clip, - core::rect *checkClientArea) override; - - //! draws a standard 3d menu pane - /** Used for drawing for menus and context menus. - It uses the colors EGDC_3D_DARK_SHADOW, EGDC_3D_HIGH_LIGHT, EGDC_3D_SHADOW and - EGDC_3D_FACE for this. See EGUI_DEFAULT_COLOR for details. - \param element: Pointer to the element which wishes to draw this. This parameter - is usually not used by ISkin, but can be used for example by more complex - implementations to find out how to draw the part exactly. - \param rect: Defining area where to draw. - \param clip: Clip area. */ - virtual void draw3DMenuPane(IGUIElement *element, - const core::rect &rect, - const core::rect *clip = 0) override; - - //! draws a standard 3d tool bar - /** Used for drawing for toolbars and menus. - \param element: Pointer to the element which wishes to draw this. This parameter - is usually not used by ISkin, but can be used for example by more complex - implementations to find out how to draw the part exactly. - \param rect: Defining area where to draw. - \param clip: Clip area. */ - virtual void draw3DToolBar(IGUIElement *element, - const core::rect &rect, - const core::rect *clip = 0) override; - - //! draws a tab button - /** Used for drawing for tab buttons on top of tabs. - \param element: Pointer to the element which wishes to draw this. This parameter - is usually not used by ISkin, but can be used for example by more complex - implementations to find out how to draw the part exactly. - \param active: Specifies if the tab is currently active. - \param rect: Defining area where to draw. - \param clip: Clip area. */ - virtual void draw3DTabButton(IGUIElement *element, bool active, - const core::rect &rect, const core::rect *clip = 0, - EGUI_ALIGNMENT alignment = EGUIA_UPPERLEFT) override; - - //! draws a tab control body - /** \param element: Pointer to the element which wishes to draw this. This parameter - is usually not used by ISkin, but can be used for example by more complex - implementations to find out how to draw the part exactly. - \param border: Specifies if the border should be drawn. - \param background: Specifies if the background should be drawn. - \param rect: Defining area where to draw. - \param clip: Clip area. */ - virtual void draw3DTabBody(IGUIElement *element, bool border, bool background, - const core::rect &rect, const core::rect *clip = 0, s32 tabHeight = -1, - EGUI_ALIGNMENT alignment = EGUIA_UPPERLEFT) override; - - //! draws an icon, usually from the skin's sprite bank - /** \param element: Pointer to the element which wishes to draw this icon. - This parameter is usually not used by IGUISkin, but can be used for example - by more complex implementations to find out how to draw the part exactly. - \param icon: Specifies the icon to be drawn. - \param position: The position to draw the icon - \param starttime: The time at the start of the animation - \param currenttime: The present time, used to calculate the frame number - \param loop: Whether the animation should loop or not - \param clip: Clip area. */ - virtual void drawIcon(IGUIElement *element, EGUI_DEFAULT_ICON icon, - const core::position2di position, - u32 starttime = 0, u32 currenttime = 0, - bool loop = false, const core::rect *clip = 0) override; - - //! draws a 2d rectangle. - /** \param element: Pointer to the element which wishes to draw this icon. - This parameter is usually not used by IGUISkin, but can be used for example - by more complex implementations to find out how to draw the part exactly. - \param color: Color of the rectangle to draw. The alpha component specifies how - transparent the rectangle will be. - \param pos: Position of the rectangle. - \param clip: Pointer to rectangle against which the rectangle will be clipped. - If the pointer is null, no clipping will be performed. */ - virtual void draw2DRectangle(IGUIElement *element, const video::SColor &color, - const core::rect &pos, const core::rect *clip = 0) override; - - //! get the type of this skin - EGUI_SKIN_TYPE getType() const override; - -private: - float Scale = 1.0f; - video::SColor Colors[EGDC_COUNT]; - s32 Sizes[EGDS_COUNT]; - u32 Icons[EGDI_COUNT]; - IGUIFont *Fonts[EGDF_COUNT]; - IGUISpriteBank *SpriteBank; - core::stringw Texts[EGDT_COUNT]; - video::IVideoDriver *Driver; - bool UseGradient; - - EGUI_SKIN_TYPE Type; -}; - -} // end namespace gui -} // end namespace irr From 2208fc06321d476f5c7066de9bc538bba6f94dcd Mon Sep 17 00:00:00 2001 From: Gregor Parzefall Date: Fri, 6 Sep 2024 21:05:38 +0200 Subject: [PATCH 17/67] Move Minetest GUISkin -> Irrlicht CGUISkin --- irr/include/IGUISkin.h | 8 +++ src/gui/guiSkin.cpp => irr/src/CGUISkin.cpp | 56 +++++++++---------- src/gui/guiSkin.h => irr/src/CGUISkin.h | 60 ++------------------- src/client/renderingengine.cpp | 27 ---------- src/gui/CMakeLists.txt | 1 - src/gui/guiButton.cpp | 4 +- src/gui/guiButton.h | 1 - 7 files changed, 42 insertions(+), 115 deletions(-) rename src/gui/guiSkin.cpp => irr/src/CGUISkin.cpp (94%) rename src/gui/guiSkin.h => irr/src/CGUISkin.h (89%) diff --git a/irr/include/IGUISkin.h b/irr/include/IGUISkin.h index 36b510606..b323983ae 100644 --- a/irr/include/IGUISkin.h +++ b/irr/include/IGUISkin.h @@ -437,6 +437,10 @@ public: virtual void draw3DButtonPaneStandard(IGUIElement *element, const core::rect &rect, const core::rect *clip = 0) = 0; + virtual void drawColored3DButtonPaneStandard(IGUIElement* element, + const core::rect& rect, + const core::rect* clip=0, + const video::SColor* colors=0) = 0; //! draws a pressed 3d button pane /** Used for drawing for example buttons in pressed state. @@ -450,6 +454,10 @@ public: virtual void draw3DButtonPanePressed(IGUIElement *element, const core::rect &rect, const core::rect *clip = 0) = 0; + virtual void drawColored3DButtonPanePressed(IGUIElement* element, + const core::rect& rect, + const core::rect* clip=0, + const video::SColor* colors=0) = 0; //! draws a sunken 3d pane /** Used for drawing the background of edit, combo or check boxes. diff --git a/src/gui/guiSkin.cpp b/irr/src/CGUISkin.cpp similarity index 94% rename from src/gui/guiSkin.cpp rename to irr/src/CGUISkin.cpp index 0ecc80f02..e9721a5fa 100644 --- a/src/gui/guiSkin.cpp +++ b/irr/src/CGUISkin.cpp @@ -4,7 +4,7 @@ // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h -#include "guiSkin.h" +#include "CGUISkin.h" #include "IGUIFont.h" #include "IGUISpriteBank.h" @@ -17,11 +17,11 @@ namespace irr namespace gui { -GUISkin::GUISkin(EGUI_SKIN_TYPE type, video::IVideoDriver* driver) +CGUISkin::CGUISkin(EGUI_SKIN_TYPE type, video::IVideoDriver* driver) : SpriteBank(0), Driver(driver), Type(type) { #ifdef _DEBUG - setDebugName("GUISkin"); + setDebugName("CGUISkin"); #endif if ((Type == EGST_WINDOWS_CLASSIC) || (Type == EGST_WINDOWS_METALLIC)) @@ -167,7 +167,7 @@ GUISkin::GUISkin(EGUI_SKIN_TYPE type, video::IVideoDriver* driver) //! destructor -GUISkin::~GUISkin() +CGUISkin::~CGUISkin() { for (u32 i=0; i= EGDF_COUNT) return; @@ -244,14 +244,14 @@ void GUISkin::setFont(IGUIFont* font, EGUI_DEFAULT_FONT which) //! gets the sprite bank stored -IGUISpriteBank* GUISkin::getSpriteBank() const +IGUISpriteBank* CGUISkin::getSpriteBank() const { return SpriteBank; } //! set a new sprite bank or remove one by passing 0 -void GUISkin::setSpriteBank(IGUISpriteBank* bank) +void CGUISkin::setSpriteBank(IGUISpriteBank* bank) { if (bank) bank->grab(); @@ -264,7 +264,7 @@ void GUISkin::setSpriteBank(IGUISpriteBank* bank) //! Returns a default icon -u32 GUISkin::getIcon(EGUI_DEFAULT_ICON icon) const +u32 CGUISkin::getIcon(EGUI_DEFAULT_ICON icon) const { if ((u32)icon < EGDI_COUNT) return Icons[icon]; @@ -274,7 +274,7 @@ u32 GUISkin::getIcon(EGUI_DEFAULT_ICON icon) const //! Sets a default icon -void GUISkin::setIcon(EGUI_DEFAULT_ICON icon, u32 index) +void CGUISkin::setIcon(EGUI_DEFAULT_ICON icon, u32 index) { if ((u32)icon < EGDI_COUNT) Icons[icon] = index; @@ -283,7 +283,7 @@ void GUISkin::setIcon(EGUI_DEFAULT_ICON icon, u32 index) //! Returns a default text. For example for Message box button captions: //! "OK", "Cancel", "Yes", "No" and so on. -const wchar_t* GUISkin::getDefaultText(EGUI_DEFAULT_TEXT text) const +const wchar_t* CGUISkin::getDefaultText(EGUI_DEFAULT_TEXT text) const { if ((u32)text < EGDT_COUNT) return Texts[text].c_str(); @@ -294,7 +294,7 @@ const wchar_t* GUISkin::getDefaultText(EGUI_DEFAULT_TEXT text) const //! Sets a default text. For example for Message box button captions: //! "OK", "Cancel", "Yes", "No" and so on. -void GUISkin::setDefaultText(EGUI_DEFAULT_TEXT which, const wchar_t* newText) +void CGUISkin::setDefaultText(EGUI_DEFAULT_TEXT which, const wchar_t* newText) { if ((u32)which < EGDT_COUNT) Texts[which] = newText; @@ -311,7 +311,7 @@ EGDC_3D_FACE for this. See EGUI_DEFAULT_COLOR for details. is usually not used by ISkin, but can be used for example by more complex implementations to find out how to draw the part exactly. */ // PATCH -void GUISkin::drawColored3DButtonPaneStandard(IGUIElement* element, +void CGUISkin::drawColored3DButtonPaneStandard(IGUIElement* element, const core::rect& r, const core::rect* clip, const video::SColor* colors) @@ -373,7 +373,7 @@ EGDC_3D_FACE for this. See EGUI_DEFAULT_COLOR for details. is usually not used by ISkin, but can be used for example by more complex implementations to find out how to draw the part exactly. */ // PATCH -void GUISkin::drawColored3DButtonPanePressed(IGUIElement* element, +void CGUISkin::drawColored3DButtonPanePressed(IGUIElement* element, const core::rect& r, const core::rect* clip, const video::SColor* colors) @@ -423,7 +423,7 @@ deep into the ground. \param rect: Defining area where to draw. \param clip: Clip area. */ // PATCH -void GUISkin::drawColored3DSunkenPane(IGUIElement* element, video::SColor bgcolor, +void CGUISkin::drawColored3DSunkenPane(IGUIElement* element, video::SColor bgcolor, bool flat, bool fillBackGround, const core::rect& r, const core::rect* clip, @@ -512,7 +512,7 @@ void GUISkin::drawColored3DSunkenPane(IGUIElement* element, video::SColor bgcolo //! draws a window background // return where to draw title bar text. // PATCH -core::rect GUISkin::drawColored3DWindowBackground(IGUIElement* element, +core::rect CGUISkin::drawColored3DWindowBackground(IGUIElement* element, bool drawTitleBar, video::SColor titleBarColor, const core::rect& r, const core::rect* clip, @@ -667,7 +667,7 @@ implementations to find out how to draw the part exactly. \param rect: Defining area where to draw. \param clip: Clip area. */ // PATCH -void GUISkin::drawColored3DMenuPane(IGUIElement* element, +void CGUISkin::drawColored3DMenuPane(IGUIElement* element, const core::rect& r, const core::rect* clip, const video::SColor* colors) { @@ -751,7 +751,7 @@ implementations to find out how to draw the part exactly. \param rect: Defining area where to draw. \param clip: Clip area. */ // PATCH -void GUISkin::drawColored3DToolBar(IGUIElement* element, +void CGUISkin::drawColored3DToolBar(IGUIElement* element, const core::rect& r, const core::rect* clip, const video::SColor* colors) @@ -804,7 +804,7 @@ implementations to find out how to draw the part exactly. \param rect: Defining area where to draw. \param clip: Clip area. */ // PATCH -void GUISkin::drawColored3DTabButton(IGUIElement* element, bool active, +void CGUISkin::drawColored3DTabButton(IGUIElement* element, bool active, const core::rect& frameRect, const core::rect* clip, EGUI_ALIGNMENT alignment, const video::SColor* colors) { @@ -891,7 +891,7 @@ implementations to find out how to draw the part exactly. \param rect: Defining area where to draw. \param clip: Clip area. */ // PATCH -void GUISkin::drawColored3DTabBody(IGUIElement* element, bool border, bool background, +void CGUISkin::drawColored3DTabBody(IGUIElement* element, bool border, bool background, const core::rect& rect, const core::rect* clip, s32 tabHeight, EGUI_ALIGNMENT alignment, const video::SColor* colors) { @@ -989,7 +989,7 @@ by more complex implementations to find out how to draw the part exactly. \param loop: Whether the animation should loop or not \param clip: Clip area. */ // PATCH -void GUISkin::drawColoredIcon(IGUIElement* element, EGUI_DEFAULT_ICON icon, +void CGUISkin::drawColoredIcon(IGUIElement* element, EGUI_DEFAULT_ICON icon, const core::position2di position, u32 starttime, u32 currenttime, bool loop, const core::rect* clip, @@ -1008,14 +1008,14 @@ void GUISkin::drawColoredIcon(IGUIElement* element, EGUI_DEFAULT_ICON icon, // END PATCH -EGUI_SKIN_TYPE GUISkin::getType() const +EGUI_SKIN_TYPE CGUISkin::getType() const { return Type; } //! draws a 2d rectangle. -void GUISkin::draw2DRectangle(IGUIElement* element, +void CGUISkin::draw2DRectangle(IGUIElement* element, const video::SColor &color, const core::rect& pos, const core::rect* clip) { @@ -1025,7 +1025,7 @@ void GUISkin::draw2DRectangle(IGUIElement* element, //! gets the colors // PATCH -void GUISkin::getColors(video::SColor* colors) +void CGUISkin::getColors(video::SColor* colors) { u32 i; for (i=0; isetColor(EGDC_3D_FACE, button_color); \ - skin->setColor(EGDC_3D_DARK_SHADOW, button_color, 0.25f); \ - skin->setColor(EGDC_3D_SHADOW, button_color, 0.5f); \ - skin->setColor(EGDC_3D_LIGHT, button_color); \ - skin->setColor(EGDC_3D_HIGH_LIGHT, button_color, 1.5f); \ - } - - #define getElementSkinColor(color) \ - { \ - if (!Colors) \ - { \ - IGUISkin* skin = Environment->getSkin(); \ - if (skin) \ - return skin->getColor(color); \ - } \ - return Colors[color]; \ - } - - #define setElementSkinColor(which, newColor, shading) \ - { \ - if (!Colors) \ - { \ - Colors = new video::SColor[EGDC_COUNT]; \ - GUISkin* skin = (GUISkin *)Environment->getSkin(); \ - if (skin) \ - skin->getColors(Colors); \ - } \ - Colors[which] = newColor; \ - setShading(Colors[which],shading); \ - } } // end namespace gui -//! Sets the shading -inline void setShading(video::SColor &color,f32 s) // :PATCH: -{ - if (s < 1.0f) - { - color.setRed(color.getRed() * s); - color.setGreen(color.getGreen() * s); - color.setBlue(color.getBlue() * s); - } - else if (s > 1.0f) - { - s -= 1.0f; - - color.setRed(color.getRed() + (255 - color.getRed()) * s); - color.setGreen(color.getGreen() + (255 - color.getGreen()) * s); - color.setBlue(color.getBlue() + (255 - color.getBlue()) * s); - } -} } // end namespace irr -#endif diff --git a/src/client/renderingengine.cpp b/src/client/renderingengine.cpp index 4400dd90e..c4933e062 100644 --- a/src/client/renderingengine.cpp +++ b/src/client/renderingengine.cpp @@ -36,7 +36,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "inputhandler.h" #include "gettext.h" #include "filesys.h" -#include "../gui/guiSkin.h" #include "irrlicht_changes/static_text.h" #include "irr_ptr.h" @@ -126,27 +125,6 @@ IShaderConstantSetter *FogShaderConstantSetterFactory::create() /* Other helpers */ -static gui::GUISkin *createSkin(gui::IGUIEnvironment *environment, - gui::EGUI_SKIN_TYPE type, video::IVideoDriver *driver) -{ - gui::GUISkin *skin = new gui::GUISkin(type, driver); - - gui::IGUIFont *builtinfont = environment->getBuiltInFont(); - gui::IGUIFontBitmap *bitfont = nullptr; - if (builtinfont && builtinfont->getType() == gui::EGFT_BITMAP) - bitfont = (gui::IGUIFontBitmap*)builtinfont; - - gui::IGUISpriteBank *bank = 0; - skin->setFont(builtinfont); - - if (bitfont) - bank = bitfont->getSpriteBank(); - - skin->setSpriteBank(bank); - - return skin; -} - static std::optional chooseVideoDriver() { auto &&configured_name = g_settings->get("video_driver"); @@ -250,11 +228,6 @@ RenderingEngine::RenderingEngine(IEventReceiver *receiver) s_singleton = this; - auto skin = createSkin(m_device->getGUIEnvironment(), - gui::EGST_WINDOWS_METALLIC, driver); - m_device->getGUIEnvironment()->setSkin(skin); - skin->drop(); - g_settings->registerChangedCallback("fullscreen", settingChangedCallback, this); g_settings->registerChangedCallback("window_maximized", settingChangedCallback, this); } diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 73bbecb02..04a03609d 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -19,7 +19,6 @@ set(gui_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/guiScene.cpp ${CMAKE_CURRENT_SOURCE_DIR}/guiScrollBar.cpp ${CMAKE_CURRENT_SOURCE_DIR}/guiScrollContainer.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/guiSkin.cpp ${CMAKE_CURRENT_SOURCE_DIR}/guiTable.cpp ${CMAKE_CURRENT_SOURCE_DIR}/guiHyperText.cpp ${CMAKE_CURRENT_SOURCE_DIR}/guiVolumeChange.cpp diff --git a/src/gui/guiButton.cpp b/src/gui/guiButton.cpp index d78433edd..9592ba922 100644 --- a/src/gui/guiButton.cpp +++ b/src/gui/guiButton.cpp @@ -253,8 +253,8 @@ void GUIButton::draw() setFromState(); } - GUISkin* skin = dynamic_cast(Environment->getSkin()); video::IVideoDriver* driver = Environment->getVideoDriver(); + IGUISkin *skin = Environment->getSkin(); // END PATCH if (DrawBorder) @@ -737,7 +737,7 @@ void GUIButton::setFromStyle(const StyleSpec& style) Padding.UpperLeftCorner + BgMiddle.UpperLeftCorner, Padding.LowerRightCorner + BgMiddle.LowerRightCorner); - GUISkin* skin = dynamic_cast(Environment->getSkin()); + IGUISkin *skin = Environment->getSkin(); core::vector2d defaultPressOffset( skin->getSize(irr::gui::EGDS_BUTTON_PRESSED_IMAGE_OFFSET_X), skin->getSize(irr::gui::EGDS_BUTTON_PRESSED_IMAGE_OFFSET_Y)); diff --git a/src/gui/guiButton.h b/src/gui/guiButton.h index 4fad8747c..dd71788ba 100644 --- a/src/gui/guiButton.h +++ b/src/gui/guiButton.h @@ -10,7 +10,6 @@ #include "IGUISpriteBank.h" #include "ITexture.h" #include "SColor.h" -#include "guiSkin.h" #include "StyleSpec.h" using namespace irr; From 733a019bf5aefddb824e5643b791ca25fc620b03 Mon Sep 17 00:00:00 2001 From: sfence Date: Sun, 8 Sep 2024 13:53:43 +0200 Subject: [PATCH 18/67] macOS: make mute sound actually work (#15128) --- src/client/sound/sound_manager.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/client/sound/sound_manager.cpp b/src/client/sound/sound_manager.cpp index 679d3a155..6aae5bb7f 100644 --- a/src/client/sound/sound_manager.cpp +++ b/src/client/sound/sound_manager.cpp @@ -29,6 +29,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "filesys.h" #include "porting.h" +#include + namespace sound { void OpenALSoundManager::stepStreams(f32 dtime) @@ -347,6 +349,13 @@ void OpenALSoundManager::updateListener(const v3f &pos_, const v3f &vel_, void OpenALSoundManager::setListenerGain(f32 gain) { +#if defined(__APPLE__) + /* macOS OpenAL implementation ignore setting AL_GAIN to zero + * so we use smallest possible value + */ + if (gain == 0.0f) + gain = std::numeric_limits::min(); +#endif alListenerf(AL_GAIN, gain); } From 8617993386991eef6ff9735f7858cb96b959018f Mon Sep 17 00:00:00 2001 From: sfence Date: Thu, 12 Sep 2024 23:40:03 +0200 Subject: [PATCH 19/67] Add SDL2 options to compiling README (#15136) --- README.md | 1 + doc/compiling/README.md | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/README.md b/README.md index 5724359d6..919cb144c 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,7 @@ Command-line options Compiling --------- +- [Compiling - common information](doc/compiling/README.md) - [Compiling on GNU/Linux](doc/compiling/linux.md) - [Compiling on Windows](doc/compiling/windows.md) - [Compiling on MacOS](doc/compiling/macos.md) diff --git a/doc/compiling/README.md b/doc/compiling/README.md index a1ab1ebbd..c394b2be0 100644 --- a/doc/compiling/README.md +++ b/doc/compiling/README.md @@ -22,6 +22,7 @@ General options and their default values: MinSizeRel - Release build with -Os passed to compiler to make executable as small as possible PRECOMPILE_HEADERS=FALSE - Precompile some headers (experimental; requires CMake 3.16 or later) PRECOMPILED_HEADERS_PATH= - Path to a file listing all headers to precompile (default points to src/precompiled_headers.txt) + USE_SDL2=TRUE - Build with SDL2; Enables IrrlichtMt device SDL2 ENABLE_CURL=ON - Build with cURL; Enables use of online mod repo, public serverlist and remote media fetching via http ENABLE_CURSES=ON - Build with (n)curses; Enables a server side terminal (command line option: --terminal) ENABLE_GETTEXT=ON - Build with Gettext; Allows using translations @@ -43,6 +44,9 @@ General options and their default values: Library specific options: + SDL2_DLL - Only if building with SDL2 on Windows; path to libSDL2.dll + SDL2_INCLUDE_DIRS - Only if building with SDL2; directory where SDL.h is located + SDL2_LIBRARIES - Only if building with SDL2; path to libSDL2.a/libSDL2.so/libSDL2.lib CURL_DLL - Only if building with cURL on Windows; path to libcurl.dll CURL_INCLUDE_DIR - Only if building with cURL; directory where curl.h is located CURL_LIBRARY - Only if building with cURL; path to libcurl.a/libcurl.so/libcurl.lib From af67353f7aee3d7b6a5d7dcc42784f98f0c935b8 Mon Sep 17 00:00:00 2001 From: grorp Date: Thu, 12 Sep 2024 23:41:47 +0200 Subject: [PATCH 20/67] Only apply "touch_punch_gesture" when wielded item has no on_use callback (#15098) --- doc/lua_api.md | 10 +++++++++- src/client/game.cpp | 2 +- src/itemdef.cpp | 7 +++++-- src/itemdef.h | 3 ++- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/doc/lua_api.md b/doc/lua_api.md index ea728cfbe..f50ea0cb5 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -9337,9 +9337,17 @@ Used by `minetest.register_node`, `minetest.register_craftitem`, and -- If specified as a table, the field to be used is selected according to -- the current `pointed_thing`. -- There are three possible TouchInteractionMode values: - -- * "user" (meaning depends on client-side settings) -- * "long_dig_short_place" (long tap = dig, short tap = place) -- * "short_dig_long_place" (short tap = dig, long tap = place) + -- * "user": + -- * For `pointed_object`: Equivalent to "short_dig_long_place" if the + -- client-side setting "touch_punch_gesture" is "short_tap" (the + -- default value) and the item is able to punch (i.e. has no on_use + -- callback defined). + -- Equivalent to "long_dig_short_place" otherwise. + -- * For `pointed_node` and `pointed_nothing`: + -- Equivalent to "long_dig_short_place". + -- * The behavior of "user" may change in the future. -- The default value is "user". sound = { diff --git a/src/client/game.cpp b/src/client/game.cpp index 5855be96f..36cb5f4bb 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -3357,7 +3357,7 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud) infostream << "Pointing at " << pointed.dump() << std::endl; if (g_touchcontrols) { - auto mode = selected_def.touch_interaction.getMode(pointed.type); + auto mode = selected_def.touch_interaction.getMode(selected_def, pointed.type); g_touchcontrols->applyContextControls(mode); // applyContextControls may change dig/place input. // Update again so that TOSERVER_INTERACT packets have the correct controls set. diff --git a/src/itemdef.cpp b/src/itemdef.cpp index ad2ed4847..220c6fbb6 100644 --- a/src/itemdef.cpp +++ b/src/itemdef.cpp @@ -45,7 +45,8 @@ TouchInteraction::TouchInteraction() pointed_object = TouchInteractionMode_USER; } -TouchInteractionMode TouchInteraction::getMode(PointedThingType pointed_type) const +TouchInteractionMode TouchInteraction::getMode(const ItemDefinition &selected_def, + PointedThingType pointed_type) const { TouchInteractionMode result; switch (pointed_type) { @@ -63,7 +64,9 @@ TouchInteractionMode TouchInteraction::getMode(PointedThingType pointed_type) co } if (result == TouchInteractionMode_USER) { - if (pointed_type == POINTEDTHING_OBJECT) + if (pointed_type == POINTEDTHING_OBJECT && !selected_def.usable) + // Only apply when we're actually able to punch the object, i.e. when + // the selected item has no on_use callback defined. result = g_settings->get("touch_punch_gesture") == "long_tap" ? LONG_DIG_SHORT_PLACE : SHORT_DIG_LONG_PLACE; else diff --git a/src/itemdef.h b/src/itemdef.h index 4a227ebe1..44fab8d91 100644 --- a/src/itemdef.h +++ b/src/itemdef.h @@ -71,7 +71,8 @@ struct TouchInteraction TouchInteraction(); // Returns the right mode for the pointed thing and resolves any occurrence // of TouchInteractionMode_USER into an actual mode. - TouchInteractionMode getMode(PointedThingType pointed_type) const; + TouchInteractionMode getMode(const ItemDefinition &selected_def, + PointedThingType pointed_type) const; void serialize(std::ostream &os) const; void deSerialize(std::istream &is); }; From 9c2b2c002cbb2f68822098878cdabc895b2458f1 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Fri, 30 Aug 2024 15:39:43 +0200 Subject: [PATCH 21/67] Count duplicate packets as congestion indicator --- src/network/mtp/impl.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/network/mtp/impl.cpp b/src/network/mtp/impl.cpp index 00535945e..96baffaf4 100644 --- a/src/network/mtp/impl.cpp +++ b/src/network/mtp/impl.cpp @@ -739,16 +739,16 @@ void Channel::UpdateTimers(float dtime) if (packet_loss_counter > 1.0f) { packet_loss_counter -= 1.0f; - unsigned int packet_loss = 11; /* use a neutral value for initialization */ - unsigned int packets_successful = 0; - //unsigned int packet_too_late = 0; + unsigned int packet_loss; + unsigned int packets_successful; + unsigned int packet_too_late; bool reasonable_amount_of_data_transmitted = false; { MutexAutoLock internal(m_internal_mutex); packet_loss = current_packet_loss; - //packet_too_late = current_packet_too_late; + packet_too_late = current_packet_too_late; packets_successful = current_packet_successful; if (current_bytes_transfered > (unsigned int) (m_window_size*512/2)) { @@ -759,6 +759,11 @@ void Channel::UpdateTimers(float dtime) current_packet_successful = 0; } + // Packets too late means either packet duplication along the way + // or we were too fast in resending it (which should be self-regulating). + // Count this a signal of congestion, like packet loss. + packet_loss = std::min(packet_loss + packet_too_late, packets_successful); + /* dynamic window size */ float successful_to_lost_ratio = 0.0f; bool done = false; From 42af7cc1c5257fee8d437bc9c241cb260e8f8c46 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Fri, 30 Aug 2024 15:58:02 +0200 Subject: [PATCH 22/67] Nerf protocol window sizes Probably due to a unit misunderstanding a long time ago the window sizes were quite insane (especially the default). In practice this was sometimes hidden by other bugs, games trying their best to be lightweight or didn't matter on high-quality internet connections. --- src/network/mtp/impl.cpp | 1 + src/network/mtp/internal.h | 17 +++++++++++++---- src/network/mtp/threads.cpp | 1 + 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/network/mtp/impl.cpp b/src/network/mtp/impl.cpp index 96baffaf4..483765ea4 100644 --- a/src/network/mtp/impl.cpp +++ b/src/network/mtp/impl.cpp @@ -751,6 +751,7 @@ void Channel::UpdateTimers(float dtime) packet_too_late = current_packet_too_late; packets_successful = current_packet_successful; + // has half the window even been used? if (current_bytes_transfered > (unsigned int) (m_window_size*512/2)) { reasonable_amount_of_data_transmitted = true; } diff --git a/src/network/mtp/internal.h b/src/network/mtp/internal.h index f6ab1f159..4cf6cb57a 100644 --- a/src/network/mtp/internal.h +++ b/src/network/mtp/internal.h @@ -354,15 +354,24 @@ private: static ConnectionCommandPtr create(ConnectionCommandType type); }; -/* maximum window size to use, 0xFFFF is theoretical maximum. don't think about +/* + * Window sizes to use, in packets (not bytes!). + * 0xFFFF is theoretical maximum. don't think about * touching it, the less you're away from it the more likely data corruption * will occur + * + * Note: window sizes directly translate to maximum possible throughput, e.g. + * (2048 * 512 bytes) / 33ms = 15 MiB/s */ + +// Due to backwards compatibility we have different window sizes for what we'll +// accept from peers vs. what we use for sending. #define MAX_RELIABLE_WINDOW_SIZE 0x8000 +#define MAX_RELIABLE_WINDOW_SIZE_SEND 2048 /* starting value for window size */ -#define START_RELIABLE_WINDOW_SIZE 0x400 +#define START_RELIABLE_WINDOW_SIZE 64 /* minimum value for window size */ -#define MIN_RELIABLE_WINDOW_SIZE 0x40 +#define MIN_RELIABLE_WINDOW_SIZE 32 class Channel { @@ -430,7 +439,7 @@ public: void setWindowSize(long size) { - m_window_size = (u16)rangelim(size, MIN_RELIABLE_WINDOW_SIZE, MAX_RELIABLE_WINDOW_SIZE); + m_window_size = (u16)rangelim(size, MIN_RELIABLE_WINDOW_SIZE, MAX_RELIABLE_WINDOW_SIZE_SEND); } private: diff --git a/src/network/mtp/threads.cpp b/src/network/mtp/threads.cpp index d1a1e2a34..778c771f3 100644 --- a/src/network/mtp/threads.cpp +++ b/src/network/mtp/threads.cpp @@ -327,6 +327,7 @@ void ConnectionSendThread::sendAsPacketReliable(BufferedPacketPtr &p, Channel *c channel->outgoing_reliables_sent.insert(p, (channel->readOutgoingSequenceNumber() - MAX_RELIABLE_WINDOW_SIZE) % (MAX_RELIABLE_WINDOW_SIZE + 1)); + // wtf is this calculation?? ^ } catch (AlreadyExistsException &e) { LOG(derr_con << m_connection->getDesc() From f54f2c1601b7fb23e2bd3cd576f18b0f5d2fc3b3 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sat, 31 Aug 2024 17:30:37 +0200 Subject: [PATCH 23/67] Fix RTT set before value is available --- src/network/mtp/impl.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/network/mtp/impl.cpp b/src/network/mtp/impl.cpp index 483765ea4..22c3f9804 100644 --- a/src/network/mtp/impl.cpp +++ b/src/network/mtp/impl.cpp @@ -995,13 +995,15 @@ bool UDPPeer::isTimedOut(float timeout, std::string &reason) void UDPPeer::reportRTT(float rtt) { - if (rtt < 0.0) { + if (rtt < 0) return; - } RTTStatistics(rtt,"rudp",MAX_RELIABLE_WINDOW_SIZE*10); // use this value to decide the resend timeout - float timeout = getStat(AVG_RTT) * RESEND_TIMEOUT_FACTOR; + const float rtt_stat = getStat(AVG_RTT); + if (rtt_stat < 0) + return; + float timeout = rtt_stat * RESEND_TIMEOUT_FACTOR; if (timeout < RESEND_TIMEOUT_MIN) timeout = RESEND_TIMEOUT_MIN; if (timeout > RESEND_TIMEOUT_MAX) From 72c306d92053bb4079488e0eb67e1b88188b1d63 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sat, 31 Aug 2024 17:16:48 +0200 Subject: [PATCH 24/67] Improve some protocol code log messages also get rid of the very noisy socket debug message that are useless in a world where Wireshark exists. --- src/main.cpp | 1 - src/network/mtp/impl.cpp | 8 ++++- src/network/mtp/threads.cpp | 37 ++++++++++----------- src/network/socket.cpp | 64 ------------------------------------- src/network/socket.h | 2 -- 5 files changed, 26 insertions(+), 86 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 9f358bb66..30db81aa9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -531,7 +531,6 @@ static bool setup_log_params(const Settings &cmd_args) if (cmd_args.getFlag("trace")) { dstream << _("Enabling trace level debug output") << std::endl; g_logger.addOutput(&stderr_output, LL_TRACE); - socket_enable_debug_output = true; } return true; diff --git a/src/network/mtp/impl.cpp b/src/network/mtp/impl.cpp index 22c3f9804..1ef5eb853 100644 --- a/src/network/mtp/impl.cpp +++ b/src/network/mtp/impl.cpp @@ -1009,7 +1009,13 @@ void UDPPeer::reportRTT(float rtt) if (timeout > RESEND_TIMEOUT_MAX) timeout = RESEND_TIMEOUT_MAX; + float timeout_old = getResendTimeout(); setResendTimeout(timeout); + + if (std::abs(timeout - timeout_old) >= 0.001f) { + dout_con << m_connection->getDesc() << " set resend timeout " << timeout + << " (rtt=" << rtt_stat << ") for peer id: " << id << std::endl; + } } bool UDPPeer::Ping(float dtime,SharedBuffer& data) @@ -1129,7 +1135,7 @@ bool UDPPeer::processReliableSendCommand( u16 packets_available = toadd.size(); /* we didn't get a single sequence number no need to fill queue */ if (!have_initial_sequence_number) { - LOG(derr_con << m_connection->getDesc() << "Ran out of sequence numbers!" << std::endl); + dout_con << m_connection->getDesc() << " No sequence numbers available!" << std::endl; return false; } diff --git a/src/network/mtp/threads.cpp b/src/network/mtp/threads.cpp index 778c771f3..50b7fa1e3 100644 --- a/src/network/mtp/threads.cpp +++ b/src/network/mtp/threads.cpp @@ -35,7 +35,6 @@ namespace con #define PROFILE(a) #undef DEBUG_CONNECTION_KBPS #else -/* this mutex is used to achieve log message consistency */ #define PROFILE(a) a //#define DEBUG_CONNECTION_KBPS #undef DEBUG_CONNECTION_KBPS @@ -221,7 +220,8 @@ void ConnectionSendThread::runTimeouts(float dtime, u32 peer_packet_quota) } float resend_timeout = udpPeer->getResendTimeout(); - for (Channel &channel : udpPeer->channels) { + for (int ch = 0; ch < CHANNEL_COUNT; ch++) { + auto &channel = udpPeer->channels[ch]; // Remove timed out incomplete unreliable split packets channel.incoming_splits.removeUnreliableTimedOuts(dtime, peer_timeout); @@ -242,8 +242,8 @@ void ConnectionSendThread::runTimeouts(float dtime, u32 peer_packet_quota) if (!timed_outs.empty()) { dout_con << m_connection->getDesc() << "Skipping re-send of " << timed_outs.size() << - " timed-out reliables to peer_id " << udpPeer->id - << " (half-open)." << std::endl; + " timed-out reliables to peer_id=" << udpPeer->id + << " channel=" << ch << " (half-open)." << std::endl; } continue; } @@ -256,7 +256,14 @@ void ConnectionSendThread::runTimeouts(float dtime, u32 peer_packet_quota) for (const auto &k : timed_outs) resendReliable(channel, k.get(), resend_timeout); + auto ws_old = channel.getWindowSize(); channel.UpdateTimers(dtime); + auto ws_new = channel.getWindowSize(); + if (ws_old != ws_new) { + dout_con << m_connection->getDesc() << + "Window size adjusted to " << ws_new << " for peer_id=" + << udpPeer->id << " channel=" << ch << std::endl; + } } /* send ping if necessary */ @@ -309,12 +316,12 @@ void ConnectionSendThread::rawSend(const BufferedPacket *p) assert(p); try { m_connection->m_udpSocket.Send(p->address, p->data, p->size()); - LOG(dout_con << m_connection->getDesc() - << " rawSend: " << p->size() - << " bytes sent" << std::endl); + //LOG(dout_con << m_connection->getDesc() + // << " rawSend: " << p->size() + // << " bytes sent" << std::endl); } catch (SendFailedException &e) { LOG(derr_con << m_connection->getDesc() - << "Connection::rawSend(): SendFailedException: " + << "SendFailedException: " << e.what() << " to " << p->address.serializeString() << std::endl); } } @@ -686,9 +693,9 @@ void ConnectionSendThread::sendPackets(float dtime, u32 peer_packet_quota) PROFILE(ScopeProfiler peerprofiler(g_profiler, peerIdentifier.str(), SPT_AVG)); - LOG(dout_con << m_connection->getDesc() - << " Handle per peer queues: peer_id=" << peerId - << " packet quota: " << peer->m_increment_packets_remaining << std::endl); + //LOG(dout_con << m_connection->getDesc() + // << " Handle per peer queues: peer_id=" << peerId + // << " packet quota: " << peer->m_increment_packets_remaining << std::endl); // first send queued reliable packets for all peers (if possible) for (unsigned int i = 0; i < CHANNEL_COUNT; i++) { @@ -1191,7 +1198,7 @@ SharedBuffer ConnectionReceiveThread::handlePacketType_Control(Channel *chan // an overflow is quite unlikely but as it'd result in major // rtt miscalculation we handle it here if (current_time > p->absolute_send_time) { - float rtt = (current_time - p->absolute_send_time) / 1000.0; + float rtt = (current_time - p->absolute_send_time) / 1000.0f; // Let peer calculate stuff according to it // (avg_rtt and resend_timeout) @@ -1336,12 +1343,6 @@ SharedBuffer ConnectionReceiveThread::handlePacketType_Reliable(Channel *cha << ", seqnum: " << seqnum << std::endl;) m_connection->sendAck(peer->id, channelnum, seqnum); - // we already have this packet so this one was on wire at least - // the current timeout - // we don't know how long this packet was on wire don't do silly guessing - // dynamic_cast(&peer)-> - // reportRTT(dynamic_cast(&peer)->getResendTimeout()); - throw ProcessedSilentlyException("Retransmitting ack for old packet"); } } diff --git a/src/network/socket.cpp b/src/network/socket.cpp index 9fbbaa34e..17e71d860 100644 --- a/src/network/socket.cpp +++ b/src/network/socket.cpp @@ -50,9 +50,6 @@ typedef int socklen_t; #define SOCKET_ERR_STR(e) strerror(e) #endif -// Set to true to enable verbose debug output -bool socket_enable_debug_output = false; // yuck - static bool g_sockets_initialized = false; // Initialize sockets @@ -104,12 +101,6 @@ bool UDPSocket::init(bool ipv6, bool noExceptions) m_addr_family = ipv6 ? AF_INET6 : AF_INET; m_handle = socket(m_addr_family, SOCK_DGRAM, IPPROTO_UDP); - if (socket_enable_debug_output) { - tracestream << "UDPSocket(" << (int)m_handle - << ")::UDPSocket(): ipv6 = " << (ipv6 ? "true" : "false") - << std::endl; - } - if (m_handle < 0) { if (noExceptions) { return false; @@ -135,11 +126,6 @@ bool UDPSocket::init(bool ipv6, bool noExceptions) UDPSocket::~UDPSocket() { - if (socket_enable_debug_output) { - tracestream << "UDPSocket( " << (int)m_handle << ")::~UDPSocket()" - << std::endl; - } - if (m_handle >= 0) { #ifdef _WIN32 closesocket(m_handle); @@ -151,12 +137,6 @@ UDPSocket::~UDPSocket() void UDPSocket::Bind(Address addr) { - if (socket_enable_debug_output) { - tracestream << "UDPSocket(" << (int)m_handle - << ")::Bind(): " << addr.serializeString() << ":" - << addr.getPort() << std::endl; - } - if (addr.getFamily() != m_addr_family) { const char *errmsg = "Socket and bind address families do not match"; @@ -202,30 +182,6 @@ void UDPSocket::Send(const Address &destination, const void *data, int size) if (INTERNET_SIMULATOR) dumping_packet = myrand() % INTERNET_SIMULATOR_PACKET_LOSS == 0; - if (socket_enable_debug_output) { - // Print packet destination and size - tracestream << (int)m_handle << " -> "; - destination.print(tracestream); - tracestream << ", size=" << size; - - // Print packet contents - tracestream << ", data="; - for (int i = 0; i < size && i < 20; i++) { - if (i % 2 == 0) - tracestream << " "; - unsigned int a = ((const unsigned char *)data)[i]; - tracestream << std::hex << std::setw(2) << std::setfill('0') << a; - } - - if (size > 20) - tracestream << "..."; - - if (dumping_packet) - tracestream << " (DUMPED BY INTERNET_SIMULATOR)"; - - tracestream << std::endl; - } - if (dumping_packet) { // Lol let's forget it tracestream << "UDPSocket::Send(): INTERNET_SIMULATOR: dumping packet." @@ -302,26 +258,6 @@ int UDPSocket::Receive(Address &sender, void *data, int size) sender = Address(address_ip, address_port); } - if (socket_enable_debug_output) { - // Print packet sender and size - tracestream << (int)m_handle << " <- "; - sender.print(tracestream); - tracestream << ", size=" << received; - - // Print packet contents - tracestream << ", data="; - for (int i = 0; i < received && i < 20; i++) { - if (i % 2 == 0) - tracestream << " "; - unsigned int a = ((const unsigned char *)data)[i]; - tracestream << std::hex << std::setw(2) << std::setfill('0') << a; - } - if (received > 20) - tracestream << "..."; - - tracestream << std::endl; - } - return received; } diff --git a/src/network/socket.h b/src/network/socket.h index c3758a9d8..28b69c7b8 100644 --- a/src/network/socket.h +++ b/src/network/socket.h @@ -25,8 +25,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "irrlichttypes.h" #include "networkexceptions.h" -extern bool socket_enable_debug_output; - void sockets_init(); void sockets_cleanup(); From b12e67699a94505d804c9603a990128ef6621e4c Mon Sep 17 00:00:00 2001 From: nauta-turbidus <88062389+nauta-turbidus@users.noreply.github.com> Date: Thu, 12 Sep 2024 23:42:33 +0200 Subject: [PATCH 25/67] Document negative saturation (#15062) --- doc/lua_api.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/doc/lua_api.md b/doc/lua_api.md index f50ea0cb5..2f94fd796 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -8540,8 +8540,17 @@ child will follow movement and rotation of that bone. * Passing no arguments resets lighting to its default values. * `light_definition` is a table with the following optional fields: * `saturation` sets the saturation (vividness; default: `1.0`). - * values > 1 increase the saturation - * values in [0,1] decrease the saturation + * It is applied according to the function `result = b*(1-s) + c*s`, where: + * `c` is the original color + * `b` is the greyscale version of the color with the same luma + * `s` is the saturation set here + * The resulting color always has the same luma (perceived brightness) as the original. + * This means that: + * values > 1 oversaturate + * values < 1 down to 0 desaturate, 0 being entirely greyscale + * values < 0 cause an effect similar to inversion, + but keeping original luma and being symmetrical in terms of saturation + (eg. -1 and 1 is the same saturation and luma, but different hues) * `shadows` is a table that controls ambient shadows * `intensity` sets the intensity of the shadows from 0 (no shadows, default) to 1 (blackness) * This value has no effect on clients who have the "Dynamic Shadows" shader disabled. From 38b4505ad7298da2753dd9cb12d75120f9aed60f Mon Sep 17 00:00:00 2001 From: 1F616EMO~nya Date: Fri, 13 Sep 2024 05:42:46 +0800 Subject: [PATCH 26/67] Allow requesting reconnect when mods kick player (#14971) --- builtin/game/misc.lua | 6 +++--- doc/lua_api.md | 5 +++-- src/network/clientpackethandler.cpp | 31 +++++++++++------------------ src/script/lua_api/l_server.cpp | 6 ++++-- src/script/lua_api/l_server.h | 2 +- src/server.cpp | 11 +++------- src/server.h | 4 ++-- 7 files changed, 28 insertions(+), 37 deletions(-) diff --git a/builtin/game/misc.lua b/builtin/game/misc.lua index a8a6700f9..91ca738a4 100644 --- a/builtin/game/misc.lua +++ b/builtin/game/misc.lua @@ -6,14 +6,14 @@ local S = core.get_translator("__builtin") -- Misc. API functions -- --- @spec core.kick_player(String, String) :: Boolean -function core.kick_player(player_name, reason) +-- @spec core.kick_player(String, String, Boolean) :: Boolean +function core.kick_player(player_name, reason, reconnect) if type(reason) == "string" then reason = "Kicked: " .. reason else reason = "Kicked." end - return core.disconnect_player(player_name, reason) + return core.disconnect_player(player_name, reason, reconnect) end function core.check_player_privs(name, ...) diff --git a/doc/lua_api.md b/doc/lua_api.md index 2f94fd796..34af38abc 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -6999,10 +6999,11 @@ Bans * Returns boolean indicating success * `minetest.unban_player_or_ip(ip_or_name)`: remove ban record matching IP address or name -* `minetest.kick_player(name, [reason])`: disconnect a player with an optional +* `minetest.kick_player(name[, reason[, reconnect]])`: disconnect a player with an optional reason. * Returns boolean indicating success (false if player nonexistent) -* `minetest.disconnect_player(name, [reason])`: disconnect a player with an + * If `reconnect` is true, allow the user to reconnect. +* `minetest.disconnect_player(name[, reason[, reconnect]])`: disconnect a player with an optional reason, this will not prefix with 'Kicked: ' like kick_player. If no reason is given, it will default to 'Disconnected.' * Returns boolean indicating success (false if player nonexistent) diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index 4eefd1c59..a1bffbb93 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -204,7 +204,6 @@ void Client::handleCommand_AccessDenied(NetworkPacket* pkt) // to be processed even if the serialization format has // not been agreed yet, the same as TOCLIENT_INIT. m_access_denied = true; - m_access_denied_reason = "Unknown"; if (pkt->getCommand() != TOCLIENT_ACCESS_DENIED) { // Legacy code from 0.4.12 and older but is still used @@ -223,29 +222,23 @@ void Client::handleCommand_AccessDenied(NetworkPacket* pkt) u8 denyCode; *pkt >> denyCode; - if (denyCode == SERVER_ACCESSDENIED_SHUTDOWN || - denyCode == SERVER_ACCESSDENIED_CRASH) { + if (pkt->getRemainingBytes() > 0) *pkt >> m_access_denied_reason; - if (m_access_denied_reason.empty()) + + if (m_access_denied_reason.empty()) { + if (denyCode >= SERVER_ACCESSDENIED_MAX) { + m_access_denied_reason = gettext("Unknown disconnect reason."); + } else if (denyCode != SERVER_ACCESSDENIED_CUSTOM_STRING) { m_access_denied_reason = gettext(accessDeniedStrings[denyCode]); + } + } + + if (denyCode == SERVER_ACCESSDENIED_TOO_MANY_USERS) { + m_access_denied_reconnect = true; + } else if (pkt->getRemainingBytes() > 0) { u8 reconnect; *pkt >> reconnect; m_access_denied_reconnect = reconnect & 1; - } else if (denyCode == SERVER_ACCESSDENIED_CUSTOM_STRING) { - *pkt >> m_access_denied_reason; - } else if (denyCode == SERVER_ACCESSDENIED_TOO_MANY_USERS) { - m_access_denied_reason = gettext(accessDeniedStrings[denyCode]); - m_access_denied_reconnect = true; - } else if (denyCode < SERVER_ACCESSDENIED_MAX) { - m_access_denied_reason = gettext(accessDeniedStrings[denyCode]); - } else { - // Allow us to add new error messages to the - // protocol without raising the protocol version, if we want to. - // Until then (which may be never), this is outside - // of the defined protocol. - *pkt >> m_access_denied_reason; - if (m_access_denied_reason.empty()) - m_access_denied_reason = "Unknown"; } } diff --git a/src/script/lua_api/l_server.cpp b/src/script/lua_api/l_server.cpp index 69f5cf9a0..82170f936 100644 --- a/src/script/lua_api/l_server.cpp +++ b/src/script/lua_api/l_server.cpp @@ -365,7 +365,7 @@ int ModApiServer::l_ban_player(lua_State *L) return 1; } -// disconnect_player(name, [reason]) -> success +// disconnect_player(name[, reason[, reconnect]]) -> success int ModApiServer::l_disconnect_player(lua_State *L) { NO_MAP_LOCK_REQUIRED; @@ -388,7 +388,9 @@ int ModApiServer::l_disconnect_player(lua_State *L) return 1; } - server->DenyAccess(player->getPeerId(), SERVER_ACCESSDENIED_CUSTOM_STRING, message); + bool reconnect = readParam(L, 3, false); + + server->DenyAccess(player->getPeerId(), SERVER_ACCESSDENIED_CUSTOM_STRING, message, reconnect); lua_pushboolean(L, true); return 1; } diff --git a/src/script/lua_api/l_server.h b/src/script/lua_api/l_server.h index 505dce735..a0fae79bd 100644 --- a/src/script/lua_api/l_server.h +++ b/src/script/lua_api/l_server.h @@ -106,7 +106,7 @@ private: // unban_player_or_ip() static int l_unban_player_or_ip(lua_State *L); - // disconnect_player(name, [reason]) -> success + // disconnect_player(name[, reason[, reconnect]]) -> success static int l_disconnect_player(lua_State *L); // remove_player(name) diff --git a/src/server.cpp b/src/server.cpp index c76155015..92f97172b 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1383,17 +1383,12 @@ void Server::SendBreath(session_t peer_id, u16 breath) } void Server::SendAccessDenied(session_t peer_id, AccessDeniedCode reason, - const std::string &custom_reason, bool reconnect) + std::string_view custom_reason, bool reconnect) { assert(reason < SERVER_ACCESSDENIED_MAX); NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id); - pkt << (u8)reason; - if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING) - pkt << custom_reason; - else if (reason == SERVER_ACCESSDENIED_SHUTDOWN || - reason == SERVER_ACCESSDENIED_CRASH) - pkt << custom_reason << (u8)reconnect; + pkt << (u8)reason << custom_reason << (u8)reconnect; Send(&pkt); } @@ -2829,7 +2824,7 @@ void Server::DenySudoAccess(session_t peer_id) void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason, - const std::string &custom_reason, bool reconnect) + std::string_view custom_reason, bool reconnect) { SendAccessDenied(peer_id, reason, custom_reason, reconnect); m_clients.event(peer_id, CSE_SetDenied); diff --git a/src/server.h b/src/server.h index 17eb9d769..58805c667 100644 --- a/src/server.h +++ b/src/server.h @@ -364,7 +364,7 @@ public: void DenySudoAccess(session_t peer_id); void DenyAccess(session_t peer_id, AccessDeniedCode reason, - const std::string &custom_reason = "", bool reconnect = false); + std::string_view custom_reason = "", bool reconnect = false); void kickAllPlayers(AccessDeniedCode reason, const std::string &str_reason, bool reconnect); void acceptAuth(session_t peer_id, bool forSudoMode); @@ -485,7 +485,7 @@ private: void SendHP(session_t peer_id, u16 hp, bool effect); void SendBreath(session_t peer_id, u16 breath); void SendAccessDenied(session_t peer_id, AccessDeniedCode reason, - const std::string &custom_reason, bool reconnect = false); + std::string_view custom_reason, bool reconnect = false); void SendDeathscreen(session_t peer_id, bool set_camera_point_target, v3f camera_point_target); void SendItemDef(session_t peer_id, IItemDefManager *itemdef, u16 protocol_version); From a6219ab955ab20a946449879931685554840f6bc Mon Sep 17 00:00:00 2001 From: j-r Date: Sat, 14 Sep 2024 12:09:56 +0200 Subject: [PATCH 27/67] Fix alignment in implicit client hotbar definition Used when an older server doesn't send it. --- src/client/hud.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/hud.cpp b/src/client/hud.cpp index 3ff83bdae..0a5db6858 100644 --- a/src/client/hud.cpp +++ b/src/client/hud.cpp @@ -383,7 +383,7 @@ void Hud::drawLuaElements(const v3s16 &camera_offset) elems.push_back(&minimap); } if (client->getProtoVersion() < 46 && player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE) { - hotbar = {HUD_ELEM_HOTBAR, v2f(0.5, 1), "", v2f(), "", 0 , 0, 0, v2f(-0.5, -1), + hotbar = {HUD_ELEM_HOTBAR, v2f(0.5, 1), "", v2f(), "", 0 , 0, 0, v2f(0, -1), v2f(0, -4), v3f(), v2s32(), 0, "", 0}; elems.push_back(&hotbar); } From c54f5a21374b1af83c252b698f397d5dea68ac18 Mon Sep 17 00:00:00 2001 From: DS Date: Sat, 14 Sep 2024 12:10:11 +0200 Subject: [PATCH 28/67] Move std::tie out of headers --- src/object_properties.cpp | 22 ++++++++++++++++++++++ src/object_properties.h | 26 +++----------------------- src/player.cpp | 17 +++++++++++++++++ src/player.h | 21 +++------------------ 4 files changed, 45 insertions(+), 41 deletions(-) diff --git a/src/object_properties.cpp b/src/object_properties.cpp index 5fb6a7d41..7a70714a2 100644 --- a/src/object_properties.cpp +++ b/src/object_properties.cpp @@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "log.h" #include "util/serialize.h" #include +#include static const video::SColor NULL_BGCOLOR{0, 1, 1, 1}; @@ -85,6 +86,27 @@ std::string ObjectProperties::dump() const return os.str(); } +static auto tie(const ObjectProperties &o) +{ + // Make sure to add new members to this list! + return std::tie( + o.textures, o.colors, o.collisionbox, o.selectionbox, o.visual, o.mesh, + o.damage_texture_modifier, o.nametag, o.infotext, o.wield_item, o.visual_size, + o.nametag_color, o.nametag_bgcolor, o.spritediv, o.initial_sprite_basepos, + o.stepheight, o.automatic_rotate, o.automatic_face_movement_dir_offset, + o.automatic_face_movement_max_rotation_per_sec, o.eye_height, o.zoom_fov, + o.hp_max, o.breath_max, o.glow, o.pointable, o.physical, o.collideWithObjects, + o.rotate_selectionbox, o.is_visible, o.makes_footstep_sound, + o.automatic_face_movement_dir, o.backface_culling, o.static_save, o.use_texture_alpha, + o.shaded, o.show_on_minimap + ); +} + +bool ObjectProperties::operator==(const ObjectProperties &other) const +{ + return tie(*this) == tie(other); +} + bool ObjectProperties::validate() { const char *func = "ObjectProperties::validate(): "; diff --git a/src/object_properties.h b/src/object_properties.h index 1f8384c77..88c2a2678 100644 --- a/src/object_properties.h +++ b/src/object_properties.h @@ -20,11 +20,9 @@ with this program; if not, write to the Free Software Foundation, Inc., #pragma once #include -#include #include #include "irrlichttypes_bloated.h" #include -#include #include #include "util/pointabilities.h" @@ -77,28 +75,10 @@ struct ObjectProperties std::string dump() const; -private: - auto tie() const { - // Make sure to add new members to this list! - return std::tie( - textures, colors, collisionbox, selectionbox, visual, mesh, damage_texture_modifier, - nametag, infotext, wield_item, visual_size, nametag_color, nametag_bgcolor, - spritediv, initial_sprite_basepos, stepheight, automatic_rotate, - automatic_face_movement_dir_offset, automatic_face_movement_max_rotation_per_sec, - eye_height, zoom_fov, hp_max, breath_max, glow, pointable, physical, - collideWithObjects, rotate_selectionbox, is_visible, makes_footstep_sound, - automatic_face_movement_dir, backface_culling, static_save, use_texture_alpha, - shaded, show_on_minimap - ); - } - -public: - bool operator==(const ObjectProperties &other) const { - return tie() == other.tie(); - }; + bool operator==(const ObjectProperties &other) const; bool operator!=(const ObjectProperties &other) const { - return tie() != other.tie(); - }; + return !(*this == other); + } /** * Check limits of some important properties that'd cause exceptions later on. diff --git a/src/player.cpp b/src/player.cpp index fd902aa83..fd25626ca 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "settings.h" #include "log.h" #include "porting.h" // strlcpy +#include bool is_valid_player_name(std::string_view name) { @@ -229,3 +230,19 @@ void PlayerControl::unpackKeysPressed(u32 keypress_bits) place = keypress_bits & (1 << 8); zoom = keypress_bits & (1 << 9); } + +static auto tie(const PlayerPhysicsOverride &o) +{ + // Make sure to add new members to this list! + return std::tie( + o.speed, o.jump, o.gravity, o.sneak, o.sneak_glitch, o.new_move, o.speed_climb, + o.speed_crouch, o.liquid_fluidity, o.liquid_fluidity_smooth, o.liquid_sink, + o.acceleration_default, o.acceleration_air, o.speed_fast, o.acceleration_fast, + o.speed_walk + ); +} + +bool PlayerPhysicsOverride::operator==(const PlayerPhysicsOverride &other) const +{ + return tie(*this) == tie(other); +} diff --git a/src/player.h b/src/player.h index 7d92808cf..53411fea4 100644 --- a/src/player.h +++ b/src/player.h @@ -24,10 +24,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "constants.h" #include "util/basic_macros.h" #include "util/string.h" -#include #include #include -#include #include #define PLAYERNAME_SIZE 20 @@ -133,23 +131,10 @@ struct PlayerPhysicsOverride float acceleration_fast = 1.f; float speed_walk = 1.f; -private: - auto tie() const { - // Make sure to add new members to this list! - return std::tie( - speed, jump, gravity, sneak, sneak_glitch, new_move, speed_climb, speed_crouch, - liquid_fluidity, liquid_fluidity_smooth, liquid_sink, acceleration_default, - acceleration_air, speed_fast, acceleration_fast, speed_walk - ); - } - -public: - bool operator==(const PlayerPhysicsOverride &other) const { - return tie() == other.tie(); - }; + bool operator==(const PlayerPhysicsOverride &other) const; bool operator!=(const PlayerPhysicsOverride &other) const { - return tie() != other.tie(); - }; + return !(*this == other); + } }; class Map; From f9c0354af17c655e3e385c982fef0c1b67e61336 Mon Sep 17 00:00:00 2001 From: Gregor Parzefall Date: Fri, 13 Sep 2024 13:14:30 +0200 Subject: [PATCH 29/67] Add colorspec_to_table to the Lua API --- doc/lua_api.md | 4 ++++ games/devtest/mods/unittests/color.lua | 17 +++++++++++++++++ games/devtest/mods/unittests/init.lua | 1 + src/script/lua_api/l_util.cpp | 17 +++++++++++++++++ src/script/lua_api/l_util.h | 3 +++ 5 files changed, 42 insertions(+) create mode 100644 games/devtest/mods/unittests/color.lua diff --git a/doc/lua_api.md b/doc/lua_api.md index 34af38abc..ec00b5130 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -5655,6 +5655,10 @@ Utilities * `minetest.colorspec_to_bytes(colorspec)`: Converts a ColorSpec to a raw string of four bytes in an RGBA layout, returned as a string. * `colorspec`: The ColorSpec to convert +* `minetest.colorspec_to_table(colorspec)`: Converts a ColorSpec into RGBA table + form. If the ColorSpec is invalid, returns `nil`. You can use this to parse + ColorStrings. + * `colorspec`: The ColorSpec to convert * `minetest.encode_png(width, height, data, [compression])`: Encode a PNG image and return it in string form. * `width`: Width of the image diff --git a/games/devtest/mods/unittests/color.lua b/games/devtest/mods/unittests/color.lua new file mode 100644 index 000000000..86154445c --- /dev/null +++ b/games/devtest/mods/unittests/color.lua @@ -0,0 +1,17 @@ +local function assert_colors_equal(c1, c2) + if type(c1) == "table" and type(c2) == "table" then + assert(c1.r == c2.r and c1.g == c2.g and c1.b == c2.b and c1.a == c2.a) + else + assert(c1 == c2) + end +end + +local function test_color_conversion() + assert_colors_equal(core.colorspec_to_table("#fff"), {r = 255, g = 255, b = 255, a = 255}) + assert_colors_equal(core.colorspec_to_table(0xFF00FF00), {r = 0, g = 255, b = 0, a = 255}) + assert_colors_equal(core.colorspec_to_table("#00000000"), {r = 0, g = 0, b = 0, a = 0}) + assert_colors_equal(core.colorspec_to_table("green"), {r = 0, g = 128, b = 0, a = 255}) + assert_colors_equal(core.colorspec_to_table("gren"), nil) +end + +unittests.register("test_color_conversion", test_color_conversion) diff --git a/games/devtest/mods/unittests/init.lua b/games/devtest/mods/unittests/init.lua index eae003a2a..a967a986f 100644 --- a/games/devtest/mods/unittests/init.lua +++ b/games/devtest/mods/unittests/init.lua @@ -187,6 +187,7 @@ dofile(modpath .. "/raycast.lua") dofile(modpath .. "/inventory.lua") dofile(modpath .. "/load_time.lua") dofile(modpath .. "/on_shutdown.lua") +dofile(modpath .. "/color.lua") -------------- diff --git a/src/script/lua_api/l_util.cpp b/src/script/lua_api/l_util.cpp index 79eb38629..0c66521f7 100644 --- a/src/script/lua_api/l_util.cpp +++ b/src/script/lua_api/l_util.cpp @@ -626,6 +626,20 @@ int ModApiUtil::l_colorspec_to_bytes(lua_State *L) return 0; } +// colorspec_to_table(colorspec) +int ModApiUtil::l_colorspec_to_table(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + video::SColor color(0); + if (read_color(L, 1, &color)) { + push_ARGB8(L, color); + return 1; + } + + return 0; +} + // encode_png(w, h, data, level) int ModApiUtil::l_encode_png(lua_State *L) { @@ -726,6 +740,7 @@ void ModApiUtil::Initialize(lua_State *L, int top) API_FCT(sha256); API_FCT(colorspec_to_colorstring); API_FCT(colorspec_to_bytes); + API_FCT(colorspec_to_table); API_FCT(encode_png); @@ -761,6 +776,7 @@ void ModApiUtil::InitializeClient(lua_State *L, int top) API_FCT(sha256); API_FCT(colorspec_to_colorstring); API_FCT(colorspec_to_bytes); + API_FCT(colorspec_to_table); API_FCT(get_last_run_mod); API_FCT(set_last_run_mod); @@ -805,6 +821,7 @@ void ModApiUtil::InitializeAsync(lua_State *L, int top) API_FCT(sha256); API_FCT(colorspec_to_colorstring); API_FCT(colorspec_to_bytes); + API_FCT(colorspec_to_table); API_FCT(encode_png); diff --git a/src/script/lua_api/l_util.h b/src/script/lua_api/l_util.h index e0daf3e79..442e0749d 100644 --- a/src/script/lua_api/l_util.h +++ b/src/script/lua_api/l_util.h @@ -122,6 +122,9 @@ private: // colorspec_to_bytes(colorspec) static int l_colorspec_to_bytes(lua_State *L); + // colorspec_to_table(colorspec) + static int l_colorspec_to_table(lua_State *L); + // encode_png(w, h, data, level) static int l_encode_png(lua_State *L); From 7bab390413845f78cf80a0b95e066b9c18e24fe7 Mon Sep 17 00:00:00 2001 From: Gregor Parzefall Date: Fri, 13 Sep 2024 13:14:31 +0200 Subject: [PATCH 30/67] Add time_to_day_night_ratio to the Lua API --- doc/lua_api.md | 4 ++++ src/script/lua_api/l_util.cpp | 15 +++++++++++++++ src/script/lua_api/l_util.h | 3 +++ 3 files changed, 22 insertions(+) diff --git a/doc/lua_api.md b/doc/lua_api.md index ec00b5130..ad8eacb06 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -5659,6 +5659,9 @@ Utilities form. If the ColorSpec is invalid, returns `nil`. You can use this to parse ColorStrings. * `colorspec`: The ColorSpec to convert +* `minetest.time_to_day_night_ratio(time_of_day)`: Returns a "day-night ratio" value + (as accepted by `ObjectRef:override_day_night_ratio`) that is equivalent to + the given "time of day" value (as returned by `minetest.get_timeofday`). * `minetest.encode_png(width, height, data, [compression])`: Encode a PNG image and return it in string form. * `width`: Width of the image @@ -8519,6 +8522,7 @@ child will follow movement and rotation of that bone. * `0`...`1`: Overrides day-night ratio, controlling sunlight to a specific amount. * Passing no arguments disables override, defaulting to sunlight based on day-night cycle + * See also `minetest.time_to_day_night_ratio`, * `get_day_night_ratio()`: returns the ratio or nil if it isn't overridden * `set_local_animation(idle, walk, dig, walk_while_dig, frame_speed)`: set animation for player model in third person view. diff --git a/src/script/lua_api/l_util.cpp b/src/script/lua_api/l_util.cpp index 0c66521f7..75a11a050 100644 --- a/src/script/lua_api/l_util.cpp +++ b/src/script/lua_api/l_util.cpp @@ -45,6 +45,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "my_sha256.h" #include "util/png.h" #include "player.h" +#include "daynightratio.h" #include // only available in zstd 1.3.5+ @@ -640,6 +641,17 @@ int ModApiUtil::l_colorspec_to_table(lua_State *L) return 0; } +// time_to_day_night_ratio(time_of_day) +int ModApiUtil::l_time_to_day_night_ratio(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + float time_of_day = lua_tonumber(L, 1) * 24000; + u32 dnr = time_to_daynight_ratio(time_of_day, true); + lua_pushnumber(L, dnr / 1000.0f); + return 1; +} + // encode_png(w, h, data, level) int ModApiUtil::l_encode_png(lua_State *L) { @@ -741,6 +753,7 @@ void ModApiUtil::Initialize(lua_State *L, int top) API_FCT(colorspec_to_colorstring); API_FCT(colorspec_to_bytes); API_FCT(colorspec_to_table); + API_FCT(time_to_day_night_ratio); API_FCT(encode_png); @@ -777,6 +790,7 @@ void ModApiUtil::InitializeClient(lua_State *L, int top) API_FCT(colorspec_to_colorstring); API_FCT(colorspec_to_bytes); API_FCT(colorspec_to_table); + API_FCT(time_to_day_night_ratio); API_FCT(get_last_run_mod); API_FCT(set_last_run_mod); @@ -822,6 +836,7 @@ void ModApiUtil::InitializeAsync(lua_State *L, int top) API_FCT(colorspec_to_colorstring); API_FCT(colorspec_to_bytes); API_FCT(colorspec_to_table); + API_FCT(time_to_day_night_ratio); API_FCT(encode_png); diff --git a/src/script/lua_api/l_util.h b/src/script/lua_api/l_util.h index 442e0749d..89cc684e1 100644 --- a/src/script/lua_api/l_util.h +++ b/src/script/lua_api/l_util.h @@ -125,6 +125,9 @@ private: // colorspec_to_table(colorspec) static int l_colorspec_to_table(lua_State *L); + // time_to_day_night_ratio(time_of_day) + static int l_time_to_day_night_ratio(lua_State *L); + // encode_png(w, h, data, level) static int l_encode_png(lua_State *L); From 6f23de41fb9566b00757c5f6fee6d3904a40a0d9 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Wed, 11 Sep 2024 16:40:58 +0200 Subject: [PATCH 31/67] Refresh windows toolchain and libs --- util/buildbot/common.sh | 16 +++++++-------- util/buildbot/download_toolchain.sh | 5 +++-- util/buildbot/sha256sums.txt | 30 ++++++++++++++--------------- 3 files changed, 26 insertions(+), 25 deletions(-) diff --git a/util/buildbot/common.sh b/util/buildbot/common.sh index a7fa3b5d3..ff3aef2e9 100644 --- a/util/buildbot/common.sh +++ b/util/buildbot/common.sh @@ -5,17 +5,17 @@ CORE_NAME=minetest ogg_version=1.3.5 openal_version=1.23.1 vorbis_version=1.3.7 -curl_version=8.5.0 +curl_version=8.9.1 gettext_version=0.20.2 -freetype_version=2.13.2 -sqlite3_version=3.44.2 -luajit_version=20240125 +freetype_version=2.13.3 +sqlite3_version=3.46.1 +luajit_version=20240905 leveldb_version=1.23 zlib_version=1.3.1 -zstd_version=1.5.5 +zstd_version=1.5.6 libjpeg_version=3.0.1 -libpng_version=1.6.40 -sdl2_version=2.30.3 +libpng_version=1.6.43 +sdl2_version=2.30.7 download () { local url=$1 @@ -80,7 +80,7 @@ _dlls () { add_cmake_libs () { cmake_args+=( - -DPNG_LIBRARY=$libdir/libpng/lib/libpng.dll.a + -DPNG_LIBRARY=$libdir/libpng/lib/libpng16.dll.a -DPNG_PNG_INCLUDE_DIR=$libdir/libpng/include -DPNG_DLL="$(_dlls $libdir/libpng/bin/*)" diff --git a/util/buildbot/download_toolchain.sh b/util/buildbot/download_toolchain.sh index 3097f803b..d7d7afbe2 100755 --- a/util/buildbot/download_toolchain.sh +++ b/util/buildbot/download_toolchain.sh @@ -10,8 +10,9 @@ fi # * Clang + LLD + libc++ instead of GCC + binutils + stdc++ # * Mingw-w64 with UCRT enabled and winpthreads support # why are we avoiding GCC? -> Thread Local Storage (TLS) is totally broken -name=llvm-mingw-20231128-ucrt-ubuntu-20.04-x86_64.tar.xz -wget "https://github.com/mstorsjo/llvm-mingw/releases/download/20231128/$name" -O "$name" +date=20240619 +name=llvm-mingw-${date}-ucrt-ubuntu-20.04-x86_64.tar.xz +wget "https://github.com/mstorsjo/llvm-mingw/releases/download/$date/$name" -O "$name" sha256sum -w -c <(grep -F "$name" "$topdir/sha256sums.txt") tar -xaf "$name" -C "$1" --strip-components=1 rm -f "$name" diff --git a/util/buildbot/sha256sums.txt b/util/buildbot/sha256sums.txt index 0587e6ea1..310ab6a6e 100644 --- a/util/buildbot/sha256sums.txt +++ b/util/buildbot/sha256sums.txt @@ -1,7 +1,7 @@ -753dc38c591e078eae6a0a6b25f69826211256f444f3691a170670d8a12988f9 curl-8.5.0-win32.zip -aa86abc3eb054d74d5fe15996f281cf84230a61b4ab7b3a702ab7dbb71e1203f curl-8.5.0-win64.zip -3e9d7bbca953b96dfd65acc28baaa87e8881aab29809ba03b9c9aefe3d071189 freetype-2.13.2-win32.zip -acf901e93aedbcfa92eb3aab1def252676af845b1747ca5c3e7c5866576168cc freetype-2.13.2-win64.zip +627d4111ee655a68e806251974ba9d0337efac19cb07d499689c44c328a23775 curl-8.9.1-win32.zip +ed906726531388441d7f93fc0a1c9d567d476fbc8cfbae19dc5a0f7288949abe curl-8.9.1-win64.zip +7a94b9e69d4872489228ad7cca6a16117a433f809d9b20fa3e44e1616a33c5d7 freetype-2.13.3-win32.zip +f7d882319790f72ebc8eff00526388432bd26bff3a56c4ef5cce0a829bbbef0d freetype-2.13.3-win64.zip 41b10766de2773f0f0851fde16b363024685e0397f4bb2e5cd2a7be196960a01 gettext-0.20.2-win32.zip 1ceed167ff16fea944f76ab6ea2969160c71a67419259b17c9c523e7a01eb883 gettext-0.20.2-win64.zip 53dfd31285f470fcf0dca88217c5cf9c557729af6d103afae5936e72ddc38d3c libjpeg-3.0.1-win32.zip @@ -10,20 +10,20 @@ f54e9a577e2db47ed28f4a01e74181d2c607627c551d30f48263e01b59e84f67 libleveldb-1.2 2f039848a4e6c05a2347fe5a7fa63c430dd08d1bc88235645a863c859e14f5f8 libleveldb-1.23-win64.zip 0df94afb8efa361cceb132ecf9491720afbc45ba844a7b1c94607295829b53ca libogg-1.3.5-win32.zip 5c4acb4c99429a04b5e69650719b2eb17616bf52837d2372a0f859952eebce48 libogg-1.3.5-win64.zip -6baf4e819bfb3573760524b5dc9a04b5e479090d6d2046b86cf39a3107c0071f libpng-1.6.40-win32.zip -c02e029f01fce44baea7f4aecfd2564bd8a03507c0c6af8b03339ae0452c8b7d libpng-1.6.40-win64.zip +fb61536bfce414fdecb30dfbdc8b26e87969ee30b420f5fb8542f7573a1c1d12 libpng-1.6.43-win32.zip +ccd0b8ecbaa07028067a99dd4314ec7799445f80a28ddc86fa3f6bf25700177b libpng-1.6.43-win64.zip 456ece10a2be4247b27fbe88f88ddd54aae604736a6b76ba9a922b602fe40f40 libvorbis-1.3.7-win32.zip 57f4db02da00556895bb63fafa6e46b5f7dac87c25fde27af4315f56a1aa7a86 libvorbis-1.3.7-win64.zip -0f21ff3be90311092fe32e0e30878ef3ae9d9437b8d9ac25ef279e0d84e9bb8e llvm-mingw-20231128-ucrt-ubuntu-20.04-x86_64.tar.xz -da6ad10632cf172992158e9ea0977a87914b5d5de93a972c3430b6a412237556 luajit-20240125-win32.zip -2b1dabe83d478b398cf9226d96de7fa62c973365c4aea70d27ba5782fb49d2d0 luajit-20240125-win64.zip +27d33157cc252c29ad6f777a96a0d94176fea1b534ff09b5071485def143b90e llvm-mingw-20240619-ucrt-ubuntu-20.04-x86_64.tar.xz +5380bbb0bfd4482b5774e4f7c0ff58cc0857477b88a88a178316a464d3459cf1 luajit-20240905-win32.zip +5805c75c61bf948f790e6f845adc94a4946e43ab8a78c5b5b441550f8a665d2c luajit-20240905-win64.zip e2443451fe5c2066eb564c64b8a1762738a88b7fd749c8b5907fed45c785497b openal-soft-1.23.1-win32.zip cb041445a118469caefbad2647470cb8571c8337bce2adc07634011ab5625417 openal-soft-1.23.1-win64.zip -574e0847e622ff09ab23e2b22b77685a2ab6ee43de3e2932f3e8a14a4d7b9338 sdl2-2.30.3-win32.zip -6127afdfc7b6a4ade8caf9a7267748ffea974f729866dd5be96c7a69d2f0fee7 sdl2-2.30.3-win64.zip -326701086a0ed66e09a9f3ec4d971654c13b6bd79cfdd079c947ecdcd6409525 sqlite3-3.44.2-win32.zip -b2d474e3625f8f426b6cc5c0ecac831a1de46f7d1027bf4a9f6267b0b0411d42 sqlite3-3.44.2-win64.zip +af09a54f1f5d75ef6e1bf63662489ca57d44b6b522446638afe35e59b8456a3c sdl2-2.30.7-win32.zip +613abc34a84ed2c3b050314b340ba7e675879e8ed7848e6a28cd9c50262a33b0 sdl2-2.30.7-win64.zip +9685857ae0b418068ad4324e3711121bda97488d19235a0e68a6060162e014d7 sqlite3-3.46.1-win32.zip +7e2990619b1fd1d5ed654d1df77ea809d4332c2e914ea8bba53b2cf5acdf10ff sqlite3-3.46.1-win64.zip 8af10515d57dbfee5d2106cd66cafa2adeb4270d4c6047ccbf7e8b5d2d50681c zlib-1.3.1-win32.zip ad43f5d23052590c65633530743e5d622cc76b33c109072e6fd7b487aff56bca zlib-1.3.1-win64.zip -3564dabbe17ec4ecae1fb9a78fe48d9f7c71e2b1166456f6ee27e52fd9c84357 zstd-1.5.5-win32.zip -e61b1f327ce2d836d1f8ca00c40ac77d3ab5309135851c98229bbdf82b060ae5 zstd-1.5.5-win64.zip +e1bd36f6da039ee8c1694509f379a5023c05d6c90905a2cbb424f0395167570a zstd-1.5.6-win32.zip +f65b75b04b00f6bda859a7c60667f735c664a893bf7796b38393c16cc40a1a82 zstd-1.5.6-win64.zip From 4aec4fbe6f62688bc7dee3c227c0241eee977c7e Mon Sep 17 00:00:00 2001 From: DS Date: Sun, 15 Sep 2024 13:47:45 +0200 Subject: [PATCH 32/67] Add support for Tracy profiler (#15113) --- CMakeLists.txt | 21 +++ doc/compiling/README.md | 2 + doc/developing/misc.md | 53 +++++++- doc/lua_api.md | 10 ++ irr/src/CMakeLists.txt | 4 + src/CMakeLists.txt | 6 + src/client/clientlauncher.cpp | 5 + src/client/clientmap.cpp | 3 + src/client/content_mapblock.cpp | 3 + src/client/game.cpp | 26 +++- src/client/mapblock_mesh.cpp | 3 + src/client/sound/sound_manager.cpp | 3 + src/cmake_config.h.in | 1 + src/gui/guiEngine.cpp | 7 +- src/porting.cpp | 3 + src/script/cpp_api/s_base.cpp | 8 ++ src/script/cpp_api/s_security.cpp | 12 +- src/server.cpp | 13 ++ src/util/tracy_wrapper.h | 200 +++++++++++++++++++++++++++++ 19 files changed, 379 insertions(+), 4 deletions(-) create mode 100644 src/util/tracy_wrapper.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 54a830089..a9a0ef000 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,6 +56,11 @@ if((WIN32 AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") OR APPLE) endif() set(ENABLE_LTO ${DEFAULT_ENABLE_LTO} CACHE BOOL "Use Link Time Optimization") +set(BUILD_WITH_TRACY FALSE CACHE BOOL + "Fetch and build with the Tracy profiler client") +set(FETCH_TRACY_GIT_TAG "master" CACHE STRING + "Git tag for fetching Tracy client. Match with your server (gui) version") + set(DEFAULT_RUN_IN_PLACE FALSE) if(WIN32) set(DEFAULT_RUN_IN_PLACE TRUE) @@ -370,3 +375,19 @@ if(BUILD_DOCUMENTATION) ) endif() endif() + +# Fetch Tracy +if(BUILD_WITH_TRACY) + include(FetchContent) + + message(STATUS "Fetching Tracy (${FETCH_TRACY_GIT_TAG})...") + FetchContent_Declare( + tracy + GIT_REPOSITORY https://github.com/wolfpld/tracy.git + GIT_TAG ${FETCH_TRACY_GIT_TAG} + GIT_SHALLOW TRUE + GIT_PROGRESS TRUE + ) + FetchContent_MakeAvailable(tracy) + message(STATUS "Fetching Tracy - done") +endif() diff --git a/doc/compiling/README.md b/doc/compiling/README.md index c394b2be0..bfe91950f 100644 --- a/doc/compiling/README.md +++ b/doc/compiling/README.md @@ -40,6 +40,8 @@ General options and their default values: ENABLE_UPDATE_CHECKER=TRUE - Whether to enable update checks by default INSTALL_DEVTEST=FALSE - Whether the Development Test game should be installed alongside Minetest USE_GPROF=FALSE - Enable profiling using GProf + BUILD_WITH_TRACY=FALSE - Fetch and build with the Tracy profiler client + FETCH_TRACY_GIT_TAG=master - Git tag for fetching Tracy client. Match with your server (gui) version VERSION_EXTRA= - Text to append to version (e.g. VERSION_EXTRA=foobar -> Minetest 0.4.9-foobar) Library specific options: diff --git a/doc/developing/misc.md b/doc/developing/misc.md index 1d3d8c941..2ac843caf 100644 --- a/doc/developing/misc.md +++ b/doc/developing/misc.md @@ -1,6 +1,6 @@ # Miscellaneous -## Profiling Minetest on Linux +## Profiling Minetest on Linux with perf We will be using a tool called "perf", which you can get by installing `perf` or `linux-perf` or `linux-tools-common`. @@ -36,3 +36,54 @@ Give both files to the developer and also provide: * commit the source was built from and/or modified source code (if applicable) Hotspot will resolve symbols correctly when pointing the sysroot option at the collected libs. + + +## Profiling with Tracy + +[Tracy](https://github.com/wolfpld/tracy) is +> A real time, nanosecond resolution, remote telemetry, hybrid frame and sampling +> profiler for games and other applications. + +It allows one to annotate important functions and generate traces, where one can +see when each individual function call happened, and how long it took. + +Tracy can also record when frames, e.g. server step, start and end, and inspect +frames that took longer than usual. Minetest already contains annotations for +its frames. + +See also [Tracy's official documentation](https://github.com/wolfpld/tracy/releases/latest/download/tracy.pdf). + +### Installing + +Tracy consists of a client (Minetest) and a server (the gui). + +Install the server, e.g. using your package manager. + +### Building + +Build Minetest with `-DDBUILD_WITH_TRACY=1`, this will fetch Tracy for building +the Tracy client. And use `FETCH_TRACY_GIT_TAG` to get a version matching your +Tracy server, e.g. `-DFETCH_TRACY_GIT_TAG=v0.11.0` if it's `0.11.0`. + +To actually use Tracy, you also have to enable it with Tracy's build options: +``` +-DTRACY_ENABLE=1 -DTRACY_ONLY_LOCALHOST=1 +``` + +See Tracy's documentation for more build options. + +### Using in C++ + +Start the Tracy server and Minetest. You should see Minetest in the menu. + +To actually get useful traces, you have to annotate functions with `ZoneScoped` +macros and recompile. Please refer to Tracy's official documentation. + +### Using in Lua + +Tracy also supports Lua. +If built with Tracy, Minetest loads its API in the global `tracy` table. +See Tracy's official documentation for more information. + +Note: The whole Tracy Lua API is accessible to all mods. And we don't check if it +is or becomes insecure. Run untrusted mods at your own risk. diff --git a/doc/lua_api.md b/doc/lua_api.md index ad8eacb06..83f186804 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -11394,6 +11394,16 @@ Functions: bit.tobit, bit.tohex, bit.bnot, bit.band, bit.bor, bit.bxor, bit.lshi See http://bitop.luajit.org/ for advanced information. +Tracy Profiler +-------------- + +Minetest can be built with support for the Tracy profiler, which can also be +useful for profiling mods and is exposed to Lua as the global `tracy`. + +See doc/developing/misc.md for details. + +Note: This is a development feature and not covered by compatibility promises. + Error Handling -------------- diff --git a/irr/src/CMakeLists.txt b/irr/src/CMakeLists.txt index f5bc675e4..742d27f72 100644 --- a/irr/src/CMakeLists.txt +++ b/irr/src/CMakeLists.txt @@ -468,6 +468,10 @@ foreach(object_lib target_include_directories(${object_lib} PRIVATE ${link_includes}) # Add objects from object library to main library target_sources(IrrlichtMt PRIVATE $) + + if(BUILD_WITH_TRACY) + target_link_libraries(${object_lib} PRIVATE Tracy::TracyClient) + endif() endforeach() # Alias target provides add_submodule compatibility diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0ea8a40a9..cad22ca6f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -648,6 +648,9 @@ if(BUILD_CLIENT) if(BUILD_UNITTESTS OR BUILD_BENCHMARKS) target_link_libraries(${PROJECT_NAME} Catch2::Catch2) endif() + if(BUILD_WITH_TRACY) + target_link_libraries(${PROJECT_NAME} Tracy::TracyClient) + endif() if(PRECOMPILE_HEADERS) target_precompile_headers(${PROJECT_NAME} PRIVATE ${PRECOMPILED_HEADERS_LIST}) @@ -715,6 +718,9 @@ if(BUILD_SERVER) if(BUILD_UNITTESTS OR BUILD_BENCHMARKS) target_link_libraries(${PROJECT_NAME}server Catch2::Catch2) endif() + if(BUILD_WITH_TRACY) + target_link_libraries(${PROJECT_NAME}server Tracy::TracyClient) + endif() if(PRECOMPILE_HEADERS) target_precompile_headers(${PROJECT_NAME}server PRIVATE ${PRECOMPILED_HEADERS_LIST}) diff --git a/src/client/clientlauncher.cpp b/src/client/clientlauncher.cpp index e86fb4425..1c9e397ca 100644 --- a/src/client/clientlauncher.cpp +++ b/src/client/clientlauncher.cpp @@ -35,6 +35,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "version.h" #include "renderingengine.h" #include "network/networkexceptions.h" +#include "util/tracy_wrapper.h" #include #include #include @@ -544,15 +545,19 @@ void ClientLauncher::main_menu(MainMenuData *menudata) video::IVideoDriver *driver = m_rendering_engine->get_video_driver(); infostream << "Waiting for other menus" << std::endl; + auto framemarker = FrameMarker("ClientLauncher::main_menu()-wait-frame").started(); while (m_rendering_engine->run() && !*kill) { if (!isMenuActive()) break; driver->beginScene(true, true, video::SColor(255, 128, 128, 128)); m_rendering_engine->get_gui_env()->drawAll(); driver->endScene(); + framemarker.end(); // On some computers framerate doesn't seem to be automatically limited sleep_ms(25); + framemarker.start(); } + framemarker.end(); infostream << "Waited for other menus" << std::endl; auto *cur_control = m_rendering_engine->get_raw_device()->getCursorControl(); diff --git a/src/client/clientmap.cpp b/src/client/clientmap.cpp index b4356dc27..12945ed1b 100644 --- a/src/client/clientmap.cpp +++ b/src/client/clientmap.cpp @@ -31,6 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "settings.h" #include "camera.h" // CameraModes #include "util/basic_macros.h" +#include "util/tracy_wrapper.h" #include "client/renderingengine.h" #include @@ -714,6 +715,8 @@ void ClientMap::touchMapBlocks() void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) { + ZoneScoped; + bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT; std::string prefix; diff --git a/src/client/content_mapblock.cpp b/src/client/content_mapblock.cpp index 4f4056668..f7852ad1c 100644 --- a/src/client/content_mapblock.cpp +++ b/src/client/content_mapblock.cpp @@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "util/basic_macros.h" #include "util/numeric.h" #include "util/directiontables.h" +#include "util/tracy_wrapper.h" #include "mapblock_mesh.h" #include "settings.h" #include "nodedef.h" @@ -1750,6 +1751,8 @@ void MapblockMeshGenerator::drawNode() void MapblockMeshGenerator::generate() { + ZoneScoped; + for (cur_node.p.Z = 0; cur_node.p.Z < data->side_length; cur_node.p.Z++) for (cur_node.p.Y = 0; cur_node.p.Y < data->side_length; cur_node.p.Y++) for (cur_node.p.X = 0; cur_node.p.X < data->side_length; cur_node.p.X++) { diff --git a/src/client/game.cpp b/src/client/game.cpp index 36cb5f4bb..6e01f2ffe 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -79,6 +79,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "hud.h" #include "clientdynamicinfo.h" #include +#include "util/tracy_wrapper.h" #if USE_SOUND #include "client/sound/sound_openal.h" @@ -1140,6 +1141,8 @@ bool Game::startup(bool *kill, void Game::run() { + ZoneScoped; + ProfilerGraph graph; RunStats stats = {}; CameraOrientation cam_view_target = {}; @@ -1167,15 +1170,21 @@ void Game::run() const bool initial_window_maximized = !g_settings->getBool("fullscreen") && g_settings->getBool("window_maximized"); + auto framemarker = FrameMarker("Game::run()-frame").started(); + while (m_rendering_engine->run() && !(*kill || g_gamecallback->shutdown_requested || (server && server->isShutdownRequested()))) { + framemarker.end(); + // Calculate dtime = // m_rendering_engine->run() from this iteration // + Sleep time until the wanted FPS are reached draw_times.limit(device, &dtime, g_menumgr.pausesGame()); + framemarker.start(); + const auto current_dynamic_info = ClientDynamicInfo::getCurrent(); if (!current_dynamic_info.equal(client_display_info)) { client_display_info = current_dynamic_info; @@ -1232,6 +1241,8 @@ void Game::run() } } + framemarker.end(); + RenderingEngine::autosaveScreensizeAndCo(initial_screen_size, initial_window_maximized); } @@ -1671,9 +1682,13 @@ bool Game::connectToServer(const GameStartData &start_data, fps_control.reset(); + auto framemarker = FrameMarker("Game::connectToServer()-frame").started(); + while (m_rendering_engine->run()) { + framemarker.end(); fps_control.limit(device, &dtime); + framemarker.start(); // Update client and server step(dtime); @@ -1719,6 +1734,7 @@ bool Game::connectToServer(const GameStartData &start_data, // Update status showOverlayMessage(N_("Connecting to server..."), dtime, 20); } + framemarker.end(); } catch (con::PeerNotFoundException &e) { warningstream << "This should not happen. Please report a bug." << std::endl; return false; @@ -1736,9 +1752,11 @@ bool Game::getServerContent(bool *aborted) fps_control.reset(); + auto framemarker = FrameMarker("Game::getServerContent()-frame").started(); while (m_rendering_engine->run()) { - + framemarker.end(); fps_control.limit(device, &dtime); + framemarker.start(); // Update client and server step(dtime); @@ -1804,6 +1822,7 @@ bool Game::getServerContent(bool *aborted) texture_src, dtime, progress); } } + framemarker.end(); *aborted = true; infostream << "Connect aborted [device]" << std::endl; @@ -2773,6 +2792,8 @@ void Game::updatePauseState() inline void Game::step(f32 dtime) { + ZoneScoped; + if (server) { float fps_max = (!device->isWindowFocused() || g_menumgr.pausesGame()) ? g_settings->getFloat("fps_max_unfocused") : @@ -4052,6 +4073,7 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos, void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime, const CameraOrientation &cam) { + ZoneScoped; TimeTaker tt_update("Game::updateFrame()"); LocalPlayer *player = client->getEnv().getLocalPlayer(); @@ -4311,6 +4333,8 @@ void Game::updateShadows() void Game::drawScene(ProfilerGraph *graph, RunStats *stats) { + ZoneScoped; + const video::SColor fog_color = this->sky->getFogColor(); const video::SColor sky_color = this->sky->getSkyColor(); diff --git a/src/client/mapblock_mesh.cpp b/src/client/mapblock_mesh.cpp index 32d559149..9c0caa9d0 100644 --- a/src/client/mapblock_mesh.cpp +++ b/src/client/mapblock_mesh.cpp @@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "minimap.h" #include "content_mapblock.h" #include "util/directiontables.h" +#include "util/tracy_wrapper.h" #include "client/meshgen/collector.h" #include "client/renderingengine.h" #include @@ -611,6 +612,8 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs m_last_crack(-1), m_last_daynight_ratio((u32) -1) { + ZoneScoped; + for (auto &m : m_mesh) m = new scene::SMesh(); m_enable_shaders = data->m_use_shaders; diff --git a/src/client/sound/sound_manager.cpp b/src/client/sound/sound_manager.cpp index 6aae5bb7f..fc171d565 100644 --- a/src/client/sound/sound_manager.cpp +++ b/src/client/sound/sound_manager.cpp @@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "sound_singleton.h" #include "util/numeric.h" // myrand() +#include "util/tracy_wrapper.h" #include "filesys.h" #include "porting.h" @@ -501,6 +502,8 @@ void *OpenALSoundManager::run() u64 t_step_start = porting::getTimeMs(); while (true) { + auto framemarker = FrameMarker("OpenALSoundManager::run()-frame").started(); + auto get_time_since_last_step = [&] { return (f32)(porting::getTimeMs() - t_step_start); }; diff --git a/src/cmake_config.h.in b/src/cmake_config.h.in index a8eb53edd..5dc6e4b74 100644 --- a/src/cmake_config.h.in +++ b/src/cmake_config.h.in @@ -41,3 +41,4 @@ #cmakedefine01 BUILD_UNITTESTS #cmakedefine01 BUILD_BENCHMARKS #cmakedefine01 USE_SDL2 +#cmakedefine01 BUILD_WITH_TRACY diff --git a/src/gui/guiEngine.cpp b/src/gui/guiEngine.cpp index fdc13fa14..988d2924b 100644 --- a/src/gui/guiEngine.cpp +++ b/src/gui/guiEngine.cpp @@ -40,6 +40,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include #include "client/imagefilters.h" +#include "util/tracy_wrapper.h" #if USE_SOUND #include "client/sound/sound_openal.h" @@ -329,9 +330,12 @@ void GUIEngine::run() fps_control.reset(); - while (m_rendering_engine->run() && !m_startgame && !m_kill) { + auto framemarker = FrameMarker("GUIEngine::run()-frame").started(); + while (m_rendering_engine->run() && !m_startgame && !m_kill) { + framemarker.end(); fps_control.limit(device, &dtime); + framemarker.start(); if (device->isWindowVisible()) { // check if we need to update the "upper left corner"-text @@ -371,6 +375,7 @@ void GUIEngine::run() m_menu->getAndroidUIInput(); #endif } + framemarker.end(); m_script->beforeClose(); diff --git a/src/porting.cpp b/src/porting.cpp index da972926a..f6409c56c 100644 --- a/src/porting.cpp +++ b/src/porting.cpp @@ -73,6 +73,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "filesys.h" #include "log.h" #include "util/string.h" +#include "util/tracy_wrapper.h" #include #include #include @@ -960,6 +961,8 @@ void TrackFreedMemory(size_t amount) void TriggerMemoryTrim() { + ZoneScoped; + constexpr auto MO = std::memory_order_relaxed; if (memory_freed.load(MO) >= MEMORY_TRIM_THRESHOLD) { // Synchronize call diff --git a/src/script/cpp_api/s_base.cpp b/src/script/cpp_api/s_base.cpp index e9907f304..bdd2514e6 100644 --- a/src/script/cpp_api/s_base.cpp +++ b/src/script/cpp_api/s_base.cpp @@ -32,6 +32,9 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "client/client.h" #endif +#if BUILD_WITH_TRACY + #include "tracy/TracyLua.hpp" +#endif extern "C" { #include "lualib.h" @@ -95,6 +98,11 @@ ScriptApiBase::ScriptApiBase(ScriptingType type): lua_pushstring(m_luastack, LUA_BITLIBNAME); lua_call(m_luastack, 1, 0); +#if BUILD_WITH_TRACY + // Load tracy lua bindings + tracy::LuaRegister(m_luastack); +#endif + // Make the ScriptApiBase* accessible to ModApiBase #if INDIRECT_SCRIPTAPI_RIDX *(void **)(lua_newuserdata(m_luastack, sizeof(void *))) = this; diff --git a/src/script/cpp_api/s_security.cpp b/src/script/cpp_api/s_security.cpp index 7c8ba8931..9a4b0763b 100644 --- a/src/script/cpp_api/s_security.cpp +++ b/src/script/cpp_api/s_security.cpp @@ -109,7 +109,12 @@ void ScriptApiSecurity::initializeSecurity() "string", "table", "math", - "bit" + "bit", + // Not sure if completely safe. But if someone enables tracy, they'll + // know what they do. +#if BUILD_WITH_TRACY + "tracy", +#endif }; static const char *io_whitelist[] = { "close", @@ -303,6 +308,11 @@ void ScriptApiSecurity::initializeSecurityClient() "table", "math", "bit", + // Not sure if completely safe. But if someone enables tracy, they'll + // know what they do. +#if BUILD_WITH_TRACY + "tracy", +#endif }; static const char *os_whitelist[] = { "clock", diff --git a/src/server.cpp b/src/server.cpp index 92f97172b..6421fc175 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -75,6 +75,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "gameparams.h" #include "particles.h" #include "gettext.h" +#include "util/tracy_wrapper.h" class ClientNotFoundException : public BaseException { @@ -101,6 +102,8 @@ private: void *ServerThread::run() { + ZoneScoped; + BEGIN_DEBUG_EXCEPTION_HANDLER /* @@ -110,6 +113,7 @@ void *ServerThread::run() * server-step frequency. Receive() is used for waiting between the steps. */ + auto framemarker = FrameMarker("ServerThread::run()-frame").started(); try { m_server->AsyncRunStep(0.0f, true); } catch (con::ConnectionBindFailed &e) { @@ -119,10 +123,12 @@ void *ServerThread::run() } catch (ModError &e) { m_server->setAsyncFatalError(e.what()); } + framemarker.end(); float dtime = 0.0f; while (!stopRequested()) { + framemarker.start(); ScopeProfiler spm(g_profiler, "Server::RunStep() (max)", SPT_MAX); u64 t0 = porting::getTimeUs(); @@ -149,6 +155,7 @@ void *ServerThread::run() } dtime = 1e-6f * (porting::getTimeUs() - t0); + framemarker.end(); } END_DEBUG_EXCEPTION_HANDLER @@ -607,6 +614,9 @@ void Server::step() void Server::AsyncRunStep(float dtime, bool initial_step) { + ZoneScoped; + auto framemarker = FrameMarker("Server::AsyncRunStep()-frame").started(); + { // Send blocks to clients SendBlocks(dtime); @@ -1055,6 +1065,9 @@ void Server::AsyncRunStep(float dtime, bool initial_step) void Server::Receive(float timeout) { + ZoneScoped; + auto framemarker = FrameMarker("Server::Receive()-frame").started(); + const u64 t0 = porting::getTimeUs(); const float timeout_us = timeout * 1e6f; auto remaining_time_us = [&]() -> float { diff --git a/src/util/tracy_wrapper.h b/src/util/tracy_wrapper.h new file mode 100644 index 000000000..0c61ba837 --- /dev/null +++ b/src/util/tracy_wrapper.h @@ -0,0 +1,200 @@ +/* +Minetest +Copyright (C) 2024 DS + +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. +*/ + +/* + * Wrapper for , so that we can use Tracy's macros without + * having it as mandatory dependency. + * + * For annotations that you don't intend to upstream, you can also include + * directly (which also works in irr/). + */ + +#pragma once + +#include "config.h" +#include "util/basic_macros.h" + +#if BUILD_WITH_TRACY + +#include // IWYU pragma: export + +#else + +// Copied from Tracy.hpp + +#define TracyNoop + +#define ZoneNamed(x,y) +#define ZoneNamedN(x,y,z) +#define ZoneNamedC(x,y,z) +#define ZoneNamedNC(x,y,z,w) + +#define ZoneTransient(x,y) +#define ZoneTransientN(x,y,z) + +#define ZoneScoped +#define ZoneScopedN(x) +#define ZoneScopedC(x) +#define ZoneScopedNC(x,y) + +#define ZoneText(x,y) +#define ZoneTextV(x,y,z) +#define ZoneTextF(x,...) +#define ZoneTextVF(x,y,...) +#define ZoneName(x,y) +#define ZoneNameV(x,y,z) +#define ZoneNameF(x,...) +#define ZoneNameVF(x,y,...) +#define ZoneColor(x) +#define ZoneColorV(x,y) +#define ZoneValue(x) +#define ZoneValueV(x,y) +#define ZoneIsActive false +#define ZoneIsActiveV(x) false + +#define FrameMark +#define FrameMarkNamed(x) +#define FrameMarkStart(x) +#define FrameMarkEnd(x) + +#define FrameImage(x,y,z,w,a) + +#define TracyLockable( type, varname ) type varname +#define TracyLockableN( type, varname, desc ) type varname +#define TracySharedLockable( type, varname ) type varname +#define TracySharedLockableN( type, varname, desc ) type varname +#define LockableBase( type ) type +#define SharedLockableBase( type ) type +#define LockMark(x) (void)x +#define LockableName(x,y,z) + +#define TracyPlot(x,y) +#define TracyPlotConfig(x,y,z,w,a) + +#define TracyMessage(x,y) +#define TracyMessageL(x) +#define TracyMessageC(x,y,z) +#define TracyMessageLC(x,y) +#define TracyAppInfo(x,y) + +#define TracyAlloc(x,y) +#define TracyFree(x) +#define TracySecureAlloc(x,y) +#define TracySecureFree(x) + +#define TracyAllocN(x,y,z) +#define TracyFreeN(x,y) +#define TracySecureAllocN(x,y,z) +#define TracySecureFreeN(x,y) + +#define ZoneNamedS(x,y,z) +#define ZoneNamedNS(x,y,z,w) +#define ZoneNamedCS(x,y,z,w) +#define ZoneNamedNCS(x,y,z,w,a) + +#define ZoneTransientS(x,y,z) +#define ZoneTransientNS(x,y,z,w) + +#define ZoneScopedS(x) +#define ZoneScopedNS(x,y) +#define ZoneScopedCS(x,y) +#define ZoneScopedNCS(x,y,z) + +#define TracyAllocS(x,y,z) +#define TracyFreeS(x,y) +#define TracySecureAllocS(x,y,z) +#define TracySecureFreeS(x,y) + +#define TracyAllocNS(x,y,z,w) +#define TracyFreeNS(x,y,z) +#define TracySecureAllocNS(x,y,z,w) +#define TracySecureFreeNS(x,y,z) + +#define TracyMessageS(x,y,z) +#define TracyMessageLS(x,y) +#define TracyMessageCS(x,y,z,w) +#define TracyMessageLCS(x,y,z) + +#define TracySourceCallbackRegister(x,y) +#define TracyParameterRegister(x,y) +#define TracyParameterSetup(x,y,z,w) +#define TracyIsConnected false +#define TracyIsStarted false +#define TracySetProgramName(x) + +#define TracyFiberEnter(x) +#define TracyFiberEnterHint(x,y) +#define TracyFiberLeave + +#endif + + +// Helper for making sure frames end in all possible control flow path +class FrameMarker +{ + const char *m_name; + bool m_started = false; + +public: + FrameMarker(const char *name) : m_name(name) {} + + ~FrameMarker() { end(); } + + DISABLE_CLASS_COPY(FrameMarker) + + FrameMarker(FrameMarker &&other) noexcept : + m_name(other.m_name), m_started(other.m_started) + { + other.m_started = false; + } + + FrameMarker &operator=(FrameMarker &&other) noexcept + { + if (&other != this) { + end(); + m_name = other.m_name; + m_started = other.m_started; + other.m_started = false; + } + return *this; + } + + FrameMarker &&started() && + { + if (!m_started) { + FrameMarkStart(m_name); + m_started = true; + } + return std::move(*this); + } + + void start() + { + // no move happens, because we drop the reference + (void)std::move(*this).started(); + } + + void end() + { + if (m_started) { + m_started = false; + FrameMarkEnd(m_name); + } + } +}; From 47f199e6cb7af2705d6baee9a3e889fae5126183 Mon Sep 17 00:00:00 2001 From: grorp Date: Mon, 16 Sep 2024 10:16:27 +0200 Subject: [PATCH 33/67] Avoid cloud jump when switching between mainmenu and loading screen (#15163) ... by using the same Clouds object for both. The mainmenu clouds already used shaders before. I had to choose between both or neither, so now both the mainmenu clouds and the loading screen clouds use shaders if available. --- src/client/clientlauncher.cpp | 4 +++- src/client/clouds.cpp | 9 +++------ src/client/clouds.h | 6 +++--- src/gui/guiEngine.cpp | 29 ++--------------------------- src/gui/guiEngine.h | 16 +--------------- 5 files changed, 12 insertions(+), 52 deletions(-) diff --git a/src/client/clientlauncher.cpp b/src/client/clientlauncher.cpp index 1c9e397ca..e99fbff42 100644 --- a/src/client/clientlauncher.cpp +++ b/src/client/clientlauncher.cpp @@ -140,8 +140,10 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args) // Create the menu clouds // This is only global so it can be used by RenderingEngine::draw_load_screen(). assert(!g_menucloudsmgr && !g_menuclouds); + std::unique_ptr ssrc(createShaderSource()); + ssrc->addShaderConstantSetterFactory(new FogShaderConstantSetterFactory()); g_menucloudsmgr = m_rendering_engine->get_scene_manager()->createNewSceneManager(); - g_menuclouds = new Clouds(g_menucloudsmgr, nullptr, -1, rand()); + g_menuclouds = new Clouds(g_menucloudsmgr, ssrc.get(), -1, rand()); g_menuclouds->setHeight(100.0f); g_menuclouds->update(v3f(0, 0, 0), video::SColor(255, 240, 240, 255)); scene::ICameraSceneNode* camera; diff --git a/src/client/clouds.cpp b/src/client/clouds.cpp index 64e4b775a..71028768e 100644 --- a/src/client/clouds.cpp +++ b/src/client/clouds.cpp @@ -28,11 +28,9 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "settings.h" #include - -// Menu clouds are created later class Clouds; -Clouds *g_menuclouds = NULL; -scene::ISceneManager *g_menucloudsmgr = NULL; +scene::ISceneManager *g_menucloudsmgr = nullptr; +Clouds *g_menuclouds = nullptr; // Constant for now static constexpr const float cloud_size = BS * 64.0f; @@ -49,9 +47,8 @@ Clouds::Clouds(scene::ISceneManager* mgr, IShaderSource *ssrc, scene::ISceneNode(mgr->getRootSceneNode(), mgr, id), m_seed(seed) { + assert(ssrc); m_enable_shaders = g_settings->getBool("enable_shaders"); - // menu clouds use shader-less clouds for simplicity (ssrc == NULL) - m_enable_shaders = m_enable_shaders && ssrc; m_material.Lighting = false; m_material.BackfaceCulling = true; diff --git a/src/client/clouds.h b/src/client/clouds.h index 332aa81e9..acd4b0cfb 100644 --- a/src/client/clouds.h +++ b/src/client/clouds.h @@ -36,11 +36,11 @@ namespace irr::scene } // Menu clouds +// The mainmenu and the loading screen use the same Clouds object so that the +// clouds don't jump when switching between the two. class Clouds; -extern Clouds *g_menuclouds; - -// Scene manager used for menu clouds extern scene::ISceneManager *g_menucloudsmgr; +extern Clouds *g_menuclouds; class Clouds : public scene::ISceneNode { diff --git a/src/gui/guiEngine.cpp b/src/gui/guiEngine.cpp index 988d2924b..4a3d53f51 100644 --- a/src/gui/guiEngine.cpp +++ b/src/gui/guiEngine.cpp @@ -142,10 +142,6 @@ GUIEngine::GUIEngine(JoystickController *joystick, // create texture source m_texture_source = std::make_unique(rendering_engine->get_video_driver()); - // create shader source - // (currently only used by clouds) - m_shader_source.reset(createShaderSource()); - // create soundmanager #if USE_SOUND if (g_settings->getBool("enable_sound") && g_sound_manager_singleton.get()) { @@ -296,10 +292,6 @@ void GUIEngine::run() IrrlichtDevice *device = m_rendering_engine->get_raw_device(); video::IVideoDriver *driver = device->getVideoDriver(); - // Always create clouds because they may or may not be - // needed based on the game selected - cloudInit(); - unsigned int text_height = g_fontengine->getTextHeight(); // Reset fog color @@ -395,8 +387,6 @@ GUIEngine::~GUIEngine() m_irr_toplefttext->remove(); - m_cloud.clouds.reset(); - // delete textures for (image_definition &texture : m_textures) { if (texture.texture) @@ -404,26 +394,11 @@ GUIEngine::~GUIEngine() } } -/******************************************************************************/ -void GUIEngine::cloudInit() -{ - m_shader_source->addShaderConstantSetterFactory( - new FogShaderConstantSetterFactory()); - - m_cloud.clouds = make_irr(m_smgr, m_shader_source.get(), -1, rand()); - m_cloud.clouds->setHeight(100.0f); - m_cloud.clouds->update(v3f(0, 0, 0), video::SColor(255,240,240,255)); - - m_cloud.camera = m_smgr->addCameraSceneNode(0, - v3f(0,0,0), v3f(0, 60, 100)); - m_cloud.camera->setFarValue(10000); -} - /******************************************************************************/ void GUIEngine::drawClouds(float dtime) { - m_cloud.clouds->step(dtime*3); - m_smgr->drawAll(); + g_menuclouds->step(dtime * 3); + g_menucloudsmgr->drawAll(); } /******************************************************************************/ diff --git a/src/gui/guiEngine.h b/src/gui/guiEngine.h index fa4e1ebd3..2df0a0b60 100644 --- a/src/gui/guiEngine.h +++ b/src/gui/guiEngine.h @@ -203,8 +203,6 @@ private: MainMenuData *m_data = nullptr; /** texture source */ std::unique_ptr m_texture_source; - /** shader source */ - std::unique_ptr m_shader_source; /** sound manager */ std::unique_ptr m_sound_manager; @@ -279,23 +277,11 @@ private: /** and text that is in it */ EnrichedString m_toplefttext; - /** initialize cloud subsystem */ - void cloudInit(); /** do preprocessing for cloud subsystem */ void drawClouds(float dtime); - /** internam data required for drawing clouds */ - struct clouddata { - /** pointer to cloud class */ - irr_ptr clouds; - /** camera required for drawing clouds */ - scene::ICameraSceneNode *camera = nullptr; - }; - /** is drawing of clouds enabled atm */ - bool m_clouds_enabled = true; - /** data used to draw clouds */ - clouddata m_cloud; + bool m_clouds_enabled = true; static void fullscreenChangedCallback(const std::string &name, void *data); }; From 740dc0162e4d4891ecbadae7375d5e00b973e7f9 Mon Sep 17 00:00:00 2001 From: grorp Date: Mon, 16 Sep 2024 10:16:55 +0200 Subject: [PATCH 34/67] Don't use fixed pipeline lighting for stars (#15164) --- src/client/sky.cpp | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/client/sky.cpp b/src/client/sky.cpp index f309d444c..50ef56498 100644 --- a/src/client/sky.cpp +++ b/src/client/sky.cpp @@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include #include +#include "client/mesh.h" #include "client/tile.h" #include "noise.h" // easeCurve #include "profiler.h" @@ -77,10 +78,9 @@ Sky::Sky(s32 id, RenderingEngine *rendering_engine, ITextureSource *tsrc, IShade // Create materials m_materials[0] = baseMaterial(); - // FIXME: shouldn't this check m_enable_shaders? - m_materials[0].MaterialType = ssrc->getShaderInfo(ssrc->getShader("stars_shader", TILE_MATERIAL_ALPHA)).material; - m_materials[0].Lighting = true; - m_materials[0].ColorMaterial = video::ECM_NONE; + m_materials[0].MaterialType = m_enable_shaders ? + ssrc->getShaderInfo(ssrc->getShader("stars_shader", TILE_MATERIAL_ALPHA)).material : + video::EMT_TRANSPARENT_ALPHA_CHANNEL; m_materials[1] = baseMaterial(); m_materials[1].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; @@ -688,7 +688,10 @@ void Sky::draw_stars(video::IVideoDriver * driver, float wicked_time_of_day) color.a *= alpha; if (color.a <= 0.0f) // Stars are only drawn when not fully transparent return; - m_materials[0].EmissiveColor = color.toSColor(); + if (m_enable_shaders) + m_materials[0].EmissiveColor = color.toSColor(); + else + setMeshBufferColor(m_stars.get(), color.toSColor()); auto sky_rotation = core::matrix4().setRotationAxisRadians(2.0f * M_PI * (wicked_time_of_day - 0.25f), v3f(0.0f, 0.0f, 1.0f)); auto world_matrix = driver->getTransform(video::ETS_WORLD); @@ -835,7 +838,6 @@ void Sky::updateStars() vertices.reserve(4 * m_star_params.count); indices.reserve(6 * m_star_params.count); - video::SColor fallback_color = m_star_params.starcolor; // used on GLES 2 “without shaders” PcgRandom rgen(m_seed); float d = (0.006 / 2) * m_star_params.scale; for (u16 i = 0; i < m_star_params.count; i++) { @@ -854,10 +856,10 @@ void Sky::updateStars() a.rotateVect(p1); a.rotateVect(p2); a.rotateVect(p3); - vertices.push_back(video::S3DVertex(p, {}, fallback_color, {})); - vertices.push_back(video::S3DVertex(p1, {}, fallback_color, {})); - vertices.push_back(video::S3DVertex(p2, {}, fallback_color, {})); - vertices.push_back(video::S3DVertex(p3, {}, fallback_color, {})); + vertices.push_back(video::S3DVertex(p, {}, {}, {})); + vertices.push_back(video::S3DVertex(p1, {}, {}, {})); + vertices.push_back(video::S3DVertex(p2, {}, {}, {})); + vertices.push_back(video::S3DVertex(p3, {}, {}, {})); } for (u16 i = 0; i < m_star_params.count; i++) { indices.push_back(i * 4 + 0); @@ -867,7 +869,8 @@ void Sky::updateStars() indices.push_back(i * 4 + 3); indices.push_back(i * 4 + 0); } - m_stars->setHardwareMappingHint(scene::EHM_STATIC); + if (m_enable_shaders) + m_stars->setHardwareMappingHint(scene::EHM_STATIC); } void Sky::setSkyColors(const SkyColor &sky_color) From 65af606729f7e3c162bf0b77a02570697f784c66 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Tue, 10 Sep 2024 18:41:57 +0200 Subject: [PATCH 35/67] Fix CAO mesh lighting with shaders disabled the 'Lighting' material flag does not have portable behavior --- src/client/content_cao.cpp | 30 +++++++++++------------------- src/client/mesh.cpp | 7 ------- src/client/mesh.h | 5 ----- 3 files changed, 11 insertions(+), 31 deletions(-) diff --git a/src/client/content_cao.cpp b/src/client/content_cao.cpp index 72f24dfca..b87d36c4f 100644 --- a/src/client/content_cao.cpp +++ b/src/client/content_cao.cpp @@ -186,6 +186,12 @@ static bool logOnce(const std::ostringstream &from, std::ostream &log_to) return true; } +static void setEmissiveColor(scene::ISceneNode *node, video::SColor color) +{ + for (u32 i = 0; i < node->getMaterialCount(); ++i) + node->getMaterial(i).EmissiveColor = color; +} + /* TestCAO */ @@ -774,8 +780,6 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr) // set vertex colors to ensure alpha is set setMeshColor(m_animated_meshnode->getMesh(), video::SColor(0xFFFFFFFF)); - setAnimatedMeshColor(m_animated_meshnode, video::SColor(0xFFFFFFFF)); - setSceneNodeMaterials(m_animated_meshnode); m_animated_meshnode->forEachMaterial([this] (auto &mat) { @@ -923,26 +927,15 @@ void GenericCAO::setNodeLight(const video::SColor &light_color) } if (m_enable_shaders) { - if (m_prop.visual == "upright_sprite") { - if (!m_meshnode) - return; - for (u32 i = 0; i < m_meshnode->getMaterialCount(); ++i) - m_meshnode->getMaterial(i).EmissiveColor = light_color; - } else { - scene::ISceneNode *node = getSceneNode(); - if (!node) - return; - - for (u32 i = 0; i < node->getMaterialCount(); ++i) { - video::SMaterial &material = node->getMaterial(i); - material.EmissiveColor = light_color; - } - } + auto *node = getSceneNode(); + if (!node) + return; + setEmissiveColor(node, light_color); } else { if (m_meshnode) { setMeshColor(m_meshnode->getMesh(), light_color); } else if (m_animated_meshnode) { - setAnimatedMeshColor(m_animated_meshnode, light_color); + setMeshColor(m_animated_meshnode->getMesh(), light_color); } else if (m_spritenode) { m_spritenode->setColor(light_color); } @@ -1404,7 +1397,6 @@ void GenericCAO::updateTextures(std::string mod) material.MaterialType = m_material_type; material.MaterialTypeParam = m_material_type_param; material.TextureLayers[0].Texture = texture; - material.Lighting = true; material.BackfaceCulling = m_prop.backface_culling; // don't filter low-res textures, makes them look blurry diff --git a/src/client/mesh.cpp b/src/client/mesh.cpp index 6196e04d4..43c4f475b 100644 --- a/src/client/mesh.cpp +++ b/src/client/mesh.cpp @@ -181,13 +181,6 @@ void setMeshBufferColor(scene::IMeshBuffer *buf, const video::SColor &color) ((video::S3DVertex *) (vertices + i * stride))->Color = color; } -void setAnimatedMeshColor(scene::IAnimatedMeshSceneNode *node, const video::SColor &color) -{ - for (u32 i = 0; i < node->getMaterialCount(); ++i) { - node->getMaterial(i).EmissiveColor = color; - } -} - void setMeshColor(scene::IMesh *mesh, const video::SColor &color) { if (mesh == NULL) diff --git a/src/client/mesh.h b/src/client/mesh.h index 35d3886aa..931a5d818 100644 --- a/src/client/mesh.h +++ b/src/client/mesh.h @@ -59,11 +59,6 @@ void setMeshBufferColor(scene::IMeshBuffer *buf, const video::SColor &color); */ void setMeshColor(scene::IMesh *mesh, const video::SColor &color); -/* - Set a constant color for an animated mesh -*/ -void setAnimatedMeshColor(scene::IAnimatedMeshSceneNode *node, const video::SColor &color); - /*! * Overwrites the color of a mesh buffer. * The color is darkened based on the normal vector of the vertices. From 0fdcba197f03435d2efeca9de61dc584bd594708 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Tue, 10 Sep 2024 18:59:16 +0200 Subject: [PATCH 36/67] Fix VBO hint in content_cao --- src/client/content_cao.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/client/content_cao.cpp b/src/client/content_cao.cpp index b87d36c4f..467c74c42 100644 --- a/src/client/content_cao.cpp +++ b/src/client/content_cao.cpp @@ -814,15 +814,21 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr) } /* Set VBO hint */ - // - if shaders are disabled we modify the mesh often - // - sprites are also modified often - // - the wieldmesh sets its own hint - // - bone transformations do not need to modify the vertex data + // wieldmesh sets its own hint, no need to handle it if (m_enable_shaders && (m_meshnode || m_animated_meshnode)) { - if (m_meshnode) + // sprite uses vertex animation + if (m_meshnode && m_prop.visual != "upright_sprite") m_meshnode->getMesh()->setHardwareMappingHint(scene::EHM_STATIC); - if (m_animated_meshnode) - m_animated_meshnode->getMesh()->setHardwareMappingHint(scene::EHM_STATIC); + + if (m_animated_meshnode) { + auto *mesh = m_animated_meshnode->getMesh(); + // skinning happens on the CPU + if (m_animated_meshnode->getJointCount() > 0) + mesh->setHardwareMappingHint(scene::EHM_STREAM, scene::EBT_VERTEX); + else + mesh->setHardwareMappingHint(scene::EHM_STATIC, scene::EBT_VERTEX); + mesh->setHardwareMappingHint(scene::EHM_STATIC, scene::EBT_INDEX); + } } /* don't update while punch texture modifier is active */ From cc26b5384cc0eb1ab54ba5b796c9c2160777fe20 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Tue, 10 Sep 2024 20:29:02 +0200 Subject: [PATCH 37/67] Mark buffer as dirty in mesh helpers unclear if this fixes any actual bug --- src/client/mesh.cpp | 11 ++++++++--- src/client/mesh.h | 6 +++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/client/mesh.cpp b/src/client/mesh.cpp index 43c4f475b..1e32fcfd1 100644 --- a/src/client/mesh.cpp +++ b/src/client/mesh.cpp @@ -34,7 +34,7 @@ inline static void applyShadeFactor(video::SColor& color, float factor) color.setBlue(core::clamp(core::round32(color.getBlue()*factor), 0, 255)); } -void applyFacesShading(video::SColor &color, const v3f &normal) +void applyFacesShading(video::SColor &color, const v3f normal) { /* Some drawtypes have normals set to (0, 0, 0), this must result in @@ -133,6 +133,7 @@ void scaleMesh(scene::IMesh *mesh, v3f scale) for (u32 i = 0; i < vertex_count; i++) ((video::S3DVertex *)(vertices + i * stride))->Pos *= scale; + buf->setDirty(scene::EBT_VERTEX); buf->recalculateBoundingBox(); // calculate total bounding box @@ -161,6 +162,7 @@ void translateMesh(scene::IMesh *mesh, v3f vec) for (u32 i = 0; i < vertex_count; i++) ((video::S3DVertex *)(vertices + i * stride))->Pos += vec; + buf->setDirty(scene::EBT_VERTEX); buf->recalculateBoundingBox(); // calculate total bounding box @@ -172,16 +174,17 @@ void translateMesh(scene::IMesh *mesh, v3f vec) mesh->setBoundingBox(bbox); } -void setMeshBufferColor(scene::IMeshBuffer *buf, const video::SColor &color) +void setMeshBufferColor(scene::IMeshBuffer *buf, const video::SColor color) { const u32 stride = getVertexPitchFromType(buf->getVertexType()); u32 vertex_count = buf->getVertexCount(); u8 *vertices = (u8 *) buf->getVertices(); for (u32 i = 0; i < vertex_count; i++) ((video::S3DVertex *) (vertices + i * stride))->Color = color; + buf->setDirty(scene::EBT_VERTEX); } -void setMeshColor(scene::IMesh *mesh, const video::SColor &color) +void setMeshColor(scene::IMesh *mesh, const video::SColor color) { if (mesh == NULL) return; @@ -202,6 +205,7 @@ static void applyToMesh(scene::IMesh *mesh, const F &fn) char *vertices = reinterpret_cast(buf->getVertices()); for (u32 i = 0; i < vertex_count; i++) fn(reinterpret_cast(vertices + i * stride)); + buf->setDirty(scene::EBT_VERTEX); } } @@ -218,6 +222,7 @@ void colorizeMeshBuffer(scene::IMeshBuffer *buf, const video::SColor *buffercolo // Apply shading applyFacesShading(*vc, vertex->Normal); } + buf->setDirty(scene::EBT_VERTEX); } void setMeshColorByNormalXYZ(scene::IMesh *mesh, diff --git a/src/client/mesh.h b/src/client/mesh.h index 931a5d818..c04cfb0af 100644 --- a/src/client/mesh.h +++ b/src/client/mesh.h @@ -27,7 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc., * Applies shading to a color based on the surface's * normal vector. */ -void applyFacesShading(video::SColor &color, const v3f &normal); +void applyFacesShading(video::SColor &color, const v3f normal); /* Create a new cube mesh. @@ -52,12 +52,12 @@ void translateMesh(scene::IMesh *mesh, v3f vec); /*! * Sets a constant color for all vertices in the mesh buffer. */ -void setMeshBufferColor(scene::IMeshBuffer *buf, const video::SColor &color); +void setMeshBufferColor(scene::IMeshBuffer *buf, const video::SColor color); /* Set a constant color for all vertices in the mesh */ -void setMeshColor(scene::IMesh *mesh, const video::SColor &color); +void setMeshColor(scene::IMesh *mesh, const video::SColor color); /*! * Overwrites the color of a mesh buffer. From 6f275e2ba0956e5ec49bf2028dfb11898133af84 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Tue, 10 Sep 2024 21:02:22 +0200 Subject: [PATCH 38/67] Remove dead code in COpenGL3MaterialBaseCB --- client/shaders/Irrlicht/Solid.vsh | 1 - irr/src/OpenGL/FixedPipelineRenderer.cpp | 47 +++++++++++------------- irr/src/OpenGL/FixedPipelineRenderer.h | 17 +-------- 3 files changed, 22 insertions(+), 43 deletions(-) diff --git a/client/shaders/Irrlicht/Solid.vsh b/client/shaders/Irrlicht/Solid.vsh index 7379e5bb4..fd7467f5c 100644 --- a/client/shaders/Irrlicht/Solid.vsh +++ b/client/shaders/Irrlicht/Solid.vsh @@ -11,7 +11,6 @@ attribute vec2 inTexCoord0; uniform mat4 uWVPMatrix; uniform mat4 uWVMatrix; -uniform mat4 uNMatrix; uniform mat4 uTMatrix0; uniform float uThickness; diff --git a/irr/src/OpenGL/FixedPipelineRenderer.cpp b/irr/src/OpenGL/FixedPipelineRenderer.cpp index 7c4adf719..f87220b39 100644 --- a/irr/src/OpenGL/FixedPipelineRenderer.cpp +++ b/irr/src/OpenGL/FixedPipelineRenderer.cpp @@ -4,6 +4,7 @@ // For conditions of distribution and use, see copyright notice in Irrlicht.h #include "FixedPipelineRenderer.h" +#include "os.h" #include "IVideoDriver.h" @@ -15,23 +16,20 @@ namespace video // Base callback COpenGL3MaterialBaseCB::COpenGL3MaterialBaseCB() : - FirstUpdateBase(true), WVPMatrixID(-1), WVMatrixID(-1), NMatrixID(-1), + FirstUpdateBase(true), WVPMatrixID(-1), WVMatrixID(-1), FogEnableID(-1), FogTypeID(-1), FogColorID(-1), FogStartID(-1), - FogEndID(-1), FogDensityID(-1), ThicknessID(-1), LightEnable(false), MaterialAmbient(SColorf(0.f, 0.f, 0.f)), MaterialDiffuse(SColorf(0.f, 0.f, 0.f)), MaterialEmissive(SColorf(0.f, 0.f, 0.f)), MaterialSpecular(SColorf(0.f, 0.f, 0.f)), - MaterialShininess(0.f), FogEnable(0), FogType(1), FogColor(SColorf(0.f, 0.f, 0.f, 1.f)), FogStart(0.f), FogEnd(0.f), FogDensity(0.f), Thickness(1.f) + FogEndID(-1), FogDensityID(-1), ThicknessID(-1), Thickness(1.f), FogEnable(false) { } void COpenGL3MaterialBaseCB::OnSetMaterial(const SMaterial &material) { - LightEnable = material.Lighting; - MaterialAmbient = SColorf(material.AmbientColor); - MaterialDiffuse = SColorf(material.DiffuseColor); - MaterialEmissive = SColorf(material.EmissiveColor); - MaterialSpecular = SColorf(material.SpecularColor); - MaterialShininess = material.Shininess; +#ifdef _DEBUG + if (material.Lighting) + os::Printer::log("Lighted material not supported in unified driver.", ELL_INFORMATION); +#endif - FogEnable = material.FogEnable ? 1 : 0; + FogEnable = material.FogEnable; Thickness = (material.Thickness > 0.f) ? material.Thickness : 1.f; } @@ -43,7 +41,6 @@ void COpenGL3MaterialBaseCB::OnSetConstants(IMaterialRendererServices *services, if (FirstUpdateBase) { WVPMatrixID = services->getVertexShaderConstantID("uWVPMatrix"); WVMatrixID = services->getVertexShaderConstantID("uWVMatrix"); - NMatrixID = services->getVertexShaderConstantID("uNMatrix"); FogEnableID = services->getVertexShaderConstantID("uFogEnable"); FogTypeID = services->getVertexShaderConstantID("uFogType"); @@ -56,31 +53,29 @@ void COpenGL3MaterialBaseCB::OnSetConstants(IMaterialRendererServices *services, FirstUpdateBase = false; } - const core::matrix4 W = driver->getTransform(ETS_WORLD); - const core::matrix4 V = driver->getTransform(ETS_VIEW); - const core::matrix4 P = driver->getTransform(ETS_PROJECTION); + const core::matrix4 &W = driver->getTransform(ETS_WORLD); + const core::matrix4 &V = driver->getTransform(ETS_VIEW); + const core::matrix4 &P = driver->getTransform(ETS_PROJECTION); - core::matrix4 Matrix = P * V * W; - services->setPixelShaderConstant(WVPMatrixID, Matrix.pointer(), 16); - - Matrix = V * W; + core::matrix4 Matrix = V * W; services->setPixelShaderConstant(WVMatrixID, Matrix.pointer(), 16); - Matrix.makeInverse(); - services->setPixelShaderConstant(NMatrixID, Matrix.getTransposed().pointer(), 16); + Matrix = P * Matrix; + services->setPixelShaderConstant(WVPMatrixID, Matrix.pointer(), 16); - services->setPixelShaderConstant(FogEnableID, &FogEnable, 1); + s32 TempEnable = FogEnable ? 1 : 0; + services->setPixelShaderConstant(FogEnableID, &TempEnable, 1); if (FogEnable) { SColor TempColor(0); E_FOG_TYPE TempType = EFT_FOG_LINEAR; - bool TempPerFragment = false; - bool TempRange = false; + f32 FogStart, FogEnd, FogDensity; + bool unused = false; - driver->getFog(TempColor, TempType, FogStart, FogEnd, FogDensity, TempPerFragment, TempRange); + driver->getFog(TempColor, TempType, FogStart, FogEnd, FogDensity, unused, unused); - FogType = (s32)TempType; - FogColor = SColorf(TempColor); + s32 FogType = (s32)TempType; + SColorf FogColor(TempColor); services->setPixelShaderConstant(FogTypeID, &FogType, 1); services->setPixelShaderConstant(FogColorID, reinterpret_cast(&FogColor), 4); diff --git a/irr/src/OpenGL/FixedPipelineRenderer.h b/irr/src/OpenGL/FixedPipelineRenderer.h index a07af1df9..89e251a35 100644 --- a/irr/src/OpenGL/FixedPipelineRenderer.h +++ b/irr/src/OpenGL/FixedPipelineRenderer.h @@ -26,7 +26,6 @@ protected: s32 WVPMatrixID; s32 WVMatrixID; - s32 NMatrixID; s32 FogEnableID; s32 FogTypeID; @@ -37,22 +36,8 @@ protected: s32 ThicknessID; - bool LightEnable; - SColorf GlobalAmbient; - SColorf MaterialAmbient; - SColorf MaterialDiffuse; - SColorf MaterialEmissive; - SColorf MaterialSpecular; - f32 MaterialShininess; - - s32 FogEnable; - s32 FogType; - SColorf FogColor; - f32 FogStart; - f32 FogEnd; - f32 FogDensity; - f32 Thickness; + bool FogEnable; }; class COpenGL3MaterialSolidCB : public COpenGL3MaterialBaseCB From 58ea11c2b3101667e7a5ed118bf1cb2204f63586 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Thu, 12 Sep 2024 17:18:13 +0200 Subject: [PATCH 39/67] Add some debug helpers around this area --- irr/include/CIndexBuffer.h | 14 ++++++++++++++ irr/include/CVertexBuffer.h | 14 ++++++++++++++ irr/include/IReferenceCounted.h | 8 ++++++-- irr/src/CMakeLists.txt | 3 +++ irr/src/os.h | 1 - 5 files changed, 37 insertions(+), 3 deletions(-) diff --git a/irr/include/CIndexBuffer.h b/irr/include/CIndexBuffer.h index 4318ddaab..904b0ab9a 100644 --- a/irr/include/CIndexBuffer.h +++ b/irr/include/CIndexBuffer.h @@ -7,6 +7,13 @@ #include #include "IIndexBuffer.h" +// Define to receive warnings when violating the hw mapping hints +//#define INDEXBUFFER_HINT_DEBUG + +#ifdef INDEXBUFFER_HINT_DEBUG +#include "../src/os.h" +#endif + namespace irr { namespace scene @@ -58,6 +65,13 @@ public: void setDirty() override { ++ChangedID; +#ifdef INDEXBUFFER_HINT_DEBUG + if (MappingHint == EHM_STATIC && HWBuffer) { + char buf[100]; + snprintf_irr(buf, sizeof(buf), "CIndexBuffer @ %p modified, but it has a static hint", this); + os::Printer::log(buf, ELL_WARNING); + } +#endif } u32 getChangedID() const override { return ChangedID; } diff --git a/irr/include/CVertexBuffer.h b/irr/include/CVertexBuffer.h index 3559bbddb..4b3f33688 100644 --- a/irr/include/CVertexBuffer.h +++ b/irr/include/CVertexBuffer.h @@ -7,6 +7,13 @@ #include #include "IVertexBuffer.h" +// Define to receive warnings when violating the hw mapping hints +//#define VERTEXBUFFER_HINT_DEBUG + +#ifdef VERTEXBUFFER_HINT_DEBUG +#include "../src/os.h" +#endif + namespace irr { namespace scene @@ -87,6 +94,13 @@ public: void setDirty() override { ++ChangedID; +#ifdef VERTEXBUFFER_HINT_DEBUG + if (MappingHint == EHM_STATIC && HWBuffer) { + char buf[100]; + snprintf_irr(buf, sizeof(buf), "CVertexBuffer @ %p modified, but it has a static hint", this); + os::Printer::log(buf, ELL_WARNING); + } +#endif } u32 getChangedID() const override { return ChangedID; } diff --git a/irr/include/IReferenceCounted.h b/irr/include/IReferenceCounted.h index e1000d389..68aa20fb6 100644 --- a/irr/include/IReferenceCounted.h +++ b/irr/include/IReferenceCounted.h @@ -42,7 +42,7 @@ class IReferenceCounted public: //! Constructor. IReferenceCounted() : - DebugName(0), ReferenceCounter(1) + ReferenceCounter(1) { } @@ -136,6 +136,7 @@ public: return ReferenceCounter; } +#ifdef _DEBUG //! Returns the debug name of the object. /** The Debugname may only be set and changed by the object itself. This method should only be used in Debug mode. @@ -157,7 +158,10 @@ protected: private: //! The debug name. - const c8 *DebugName; + const c8 *DebugName = nullptr; +#endif + +private: //! The reference counter. Mutable to do reference counting on const objects. mutable s32 ReferenceCounter; diff --git a/irr/src/CMakeLists.txt b/irr/src/CMakeLists.txt index 742d27f72..22a0d0093 100644 --- a/irr/src/CMakeLists.txt +++ b/irr/src/CMakeLists.txt @@ -510,6 +510,9 @@ target_link_libraries(IrrlichtMt PRIVATE if(WIN32) target_compile_definitions(IrrlichtMt INTERFACE _IRR_WINDOWS_API_) # used in _IRR_DEBUG_BREAK_IF definition in a public header endif() +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + target_compile_definitions(IrrlichtMt INTERFACE _DEBUG) # same +endif() if(APPLE OR ANDROID OR EMSCRIPTEN) target_compile_definitions(IrrlichtMt PUBLIC IRR_MOBILE_PATHS) endif() diff --git a/irr/src/os.h b/irr/src/os.h index 58699ab3e..bcc096f95 100644 --- a/irr/src/os.h +++ b/irr/src/os.h @@ -52,7 +52,6 @@ public: // prints out a string to the console out stdout or debug log or whatever static void print(const c8 *message, ELOG_LEVEL ll = ELL_INFORMATION); static void log(const c8 *message, ELOG_LEVEL ll = ELL_INFORMATION); - static void log(const wchar_t *message, ELOG_LEVEL ll = ELL_INFORMATION); // The string ": " is added between message and hint static void log(const c8 *message, const c8 *hint, ELOG_LEVEL ll = ELL_INFORMATION); From 6dfd61cba0f31da0895395aa9183ea7b0e2b88e3 Mon Sep 17 00:00:00 2001 From: wrrrzr <161970349+wrrrzr@users.noreply.github.com> Date: Wed, 18 Sep 2024 13:17:55 +0300 Subject: [PATCH 40/67] Fix TODO in joystick code (#15179) --- src/client/joystick_controller.h | 5 +++++ src/gui/guiFormSpecMenu.cpp | 5 ++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/client/joystick_controller.h b/src/client/joystick_controller.h index 98486df43..d74cc3db6 100644 --- a/src/client/joystick_controller.h +++ b/src/client/joystick_controller.h @@ -155,6 +155,11 @@ public: float getMovementDirection(); float getMovementSpeed(); + u8 getJoystickId() const + { + return m_joystick_id; + } + f32 doubling_dtime; private: diff --git a/src/gui/guiFormSpecMenu.cpp b/src/gui/guiFormSpecMenu.cpp index 0371c26f3..40a445a0c 100644 --- a/src/gui/guiFormSpecMenu.cpp +++ b/src/gui/guiFormSpecMenu.cpp @@ -3976,10 +3976,9 @@ bool GUIFormSpecMenu::preprocessEvent(const SEvent& event) } if (event.EventType == irr::EET_JOYSTICK_INPUT_EVENT) { - /* TODO add a check like: - if (event.JoystickEvent != joystick_we_listen_for) + if (event.JoystickEvent.Joystick != m_joystick->getJoystickId()) return false; - */ + bool handled = m_joystick->handleEvent(event.JoystickEvent); if (handled) { if (m_joystick->wasKeyDown(KeyType::ESC)) { From 70e169f1652ecd68d5f32d627d253ec531225183 Mon Sep 17 00:00:00 2001 From: grorp Date: Wed, 18 Sep 2024 12:18:28 +0200 Subject: [PATCH 41/67] Drop fixed pipeline lighting stuff (#15165) --- .../shaders/cloud_shader/opengl_vertex.glsl | 4 +- .../shaders/object_shader/opengl_vertex.glsl | 4 +- .../shaders/stars_shader/opengl_fragment.glsl | 4 +- irr/include/EMaterialProps.h | 12 -- irr/include/SMaterial.h | 99 +------------- irr/include/SOverrideMaterial.h | 12 -- irr/src/CAnimatedMeshSceneNode.cpp | 3 - irr/src/CB3DMeshFileLoader.cpp | 20 +-- irr/src/CBillboardSceneNode.cpp | 1 - irr/src/CMeshSceneNode.cpp | 1 - irr/src/CNullDriver.cpp | 12 +- irr/src/COBJMeshFileLoader.cpp | 2 +- irr/src/COBJMeshFileLoader.h | 4 - irr/src/COpenGLDriver.cpp | 121 +----------------- irr/src/CXMeshFileLoader.cpp | 6 +- irr/src/OpenGL/Driver.cpp | 2 - irr/src/OpenGL/FixedPipelineRenderer.cpp | 6 - src/client/camera.cpp | 2 +- src/client/clientmap.cpp | 1 - src/client/clouds.cpp | 5 +- src/client/content_cao.cpp | 69 +--------- src/client/content_cso.cpp | 1 - src/client/hud.cpp | 4 - src/client/mapblock_mesh.cpp | 1 - src/client/mesh.cpp | 2 - src/client/minimap.cpp | 1 - src/client/particles.cpp | 1 - src/client/shader.cpp | 10 +- src/client/shadows/shadowsScreenQuad.cpp | 1 - src/client/sky.cpp | 40 +++--- src/client/wieldmesh.cpp | 24 +--- src/client/wieldmesh.h | 5 +- src/gui/guiScene.cpp | 1 - src/irrlicht_changes/CGUITTFont.cpp | 4 - 34 files changed, 59 insertions(+), 426 deletions(-) diff --git a/client/shaders/cloud_shader/opengl_vertex.glsl b/client/shaders/cloud_shader/opengl_vertex.glsl index 3f2e7d9b3..ebf4aae49 100644 --- a/client/shaders/cloud_shader/opengl_vertex.glsl +++ b/client/shaders/cloud_shader/opengl_vertex.glsl @@ -1,4 +1,4 @@ -uniform lowp vec4 emissiveColor; +uniform lowp vec4 materialColor; varying lowp vec4 varColor; @@ -14,7 +14,7 @@ void main(void) vec4 color = inVertexColor; #endif - color *= emissiveColor; + color *= materialColor; varColor = color; eyeVec = -(mWorldView * inVertexPosition).xyz; diff --git a/client/shaders/object_shader/opengl_vertex.glsl b/client/shaders/object_shader/opengl_vertex.glsl index 65acba92a..05134a5f6 100644 --- a/client/shaders/object_shader/opengl_vertex.glsl +++ b/client/shaders/object_shader/opengl_vertex.glsl @@ -1,7 +1,7 @@ uniform mat4 mWorld; uniform vec3 dayLight; uniform float animationTimer; -uniform lowp vec4 emissiveColor; +uniform lowp vec4 materialColor; varying vec3 vNormal; varying vec3 vPosition; @@ -115,7 +115,7 @@ void main(void) vec4 color = inVertexColor; #endif - color *= emissiveColor; + color *= materialColor; // The alpha gives the ratio of sunlight in the incoming light. nightRatio = 1.0 - color.a; diff --git a/client/shaders/stars_shader/opengl_fragment.glsl b/client/shaders/stars_shader/opengl_fragment.glsl index 224032fa3..e991e4f94 100644 --- a/client/shaders/stars_shader/opengl_fragment.glsl +++ b/client/shaders/stars_shader/opengl_fragment.glsl @@ -1,6 +1,6 @@ -uniform lowp vec4 emissiveColor; +uniform lowp vec4 materialColor; void main(void) { - gl_FragColor = emissiveColor; + gl_FragColor = materialColor; } diff --git a/irr/include/EMaterialProps.h b/irr/include/EMaterialProps.h index 6f37c95b8..765084340 100644 --- a/irr/include/EMaterialProps.h +++ b/irr/include/EMaterialProps.h @@ -18,12 +18,6 @@ enum E_MATERIAL_PROP //! Corresponds to SMaterial::PointCloud. EMP_POINTCLOUD = 0x2, - //! Corresponds to SMaterial::GouraudShading. - EMP_GOURAUD_SHADING = 0x4, - - //! Corresponds to SMaterial::Lighting. - EMP_LIGHTING = 0x8, - //! Corresponds to SMaterial::ZBuffer. EMP_ZBUFFER = 0x10, @@ -48,9 +42,6 @@ enum E_MATERIAL_PROP //! Corresponds to SMaterial::FogEnable. EMP_FOG_ENABLE = 0x800, - //! Corresponds to SMaterial::NormalizeNormals. - EMP_NORMALIZE_NORMALS = 0x1000, - //! Corresponds to SMaterialLayer::TextureWrapU, TextureWrapV and //! TextureWrapW. EMP_TEXTURE_WRAP = 0x2000, @@ -61,9 +52,6 @@ enum E_MATERIAL_PROP //! Corresponds to SMaterial::ColorMask. EMP_COLOR_MASK = 0x8000, - //! Corresponds to SMaterial::ColorMaterial. - EMP_COLOR_MATERIAL = 0x10000, - //! Corresponds to SMaterial::UseMipMaps. EMP_USE_MIP_MAPS = 0x20000, diff --git a/irr/include/SMaterial.h b/irr/include/SMaterial.h index 8f24b9984..cceccad78 100644 --- a/irr/include/SMaterial.h +++ b/irr/include/SMaterial.h @@ -194,29 +194,6 @@ enum E_ANTI_ALIASING_MODE EAAM_ALPHA_TO_COVERAGE = 4 }; -//! These flags allow to define the interpretation of vertex color when lighting is enabled -/** Without lighting being enabled the vertex color is the only value defining the fragment color. -Once lighting is enabled, the four values for diffuse, ambient, emissive, and specular take over. -With these flags it is possible to define which lighting factor shall be defined by the vertex color -instead of the lighting factor which is the same for all faces of that material. -The default is to use vertex color for the diffuse value, another pretty common value is to use -vertex color for both diffuse and ambient factor. */ -enum E_COLOR_MATERIAL -{ - //! Don't use vertex color for lighting - ECM_NONE = 0, - //! Use vertex color for diffuse light, this is default - ECM_DIFFUSE, - //! Use vertex color for ambient light - ECM_AMBIENT, - //! Use vertex color for emissive light - ECM_EMISSIVE, - //! Use vertex color for specular light - ECM_SPECULAR, - //! Use vertex color for both diffuse and ambient light - ECM_DIFFUSE_AND_AMBIENT -}; - //! Names for polygon offset direction const c8 *const PolygonOffsetDirectionNames[] = { "Back", @@ -262,16 +239,14 @@ class SMaterial public: //! Default constructor. Creates a solid, lit material with white colors SMaterial() : - MaterialType(EMT_SOLID), AmbientColor(255, 255, 255, 255), - DiffuseColor(255, 255, 255, 255), EmissiveColor(0, 0, 0, 0), - SpecularColor(255, 255, 255, 255), Shininess(0.0f), + MaterialType(EMT_SOLID), ColorParam(0, 0, 0, 0), MaterialTypeParam(0.0f), Thickness(1.0f), ZBuffer(ECFN_LESSEQUAL), - AntiAliasing(EAAM_SIMPLE), ColorMask(ECP_ALL), ColorMaterial(ECM_DIFFUSE), + AntiAliasing(EAAM_SIMPLE), ColorMask(ECP_ALL), BlendOperation(EBO_NONE), BlendFactor(0.0f), PolygonOffsetDepthBias(0.f), PolygonOffsetSlopeScale(0.f), Wireframe(false), PointCloud(false), - GouraudShading(true), Lighting(true), ZWriteEnable(EZW_AUTO), + ZWriteEnable(EZW_AUTO), BackfaceCulling(true), FrontfaceCulling(false), FogEnable(false), - NormalizeNormals(false), UseMipMaps(true) + UseMipMaps(true) { } @@ -281,42 +256,9 @@ public: //! Type of the material. Specifies how everything is blended together E_MATERIAL_TYPE MaterialType; - //! How much ambient light (a global light) is reflected by this material. - /** The default is full white, meaning objects are completely - globally illuminated. Reduce this if you want to see diffuse - or specular light effects. */ - SColor AmbientColor; - - //! How much diffuse light coming from a light source is reflected by this material. - /** The default is full white. */ - SColor DiffuseColor; - - //! Light emitted by this material. Default is to emit no light. - SColor EmissiveColor; - - //! How much specular light (highlights from a light) is reflected. - /** The default is to reflect white specular light. See - SMaterial::Shininess on how to enable specular lights. */ - SColor SpecularColor; - - //! Value affecting the size of specular highlights. - /** A value of 20 is common. If set to 0, no specular - highlights are being used. To activate, simply set the - shininess of a material to a value in the range [0.5;128]: - \code - sceneNode->getMaterial(0).Shininess = 20.0f; - \endcode - - You can change the color of the highlights using - \code - sceneNode->getMaterial(0).SpecularColor.set(255,255,255,255); - \endcode - - The specular color of the dynamic lights - (SLight::SpecularColor) will influence the the highlight color - too, but they are set to a useful value by default when - creating the light scene node.*/ - f32 Shininess; + //! Custom color parameter, can be used by custom shader materials. + // See MainShaderConstantSetter in Minetest. + SColor ColorParam; //! Free parameter, dependent on the material type. /** Mostly ignored, used for example in @@ -344,14 +286,6 @@ public: depth or stencil buffer, or using Red and Green for Stereo rendering. */ u8 ColorMask : 4; - //! Defines the interpretation of vertex color in the lighting equation - /** Values should be chosen from E_COLOR_MATERIAL. - When lighting is enabled, vertex color can be used instead of the - material values for light modulation. This allows to easily change e.g. the - diffuse light behavior of each face. The default, ECM_DIFFUSE, will result in - a very similar rendering as with lighting turned off, just with light shading. */ - u8 ColorMaterial : 3; - //! Store the blend operation of choice /** Values to be chosen from E_BLEND_OPERATION. */ E_BLEND_OPERATION BlendOperation : 4; @@ -392,12 +326,6 @@ public: //! Draw as point cloud or filled triangles? Default: false bool PointCloud : 1; - //! Flat or Gouraud shading? Default: true - bool GouraudShading : 1; - - //! Will this material be lighted? Default: true - bool Lighting : 1; - //! Is the zbuffer writable or is it read-only. Default: EZW_AUTO. /** If this parameter is not EZW_OFF, you probably also want to set ZBuffer to values other than ECFN_DISABLED */ @@ -412,10 +340,6 @@ public: //! Is fog enabled? Default: false bool FogEnable : 1; - //! Should normals be normalized? - /** Always use this if the mesh lit and scaled. Default: false */ - bool NormalizeNormals : 1; - //! Shall mipmaps be used if available /** Sometimes, disabling mipmap usage can be useful. Default: true */ bool UseMipMaps : 1; @@ -486,26 +410,17 @@ public: { bool different = MaterialType != b.MaterialType || - AmbientColor != b.AmbientColor || - DiffuseColor != b.DiffuseColor || - EmissiveColor != b.EmissiveColor || - SpecularColor != b.SpecularColor || - Shininess != b.Shininess || MaterialTypeParam != b.MaterialTypeParam || Thickness != b.Thickness || Wireframe != b.Wireframe || PointCloud != b.PointCloud || - GouraudShading != b.GouraudShading || - Lighting != b.Lighting || ZBuffer != b.ZBuffer || ZWriteEnable != b.ZWriteEnable || BackfaceCulling != b.BackfaceCulling || FrontfaceCulling != b.FrontfaceCulling || FogEnable != b.FogEnable || - NormalizeNormals != b.NormalizeNormals || AntiAliasing != b.AntiAliasing || ColorMask != b.ColorMask || - ColorMaterial != b.ColorMaterial || BlendOperation != b.BlendOperation || BlendFactor != b.BlendFactor || PolygonOffsetDepthBias != b.PolygonOffsetDepthBias || diff --git a/irr/include/SOverrideMaterial.h b/irr/include/SOverrideMaterial.h index c52a55b55..1ae324211 100644 --- a/irr/include/SOverrideMaterial.h +++ b/irr/include/SOverrideMaterial.h @@ -98,12 +98,6 @@ struct SOverrideMaterial case EMP_POINTCLOUD: material.PointCloud = Material.PointCloud; break; - case EMP_GOURAUD_SHADING: - material.GouraudShading = Material.GouraudShading; - break; - case EMP_LIGHTING: - material.Lighting = Material.Lighting; - break; case EMP_ZBUFFER: material.ZBuffer = Material.ZBuffer; break; @@ -140,9 +134,6 @@ struct SOverrideMaterial case EMP_FOG_ENABLE: material.FogEnable = Material.FogEnable; break; - case EMP_NORMALIZE_NORMALS: - material.NormalizeNormals = Material.NormalizeNormals; - break; case EMP_TEXTURE_WRAP: for (u32 i = 0; i < MATERIAL_MAX_TEXTURES; ++i) { if (EnableLayerProps[i]) { @@ -158,9 +149,6 @@ struct SOverrideMaterial case EMP_COLOR_MASK: material.ColorMask = Material.ColorMask; break; - case EMP_COLOR_MATERIAL: - material.ColorMaterial = Material.ColorMaterial; - break; case EMP_USE_MIP_MAPS: material.UseMipMaps = Material.UseMipMaps; break; diff --git a/irr/src/CAnimatedMeshSceneNode.cpp b/irr/src/CAnimatedMeshSceneNode.cpp index c3a71f943..295d408f3 100644 --- a/irr/src/CAnimatedMeshSceneNode.cpp +++ b/irr/src/CAnimatedMeshSceneNode.cpp @@ -258,7 +258,6 @@ void CAnimatedMeshSceneNode::render() // for debug purposes only: if (DebugDataVisible && PassCount == 1) { video::SMaterial debug_mat; - debug_mat.Lighting = false; debug_mat.AntiAliasing = 0; driver->setMaterial(debug_mat); // show normals @@ -280,7 +279,6 @@ void CAnimatedMeshSceneNode::render() } debug_mat.ZBuffer = video::ECFN_DISABLED; - debug_mat.Lighting = false; driver->setMaterial(debug_mat); if (DebugDataVisible & scene::EDS_BBOX) @@ -316,7 +314,6 @@ void CAnimatedMeshSceneNode::render() // show mesh if (DebugDataVisible & scene::EDS_MESH_WIRE_OVERLAY) { - debug_mat.Lighting = false; debug_mat.Wireframe = true; debug_mat.ZBuffer = video::ECFN_DISABLED; driver->setMaterial(debug_mat); diff --git a/irr/src/CB3DMeshFileLoader.cpp b/irr/src/CB3DMeshFileLoader.cpp index 4cd7b1d82..4d78860b2 100644 --- a/irr/src/CB3DMeshFileLoader.cpp +++ b/irr/src/CB3DMeshFileLoader.cpp @@ -485,7 +485,8 @@ bool CB3DMeshFileLoader::readChunkTRIS(scene::SSkinMeshBuffer *meshBuffer, u32 m video::S3DVertex *Vertex = meshBuffer->getVertex(meshBuffer->getVertexCount() - 1); if (!HasVertexColors) - Vertex->Color = B3dMaterial->Material.DiffuseColor; + Vertex->Color = video::SColorf(B3dMaterial->red, B3dMaterial->green, + B3dMaterial->blue, B3dMaterial->alpha).toSColor(); else if (Vertex->Color.getAlpha() == 255) Vertex->Color.setAlpha((s32)(B3dMaterial->alpha * 255.0f)); @@ -890,23 +891,8 @@ bool CB3DMeshFileLoader::readChunkBRUS() } } - B3dMaterial.Material.DiffuseColor = video::SColorf(B3dMaterial.red, B3dMaterial.green, B3dMaterial.blue, B3dMaterial.alpha).toSColor(); - B3dMaterial.Material.ColorMaterial = video::ECM_NONE; - //------ Material fx ------ - if (B3dMaterial.fx & 1) { // full-bright - B3dMaterial.Material.AmbientColor = video::SColor(255, 255, 255, 255); - B3dMaterial.Material.Lighting = false; - } else - B3dMaterial.Material.AmbientColor = B3dMaterial.Material.DiffuseColor; - - if (B3dMaterial.fx & 2) // use vertex colors instead of brush color - B3dMaterial.Material.ColorMaterial = video::ECM_DIFFUSE_AND_AMBIENT; - - if (B3dMaterial.fx & 4) // flatshaded - B3dMaterial.Material.GouraudShading = false; - if (B3dMaterial.fx & 16) // disable backface culling B3dMaterial.Material.BackfaceCulling = false; @@ -914,8 +900,6 @@ bool CB3DMeshFileLoader::readChunkBRUS() B3dMaterial.Material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; B3dMaterial.Material.ZWriteEnable = video::EZW_OFF; } - - B3dMaterial.Material.Shininess = B3dMaterial.shininess; } B3dStack.erase(B3dStack.size() - 1); diff --git a/irr/src/CBillboardSceneNode.cpp b/irr/src/CBillboardSceneNode.cpp index db75a2af4..1c6d88dae 100644 --- a/irr/src/CBillboardSceneNode.cpp +++ b/irr/src/CBillboardSceneNode.cpp @@ -85,7 +85,6 @@ void CBillboardSceneNode::render() if (DebugDataVisible & scene::EDS_BBOX) { driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); video::SMaterial m; - m.Lighting = false; driver->setMaterial(m); driver->draw3DBox(BBoxSafe, video::SColor(0, 208, 195, 152)); } diff --git a/irr/src/CMeshSceneNode.cpp b/irr/src/CMeshSceneNode.cpp index 7ff6cad55..030e1fd15 100644 --- a/irr/src/CMeshSceneNode.cpp +++ b/irr/src/CMeshSceneNode.cpp @@ -115,7 +115,6 @@ void CMeshSceneNode::render() // for debug purposes only: if (DebugDataVisible && PassCount == 1) { video::SMaterial m; - m.Lighting = false; m.AntiAliasing = 0; driver->setMaterial(m); diff --git a/irr/src/CNullDriver.cpp b/irr/src/CNullDriver.cpp index 91f441a14..c7b296b57 100644 --- a/irr/src/CNullDriver.cpp +++ b/irr/src/CNullDriver.cpp @@ -104,7 +104,6 @@ CNullDriver::CNullDriver(io::IFileSystem *io, const core::dimension2d &scre FeatureEnabled[i] = true; InitMaterial2D.AntiAliasing = video::EAAM_OFF; - InitMaterial2D.Lighting = false; InitMaterial2D.ZWriteEnable = video::EZW_OFF; InitMaterial2D.ZBuffer = video::ECFN_DISABLED; InitMaterial2D.UseMipMaps = false; @@ -1131,15 +1130,10 @@ void CNullDriver::drawBuffers(const scene::IVertexBuffer *vb, void CNullDriver::drawMeshBufferNormals(const scene::IMeshBuffer *mb, f32 length, SColor color) { const u32 count = mb->getVertexCount(); - const bool normalize = mb->getMaterial().NormalizeNormals; - for (u32 i = 0; i < count; ++i) { - core::vector3df normalizedNormal = mb->getNormal(i); - if (normalize) - normalizedNormal.normalize(); - + core::vector3df normal = mb->getNormal(i); const core::vector3df &pos = mb->getPosition(i); - draw3DLine(pos, pos + (normalizedNormal * length), color); + draw3DLine(pos, pos + (normal * length), color); } } @@ -1306,10 +1300,8 @@ void CNullDriver::runOcclusionQuery(scene::ISceneNode *node, bool visible) OcclusionQueries[index].Run = 0; if (!visible) { SMaterial mat; - mat.Lighting = false; mat.AntiAliasing = 0; mat.ColorMask = ECP_NONE; - mat.GouraudShading = false; mat.ZWriteEnable = EZW_OFF; setMaterial(mat); } diff --git a/irr/src/COBJMeshFileLoader.cpp b/irr/src/COBJMeshFileLoader.cpp index bceba6a90..97e90c322 100644 --- a/irr/src/COBJMeshFileLoader.cpp +++ b/irr/src/COBJMeshFileLoader.cpp @@ -182,7 +182,7 @@ IAnimatedMesh *COBJMeshFileLoader::createMesh(io::IReadFile *file) mtlChanged = false; } if (currMtl) - v.Color = currMtl->Meshbuffer->Material.DiffuseColor; + v.Color = video::SColorf(0.8f, 0.8f, 0.8f, 1.0f).toSColor(); // get all vertices data in this face (current line of obj file) const core::stringc wordBuffer = copyLine(bufPtr, bufEnd); diff --git a/irr/src/COBJMeshFileLoader.h b/irr/src/COBJMeshFileLoader.h index 63e768e4f..467392a3e 100644 --- a/irr/src/COBJMeshFileLoader.h +++ b/irr/src/COBJMeshFileLoader.h @@ -43,10 +43,6 @@ private: RecalculateNormals(false) { Meshbuffer = new SMeshBuffer(); - Meshbuffer->Material.Shininess = 0.0f; - Meshbuffer->Material.AmbientColor = video::SColorf(0.2f, 0.2f, 0.2f, 1.0f).toSColor(); - Meshbuffer->Material.DiffuseColor = video::SColorf(0.8f, 0.8f, 0.8f, 1.0f).toSColor(); - Meshbuffer->Material.SpecularColor = video::SColorf(1.0f, 1.0f, 1.0f, 1.0f).toSColor(); } SObjMtl(const SObjMtl &o) : diff --git a/irr/src/COpenGLDriver.cpp b/irr/src/COpenGLDriver.cpp index 837dc05d3..e5f070f8e 100644 --- a/irr/src/COpenGLDriver.cpp +++ b/irr/src/COpenGLDriver.cpp @@ -1840,112 +1840,11 @@ void COpenGLDriver::setBasicRenderStates(const SMaterial &material, const SMater E_OPENGL_FIXED_PIPELINE_STATE tempState = FixedPipelineState; if (resetAllRenderStates || tempState == EOFPS_ENABLE || tempState == EOFPS_DISABLE_TO_ENABLE) { - // material colors - if (resetAllRenderStates || tempState == EOFPS_DISABLE_TO_ENABLE || - lastmaterial.ColorMaterial != material.ColorMaterial) { - switch (material.ColorMaterial) { - case ECM_NONE: - glDisable(GL_COLOR_MATERIAL); - break; - case ECM_DIFFUSE: - glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); - break; - case ECM_AMBIENT: - glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT); - break; - case ECM_EMISSIVE: - glColorMaterial(GL_FRONT_AND_BACK, GL_EMISSION); - break; - case ECM_SPECULAR: - glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR); - break; - case ECM_DIFFUSE_AND_AMBIENT: - glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); - break; - } - if (material.ColorMaterial != ECM_NONE) - glEnable(GL_COLOR_MATERIAL); - } - - if (resetAllRenderStates || tempState == EOFPS_DISABLE_TO_ENABLE || - lastmaterial.AmbientColor != material.AmbientColor || - lastmaterial.DiffuseColor != material.DiffuseColor || - lastmaterial.EmissiveColor != material.EmissiveColor || - lastmaterial.ColorMaterial != material.ColorMaterial) { - GLfloat color[4]; - - const f32 inv = 1.0f / 255.0f; - - if ((material.ColorMaterial != video::ECM_AMBIENT) && - (material.ColorMaterial != video::ECM_DIFFUSE_AND_AMBIENT)) { - color[0] = material.AmbientColor.getRed() * inv; - color[1] = material.AmbientColor.getGreen() * inv; - color[2] = material.AmbientColor.getBlue() * inv; - color[3] = material.AmbientColor.getAlpha() * inv; - glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, color); - } - - if ((material.ColorMaterial != video::ECM_DIFFUSE) && - (material.ColorMaterial != video::ECM_DIFFUSE_AND_AMBIENT)) { - color[0] = material.DiffuseColor.getRed() * inv; - color[1] = material.DiffuseColor.getGreen() * inv; - color[2] = material.DiffuseColor.getBlue() * inv; - color[3] = material.DiffuseColor.getAlpha() * inv; - glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, color); - } - - if (material.ColorMaterial != video::ECM_EMISSIVE) { - color[0] = material.EmissiveColor.getRed() * inv; - color[1] = material.EmissiveColor.getGreen() * inv; - color[2] = material.EmissiveColor.getBlue() * inv; - color[3] = material.EmissiveColor.getAlpha() * inv; - glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, color); - } - } - - if (resetAllRenderStates || tempState == EOFPS_DISABLE_TO_ENABLE || - lastmaterial.SpecularColor != material.SpecularColor || - lastmaterial.Shininess != material.Shininess || - lastmaterial.ColorMaterial != material.ColorMaterial) { - GLfloat color[4] = {0.f, 0.f, 0.f, 1.f}; - const f32 inv = 1.0f / 255.0f; - - glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, material.Shininess); - // disable Specular colors if no shininess is set - if ((material.Shininess != 0.0f) && - (material.ColorMaterial != video::ECM_SPECULAR)) { -#ifdef GL_EXT_separate_specular_color - if (FeatureAvailable[IRR_EXT_separate_specular_color]) - glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR); -#endif - color[0] = material.SpecularColor.getRed() * inv; - color[1] = material.SpecularColor.getGreen() * inv; - color[2] = material.SpecularColor.getBlue() * inv; - color[3] = material.SpecularColor.getAlpha() * inv; - } -#ifdef GL_EXT_separate_specular_color - else if (FeatureAvailable[IRR_EXT_separate_specular_color]) - glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR); -#endif - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, color); - } - - // shademode - if (resetAllRenderStates || tempState == EOFPS_DISABLE_TO_ENABLE || - lastmaterial.GouraudShading != material.GouraudShading) { - if (material.GouraudShading) - glShadeModel(GL_SMOOTH); - else - glShadeModel(GL_FLAT); - } - - // lighting - if (resetAllRenderStates || tempState == EOFPS_DISABLE_TO_ENABLE || - lastmaterial.Lighting != material.Lighting) { - if (material.Lighting) - glEnable(GL_LIGHTING); - else - glDisable(GL_LIGHTING); + if (resetAllRenderStates || tempState == EOFPS_DISABLE_TO_ENABLE) { + glDisable(GL_COLOR_MATERIAL); + glDisable(GL_LIGHTING); + glShadeModel(GL_SMOOTH); + glDisable(GL_NORMALIZE); } // fog @@ -1957,15 +1856,6 @@ void COpenGLDriver::setBasicRenderStates(const SMaterial &material, const SMater glDisable(GL_FOG); } - // normalization - if (resetAllRenderStates || tempState == EOFPS_DISABLE_TO_ENABLE || - lastmaterial.NormalizeNormals != material.NormalizeNormals) { - if (material.NormalizeNormals) - glEnable(GL_NORMALIZE); - else - glDisable(GL_NORMALIZE); - } - // Set fixed pipeline as active. tempState = EOFPS_ENABLE; } else if (tempState == EOFPS_ENABLE_TO_DISABLE) { @@ -2405,7 +2295,6 @@ void COpenGLDriver::setRenderStates2DMode(bool alpha, bool texture, bool alphaCh } SMaterial currentMaterial = (!OverrideMaterial2DEnabled) ? InitMaterial2D : OverrideMaterial2D; - currentMaterial.Lighting = false; if (texture) { setTransform(ETS_TEXTURE_0, core::IdentityMatrix); diff --git a/irr/src/CXMeshFileLoader.cpp b/irr/src/CXMeshFileLoader.cpp index 483955805..fc0e6e237 100644 --- a/irr/src/CXMeshFileLoader.cpp +++ b/irr/src/CXMeshFileLoader.cpp @@ -109,10 +109,6 @@ bool CXMeshFileLoader::load(io::IReadFile *file) // default material if nothing loaded if (!mesh->Materials.size()) { mesh->Materials.push_back(video::SMaterial()); - mesh->Materials[0].DiffuseColor.set(0xff777777); - mesh->Materials[0].Shininess = 0.f; - mesh->Materials[0].SpecularColor.set(0xff777777); - mesh->Materials[0].EmissiveColor.set(0xff000000); } u32 i; @@ -142,7 +138,7 @@ bool CXMeshFileLoader::load(io::IReadFile *file) if (!mesh->HasVertexColors) { for (u32 j = 0; j < mesh->FaceMaterialIndices.size(); ++j) { for (u32 id = j * 3 + 0; id <= j * 3 + 2; ++id) { - mesh->Vertices[mesh->Indices[id]].Color = mesh->Buffers[mesh->FaceMaterialIndices[j]]->Material.DiffuseColor; + mesh->Vertices[mesh->Indices[id]].Color = 0xff777777; } } } diff --git a/irr/src/OpenGL/Driver.cpp b/irr/src/OpenGL/Driver.cpp index 3a921d104..fe9a24758 100644 --- a/irr/src/OpenGL/Driver.cpp +++ b/irr/src/OpenGL/Driver.cpp @@ -1478,10 +1478,8 @@ void COpenGL3DriverBase::chooseMaterial2D() Material = InitMaterial2D; if (OverrideMaterial2DEnabled) { - OverrideMaterial2D.Lighting = false; OverrideMaterial2D.ZWriteEnable = EZW_OFF; OverrideMaterial2D.ZBuffer = ECFN_DISABLED; // it will be ECFN_DISABLED after merge - OverrideMaterial2D.Lighting = false; Material = OverrideMaterial2D; } diff --git a/irr/src/OpenGL/FixedPipelineRenderer.cpp b/irr/src/OpenGL/FixedPipelineRenderer.cpp index f87220b39..cef446587 100644 --- a/irr/src/OpenGL/FixedPipelineRenderer.cpp +++ b/irr/src/OpenGL/FixedPipelineRenderer.cpp @@ -24,13 +24,7 @@ COpenGL3MaterialBaseCB::COpenGL3MaterialBaseCB() : void COpenGL3MaterialBaseCB::OnSetMaterial(const SMaterial &material) { -#ifdef _DEBUG - if (material.Lighting) - os::Printer::log("Lighted material not supported in unified driver.", ELL_INFORMATION); -#endif - FogEnable = material.FogEnable; - Thickness = (material.Thickness > 0.f) ? material.Thickness : 1.f; } diff --git a/src/client/camera.cpp b/src/client/camera.cpp index f13046848..bf9ec0bd5 100644 --- a/src/client/camera.cpp +++ b/src/client/camera.cpp @@ -63,7 +63,7 @@ Camera::Camera(MapDrawControl &draw_control, Client *client, RenderingEngine *re // all other 3D scene nodes and before the GUI. m_wieldmgr = smgr->createNewSceneManager(); m_wieldmgr->addCameraSceneNode(); - m_wieldnode = new WieldMeshSceneNode(m_wieldmgr, -1, false); + m_wieldnode = new WieldMeshSceneNode(m_wieldmgr, -1); m_wieldnode->setItem(ItemStack(), m_client); m_wieldnode->drop(); // m_wieldmgr grabbed it diff --git a/src/client/clientmap.cpp b/src/client/clientmap.cpp index 12945ed1b..3cc3564bc 100644 --- a/src/client/clientmap.cpp +++ b/src/client/clientmap.cpp @@ -1223,7 +1223,6 @@ void ClientMap::renderMapShadows(video::IVideoDriver *driver, local_material.FrontfaceCulling = material.FrontfaceCulling; } local_material.BlendOperation = material.BlendOperation; - local_material.Lighting = false; driver->setMaterial(local_material); ++material_swaps; } diff --git a/src/client/clouds.cpp b/src/client/clouds.cpp index 71028768e..a7154c2c7 100644 --- a/src/client/clouds.cpp +++ b/src/client/clouds.cpp @@ -50,7 +50,6 @@ Clouds::Clouds(scene::ISceneManager* mgr, IShaderSource *ssrc, assert(ssrc); m_enable_shaders = g_settings->getBool("enable_shaders"); - m_material.Lighting = false; m_material.BackfaceCulling = true; m_material.FogEnable = true; m_material.AntiAliasing = video::EAAM_SIMPLE; @@ -139,7 +138,7 @@ void Clouds::updateMesh() video::SColorf c_side_2_f(m_color); video::SColorf c_bottom_f(m_color); if (m_enable_shaders) { - // shader mixes the base color, set via EmissiveColor + // shader mixes the base color, set via ColorParam c_top_f = c_side_1_f = c_side_2_f = c_bottom_f = video::SColorf(1.0f, 1.0f, 1.0f, 1.0f); } c_side_1_f.r *= 0.95f; @@ -364,7 +363,7 @@ void Clouds::render() m_material.BackfaceCulling = is3D(); if (m_enable_shaders) - m_material.EmissiveColor = m_color.toSColor(); + m_material.ColorParam = m_color.toSColor(); driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); driver->setMaterial(m_material); diff --git a/src/client/content_cao.cpp b/src/client/content_cao.cpp index 467c74c42..adec70983 100644 --- a/src/client/content_cao.cpp +++ b/src/client/content_cao.cpp @@ -186,10 +186,10 @@ static bool logOnce(const std::ostringstream &from, std::ostream &log_to) return true; } -static void setEmissiveColor(scene::ISceneNode *node, video::SColor color) +static void setColorParam(scene::ISceneNode *node, video::SColor color) { for (u32 i = 0; i < node->getMaterialCount(); ++i) - node->getMaterial(i).EmissiveColor = color; + node->getMaterial(i).ColorParam = color; } /* @@ -261,7 +261,6 @@ void TestCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr) u16 indices[] = {0,1,2,2,3,0}; buf->append(vertices, 4, indices, 6); // Set material - buf->getMaterial().Lighting = false; buf->getMaterial().BackfaceCulling = false; buf->getMaterial().TextureLayers[0].Texture = tsrc->getTextureForMesh("rat.png"); buf->getMaterial().TextureLayers[0].MinFilter = video::ETMINF_NEAREST_MIPMAP_NEAREST; @@ -648,12 +647,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr) auto setMaterial = [this] (video::SMaterial &mat) { mat.MaterialType = m_material_type; - mat.Lighting = false; mat.FogEnable = true; - if (m_enable_shaders) { - mat.GouraudShading = false; - mat.NormalizeNormals = true; - } mat.forEachTexture([] (auto &tex) { tex.MinFilter = video::ETMINF_NEAREST_MIPMAP_NEAREST; tex.MagFilter = video::ETMAGF_NEAREST; @@ -710,7 +704,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr) // Set material setMaterial(buf->getMaterial()); if (m_enable_shaders) { - buf->getMaterial().EmissiveColor = c; + buf->getMaterial().ColorParam = c; } // Add to mesh @@ -736,7 +730,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr) // Set material setMaterial(buf->getMaterial()); if (m_enable_shaders) { - buf->getMaterial().EmissiveColor = c; + buf->getMaterial().ColorParam = c; } // Add to mesh @@ -936,7 +930,7 @@ void GenericCAO::setNodeLight(const video::SColor &light_color) auto *node = getSceneNode(); if (!node) return; - setEmissiveColor(node, light_color); + setColorParam(node, light_color); } else { if (m_meshnode) { setMeshColor(m_meshnode->getMesh(), light_color); @@ -1366,15 +1360,6 @@ void GenericCAO::updateTextures(std::string mod) material.MaterialTypeParam = m_material_type_param; material.setTexture(0, tsrc->getTextureForMesh(texturestring)); - // This allows setting per-material colors. However, until a real lighting - // system is added, the code below will have no effect. Once MineTest - // has directional lighting, it should work automatically. - if (!m_prop.colors.empty()) { - material.AmbientColor = m_prop.colors[0]; - material.DiffuseColor = m_prop.colors[0]; - material.SpecularColor = m_prop.colors[0]; - } - material.forEachTexture([=] (auto &tex) { setMaterialFilters(tex, use_bilinear_filter, use_trilinear_filter, use_anisotropic_filter); @@ -1417,17 +1402,6 @@ void GenericCAO::updateTextures(std::string mod) use_anisotropic_filter); }); } - for (u32 i = 0; i < m_prop.colors.size() && - i < m_animated_meshnode->getMaterialCount(); ++i) - { - video::SMaterial &material = m_animated_meshnode->getMaterial(i); - // This allows setting per-material colors. However, until a real lighting - // system is added, the code below will have no effect. Once MineTest - // has directional lighting, it should work automatically. - material.AmbientColor = m_prop.colors[i]; - material.DiffuseColor = m_prop.colors[i]; - material.SpecularColor = m_prop.colors[i]; - } } } @@ -1445,20 +1419,9 @@ void GenericCAO::updateTextures(std::string mod) video::SMaterial &material = m_meshnode->getMaterial(i); material.MaterialType = m_material_type; material.MaterialTypeParam = m_material_type_param; - material.Lighting = false; material.setTexture(0, tsrc->getTextureForMesh(texturestring)); material.getTextureMatrix(0).makeIdentity(); - // This allows setting per-material colors. However, until a real lighting - // system is added, the code below will have no effect. Once MineTest - // has directional lighting, it should work automatically. - if(m_prop.colors.size() > i) - { - material.AmbientColor = m_prop.colors[i]; - material.DiffuseColor = m_prop.colors[i]; - material.SpecularColor = m_prop.colors[i]; - } - material.forEachTexture([=] (auto &tex) { setMaterialFilters(tex, use_bilinear_filter, use_trilinear_filter, use_anisotropic_filter); @@ -1475,15 +1438,6 @@ void GenericCAO::updateTextures(std::string mod) auto &material = m_meshnode->getMaterial(0); material.setTexture(0, tsrc->getTextureForMesh(tname)); - // This allows setting per-material colors. However, until a real lighting - // system is added, the code below will have no effect. Once MineTest - // has directional lighting, it should work automatically. - if(!m_prop.colors.empty()) { - material.AmbientColor = m_prop.colors[0]; - material.DiffuseColor = m_prop.colors[0]; - material.SpecularColor = m_prop.colors[0]; - } - material.forEachTexture([=] (auto &tex) { setMaterialFilters(tex, use_bilinear_filter, use_trilinear_filter, use_anisotropic_filter); @@ -1500,19 +1454,6 @@ void GenericCAO::updateTextures(std::string mod) auto &material = m_meshnode->getMaterial(1); material.setTexture(0, tsrc->getTextureForMesh(tname)); - // This allows setting per-material colors. However, until a real lighting - // system is added, the code below will have no effect. Once MineTest - // has directional lighting, it should work automatically. - if (m_prop.colors.size() >= 2) { - material.AmbientColor = m_prop.colors[1]; - material.DiffuseColor = m_prop.colors[1]; - material.SpecularColor = m_prop.colors[1]; - } else if (!m_prop.colors.empty()) { - material.AmbientColor = m_prop.colors[0]; - material.DiffuseColor = m_prop.colors[0]; - material.SpecularColor = m_prop.colors[0]; - } - material.forEachTexture([=] (auto &tex) { setMaterialFilters(tex, use_bilinear_filter, use_trilinear_filter, use_anisotropic_filter); diff --git a/src/client/content_cso.cpp b/src/client/content_cso.cpp index 821c2507d..733044b23 100644 --- a/src/client/content_cso.cpp +++ b/src/client/content_cso.cpp @@ -40,7 +40,6 @@ public: video::ITexture *tex = env->getGameDef()->tsrc()->getTextureForMesh("smoke_puff.png"); m_spritenode->forEachMaterial([tex] (auto &mat) { mat.TextureLayers[0].Texture = tex; - mat.Lighting = false; mat.TextureLayers[0].MinFilter = video::ETMINF_NEAREST_MIPMAP_NEAREST; mat.TextureLayers[0].MagFilter = video::ETMAGF_NEAREST; mat.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; diff --git a/src/client/hud.cpp b/src/client/hud.cpp index 0a5db6858..e4c06b542 100644 --- a/src/client/hud.cpp +++ b/src/client/hud.cpp @@ -99,7 +99,6 @@ Hud::Hud(Client *client, LocalPlayer *player, // Initialize m_selection_material - m_selection_material.Lighting = false; if (g_settings->getBool("enable_shaders")) { IShaderSource *shdrsrc = client->getShaderSource(); @@ -121,7 +120,6 @@ Hud::Hud(Client *client, LocalPlayer *player, } // Initialize m_block_bounds_material - m_block_bounds_material.Lighting = false; if (g_settings->getBool("enable_shaders")) { IShaderSource *shdrsrc = client->getShaderSource(); auto shader_id = shdrsrc->getShader("default_shader", TILE_MATERIAL_ALPHA); @@ -155,7 +153,6 @@ Hud::Hud(Client *client, LocalPlayer *player, indices[4] = 3; indices[5] = 0; - b->getMaterial().Lighting = false; b->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; b->setHardwareMappingHint(scene::EHM_STATIC); } @@ -1205,7 +1202,6 @@ void drawItemStack( video::SMaterial &material = buf->getMaterial(); material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; - material.Lighting = false; driver->setMaterial(material); driver->drawMeshBuffer(buf); } diff --git a/src/client/mapblock_mesh.cpp b/src/client/mapblock_mesh.cpp index 9c0caa9d0..1933baddf 100644 --- a/src/client/mapblock_mesh.cpp +++ b/src/client/mapblock_mesh.cpp @@ -736,7 +736,6 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs // Create material video::SMaterial material; - material.Lighting = false; material.BackfaceCulling = true; material.FogEnable = true; material.setTexture(0, p.layer.texture); diff --git a/src/client/mesh.cpp b/src/client/mesh.cpp index 1e32fcfd1..9e66404e3 100644 --- a/src/client/mesh.cpp +++ b/src/client/mesh.cpp @@ -99,7 +99,6 @@ scene::IAnimatedMesh* createCubeMesh(v3f scale) scene::IMeshBuffer *buf = new scene::SMeshBuffer(); buf->append(vertices + 4 * i, 4, indices, 6); // Set default material - buf->getMaterial().Lighting = false; buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; buf->getMaterial().forEachTexture([] (auto &tex) { tex.MinFilter = video::ETMINF_NEAREST_MIPMAP_NEAREST; @@ -401,7 +400,6 @@ scene::IMesh* convertNodeboxesToMesh(const std::vector &boxes, for (u16 j = 0; j < 6; j++) { scene::IMeshBuffer *buf = new scene::SMeshBuffer(); - buf->getMaterial().Lighting = false; buf->getMaterial().forEachTexture([] (auto &tex) { tex.MinFilter = video::ETMINF_NEAREST_MIPMAP_NEAREST; tex.MagFilter = video::ETMAGF_NEAREST; diff --git a/src/client/minimap.cpp b/src/client/minimap.cpp index b2fc0882d..4f3c81f4f 100644 --- a/src/client/minimap.cpp +++ b/src/client/minimap.cpp @@ -612,7 +612,6 @@ void Minimap::drawMinimap(core::rect rect) tex.MinFilter = video::ETMINF_LINEAR_MIPMAP_LINEAR; tex.MagFilter = video::ETMAGF_LINEAR; }); - material.Lighting = false; material.TextureLayers[0].Texture = minimap_texture; material.TextureLayers[1].Texture = data->heightmap_texture; diff --git a/src/client/particles.cpp b/src/client/particles.cpp index c19282424..1eab93579 100644 --- a/src/client/particles.cpp +++ b/src/client/particles.cpp @@ -989,7 +989,6 @@ video::SMaterial ParticleManager::getMaterialForParticle(const ClientParticleTex video::SMaterial material; // Texture - material.Lighting = false; material.BackfaceCulling = false; material.FogEnable = true; material.forEachTexture([] (auto &tex) { diff --git a/src/client/shader.cpp b/src/client/shader.cpp index 242fda81c..f43bc27dc 100644 --- a/src/client/shader.cpp +++ b/src/client/shader.cpp @@ -218,15 +218,15 @@ class MainShaderConstantSetter : public IShaderConstantSetter CachedVertexShaderSetting m_texture{"mTexture"}; // commonly used way to pass material color to shader - video::SColor m_emissive_color; - CachedPixelShaderSetting m_emissive_color_setting{"emissiveColor"}; + video::SColor m_material_color; + CachedPixelShaderSetting m_material_color_setting{"materialColor"}; public: ~MainShaderConstantSetter() = default; virtual void onSetMaterial(const video::SMaterial& material) override { - m_emissive_color = material.EmissiveColor; + m_material_color = material.ColorParam; } virtual void onSetConstants(video::IMaterialRendererServices *services) override @@ -254,8 +254,8 @@ public: m_texture.set(texture, services); } - video::SColorf emissive_color(m_emissive_color); - m_emissive_color_setting.set(emissive_color, services); + video::SColorf colorf(m_material_color); + m_material_color_setting.set(colorf, services); } }; diff --git a/src/client/shadows/shadowsScreenQuad.cpp b/src/client/shadows/shadowsScreenQuad.cpp index f0eb9ab4a..d1713578d 100644 --- a/src/client/shadows/shadowsScreenQuad.cpp +++ b/src/client/shadows/shadowsScreenQuad.cpp @@ -23,7 +23,6 @@ with this program; if not, write to the Free Software Foundation, Inc., shadowScreenQuad::shadowScreenQuad() { Material.Wireframe = false; - Material.Lighting = false; video::SColor color(0x0); Vertices[0] = video::S3DVertex( diff --git a/src/client/sky.cpp b/src/client/sky.cpp index 50ef56498..65577418e 100644 --- a/src/client/sky.cpp +++ b/src/client/sky.cpp @@ -39,7 +39,6 @@ using namespace irr::core; static video::SMaterial baseMaterial() { video::SMaterial mat; - mat.Lighting = false; mat.ZBuffer = video::ECFN_DISABLED; mat.ZWriteEnable = video::EZW_OFF; mat.AntiAliasing = 0; @@ -95,7 +94,6 @@ Sky::Sky(s32 id, RenderingEngine *rendering_engine, ITextureSource *tsrc, IShade for (int i = 5; i < 11; i++) { m_materials[i] = baseMaterial(); - m_materials[i].Lighting = true; m_materials[i].MaterialType = video::EMT_SOLID; } @@ -169,7 +167,8 @@ void Sky::render() video::SColor texel_color (255, texel->getRed(), texel->getGreen(), texel->getBlue()); m_sun_tonemap->unlock(); - m_materials[3].EmissiveColor = texel_color; + // Only accessed by our code later, not used by a shader + m_materials[3].ColorParam = texel_color; } if (m_moon_tonemap) { @@ -178,7 +177,8 @@ void Sky::render() video::SColor texel_color (255, texel->getRed(), texel->getGreen(), texel->getBlue()); m_moon_tonemap->unlock(); - m_materials[4].EmissiveColor = texel_color; + // Only accessed by our code later, not used by a shader + m_materials[4].ColorParam = texel_color; } const f32 t = 1.0f; @@ -465,11 +465,11 @@ void Sky::update(float time_of_day, float time_brightness, // which keeps previous behavior. if (m_sun_tonemap && m_default_tint) { pointcolor_sun_f.r = pointcolor_light * - (float)m_materials[3].EmissiveColor.getRed() / 255; + (float)m_materials[3].ColorParam.getRed() / 255; pointcolor_sun_f.b = pointcolor_light * - (float)m_materials[3].EmissiveColor.getBlue() / 255; + (float)m_materials[3].ColorParam.getBlue() / 255; pointcolor_sun_f.g = pointcolor_light * - (float)m_materials[3].EmissiveColor.getGreen() / 255; + (float)m_materials[3].ColorParam.getGreen() / 255; } else if (!m_default_tint) { pointcolor_sun_f = m_sky_params.fog_sun_tint; } else { @@ -498,11 +498,11 @@ void Sky::update(float time_of_day, float time_brightness, } if (m_moon_tonemap && m_default_tint) { pointcolor_moon_f.r = pointcolor_light * - (float)m_materials[4].EmissiveColor.getRed() / 255; + (float)m_materials[4].ColorParam.getRed() / 255; pointcolor_moon_f.b = pointcolor_light * - (float)m_materials[4].EmissiveColor.getBlue() / 255; + (float)m_materials[4].ColorParam.getBlue() / 255; pointcolor_moon_f.g = pointcolor_light * - (float)m_materials[4].EmissiveColor.getGreen() / 255; + (float)m_materials[4].ColorParam.getGreen() / 255; } video::SColor pointcolor_sun = pointcolor_sun_f.toSColor(); @@ -603,11 +603,8 @@ void Sky::draw_sun(video::IVideoDriver *driver, const video::SColor &suncolor, // Another magic number that contributes to the ratio 1.57 sun/moon size // difference. float d = (sunsize * 1.7) * m_sun_params.scale; - video::SColor c; - if (m_sun_tonemap) - c = video::SColor(0, 0, 0, 0); - else - c = video::SColor(255, 255, 255, 255); + video::SColor c = m_sun_tonemap ? m_materials[3].ColorParam : + video::SColor(255, 255, 255, 255); draw_sky_body(vertices, -d, d, c); place_sky_body(vertices, 90, wicked_time_of_day * 360 - 90); driver->drawIndexedTriangleList(&vertices[0], 4, indices, 2); @@ -660,11 +657,8 @@ void Sky::draw_moon(video::IVideoDriver *driver, const video::SColor &mooncolor, // Another magic number that contributes to the ratio 1.57 sun/moon size // difference. float d = (moonsize * 1.9) * m_moon_params.scale; - video::SColor c; - if (m_moon_tonemap) - c = video::SColor(0, 0, 0, 0); - else - c = video::SColor(255, 255, 255, 255); + video::SColor c = m_sun_tonemap ? m_materials[4].ColorParam : + video::SColor(255, 255, 255, 255); draw_sky_body(vertices, -d, d, c); place_sky_body(vertices, -90, wicked_time_of_day * 360 - 90); driver->drawIndexedTriangleList(&vertices[0], 4, indices, 2); @@ -689,7 +683,7 @@ void Sky::draw_stars(video::IVideoDriver * driver, float wicked_time_of_day) if (color.a <= 0.0f) // Stars are only drawn when not fully transparent return; if (m_enable_shaders) - m_materials[0].EmissiveColor = color.toSColor(); + m_materials[0].ColorParam = color.toSColor(); else setMeshBufferColor(m_stars.get(), color.toSColor()); @@ -745,7 +739,6 @@ void Sky::setSunTexture(const std::string &sun_texture, m_sun_params.tonemap = sun_tonemap; m_sun_tonemap = tsrc->isKnownSourceImage(sun_tonemap) ? tsrc->getTexture(sun_tonemap) : nullptr; - m_materials[3].Lighting = !!m_sun_tonemap; if (m_sun_params.texture == sun_texture && !m_first_update) return; @@ -765,7 +758,6 @@ void Sky::setSunTexture(const std::string &sun_texture, m_materials[3].setTexture(0, m_sun_texture); m_materials[3].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; disableTextureFiltering(m_materials[3]); - m_materials[3].Lighting = !!m_sun_tonemap; } } @@ -789,7 +781,6 @@ void Sky::setMoonTexture(const std::string &moon_texture, m_moon_params.tonemap = moon_tonemap; m_moon_tonemap = tsrc->isKnownSourceImage(moon_tonemap) ? tsrc->getTexture(moon_tonemap) : nullptr; - m_materials[4].Lighting = !!m_moon_tonemap; if (m_moon_params.texture == moon_texture && !m_first_update) return; @@ -809,7 +800,6 @@ void Sky::setMoonTexture(const std::string &moon_texture, m_materials[4].setTexture(0, m_moon_texture); m_materials[4].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; disableTextureFiltering(m_materials[4]); - m_materials[4].Lighting = !!m_moon_tonemap; } } diff --git a/src/client/wieldmesh.cpp b/src/client/wieldmesh.cpp index 148130606..e66214ae6 100644 --- a/src/client/wieldmesh.cpp +++ b/src/client/wieldmesh.cpp @@ -194,10 +194,9 @@ private: static ExtrusionMeshCache *g_extrusion_mesh_cache = nullptr; -WieldMeshSceneNode::WieldMeshSceneNode(scene::ISceneManager *mgr, s32 id, bool lighting): +WieldMeshSceneNode::WieldMeshSceneNode(scene::ISceneManager *mgr, s32 id): scene::ISceneNode(mgr->getRootSceneNode(), mgr, id), - m_material_type(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF), - m_lighting(lighting) + m_material_type(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF) { m_enable_shaders = g_settings->getBool("enable_shaders"); m_anisotropic_filter = g_settings->getBool("anisotropic_filter"); @@ -390,8 +389,7 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che // overlay is white, if present m_colors.emplace_back(true, video::SColor(0xFFFFFFFF)); // initialize the color - if (!m_lighting) - setColor(video::SColor(0xFFFFFFFF)); + setColor(video::SColor(0xFFFFFFFF)); return; } @@ -468,8 +466,7 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che } // initialize the color - if (!m_lighting) - setColor(video::SColor(0xFFFFFFFF)); + setColor(video::SColor(0xFFFFFFFF)); return; } else { const std::string inventory_image = item.getInventoryImage(idef); @@ -485,8 +482,7 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che m_colors.emplace_back(true, video::SColor(0xFFFFFFFF)); // initialize the color - if (!m_lighting) - setColor(video::SColor(0xFFFFFFFF)); + setColor(video::SColor(0xFFFFFFFF)); return; } @@ -496,7 +492,6 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che void WieldMeshSceneNode::setColor(video::SColor c) { - assert(!m_lighting); scene::IMesh *mesh = m_meshnode->getMesh(); if (!mesh) return; @@ -535,7 +530,7 @@ void WieldMeshSceneNode::setNodeLightColor(video::SColor color) if (m_enable_shaders) { for (u32 i = 0; i < m_meshnode->getMaterialCount(); ++i) { video::SMaterial &material = m_meshnode->getMaterial(i); - material.EmissiveColor = color; + material.ColorParam = color; } } else { setColor(color); @@ -565,11 +560,6 @@ void WieldMeshSceneNode::changeToMesh(scene::IMesh *mesh) mesh->setHardwareMappingHint(scene::EHM_DYNAMIC); } - m_meshnode->forEachMaterial([this] (auto &mat) { - mat.Lighting = m_lighting; - // need to normalize normals when lighting is enabled (because of setScale()) - mat.NormalizeNormals = m_lighting; - }); m_meshnode->setVisible(true); } @@ -667,7 +657,6 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result) tex.MagFilter = video::ETMAGF_NEAREST; }); material.BackfaceCulling = cull_backface; - material.Lighting = false; } rotateMeshXZby(mesh, -45); @@ -720,7 +709,6 @@ scene::SMesh *getExtrudedMesh(ITextureSource *tsrc, tex.MagFilter = video::ETMAGF_NEAREST; }); material.BackfaceCulling = true; - material.Lighting = false; material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; material.MaterialTypeParam = 0.5f; } diff --git a/src/client/wieldmesh.h b/src/client/wieldmesh.h index e2c6cd445..08240c8ef 100644 --- a/src/client/wieldmesh.h +++ b/src/client/wieldmesh.h @@ -104,7 +104,7 @@ struct ItemMesh class WieldMeshSceneNode : public scene::ISceneNode { public: - WieldMeshSceneNode(scene::ISceneManager *mgr, s32 id = -1, bool lighting = false); + WieldMeshSceneNode(scene::ISceneManager *mgr, s32 id = -1); virtual ~WieldMeshSceneNode(); void setCube(const ContentFeatures &f, v3f wield_scale); @@ -132,9 +132,6 @@ private: scene::IMeshSceneNode *m_meshnode = nullptr; video::E_MATERIAL_TYPE m_material_type; - // True if SMaterial::Lighting should be enabled. - bool m_lighting; - bool m_enable_shaders; bool m_anisotropic_filter; bool m_bilinear_filter; diff --git a/src/gui/guiScene.cpp b/src/gui/guiScene.cpp index a26cfa93f..9293ebe22 100644 --- a/src/gui/guiScene.cpp +++ b/src/gui/guiScene.cpp @@ -67,7 +67,6 @@ void GUIScene::setTexture(u32 idx, video::ITexture *texture) material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; material.MaterialTypeParam = 0.5f; material.TextureLayers[0].Texture = texture; - material.Lighting = false; material.FogEnable = true; material.TextureLayers[0].MinFilter = video::ETMINF_NEAREST_MIPMAP_NEAREST; material.TextureLayers[0].MagFilter = video::ETMAGF_NEAREST; diff --git a/src/irrlicht_changes/CGUITTFont.cpp b/src/irrlicht_changes/CGUITTFont.cpp index 4f5f52b4e..022ab46b0 100644 --- a/src/irrlicht_changes/CGUITTFont.cpp +++ b/src/irrlicht_changes/CGUITTFont.cpp @@ -1098,13 +1098,9 @@ core::array CGUITTFont::addTextSceneNode(const wchar_t* text // the default font material SMaterial mat; - mat.Lighting = true; mat.ZWriteEnable = video::EZW_OFF; - mat.NormalizeNormals = true; - mat.ColorMaterial = video::ECM_NONE; mat.MaterialType = use_transparency ? video::EMT_TRANSPARENT_ALPHA_CHANNEL : video::EMT_SOLID; mat.MaterialTypeParam = 0.01f; - mat.DiffuseColor = color; wchar_t current_char = 0, previous_char = 0; u32 n = 0; From 6d01ed5d74ff0a911416d5ceaa17df22787c88bc Mon Sep 17 00:00:00 2001 From: Desour Date: Mon, 10 Jul 2023 00:00:00 +0200 Subject: [PATCH 42/67] irr_ptr: Allow to use with forward-declared types Also add [[nodiscard]] to ::grab() (because similar named irr_ptr::grab() returns void). And use new std::is_convertible_v. --- src/irr_ptr.h | 30 ++++++++++++++++-------------- src/unittest/test_irrptr.cpp | 1 + 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/irr_ptr.h b/src/irr_ptr.h index fc4a0f558..48717976b 100644 --- a/src/irr_ptr.h +++ b/src/irr_ptr.h @@ -20,8 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #pragma once #include #include -#include "irrlichttypes.h" -#include "IReferenceCounted.h" +namespace irr { class IReferenceCounted; } /** Shared pointer for IrrLicht objects. * @@ -37,15 +36,13 @@ with this program; if not, write to the Free Software Foundation, Inc., * from such object is a bug and may lead to a crash. Indirect construction * is possible though; see the @c grab free function for details and use cases. */ -template ::value>::type> +template class irr_ptr { ReferenceCounted *value = nullptr; public: - irr_ptr() {} + irr_ptr() noexcept = default; irr_ptr(std::nullptr_t) noexcept {} @@ -53,15 +50,15 @@ public: irr_ptr(irr_ptr &&b) noexcept { reset(b.release()); } - template ::value>::type> + template , bool> = true> irr_ptr(const irr_ptr &b) noexcept { grab(b.get()); } - template ::value>::type> + template , bool> = true> irr_ptr(irr_ptr &&b) noexcept { reset(b.release()); @@ -88,16 +85,16 @@ public: return *this; } - template ::value>::type> + template , bool> = true> irr_ptr &operator=(const irr_ptr &b) noexcept { grab(b.get()); return *this; } - template ::value>::type> + template , bool> = true> irr_ptr &operator=(irr_ptr &&b) noexcept { reset(b.release()); @@ -128,6 +125,8 @@ public: */ void reset(ReferenceCounted *object = nullptr) noexcept { + static_assert(std::is_base_of_v, + "Class is not an IReferenceCounted"); if (value) value->drop(); value = object; @@ -138,6 +137,8 @@ public: */ void grab(ReferenceCounted *object) noexcept { + static_assert(std::is_base_of_v, + "Class is not an IReferenceCounted"); if (object) object->grab(); reset(object); @@ -152,6 +153,7 @@ public: * in this function and decreased when the returned pointer is destroyed. */ template +[[nodiscard]] irr_ptr grab(ReferenceCounted *object) noexcept { irr_ptr ptr; diff --git a/src/unittest/test_irrptr.cpp b/src/unittest/test_irrptr.cpp index befeefc73..61d1e302c 100644 --- a/src/unittest/test_irrptr.cpp +++ b/src/unittest/test_irrptr.cpp @@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "exceptions.h" #include "irr_ptr.h" +#include "IReferenceCounted.h" class TestIrrPtr : public TestBase { From e3efaa1733703224a6f703b1102a96d0b74681d5 Mon Sep 17 00:00:00 2001 From: Desour Date: Tue, 17 Sep 2024 10:02:34 +0200 Subject: [PATCH 43/67] Move irr_ptr.h too irr/include/ --- {src => irr/include}/irr_ptr.h | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {src => irr/include}/irr_ptr.h (100%) diff --git a/src/irr_ptr.h b/irr/include/irr_ptr.h similarity index 100% rename from src/irr_ptr.h rename to irr/include/irr_ptr.h From ecf8c7696a20c59b35709ae87d09972d2afedb0d Mon Sep 17 00:00:00 2001 From: Desour Date: Mon, 10 Jul 2023 00:00:00 +0200 Subject: [PATCH 44/67] Use irr_ptr for ClientEnvironment::m_map --- src/client/client.cpp | 2 +- src/client/clientenvironment.cpp | 11 +++++------ src/client/clientenvironment.h | 5 +++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/client/client.cpp b/src/client/client.cpp index dedbebbb4..b14ef7004 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -120,7 +120,7 @@ Client::Client( m_rendering_engine(rendering_engine), m_mesh_update_manager(std::make_unique(this)), m_env( - new ClientMap(this, rendering_engine, control, 666), + make_irr(this, rendering_engine, control, 666), tsrc, this ), m_particle_manager(std::make_unique(&m_env)), diff --git a/src/client/clientenvironment.cpp b/src/client/clientenvironment.cpp index f1ec14d3b..08c5586ea 100644 --- a/src/client/clientenvironment.cpp +++ b/src/client/clientenvironment.cpp @@ -43,10 +43,10 @@ with this program; if not, write to the Free Software Foundation, Inc., ClientEnvironment */ -ClientEnvironment::ClientEnvironment(ClientMap *map, +ClientEnvironment::ClientEnvironment(irr_ptr map, ITextureSource *texturesource, Client *client): Environment(client), - m_map(map), + m_map(std::move(map)), m_texturesource(texturesource), m_client(client) { @@ -60,18 +60,17 @@ ClientEnvironment::~ClientEnvironment() delete simple_object; } - // Drop/delete map - m_map->drop(); + m_map.reset(); delete m_local_player; } -Map & ClientEnvironment::getMap() +Map &ClientEnvironment::getMap() { return *m_map; } -ClientMap & ClientEnvironment::getClientMap() +ClientMap &ClientEnvironment::getClientMap() { return *m_map; } diff --git a/src/client/clientenvironment.h b/src/client/clientenvironment.h index bdb8b9726..db31e69f2 100644 --- a/src/client/clientenvironment.h +++ b/src/client/clientenvironment.h @@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "environment.h" #include "util/numeric.h" // IntervalLimiter #include "activeobjectmgr.h" // client::ActiveObjectMgr +#include "irr_ptr.h" #include #ifdef SERVER @@ -66,7 +67,7 @@ typedef std::unordered_map ClientActiveObjectMap; class ClientEnvironment : public Environment { public: - ClientEnvironment(ClientMap *map, ITextureSource *texturesource, Client *client); + ClientEnvironment(irr_ptr map, ITextureSource *texturesource, Client *client); ~ClientEnvironment(); Map & getMap(); @@ -151,7 +152,7 @@ public: u64 getFrameTimeDelta() const { return m_frame_dtime; } private: - ClientMap *m_map; + irr_ptr m_map; LocalPlayer *m_local_player = nullptr; ITextureSource *m_texturesource; Client *m_client; From 37b374cb92e0a73d5dd97262d8b5a12471380714 Mon Sep 17 00:00:00 2001 From: Desour Date: Tue, 11 Jul 2023 00:00:00 +0200 Subject: [PATCH 45/67] Use irr_ptr for Game::clouds --- src/client/game.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/client/game.cpp b/src/client/game.cpp index 6e01f2ffe..95f67c3a5 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -893,7 +893,7 @@ private: GUIChatConsole *gui_chat_console = nullptr; // Free using ->Drop() MapDrawControl *draw_control = nullptr; Camera *camera = nullptr; - Clouds *clouds = nullptr; // Free using ->Drop() + irr_ptr clouds; Sky *sky = nullptr; // Free using ->Drop() Hud *hud = nullptr; Minimap *mapper = nullptr; @@ -1263,8 +1263,7 @@ void Game::shutdown() if (m_shutdown_progress == 0.0f) showOverlayMessage(N_("Shutting down..."), 0, 0); - if (clouds) - clouds->drop(); + clouds.reset(); if (gui_chat_console) gui_chat_console->drop(); @@ -1524,7 +1523,7 @@ bool Game::createClient(const GameStartData &start_data) /* Clouds */ if (m_cache_enable_clouds) - clouds = new Clouds(smgr, shader_src, -1, rand()); + clouds = make_irr(smgr, shader_src, -1, rand()); /* Skybox */ From 17c041a65c91611442a8fa75bbb613ba2761ba42 Mon Sep 17 00:00:00 2001 From: Desour Date: Tue, 11 Jul 2023 00:00:00 +0200 Subject: [PATCH 46/67] Use irr_ptr for Game::gui_chat_console --- src/client/game.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/client/game.cpp b/src/client/game.cpp index 95f67c3a5..1dcaa225b 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -890,7 +890,7 @@ private: QuicktuneShortcutter *quicktune = nullptr; std::unique_ptr m_game_ui; - GUIChatConsole *gui_chat_console = nullptr; // Free using ->Drop() + irr_ptr gui_chat_console; MapDrawControl *draw_control = nullptr; Camera *camera = nullptr; irr_ptr clouds; @@ -1265,8 +1265,7 @@ void Game::shutdown() clouds.reset(); - if (gui_chat_console) - gui_chat_console->drop(); + gui_chat_console.reset(); if (sky) sky->drop(); @@ -1581,7 +1580,7 @@ bool Game::initGui() chat_backend->applySettings(); // Chat backend and console - gui_chat_console = new GUIChatConsole(guienv, guienv->getRootGUIElement(), + gui_chat_console = make_irr(guienv, guienv->getRootGUIElement(), -1, chat_backend, client, &g_menumgr); if (g_settings->getBool("touch_controls")) { @@ -2037,7 +2036,7 @@ void Game::updateStats(RunStats *stats, const FpsControl &draw_times, void Game::processUserInput(f32 dtime) { // Reset input if window not active or some menu is active - if (!device->isWindowActive() || isMenuActive() || guienv->hasFocus(gui_chat_console)) { + if (!device->isWindowActive() || isMenuActive() || guienv->hasFocus(gui_chat_console.get())) { if (m_game_focused) { m_game_focused = false; infostream << "Game lost focus" << std::endl; @@ -2060,7 +2059,7 @@ void Game::processUserInput(f32 dtime) m_game_focused = true; } - if (!guienv->hasFocus(gui_chat_console) && gui_chat_console->isOpen()) { + if (!guienv->hasFocus(gui_chat_console.get()) && gui_chat_console->isOpen()) { gui_chat_console->closeConsoleAtOnce(); } @@ -4217,7 +4216,8 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime, updateShadows(); } - m_game_ui->update(*stats, client, draw_control, cam, runData.pointed_old, gui_chat_console, dtime); + m_game_ui->update(*stats, client, draw_control, cam, runData.pointed_old, + gui_chat_console.get(), dtime); /* make sure menu is on top From b93ae33f8559258b042acec35fcb90bbfeb0b5de Mon Sep 17 00:00:00 2001 From: Desour Date: Tue, 11 Jul 2023 00:00:00 +0200 Subject: [PATCH 47/67] Use irr_ptr for Game::sky --- src/client/game.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/client/game.cpp b/src/client/game.cpp index 1dcaa225b..9022f4acc 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -595,7 +595,8 @@ public: m_client(client) {} - void setSky(Sky *sky) { + void setSky(Sky *sky) + { m_sky = sky; for (GameGlobalShaderConstantSetter *ggscs : created_nosky) { ggscs->setSky(m_sky); @@ -894,7 +895,7 @@ private: MapDrawControl *draw_control = nullptr; Camera *camera = nullptr; irr_ptr clouds; - Sky *sky = nullptr; // Free using ->Drop() + irr_ptr sky; Hud *hud = nullptr; Minimap *mapper = nullptr; @@ -1267,8 +1268,7 @@ void Game::shutdown() gui_chat_console.reset(); - if (sky) - sky->drop(); + sky.reset(); /* cleanup menus */ while (g_menumgr.menuCount() > 0) { @@ -1526,8 +1526,8 @@ bool Game::createClient(const GameStartData &start_data) /* Skybox */ - sky = new Sky(-1, m_rendering_engine, texture_src, shader_src); - scsf->setSky(sky); + sky = make_irr(-1, m_rendering_engine, texture_src, shader_src); + scsf->setSky(sky.get()); /* Pre-calculated values */ From 2b2f2dee201bef2e89c54fa54df507f0835d0295 Mon Sep 17 00:00:00 2001 From: Desour Date: Tue, 11 Jul 2023 00:00:00 +0200 Subject: [PATCH 48/67] Use make_irr instead of new + drop() in Game::handleCallbacks --- src/client/game.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/client/game.cpp b/src/client/game.cpp index 9022f4acc..33475f338 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -1871,26 +1871,26 @@ inline bool Game::handleCallbacks() } if (g_gamecallback->changepassword_requested) { - (new GUIPasswordChange(guienv, guiroot, -1, - &g_menumgr, client, texture_src))->drop(); + (void)make_irr(guienv, guiroot, -1, + &g_menumgr, client, texture_src); g_gamecallback->changepassword_requested = false; } if (g_gamecallback->changevolume_requested) { - (new GUIVolumeChange(guienv, guiroot, -1, - &g_menumgr, texture_src))->drop(); + (void)make_irr(guienv, guiroot, -1, + &g_menumgr, texture_src); g_gamecallback->changevolume_requested = false; } if (g_gamecallback->keyconfig_requested) { - (new GUIKeyChangeMenu(guienv, guiroot, -1, - &g_menumgr, texture_src))->drop(); + (void)make_irr(guienv, guiroot, -1, + &g_menumgr, texture_src); g_gamecallback->keyconfig_requested = false; } if (!g_gamecallback->show_open_url_dialog.empty()) { - (new GUIOpenURLMenu(guienv, guiroot, -1, - &g_menumgr, texture_src, g_gamecallback->show_open_url_dialog))->drop(); + (void)make_irr(guienv, guiroot, -1, + &g_menumgr, texture_src, g_gamecallback->show_open_url_dialog); g_gamecallback->show_open_url_dialog.clear(); } From 9827f9df1bbefe636401e701c47d10d146a5a119 Mon Sep 17 00:00:00 2001 From: Desour Date: Fri, 15 Sep 2023 00:00:00 +0200 Subject: [PATCH 49/67] Use irr_ptr for MapBlockMesh::m_mesh --- src/client/mapblock_mesh.cpp | 10 +++++----- src/client/mapblock_mesh.h | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/client/mapblock_mesh.cpp b/src/client/mapblock_mesh.cpp index 1933baddf..071b03132 100644 --- a/src/client/mapblock_mesh.cpp +++ b/src/client/mapblock_mesh.cpp @@ -615,7 +615,7 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs ZoneScoped; for (auto &m : m_mesh) - m = new scene::SMesh(); + m = make_irr(); m_enable_shaders = data->m_use_shaders; auto mesh_grid = client->getMeshGrid(); @@ -663,7 +663,7 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs m_bounding_radius = std::sqrt(collector.m_bounding_radius_sq); for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) { - scene::SMesh *mesh = (scene::SMesh *)m_mesh[layer]; + scene::SMesh *mesh = static_cast(m_mesh[layer].get()); for(u32 i = 0; i < collector.prebuffers[layer].size(); i++) { @@ -793,10 +793,10 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs MapBlockMesh::~MapBlockMesh() { size_t sz = 0; - for (scene::IMesh *m : m_mesh) { + for (auto &&m : m_mesh) { for (u32 i = 0; i < m->getMeshBufferCount(); i++) sz += m->getMeshBuffer(i)->getSize(); - m->drop(); + m.reset(); } for (MinimapMapblock *block : m_minimap_mapblocks) delete block; @@ -865,7 +865,7 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack, get_sunlight_color(&day_color, daynight_ratio); for (auto &daynight_diff : m_daynight_diffs) { - auto *mesh = m_mesh[daynight_diff.first.first]; + auto *mesh = m_mesh[daynight_diff.first.first].get(); mesh->setDirty(scene::EBT_VERTEX); // force reload to VBO scene::IMeshBuffer *buf = mesh-> getMeshBuffer(daynight_diff.first.second); diff --git a/src/client/mapblock_mesh.h b/src/client/mapblock_mesh.h index d2c651525..c52df5ed3 100644 --- a/src/client/mapblock_mesh.h +++ b/src/client/mapblock_mesh.h @@ -193,12 +193,12 @@ public: scene::IMesh *getMesh() { - return m_mesh[0]; + return m_mesh[0].get(); } scene::IMesh *getMesh(u8 layer) { - return m_mesh[layer]; + return m_mesh[layer].get(); } std::vector moveMinimapMapblocks() @@ -242,7 +242,7 @@ private: TileLayer tile; }; - scene::IMesh *m_mesh[MAX_TILE_LAYERS]; + irr_ptr m_mesh[MAX_TILE_LAYERS]; std::vector m_minimap_mapblocks; ITextureSource *m_tsrc; IShaderSource *m_shdrsrc; From 24efd7dc9146c61fb090420e7619b7c2000fddcf Mon Sep 17 00:00:00 2001 From: Desour Date: Fri, 15 Sep 2023 00:00:00 +0200 Subject: [PATCH 50/67] Use smart ptrs for Minimap's member vars --- src/client/minimap.cpp | 40 +++++++++++++++++++--------------------- src/client/minimap.h | 11 ++++++----- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/src/client/minimap.cpp b/src/client/minimap.cpp index 4f3c81f4f..13dca5fe9 100644 --- a/src/client/minimap.cpp +++ b/src/client/minimap.cpp @@ -201,7 +201,7 @@ Minimap::Minimap(Client *client) addMode(MINIMAP_TYPE_RADAR, 128); // Initialize minimap data - data = new MinimapData; + data = std::make_unique(); data->map_invalidated = true; data->minimap_shape_round = g_settings->getBool("minimap_shape_round"); @@ -209,11 +209,11 @@ Minimap::Minimap(Client *client) setModeIndex(0); // Create mesh buffer for minimap - m_meshbuffer = getMinimapMeshBuffer(); + m_meshbuffer = createMinimapMeshBuffer(); // Initialize and start thread - m_minimap_update_thread = new MinimapUpdateThread(); - m_minimap_update_thread->data = data; + m_minimap_update_thread = std::make_unique(); + m_minimap_update_thread->data = data.get(); m_minimap_update_thread->start(); } @@ -222,7 +222,7 @@ Minimap::~Minimap() m_minimap_update_thread->stop(); m_minimap_update_thread->wait(); - m_meshbuffer->drop(); + m_meshbuffer.reset(); if (data->minimap_mask_round) data->minimap_mask_round->drop(); @@ -232,12 +232,10 @@ Minimap::~Minimap() driver->removeTexture(data->texture); driver->removeTexture(data->heightmap_texture); - for (MinimapMarker *m : m_markers) - delete m; m_markers.clear(); - delete data; - delete m_minimap_update_thread; + data.reset(); + m_minimap_update_thread.reset(); } void Minimap::addBlock(v3s16 pos, MinimapMapblock *data) @@ -552,9 +550,9 @@ v3f Minimap::getYawVec() return v3f(1.0, 0.0, 1.0); } -scene::SMeshBuffer *Minimap::getMinimapMeshBuffer() +irr_ptr Minimap::createMinimapMeshBuffer() { - scene::SMeshBuffer *buf = new scene::SMeshBuffer(); + auto buf = make_irr(); auto &vertices = buf->Vertices->Data; auto &indices = buf->Indices->Data; vertices.resize(4); @@ -628,7 +626,7 @@ void Minimap::drawMinimap(core::rect rect) // Draw minimap driver->setTransform(video::ETS_WORLD, matrix); driver->setMaterial(material); - driver->drawMeshBuffer(m_meshbuffer); + driver->drawMeshBuffer(m_meshbuffer.get()); // Draw overlay video::ITexture *minimap_overlay = data->minimap_shape_round ? @@ -636,7 +634,7 @@ void Minimap::drawMinimap(core::rect rect) material.TextureLayers[0].Texture = minimap_overlay; material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; driver->setMaterial(material); - driver->drawMeshBuffer(m_meshbuffer); + driver->drawMeshBuffer(m_meshbuffer.get()); // Draw player marker on minimap if (data->minimap_shape_round) { @@ -648,7 +646,7 @@ void Minimap::drawMinimap(core::rect rect) material.TextureLayers[0].Texture = data->player_marker; driver->setTransform(video::ETS_WORLD, matrix); driver->setMaterial(material); - driver->drawMeshBuffer(m_meshbuffer); + driver->drawMeshBuffer(m_meshbuffer.get()); // Reset transformations driver->setTransform(video::ETS_VIEW, oldViewMat); @@ -686,17 +684,17 @@ void Minimap::drawMinimap(core::rect rect) } } -MinimapMarker* Minimap::addMarker(scene::ISceneNode *parent_node) +MinimapMarker *Minimap::addMarker(scene::ISceneNode *parent_node) { - MinimapMarker *m = new MinimapMarker(parent_node); - m_markers.push_back(m); - return m; + auto m = std::make_unique(parent_node); + auto ret = m.get(); + m_markers.push_back(std::move(m)); + return ret; } void Minimap::removeMarker(MinimapMarker **m) { - m_markers.remove(*m); - delete *m; + m_markers.remove_if([ptr = *m](const auto &up) { return up.get() == ptr; }); *m = nullptr; } @@ -710,7 +708,7 @@ void Minimap::updateActiveMarkers() data->mode.scan_height / 2, data->mode.map_size / 2); - for (MinimapMarker *marker : m_markers) { + for (auto &&marker : m_markers) { v3s16 pos = floatToInt(marker->parent_node->getAbsolutePosition() + cam_offset, BS) - pos_offset; if (pos.X < 0 || pos.X > data->mode.map_size || diff --git a/src/client/minimap.h b/src/client/minimap.h index f819deaf4..0c419fa63 100644 --- a/src/client/minimap.h +++ b/src/client/minimap.h @@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "../hud.h" #include "irrlichttypes_extrabloated.h" +#include "irr_ptr.h" #include "util/thread.h" #include "voxel.h" #include @@ -148,7 +149,7 @@ public: void blitMinimapPixelsToImageSurface(video::IImage *map_image, video::IImage *heightmap_image); - scene::SMeshBuffer *getMinimapMeshBuffer(); + irr_ptr createMinimapMeshBuffer(); MinimapMarker* addMarker(scene::ISceneNode *parent_node); void removeMarker(MinimapMarker **marker); @@ -158,20 +159,20 @@ public: video::IVideoDriver *driver; Client* client; - MinimapData *data; + std::unique_ptr data; private: ITextureSource *m_tsrc; IShaderSource *m_shdrsrc; const NodeDefManager *m_ndef; - MinimapUpdateThread *m_minimap_update_thread = nullptr; - scene::SMeshBuffer *m_meshbuffer; + std::unique_ptr m_minimap_update_thread; + irr_ptr m_meshbuffer; bool m_enable_shaders; std::vector m_modes; size_t m_current_mode_index; u16 m_surface_mode_scan_height; f32 m_angle; std::mutex m_mutex; - std::list m_markers; + std::list> m_markers; std::list m_active_markers; }; From 387856a1c329da4e953ed8131fc4de2acfec00fd Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sun, 11 Aug 2024 15:21:45 +0200 Subject: [PATCH 51/67] Load mod profiler in one of the test workflows --- .github/workflows/lua.yml | 2 +- util/test_multiplayer.sh | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/lua.yml b/.github/workflows/lua.yml index 0073eca2e..1f83c7688 100644 --- a/.github/workflows/lua.yml +++ b/.github/workflows/lua.yml @@ -35,7 +35,7 @@ jobs: - name: Integration test + devtest run: | - ./util/test_multiplayer.sh + serverconf="profiler.load=true" ./util/test_multiplayer.sh luacheck: name: "Builtin Luacheck and Unit Tests" diff --git a/util/test_multiplayer.sh b/util/test_multiplayer.sh index 624669ac1..b12908423 100755 --- a/util/test_multiplayer.sh +++ b/util/test_multiplayer.sh @@ -33,7 +33,8 @@ printf '%s\n' >"$testspath/client1.conf" \ printf '%s\n' >"$testspath/server.conf" \ max_block_send_distance=1 active_block_range=1 \ - devtest_unittests_autostart=true helper_mode=devtest + devtest_unittests_autostart=true helper_mode=devtest \ + "${serverconf:-}" ln -s "$dir/helper_mod" "$worldpath/worldmods/" From 7ae51382c8a31a6d263ebb913c90025eaf90780c Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sun, 11 Aug 2024 13:34:03 +0200 Subject: [PATCH 52/67] Refactor ABM/LBM related code --- src/script/cpp_api/s_env.cpp | 260 ++++++++++++++++++++++++++++------- src/script/cpp_api/s_env.h | 14 ++ src/script/lua_api/l_env.cpp | 87 ------------ src/script/lua_api/l_env.h | 79 +---------- src/serverenvironment.cpp | 92 ++++++------- src/serverenvironment.h | 26 ++-- src/util/basic_macros.h | 6 + 7 files changed, 295 insertions(+), 269 deletions(-) diff --git a/src/script/cpp_api/s_env.cpp b/src/script/cpp_api/s_env.cpp index 3cbb13cd2..5068e4f4d 100644 --- a/src/script/cpp_api/s_env.cpp +++ b/src/script/cpp_api/s_env.cpp @@ -25,8 +25,102 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mapgen/mapgen.h" #include "lua_api/l_env.h" #include "server.h" +#include "scripting_server.h" #include "script/common/c_content.h" +/* + LuaABM & LuaLBM +*/ + +class LuaABM : public ActiveBlockModifier { +private: + int m_id; + + std::vector m_trigger_contents; + std::vector m_required_neighbors; + float m_trigger_interval; + u32 m_trigger_chance; + bool m_simple_catch_up; + s16 m_min_y; + s16 m_max_y; +public: + LuaABM(int id, + const std::vector &trigger_contents, + const std::vector &required_neighbors, + float trigger_interval, u32 trigger_chance, bool simple_catch_up, + s16 min_y, s16 max_y): + m_id(id), + m_trigger_contents(trigger_contents), + m_required_neighbors(required_neighbors), + m_trigger_interval(trigger_interval), + m_trigger_chance(trigger_chance), + m_simple_catch_up(simple_catch_up), + m_min_y(min_y), + m_max_y(max_y) + { + } + virtual const std::vector &getTriggerContents() const + { + return m_trigger_contents; + } + virtual const std::vector &getRequiredNeighbors() const + { + return m_required_neighbors; + } + virtual float getTriggerInterval() + { + return m_trigger_interval; + } + virtual u32 getTriggerChance() + { + return m_trigger_chance; + } + virtual bool getSimpleCatchUp() + { + return m_simple_catch_up; + } + virtual s16 getMinY() + { + return m_min_y; + } + virtual s16 getMaxY() + { + return m_max_y; + } + + virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n, + u32 active_object_count, u32 active_object_count_wider) + { + auto *script = env->getScriptIface(); + script->triggerABM(m_id, p, n, active_object_count, active_object_count_wider); + } +}; + +class LuaLBM : public LoadingBlockModifierDef +{ +private: + int m_id; +public: + LuaLBM(int id, + const std::vector &trigger_contents, + const std::string &name, bool run_at_every_load): + m_id(id) + { + this->run_at_every_load = run_at_every_load; + this->trigger_contents = trigger_contents; + this->name = name; + } + + virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n, float dtime_s) + { + auto *script = env->getScriptIface(); + script->triggerLBM(m_id, p, n, dtime_s); + } +}; + +/* + ScriptApiEnv +*/ void ScriptApiEnv::environment_OnGenerated(v3s16 minp, v3s16 maxp, u32 blockseed) @@ -46,7 +140,6 @@ void ScriptApiEnv::environment_OnGenerated(v3s16 minp, v3s16 maxp, void ScriptApiEnv::environment_Step(float dtime) { SCRIPTAPI_PRECHECKHEADER - //infostream << "scriptapi_environment_step" << std::endl; // Get core.registered_globalsteps lua_getglobal(L, "core"); @@ -76,12 +169,40 @@ void ScriptApiEnv::player_event(ServerActiveObject *player, const std::string &t void ScriptApiEnv::initializeEnvironment(ServerEnvironment *env) { SCRIPTAPI_PRECHECKHEADER + + assert(env); verbosestream << "ScriptApiEnv: Environment initialized" << std::endl; setEnv(env); - /* - Add {Loading,Active}BlockModifiers to environment - */ + readABMs(); + readLBMs(); +} + +// Reads a single or a list of node names into a vector +bool ScriptApiEnv::read_nodenames(lua_State *L, int idx, std::vector &to) +{ + if (lua_istable(L, idx)) { + const int table = idx < 0 ? (lua_gettop(L) + idx + 1) : idx; + lua_pushnil(L); + while (lua_next(L, table)) { + // key at index -2 and value at index -1 + luaL_checktype(L, -1, LUA_TSTRING); + to.emplace_back(readParam(L, -1)); + // removes value, keeps key for next iteration + lua_pop(L, 1); + } + } else if (lua_isstring(L, idx)) { + to.emplace_back(readParam(L, idx)); + } else { + return false; + } + return true; +} + +void ScriptApiEnv::readABMs() +{ + SCRIPTAPI_PRECHECKHEADER + auto *env = reinterpret_cast(getEnv()); // Get core.registered_abms lua_getglobal(L, "core"); @@ -100,36 +221,12 @@ void ScriptApiEnv::initializeEnvironment(ServerEnvironment *env) std::vector trigger_contents; lua_getfield(L, current_abm, "nodenames"); - if (lua_istable(L, -1)) { - int table = lua_gettop(L); - lua_pushnil(L); - while (lua_next(L, table)) { - // key at index -2 and value at index -1 - luaL_checktype(L, -1, LUA_TSTRING); - trigger_contents.emplace_back(readParam(L, -1)); - // removes value, keeps key for next iteration - lua_pop(L, 1); - } - } else if (lua_isstring(L, -1)) { - trigger_contents.emplace_back(readParam(L, -1)); - } + read_nodenames(L, -1, trigger_contents); lua_pop(L, 1); std::vector required_neighbors; lua_getfield(L, current_abm, "neighbors"); - if (lua_istable(L, -1)) { - int table = lua_gettop(L); - lua_pushnil(L); - while (lua_next(L, table)) { - // key at index -2 and value at index -1 - luaL_checktype(L, -1, LUA_TSTRING); - required_neighbors.emplace_back(readParam(L, -1)); - // removes value, keeps key for next iteration - lua_pop(L, 1); - } - } else if (lua_isstring(L, -1)) { - required_neighbors.emplace_back(readParam(L, -1)); - } + read_nodenames(L, -1, required_neighbors); lua_pop(L, 1); float trigger_interval = 10.0; @@ -151,7 +248,7 @@ void ScriptApiEnv::initializeEnvironment(ServerEnvironment *env) luaL_checktype(L, current_abm + 1, LUA_TFUNCTION); lua_pop(L, 1); - LuaABM *abm = new LuaABM(L, id, trigger_contents, required_neighbors, + LuaABM *abm = new LuaABM(id, trigger_contents, required_neighbors, trigger_interval, trigger_chance, simple_catch_up, min_y, max_y); env->addActiveBlockModifier(abm); @@ -160,6 +257,12 @@ void ScriptApiEnv::initializeEnvironment(ServerEnvironment *env) lua_pop(L, 1); } lua_pop(L, 1); +} + +void ScriptApiEnv::readLBMs() +{ + SCRIPTAPI_PRECHECKHEADER + auto *env = reinterpret_cast(getEnv()); // Get core.registered_lbms lua_getglobal(L, "core"); @@ -177,21 +280,9 @@ void ScriptApiEnv::initializeEnvironment(ServerEnvironment *env) int id = lua_tonumber(L, -2); int current_lbm = lua_gettop(L); - std::set trigger_contents; + std::vector trigger_contents; lua_getfield(L, current_lbm, "nodenames"); - if (lua_istable(L, -1)) { - int table = lua_gettop(L); - lua_pushnil(L); - while (lua_next(L, table)) { - // key at index -2 and value at index -1 - luaL_checktype(L, -1, LUA_TSTRING); - trigger_contents.insert(readParam(L, -1)); - // removes value, keeps key for next iteration - lua_pop(L, 1); - } - } else if (lua_isstring(L, -1)) { - trigger_contents.insert(readParam(L, -1)); - } + read_nodenames(L, -1, trigger_contents); lua_pop(L, 1); std::string name; @@ -204,7 +295,7 @@ void ScriptApiEnv::initializeEnvironment(ServerEnvironment *env) luaL_checktype(L, current_lbm + 1, LUA_TFUNCTION); lua_pop(L, 1); - LuaLBM *lbm = new LuaLBM(L, id, trigger_contents, name, + LuaLBM *lbm = new LuaLBM(id, trigger_contents, name, run_at_every_load); env->addLoadingBlockModifierDef(lbm); @@ -288,7 +379,7 @@ void ScriptApiEnv::on_liquid_transformed( int index = 1; lua_createtable(L, list.size(), 0); lua_createtable(L, list.size(), 0); - for(std::pair p : list) { + for(auto &p : list) { lua_pushnumber(L, index); push_v3s16(L, p.first); lua_rawset(L, -4); @@ -332,3 +423,78 @@ bool ScriptApiEnv::has_on_mapblocks_changed() luaL_checktype(L, -1, LUA_TTABLE); return lua_objlen(L, -1) > 0; } + +void ScriptApiEnv::triggerABM(int id, v3s16 p, MapNode n, + u32 active_object_count, u32 active_object_count_wider) +{ + SCRIPTAPI_PRECHECKHEADER + + int error_handler = PUSH_ERROR_HANDLER(L); + + // Get registered_abms + lua_getglobal(L, "core"); + lua_getfield(L, -1, "registered_abms"); + luaL_checktype(L, -1, LUA_TTABLE); + lua_remove(L, -2); // Remove core + + // Get registered_abms[m_id] + lua_pushinteger(L, id); + lua_gettable(L, -2); + FATAL_ERROR_IF(lua_isnil(L, -1), "Entry with given id not found in registered_abms table"); + lua_remove(L, -2); // Remove registered_abms + + setOriginFromTable(-1); + + // Call action + luaL_checktype(L, -1, LUA_TTABLE); + lua_getfield(L, -1, "action"); + luaL_checktype(L, -1, LUA_TFUNCTION); + lua_remove(L, -2); // Remove registered_abms[m_id] + push_v3s16(L, p); + pushnode(L, n); + lua_pushnumber(L, active_object_count); + lua_pushnumber(L, active_object_count_wider); + + int result = lua_pcall(L, 4, 0, error_handler); + if (result) + scriptError(result, "LuaABM::trigger"); + + lua_pop(L, 1); // Pop error handler +} + +void ScriptApiEnv::triggerLBM(int id, v3s16 p, + const MapNode n, const float dtime_s) +{ + SCRIPTAPI_PRECHECKHEADER + + int error_handler = PUSH_ERROR_HANDLER(L); + + // Get registered_lbms + lua_getglobal(L, "core"); + lua_getfield(L, -1, "registered_lbms"); + luaL_checktype(L, -1, LUA_TTABLE); + lua_remove(L, -2); // Remove core + + // Get registered_lbms[m_id] + lua_pushinteger(L, id); + lua_gettable(L, -2); + FATAL_ERROR_IF(lua_isnil(L, -1), "Entry with given id not found in registered_lbms table"); + lua_remove(L, -2); // Remove registered_lbms + + setOriginFromTable(-1); + + // Call action + luaL_checktype(L, -1, LUA_TTABLE); + lua_getfield(L, -1, "action"); + luaL_checktype(L, -1, LUA_TFUNCTION); + lua_remove(L, -2); // Remove registered_lbms[m_id] + push_v3s16(L, p); + pushnode(L, n); + lua_pushnumber(L, dtime_s); + + int result = lua_pcall(L, 3, 0, error_handler); + if (result) + scriptError(result, "LuaLBM::trigger"); + + lua_pop(L, 1); // Pop error handler +} diff --git a/src/script/cpp_api/s_env.h b/src/script/cpp_api/s_env.h index bc4c4cd4d..8a88749fa 100644 --- a/src/script/cpp_api/s_env.h +++ b/src/script/cpp_api/s_env.h @@ -55,5 +55,19 @@ public: // Determines whether there are any on_mapblocks_changed callbacks bool has_on_mapblocks_changed(); + // Initializes environment and loads some definitions from Lua void initializeEnvironment(ServerEnvironment *env); + + void triggerABM(int id, v3s16 p, MapNode n, + u32 active_object_count, u32 active_object_count_wider); + + void triggerLBM(int id, v3s16 p, MapNode n, float dtime_s); + +private: + void readABMs(); + + void readLBMs(); + + // Reads a single or a list of node names into a vector + static bool read_nodenames(lua_State *L, int idx, std::vector &to); }; diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp index f5ed2804c..6fd0e2b2a 100644 --- a/src/script/lua_api/l_env.cpp +++ b/src/script/lua_api/l_env.cpp @@ -65,93 +65,6 @@ const EnumString ModApiEnvBase::es_BlockStatusType[] = /////////////////////////////////////////////////////////////////////////////// - -void LuaABM::trigger(ServerEnvironment *env, v3s16 p, MapNode n, - u32 active_object_count, u32 active_object_count_wider) -{ - ServerScripting *scriptIface = env->getScriptIface(); - scriptIface->realityCheck(); - - lua_State *L = scriptIface->getStack(); - sanity_check(lua_checkstack(L, 20)); - StackUnroller stack_unroller(L); - - int error_handler = PUSH_ERROR_HANDLER(L); - - // Get registered_abms - lua_getglobal(L, "core"); - lua_getfield(L, -1, "registered_abms"); - luaL_checktype(L, -1, LUA_TTABLE); - lua_remove(L, -2); // Remove core - - // Get registered_abms[m_id] - lua_pushinteger(L, m_id); - lua_gettable(L, -2); - if(lua_isnil(L, -1)) - FATAL_ERROR(""); - lua_remove(L, -2); // Remove registered_abms - - scriptIface->setOriginFromTable(-1); - - // Call action - luaL_checktype(L, -1, LUA_TTABLE); - lua_getfield(L, -1, "action"); - luaL_checktype(L, -1, LUA_TFUNCTION); - lua_remove(L, -2); // Remove registered_abms[m_id] - push_v3s16(L, p); - pushnode(L, n); - lua_pushnumber(L, active_object_count); - lua_pushnumber(L, active_object_count_wider); - - int result = lua_pcall(L, 4, 0, error_handler); - if (result) - scriptIface->scriptError(result, "LuaABM::trigger"); - - lua_pop(L, 1); // Pop error handler -} - -void LuaLBM::trigger(ServerEnvironment *env, v3s16 p, - const MapNode n, const float dtime_s) -{ - ServerScripting *scriptIface = env->getScriptIface(); - scriptIface->realityCheck(); - - lua_State *L = scriptIface->getStack(); - sanity_check(lua_checkstack(L, 20)); - StackUnroller stack_unroller(L); - - int error_handler = PUSH_ERROR_HANDLER(L); - - // Get registered_lbms - lua_getglobal(L, "core"); - lua_getfield(L, -1, "registered_lbms"); - luaL_checktype(L, -1, LUA_TTABLE); - lua_remove(L, -2); // Remove core - - // Get registered_lbms[m_id] - lua_pushinteger(L, m_id); - lua_gettable(L, -2); - FATAL_ERROR_IF(lua_isnil(L, -1), "Entry with given id not found in registered_lbms table"); - lua_remove(L, -2); // Remove registered_lbms - - scriptIface->setOriginFromTable(-1); - - // Call action - luaL_checktype(L, -1, LUA_TTABLE); - lua_getfield(L, -1, "action"); - luaL_checktype(L, -1, LUA_TFUNCTION); - lua_remove(L, -2); // Remove registered_lbms[m_id] - push_v3s16(L, p); - pushnode(L, n); - lua_pushnumber(L, dtime_s); - - int result = lua_pcall(L, 3, 0, error_handler); - if (result) - scriptIface->scriptError(result, "LuaLBM::trigger"); - - lua_pop(L, 1); // Pop error handler -} - int LuaRaycast::l_next(lua_State *L) { GET_PLAIN_ENV_PTR; diff --git a/src/script/lua_api/l_env.h b/src/script/lua_api/l_env.h index 2ed0eb114..b92a6f935 100644 --- a/src/script/lua_api/l_env.h +++ b/src/script/lua_api/l_env.h @@ -20,9 +20,10 @@ with this program; if not, write to the Free Software Foundation, Inc., #pragma once #include "lua_api/l_base.h" -#include "serverenvironment.h" #include "raycast.h" +class ServerScripting; + // base class containing helpers class ModApiEnvBase : public ModApiBase { protected: @@ -281,82 +282,6 @@ public: static void InitializeEmerge(lua_State *L, int top); }; -class LuaABM : public ActiveBlockModifier { -private: - int m_id; - - std::vector m_trigger_contents; - std::vector m_required_neighbors; - float m_trigger_interval; - u32 m_trigger_chance; - bool m_simple_catch_up; - s16 m_min_y; - s16 m_max_y; -public: - LuaABM(lua_State *L, int id, - const std::vector &trigger_contents, - const std::vector &required_neighbors, - float trigger_interval, u32 trigger_chance, bool simple_catch_up, s16 min_y, s16 max_y): - m_id(id), - m_trigger_contents(trigger_contents), - m_required_neighbors(required_neighbors), - m_trigger_interval(trigger_interval), - m_trigger_chance(trigger_chance), - m_simple_catch_up(simple_catch_up), - m_min_y(min_y), - m_max_y(max_y) - { - } - virtual const std::vector &getTriggerContents() const - { - return m_trigger_contents; - } - virtual const std::vector &getRequiredNeighbors() const - { - return m_required_neighbors; - } - virtual float getTriggerInterval() - { - return m_trigger_interval; - } - virtual u32 getTriggerChance() - { - return m_trigger_chance; - } - virtual bool getSimpleCatchUp() - { - return m_simple_catch_up; - } - virtual s16 getMinY() - { - return m_min_y; - } - virtual s16 getMaxY() - { - return m_max_y; - } - virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n, - u32 active_object_count, u32 active_object_count_wider); -}; - -class LuaLBM : public LoadingBlockModifierDef -{ -private: - int m_id; -public: - LuaLBM(lua_State *L, int id, - const std::set &trigger_contents, - const std::string &name, - bool run_at_every_load): - m_id(id) - { - this->run_at_every_load = run_at_every_load; - this->trigger_contents = trigger_contents; - this->name = name; - } - virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n, float dtime_s); -}; - //! Lua wrapper for RaycastState objects class LuaRaycast : public ModApiBase { diff --git a/src/serverenvironment.cpp b/src/serverenvironment.cpp index 24e4a587e..f79102e74 100644 --- a/src/serverenvironment.cpp +++ b/src/serverenvironment.cpp @@ -77,11 +77,11 @@ ABMWithState::ABMWithState(ActiveBlockModifier *abm_): LBMManager */ -void LBMContentMapping::deleteContents() +LBMContentMapping::~LBMContentMapping() { - for (auto &it : lbm_list) { + map.clear(); + for (auto &it : lbm_list) delete it; - } } void LBMContentMapping::addLBM(LoadingBlockModifierDef *lbm_def, IGameDef *gamedef) @@ -90,29 +90,32 @@ void LBMContentMapping::addLBM(LoadingBlockModifierDef *lbm_def, IGameDef *gamed // Unknown names get added to the global NameIdMapping. const NodeDefManager *nodedef = gamedef->ndef(); + FATAL_ERROR_IF(CONTAINS(lbm_list, lbm_def), "Same LBM registered twice"); lbm_list.push_back(lbm_def); - for (const std::string &nodeTrigger: lbm_def->trigger_contents) { - std::vector c_ids; - bool found = nodedef->getIds(nodeTrigger, c_ids); + std::vector c_ids; + + for (const auto &node : lbm_def->trigger_contents) { + bool found = nodedef->getIds(node, c_ids); if (!found) { - content_t c_id = gamedef->allocateUnknownNodeId(nodeTrigger); + content_t c_id = gamedef->allocateUnknownNodeId(node); if (c_id == CONTENT_IGNORE) { // Seems it can't be allocated. - warningstream << "Could not internalize node name \"" << nodeTrigger + warningstream << "Could not internalize node name \"" << node << "\" while loading LBM \"" << lbm_def->name << "\"." << std::endl; continue; } c_ids.push_back(c_id); } - - for (content_t c_id : c_ids) { - map[c_id].push_back(lbm_def); - } } + + SORT_AND_UNIQUE(c_ids); + + for (content_t c_id : c_ids) + map[c_id].push_back(lbm_def); } -const std::vector * +const LBMContentMapping::lbm_vector * LBMContentMapping::lookup(content_t c) const { lbm_map::const_iterator it = map.find(c); @@ -130,9 +133,7 @@ LBMManager::~LBMManager() delete m_lbm_def.second; } - for (auto &it : m_lbm_lookup) { - (it.second).deleteContents(); - } + m_lbm_lookup.clear(); } void LBMManager::addLBMDef(LoadingBlockModifierDef *lbm_def) @@ -236,7 +237,7 @@ std::string LBMManager::createIntroductionTimesString() std::ostringstream oss; for (const auto &it : m_lbm_lookup) { u32 time = it.first; - const std::vector &lbm_list = it.second.lbm_list; + auto &lbm_list = it.second.getList(); for (const auto &lbm_def : lbm_list) { // Don't add if the LBM runs at every load, // then introducement time is hardcoded @@ -255,16 +256,17 @@ void LBMManager::applyLBMs(ServerEnvironment *env, MapBlock *block, // Precondition, we need m_lbm_lookup to be initialized FATAL_ERROR_IF(!m_query_mode, "attempted to query on non fully set up LBMManager"); - v3s16 pos_of_block = block->getPosRelative(); + + const v3s16 pos_of_block = block->getPosRelative(); v3s16 pos; MapNode n; content_t c; auto it = getLBMsIntroducedAfter(stamp); + // Note: the iteration count of this outer loop is typically very low, so it's ok. for (; it != m_lbm_lookup.end(); ++it) { - // Cache previous version to speedup lookup which has a very high performance - // penalty on each call + // Cache previous lookup result since it has a high performance penalty. content_t previous_c = CONTENT_IGNORE; - const std::vector *lbm_list = nullptr; + const LBMContentMapping::lbm_vector *lbm_list = nullptr; for (pos.Z = 0; pos.Z < MAP_BLOCKSIZE; pos.Z++) for (pos.Y = 0; pos.Y < MAP_BLOCKSIZE; pos.Y++) @@ -272,7 +274,6 @@ void LBMManager::applyLBMs(ServerEnvironment *env, MapBlock *block, n = block->getNodeNoCheck(pos); c = n.getContent(); - // If content_t are not matching perform an LBM lookup if (previous_c != c) { lbm_list = it->second.lookup(c); previous_c = c; @@ -792,11 +793,9 @@ void ServerEnvironment::loadDefaultMeta() struct ActiveABM { ActiveBlockModifier *abm; - int chance; std::vector required_neighbors; - bool check_required_neighbors; // false if required_neighbors is known to be empty - s16 min_y; - s16 max_y; + int chance; + s16 min_y, max_y; }; #define CONTENT_TYPE_CACHE_MAX 64 @@ -812,16 +811,16 @@ public: bool use_timers): m_env(env) { - if(dtime_s < 0.001) + if (dtime_s < 0.001f) return; const NodeDefManager *ndef = env->getGameDef()->ndef(); for (ABMWithState &abmws : abms) { ActiveBlockModifier *abm = abmws.abm; float trigger_interval = abm->getTriggerInterval(); - if(trigger_interval < 0.001) - trigger_interval = 0.001; + if (trigger_interval < 0.001f) + trigger_interval = 0.001f; float actual_interval = dtime_s; - if(use_timers){ + if (use_timers) { abmws.timer += dtime_s; if(abmws.timer < trigger_interval) continue; @@ -831,6 +830,7 @@ public: float chance = abm->getTriggerChance(); if (chance == 0) chance = 1; + ActiveABM aabm; aabm.abm = abm; if (abm->getSimpleCatchUp()) { @@ -848,25 +848,21 @@ public: aabm.max_y = abm->getMaxY(); // Trigger neighbors - const std::vector &required_neighbors_s = - abm->getRequiredNeighbors(); - for (const std::string &required_neighbor_s : required_neighbors_s) { - ndef->getIds(required_neighbor_s, aabm.required_neighbors); - } - aabm.check_required_neighbors = !required_neighbors_s.empty(); + for (const auto &s : abm->getRequiredNeighbors()) + ndef->getIds(s, aabm.required_neighbors); + SORT_AND_UNIQUE(aabm.required_neighbors); // Trigger contents - const std::vector &contents_s = abm->getTriggerContents(); - for (const std::string &content_s : contents_s) { - std::vector ids; - ndef->getIds(content_s, ids); - for (content_t c : ids) { - if (c >= m_aabms.size()) - m_aabms.resize(c + 256, NULL); - if (!m_aabms[c]) - m_aabms[c] = new std::vector; - m_aabms[c]->push_back(aabm); - } + std::vector ids; + for (const auto &s : abm->getTriggerContents()) + ndef->getIds(s, ids); + SORT_AND_UNIQUE(ids); + for (content_t c : ids) { + if (c >= m_aabms.size()) + m_aabms.resize(c + 256, nullptr); + if (!m_aabms[c]) + m_aabms[c] = new std::vector; + m_aabms[c]->push_back(aabm); } } } @@ -967,7 +963,7 @@ public: continue; // Check neighbors - if (aabm.check_required_neighbors) { + if (!aabm.required_neighbors.empty()) { v3s16 p1; for(p1.X = p0.X-1; p1.X <= p0.X+1; p1.X++) for(p1.Y = p0.Y-1; p1.Y <= p0.Y+1; p1.Y++) diff --git a/src/serverenvironment.h b/src/serverenvironment.h index 7a388d21c..51d699cab 100644 --- a/src/serverenvironment.h +++ b/src/serverenvironment.h @@ -90,7 +90,7 @@ struct ABMWithState struct LoadingBlockModifierDef { // Set of contents to trigger on - std::set trigger_contents; + std::vector trigger_contents; std::string name; bool run_at_every_load = false; @@ -100,19 +100,25 @@ struct LoadingBlockModifierDef MapNode n, float dtime_s) {}; }; -struct LBMContentMapping +class LBMContentMapping { - typedef std::unordered_map> lbm_map; - lbm_map map; +public: + typedef std::vector lbm_vector; + typedef std::unordered_map lbm_map; - std::vector lbm_list; - - // Needs to be separate method (not inside destructor), - // because the LBMContentMapping may be copied and destructed - // many times during operation in the lbm_lookup_map. - void deleteContents(); + LBMContentMapping() = default; void addLBM(LoadingBlockModifierDef *lbm_def, IGameDef *gamedef); const lbm_map::mapped_type *lookup(content_t c) const; + const lbm_vector &getList() const { return lbm_list; } + + // This struct owns the LBM pointers. + ~LBMContentMapping(); + DISABLE_CLASS_COPY(LBMContentMapping); + ALLOW_CLASS_MOVE(LBMContentMapping); + +private: + lbm_vector lbm_list; + lbm_map map; }; class LBMManager diff --git a/src/util/basic_macros.h b/src/util/basic_macros.h index 7c3746417..f0fd4eb48 100644 --- a/src/util/basic_macros.h +++ b/src/util/basic_macros.h @@ -28,6 +28,12 @@ with this program; if not, write to the Free Software Foundation, Inc., // Requires #define CONTAINS(c, v) (std::find((c).begin(), (c).end(), (v)) != (c).end()) +// Requires +#define SORT_AND_UNIQUE(c) do { \ + std::sort((c).begin(), (c).end()); \ + (c).erase(std::unique((c).begin(), (c).end()), (c).end()); \ + } while (0) + // To disable copy constructors and assignment operations for some class // 'Foobar', add the macro DISABLE_CLASS_COPY(Foobar) in the class definition. // Note this also disables copying for any classes derived from 'Foobar' as well From 811adf5d42844bbd40e98e07773db3d16e104b90 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sun, 11 Aug 2024 14:54:02 +0200 Subject: [PATCH 53/67] Bulk LBMs (#14954) --- builtin/game/features.lua | 1 + builtin/game/misc.lua | 25 +++++++++++ builtin/game/register.lua | 7 ++- builtin/profiler/instrumentation.lua | 5 ++- doc/lua_api.md | 17 +++++++- src/script/cpp_api/s_env.cpp | 42 ++++++++---------- src/script/cpp_api/s_env.h | 4 +- src/serverenvironment.cpp | 65 +++++++++++++++++++++------- src/serverenvironment.h | 9 +++- 9 files changed, 126 insertions(+), 49 deletions(-) diff --git a/builtin/game/features.lua b/builtin/game/features.lua index 358ee8ff0..81b291e6c 100644 --- a/builtin/game/features.lua +++ b/builtin/game/features.lua @@ -43,6 +43,7 @@ core.features = { moveresult_new_pos = true, override_item_remove_fields = true, hotbar_hud_element = true, + bulk_lbms = true, } function core.has_feature(arg) diff --git a/builtin/game/misc.lua b/builtin/game/misc.lua index 91ca738a4..25e19ddb0 100644 --- a/builtin/game/misc.lua +++ b/builtin/game/misc.lua @@ -298,3 +298,28 @@ do return valid_object_iterator(core.get_objects_in_area(min_pos, max_pos)) end end + +-- +-- Helper for LBM execution, called from C++ +-- + +function core.run_lbm(id, pos_list, dtime_s) + local lbm = core.registered_lbms[id] + assert(lbm, "Entry with given id not found in registered_lbms table") + core.set_last_run_mod(lbm.mod_origin) + if lbm.bulk_action then + return lbm.bulk_action(pos_list, dtime_s) + end + -- emulate non-bulk LBMs + local expect = core.get_node(pos_list[1]).name + -- engine guarantees that + -- 1) all nodes are the same content type + -- 2) the list is up-to-date when we're called + assert(expect ~= "ignore") + for _, pos in ipairs(pos_list) do + local n = core.get_node(pos) + if n.name == expect then -- might have been changed by previous call + lbm.action(pos, n, dtime_s) + end + end +end diff --git a/builtin/game/register.lua b/builtin/game/register.lua index 76cb72f87..3d99a6925 100644 --- a/builtin/game/register.lua +++ b/builtin/game/register.lua @@ -105,7 +105,12 @@ function core.register_lbm(spec) -- Add to core.registered_lbms check_modname_prefix(spec.name) check_node_list(spec.nodenames, "nodenames") - assert(type(spec.action) == "function", "Required field 'action' of type function") + local have = spec.action ~= nil + local have_bulk = spec.bulk_action ~= nil + assert(not have or type(spec.action) == "function", "Field 'action' must be a function") + assert(not have_bulk or type(spec.bulk_action) == "function", "Field 'bulk_action' must be a function") + assert(have ~= have_bulk, "Either 'action' or 'bulk_action' must be present") + core.registered_lbms[#core.registered_lbms + 1] = spec spec.mod_origin = core.get_current_modname() or "??" end diff --git a/builtin/profiler/instrumentation.lua b/builtin/profiler/instrumentation.lua index 0ffd9e6a9..c4feda7b4 100644 --- a/builtin/profiler/instrumentation.lua +++ b/builtin/profiler/instrumentation.lua @@ -217,8 +217,9 @@ local function init() -- Wrap register_lbm() to automatically instrument lbms. local orig_register_lbm = core.register_lbm core.register_lbm = function(spec) - spec.action = instrument { - func = spec.action, + local k = spec.bulk_action ~= nil and "bulk_action" or "action" + spec[k] = instrument { + func = spec[k], class = "LBM", label = spec.label or spec.name, } diff --git a/doc/lua_api.md b/doc/lua_api.md index 83f186804..b06809aee 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -5522,6 +5522,8 @@ Utilities override_item_remove_fields = true, -- The predefined hotbar is a Lua HUD element of type `hotbar` (5.10.0) hotbar_hud_element = true, + -- Bulk LBM support (5.10.0) + bulk_lbms = true, } ``` @@ -9124,7 +9126,12 @@ Used by `minetest.register_lbm`. A loading block modifier (LBM) is used to define a function that is called for specific nodes (defined by `nodenames`) when a mapblock which contains such nodes -gets activated (not loaded!) +gets activated (not loaded!). + +Note: LBMs operate on a "snapshot" of node positions taken once before they are triggered. +That means if an LBM callback adds a node, it won't be taken into account. +However the engine guarantees that when the callback is called that all given position(s) +contain a matching node. ```lua { @@ -9148,7 +9155,13 @@ gets activated (not loaded!) action = function(pos, node, dtime_s) end, -- Function triggered for each qualifying node. -- `dtime_s` is the in-game time (in seconds) elapsed since the block - -- was last active + -- was last active. + + bulk_action = function(pos_list, dtime_s) end, + -- Function triggered with a list of all applicable node positions at once. + -- This can be provided as an alternative to `action` (not both). + -- Available since `minetest.features.bulk_lbms` (5.10.0) + -- `dtime_s`: as above } ``` diff --git a/src/script/cpp_api/s_env.cpp b/src/script/cpp_api/s_env.cpp index 5068e4f4d..deac90f3c 100644 --- a/src/script/cpp_api/s_env.cpp +++ b/src/script/cpp_api/s_env.cpp @@ -111,10 +111,11 @@ public: this->name = name; } - virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n, float dtime_s) + virtual void trigger(ServerEnvironment *env, MapBlock *block, + const std::unordered_set &positions, float dtime_s) { auto *script = env->getScriptIface(); - script->triggerLBM(m_id, p, n, dtime_s); + script->triggerLBM(m_id, block, positions, dtime_s); } }; @@ -291,10 +292,6 @@ void ScriptApiEnv::readLBMs() bool run_at_every_load = getboolfield_default(L, current_lbm, "run_at_every_load", false); - lua_getfield(L, current_lbm, "action"); - luaL_checktype(L, current_lbm + 1, LUA_TFUNCTION); - lua_pop(L, 1); - LuaLBM *lbm = new LuaLBM(id, trigger_contents, name, run_at_every_load); @@ -462,34 +459,29 @@ void ScriptApiEnv::triggerABM(int id, v3s16 p, MapNode n, lua_pop(L, 1); // Pop error handler } -void ScriptApiEnv::triggerLBM(int id, v3s16 p, - const MapNode n, const float dtime_s) +void ScriptApiEnv::triggerLBM(int id, MapBlock *block, + const std::unordered_set &positions, float dtime_s) { SCRIPTAPI_PRECHECKHEADER int error_handler = PUSH_ERROR_HANDLER(L); - // Get registered_lbms + const v3s16 pos_of_block = block->getPosRelative(); + + // Get core.run_lbm lua_getglobal(L, "core"); - lua_getfield(L, -1, "registered_lbms"); - luaL_checktype(L, -1, LUA_TTABLE); + lua_getfield(L, -1, "run_lbm"); + luaL_checktype(L, -1, LUA_TFUNCTION); lua_remove(L, -2); // Remove core - // Get registered_lbms[m_id] + // Call it lua_pushinteger(L, id); - lua_gettable(L, -2); - FATAL_ERROR_IF(lua_isnil(L, -1), "Entry with given id not found in registered_lbms table"); - lua_remove(L, -2); // Remove registered_lbms - - setOriginFromTable(-1); - - // Call action - luaL_checktype(L, -1, LUA_TTABLE); - lua_getfield(L, -1, "action"); - luaL_checktype(L, -1, LUA_TFUNCTION); - lua_remove(L, -2); // Remove registered_lbms[m_id] - push_v3s16(L, p); - pushnode(L, n); + lua_createtable(L, positions.size(), 0); + int i = 1; + for (auto &p : positions) { + push_v3s16(L, pos_of_block + p); + lua_rawseti(L, -2, i++); + } lua_pushnumber(L, dtime_s); int result = lua_pcall(L, 3, 0, error_handler); diff --git a/src/script/cpp_api/s_env.h b/src/script/cpp_api/s_env.h index 8a88749fa..4722cb522 100644 --- a/src/script/cpp_api/s_env.h +++ b/src/script/cpp_api/s_env.h @@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include class ServerEnvironment; +class MapBlock; struct ScriptCallbackState; class ScriptApiEnv : virtual public ScriptApiBase @@ -61,7 +62,8 @@ public: void triggerABM(int id, v3s16 p, MapNode n, u32 active_object_count, u32 active_object_count_wider); - void triggerLBM(int id, v3s16 p, MapNode n, float dtime_s); + void triggerLBM(int id, MapBlock *block, + const std::unordered_set &positions, float dtime_s); private: void readABMs(); diff --git a/src/serverenvironment.cpp b/src/serverenvironment.cpp index f79102e74..ac627dd50 100644 --- a/src/serverenvironment.cpp +++ b/src/serverenvironment.cpp @@ -257,40 +257,73 @@ void LBMManager::applyLBMs(ServerEnvironment *env, MapBlock *block, FATAL_ERROR_IF(!m_query_mode, "attempted to query on non fully set up LBMManager"); - const v3s16 pos_of_block = block->getPosRelative(); - v3s16 pos; - MapNode n; - content_t c; - auto it = getLBMsIntroducedAfter(stamp); + // Collect a list of all LBMs and associated positions + struct LBMToRun { + std::unordered_set p; // node positions + std::unordered_set l; + }; + std::unordered_map to_run; + // Note: the iteration count of this outer loop is typically very low, so it's ok. - for (; it != m_lbm_lookup.end(); ++it) { - // Cache previous lookup result since it has a high performance penalty. + for (auto it = getLBMsIntroducedAfter(stamp); it != m_lbm_lookup.end(); ++it) { + v3s16 pos; + content_t c; + + // Cache previous lookups since it has a high performance penalty. content_t previous_c = CONTENT_IGNORE; const LBMContentMapping::lbm_vector *lbm_list = nullptr; + LBMToRun *batch = nullptr; for (pos.Z = 0; pos.Z < MAP_BLOCKSIZE; pos.Z++) for (pos.Y = 0; pos.Y < MAP_BLOCKSIZE; pos.Y++) for (pos.X = 0; pos.X < MAP_BLOCKSIZE; pos.X++) { - n = block->getNodeNoCheck(pos); - c = n.getContent(); + c = block->getNodeNoCheck(pos).getContent(); + bool c_changed = false; if (previous_c != c) { + c_changed = true; lbm_list = it->second.lookup(c); + batch = &to_run[c]; previous_c = c; } if (!lbm_list) continue; - for (auto lbmdef : *lbm_list) { - lbmdef->trigger(env, pos + pos_of_block, n, dtime_s); - if (block->isOrphan()) - return; - n = block->getNodeNoCheck(pos); - if (n.getContent() != c) - break; // The node was changed and the LBMs no longer apply + batch->p.insert(pos); + if (c_changed) { + batch->l.insert(lbm_list->begin(), lbm_list->end()); + } else { + // we were here before so the list must be filled + assert(!batch->l.empty()); } } } + + // Actually run them + bool first = true; + for (auto &[c, batch] : to_run) { + for (auto &lbm_def : batch.l) { + if (!first) { + // The fun part: since any LBM call can change the nodes inside of he + // block, we have to recheck the positions to see if the wanted node + // is still there. + // Note that we don't rescan the whole block, we don't want to include new changes. + for (auto it2 = batch.p.begin(); it2 != batch.p.end(); ) { + if (block->getNodeNoCheck(*it2).getContent() != c) + it2 = batch.p.erase(it2); + else + ++it2; + } + } + first = false; + + if (batch.p.empty()) + break; + lbm_def->trigger(env, block, batch.p, dtime_s); + if (block->isOrphan()) + return; + } + } } /* diff --git a/src/serverenvironment.h b/src/serverenvironment.h index 51d699cab..d20cc0b3f 100644 --- a/src/serverenvironment.h +++ b/src/serverenvironment.h @@ -96,8 +96,13 @@ struct LoadingBlockModifierDef virtual ~LoadingBlockModifierDef() = default; - virtual void trigger(ServerEnvironment *env, v3s16 p, - MapNode n, float dtime_s) {}; + /// @brief Called to invoke LBM + /// @param env environment + /// @param block the block in question + /// @param positions set of node positions (block-relative!) + /// @param dtime_s game time since last deactivation + virtual void trigger(ServerEnvironment *env, MapBlock *block, + const std::unordered_set &positions, float dtime_s) {}; }; class LBMContentMapping From 4ac86db8e3300492aee0d0444e638f188a430603 Mon Sep 17 00:00:00 2001 From: Erich Schubert Date: Fri, 20 Sep 2024 15:05:51 +0200 Subject: [PATCH 54/67] Simplify getGameTime function usage (#15187) --- src/script/lua_api/l_env.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp index 6fd0e2b2a..a024d7e42 100644 --- a/src/script/lua_api/l_env.cpp +++ b/src/script/lua_api/l_env.cpp @@ -749,10 +749,7 @@ int ModApiEnv::l_get_timeofday(lua_State *L) { GET_PLAIN_ENV_PTR; - // Do it - int timeofday_mh = env->getTimeOfDay(); - float timeofday_f = (float)timeofday_mh / 24000.0f; - lua_pushnumber(L, timeofday_f); + lua_pushnumber(L, env->getTimeOfDayF()); return 1; } @@ -770,8 +767,7 @@ int ModApiEnv::l_get_gametime(lua_State *L) { GET_ENV_PTR; - int game_time = env->getGameTime(); - lua_pushnumber(L, game_time); + lua_pushnumber(L, env->getGameTime()); return 1; } From d8f1daac2546c66d28d2e36a28c013ce56bddb4e Mon Sep 17 00:00:00 2001 From: GefullteTaubenbrust2 <72752000+GefullteTaubenbrust2@users.noreply.github.com> Date: Tue, 24 Sep 2024 20:14:27 +0200 Subject: [PATCH 55/67] Visual Effects Vol. 1 (#14610) This PR adds a variety of effects to enhance the visual experience. "soft" clouds look Tinted shadows Crude water reflections (sky and sun) and waves Translucent foliage Node specular highlights Adjusted fog color (more saturated where the fog is lighter) Minor changes to volumetric lighting (crudely simulates the effect of depth) Co-authored-by: sfan5 --- builtin/settingtypes.txt | 22 +++ .../shaders/nodes_shader/opengl_fragment.glsl | 135 +++++++++++++++++- .../shaders/nodes_shader/opengl_vertex.glsl | 2 + .../object_shader/opengl_fragment.glsl | 11 +- .../volumetric_light/opengl_fragment.glsl | 4 +- doc/lua_api.md | 5 + src/client/clientevent.h | 1 + src/client/clientmap.cpp | 18 ++- src/client/clouds.cpp | 117 ++++++++++----- src/client/clouds.h | 8 ++ src/client/content_mapblock.cpp | 22 ++- src/client/content_mapblock.h | 1 + src/client/game.cpp | 11 +- src/client/shader.cpp | 9 ++ src/client/shadows/dynamicshadowsrender.h | 3 + src/client/shadows/shadowsshadercallbacks.cpp | 3 + src/client/shadows/shadowsshadercallbacks.h | 1 + src/defaultsettings.cpp | 4 + src/lighting.h | 3 + src/network/clientpackethandler.cpp | 8 ++ src/network/networkprotocol.h | 5 +- src/script/lua_api/l_object.cpp | 10 ++ src/server.cpp | 4 +- src/skyparams.h | 2 + 24 files changed, 356 insertions(+), 53 deletions(-) diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt index 54a639a89..d13f25695 100644 --- a/builtin/settingtypes.txt +++ b/builtin/settingtypes.txt @@ -403,6 +403,11 @@ enable_clouds (Clouds) bool true # Requires: enable_clouds enable_3d_clouds (3D clouds) bool true +# Use smooth cloud shading. +# +# Requires: enable_3d_clouds, enable_clouds +soft_clouds (Soft clouds) bool false + [**Filtering and Antialiasing] # Use mipmaps when scaling textures. May slightly increase performance, @@ -505,6 +510,11 @@ water_wave_length (Waving liquids wavelength) float 20.0 0.1 # Requires: shaders, enable_waving_water water_wave_speed (Waving liquids wave speed) float 5.0 +# When enabled, liquid reflections are simulated. +# +# Requires: shaders, enable_waving_water, enable_dynamic_shadows +enable_water_reflections (Liquid reflections) bool false + [**Dynamic shadows] # Set to true to enable Shadow Mapping. @@ -661,6 +671,18 @@ bloom_radius (Bloom Radius) float 1 0.1 8 # Requires: shaders, enable_post_processing, enable_bloom enable_volumetric_lighting (Volumetric lighting) bool false +[**Other Effects] + +# Simulate translucency when looking at foliage in the sunlight. +# +# Requires: shaders, enable_dynamic_shadows +enable_translucent_foliage (Translucent foliage) bool false + +# Apply specular shading to nodes. +# +# Requires: shaders, enable_dynamic_shadows +enable_node_specular (Node specular) bool false + [*Audio] # Volume of all sounds. diff --git a/client/shaders/nodes_shader/opengl_fragment.glsl b/client/shaders/nodes_shader/opengl_fragment.glsl index 46977b147..c560a8505 100644 --- a/client/shaders/nodes_shader/opengl_fragment.glsl +++ b/client/shaders/nodes_shader/opengl_fragment.glsl @@ -1,3 +1,7 @@ +#if (MATERIAL_TYPE == TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT || MATERIAL_TYPE == TILE_MATERIAL_WAVING_LIQUID_OPAQUE || MATERIAL_TYPE == TILE_MATERIAL_WAVING_LIQUID_BASIC || MATERIAL_TYPE == TILE_MATERIAL_LIQUID_TRANSPARENT) +#define MATERIAL_WAVING_LIQUID 1 +#endif + uniform sampler2D baseTexture; uniform vec3 dayLight; @@ -7,6 +11,7 @@ uniform float fogShadingParameter; // The cameraOffset is the current center of the visible world. uniform highp vec3 cameraOffset; +uniform vec3 cameraPosition; uniform float animationTimer; #ifdef ENABLE_DYNAMIC_SHADOWS // shadow texture @@ -20,6 +25,7 @@ uniform float animationTimer; uniform vec4 CameraPos; uniform float xyPerspectiveBias0; uniform float xyPerspectiveBias1; + uniform vec3 shadow_tint; varying float adj_shadow_strength; varying float cosLight; @@ -47,6 +53,49 @@ varying highp vec3 eyeVec; varying float nightRatio; #ifdef ENABLE_DYNAMIC_SHADOWS +#if (defined(MATERIAL_WAVING_LIQUID) && defined(ENABLE_WATER_REFLECTIONS) && ENABLE_WAVING_WATER) +vec4 perm(vec4 x) +{ + return mod(((x * 34.0) + 1.0) * x, 289.0); +} + +// Corresponding gradient of snoise +vec3 gnoise(vec3 p){ + vec3 a = floor(p); + vec3 d = p - a; + vec3 dd = 6.0 * d * (1.0 - d); + d = d * d * (3.0 - 2.0 * d); + + vec4 b = a.xxyy + vec4(0.0, 1.0, 0.0, 1.0); + vec4 k1 = perm(b.xyxy); + vec4 k2 = perm(k1.xyxy + b.zzww); + + vec4 c = k2 + a.zzzz; + vec4 k3 = perm(c); + vec4 k4 = perm(c + 1.0); + + vec4 o1 = fract(k3 * (1.0 / 41.0)); + vec4 o2 = fract(k4 * (1.0 / 41.0)); + + vec4 o3 = o2 * d.z + o1 * (1.0 - d.z); + vec2 o4 = o3.yw * d.x + o3.xz * (1.0 - d.x); + + vec4 dz1 = (o2 - o1) * dd.z; + vec2 dz2 = dz1.yw * d.x + dz1.xz * (1.0 - d.x); + + vec2 dx = (o3.yw - o3.xz) * dd.x; + + return vec3( + dx.y * d.y + dx.x * (1. - d.y), + (o4.y - o4.x) * dd.y, + dz2.y * d.y + dz2.x * (1. - d.y) + ); +} + +vec2 wave_noise(vec3 p, float off) { + return (gnoise(p + vec3(0.0, 0.0, off)) * 0.4 + gnoise(2.0 * p + vec3(0.0, off, off)) * 0.2 + gnoise(3.0 * p + vec3(0.0, off, off)) * 0.225 + gnoise(4.0 * p + vec3(-off, off, 0.0)) * 0.2).xz; +} +#endif // assuming near is always 1.0 float getLinearDepth() @@ -66,6 +115,14 @@ float mtsmoothstep(in float edge0, in float edge1, in float x) return t * t * (3.0 - 2.0 * t); } +float shadowCutoff(float x) { + #if defined(ENABLE_TRANSLUCENT_FOLIAGE) && MATERIAL_TYPE == TILE_MATERIAL_WAVING_LEAVES + return mtsmoothstep(0.0, 0.002, x); + #else + return step(0.0, x); + #endif +} + #ifdef COLORED_SHADOWS // c_precision of 128 fits within 7 base-10 digits @@ -92,10 +149,10 @@ vec4 getHardShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDist { vec4 texDepth = texture2D(shadowsampler, smTexCoord.xy).rgba; - float visibility = step(0.0, realDistance - texDepth.r); + float visibility = shadowCutoff(realDistance - texDepth.r); vec4 result = vec4(visibility, vec3(0.0,0.0,0.0));//unpackColor(texDepth.g)); if (visibility < 0.1) { - visibility = step(0.0, realDistance - texDepth.b); + visibility = shadowCutoff(realDistance - texDepth.b); result = vec4(visibility, unpackColor(texDepth.a)); } return result; @@ -106,7 +163,7 @@ vec4 getHardShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDist float getHardShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance) { float texDepth = texture2D(shadowsampler, smTexCoord.xy).r; - float visibility = step(0.0, realDistance - texDepth); + float visibility = shadowCutoff(realDistance - texDepth); return visibility; } @@ -378,6 +435,9 @@ void main(void) vec4 col = vec4(color.rgb * varColor.rgb, 1.0); #ifdef ENABLE_DYNAMIC_SHADOWS + // Fragment normal, can differ from vNormal which is derived from vertex normals. + vec3 fNormal = vNormal; + if (f_shadow_strength > 0.0) { float shadow_int = 0.0; vec3 shadow_color = vec3(0.0, 0.0, 0.0); @@ -414,12 +474,19 @@ void main(void) // Power ratio was measured on torches in MTG (brightness = 14). float adjusted_night_ratio = pow(max(0.0, nightRatio), 0.6); + float shadow_uncorrected = shadow_int; + // Apply self-shadowing when light falls at a narrow angle to the surface // Cosine of the cut-off angle. const float self_shadow_cutoff_cosine = 0.035; if (f_normal_length != 0 && cosLight < self_shadow_cutoff_cosine) { shadow_int = max(shadow_int, 1 - clamp(cosLight, 0.0, self_shadow_cutoff_cosine)/self_shadow_cutoff_cosine); shadow_color = mix(vec3(0.0), shadow_color, min(cosLight, self_shadow_cutoff_cosine)/self_shadow_cutoff_cosine); + +#if (MATERIAL_TYPE == TILE_MATERIAL_WAVING_LEAVES || MATERIAL_TYPE == TILE_MATERIAL_WAVING_PLANTS) + // Prevents foliage from becoming insanely bright outside the shadow map. + shadow_uncorrected = mix(shadow_int, shadow_uncorrected, clamp(distance_rate * 4.0 - 3.0, 0.0, 1.0)); +#endif } shadow_int *= f_adj_shadow_strength; @@ -428,8 +495,60 @@ void main(void) col.rgb = adjusted_night_ratio * col.rgb + // artificial light (1.0 - adjusted_night_ratio) * ( // natural light - col.rgb * (1.0 - shadow_int * (1.0 - shadow_color)) + // filtered texture color + col.rgb * (1.0 - shadow_int * (1.0 - shadow_color) * (1.0 - shadow_tint)) + // filtered texture color dayLight * shadow_color * shadow_int); // reflected filtered sunlight/moonlight + + + vec3 reflect_ray = -normalize(v_LightDirection - fNormal * dot(v_LightDirection, fNormal) * 2.0); + + vec3 viewVec = normalize(worldPosition + cameraOffset - cameraPosition); + + // Water reflections +#if (defined(MATERIAL_WAVING_LIQUID) && defined(ENABLE_WATER_REFLECTIONS) && ENABLE_WAVING_WATER) + vec3 wavePos = worldPosition * vec3(2.0, 0.0, 2.0); + float off = animationTimer * WATER_WAVE_SPEED * 10.0; + wavePos.x /= WATER_WAVE_LENGTH * 3.0; + wavePos.z /= WATER_WAVE_LENGTH * 2.0; + + // This is an analogous method to the bumpmap, except we get the gradient information directly from gnoise. + vec2 gradient = wave_noise(wavePos, off); + fNormal = normalize(normalize(fNormal) + vec3(gradient.x, 0., gradient.y) * WATER_WAVE_HEIGHT * abs(fNormal.y) * 0.25); + reflect_ray = -normalize(v_LightDirection - fNormal * dot(v_LightDirection, fNormal) * 2.0); + float fresnel_factor = dot(fNormal, viewVec); + + float brightness_factor = 1.0 - adjusted_night_ratio; + + // A little trig hack. We go from the dot product of viewVec and normal to the dot product of viewVec and tangent to apply a fresnel effect. + fresnel_factor = clamp(pow(1.0 - fresnel_factor * fresnel_factor, 8.0), 0.0, 1.0) * 0.8 + 0.2; + col.rgb *= 0.5; + vec3 reflection_color = mix(vec3(max(fogColor.r, max(fogColor.g, fogColor.b))), fogColor.rgb, f_shadow_strength); + + // Sky reflection + col.rgb += reflection_color * pow(fresnel_factor, 2.0) * 0.5 * brightness_factor; + vec3 water_reflect_color = 12.0 * dayLight * fresnel_factor * mtsmoothstep(0.85, 0.9, pow(clamp(dot(reflect_ray, viewVec), 0.0, 1.0), 32.0)) * max(1.0 - shadow_uncorrected, 0.0); + + // This line exists to prevent ridiculously bright reflection colors. + water_reflect_color /= clamp(max(water_reflect_color.r, max(water_reflect_color.g, water_reflect_color.b)) * 0.375, 1.0, 400.0); + col.rgb += water_reflect_color * f_adj_shadow_strength * brightness_factor; +#endif + +#if (defined(ENABLE_NODE_SPECULAR) && !defined(MATERIAL_WAVING_LIQUID)) + // Apply specular to blocks. + if (dot(v_LightDirection, vNormal) < 0.0) { + float intensity = 2.0 * (1.0 - (base.r * varColor.r)); + const float specular_exponent = 5.0; + const float fresnel_exponent = 4.0; + + col.rgb += + intensity * dayLight * (1.0 - nightRatio) * (1.0 - shadow_uncorrected) * f_adj_shadow_strength * + pow(max(dot(reflect_ray, viewVec), 0.0), fresnel_exponent) * pow(1.0 - abs(dot(viewVec, fNormal)), specular_exponent); + } +#endif + +#if (MATERIAL_TYPE == TILE_MATERIAL_WAVING_PLANTS || MATERIAL_TYPE == TILE_MATERIAL_WAVING_LEAVES) && defined(ENABLE_TRANSLUCENT_FOLIAGE) + // Simulate translucent foliage. + col.rgb += 4.0 * dayLight * base.rgb * normalize(base.rgb * varColor.rgb * varColor.rgb) * f_adj_shadow_strength * pow(max(-dot(v_LightDirection, viewVec), 0.0), 4.0) * max(1.0 - shadow_uncorrected, 0.0); +#endif } #endif @@ -444,7 +563,13 @@ void main(void) // Note: clarity = (1 - fogginess) float clarity = clamp(fogShadingParameter - fogShadingParameter * length(eyeVec) / fogDistance, 0.0, 1.0); - col = mix(fogColor, col, clarity); + float fogColorMax = max(max(fogColor.r, fogColor.g), fogColor.b); + // Prevent zero division. + if (fogColorMax < 0.0000001) fogColorMax = 1.0; + // For high clarity (light fog) we tint the fog color. + // For this to not make the fog color artificially dark we need to normalize using the + // fog color's brightest value. We then blend our base color with this to make the fog. + col = mix(fogColor * pow(fogColor / fogColorMax, vec4(2.0 * clarity)), col, clarity); col = vec4(col.rgb, base.a); gl_FragData[0] = col; diff --git a/client/shaders/nodes_shader/opengl_vertex.glsl b/client/shaders/nodes_shader/opengl_vertex.glsl index d96164d76..ba48189a5 100644 --- a/client/shaders/nodes_shader/opengl_vertex.glsl +++ b/client/shaders/nodes_shader/opengl_vertex.glsl @@ -256,7 +256,9 @@ void main(void) z_bias *= pFactor * pFactor / f_textureresolution / f_shadowfar; shadow_position = applyPerspectiveDistortion(m_ShadowViewProj * mWorld * (shadow_pos + vec4(normalOffsetScale * nNormal, 0.0))).xyz; +#if !defined(ENABLE_TRANSLUCENT_FOLIAGE) || MATERIAL_TYPE != TILE_MATERIAL_WAVING_LEAVES shadow_position.z -= z_bias; +#endif perspective_factor = pFactor; if (f_timeofday < 0.2) { diff --git a/client/shaders/object_shader/opengl_fragment.glsl b/client/shaders/object_shader/opengl_fragment.glsl index 2b8af3fa9..db72d7f7d 100644 --- a/client/shaders/object_shader/opengl_fragment.glsl +++ b/client/shaders/object_shader/opengl_fragment.glsl @@ -20,6 +20,7 @@ uniform float animationTimer; uniform vec4 CameraPos; uniform float xyPerspectiveBias0; uniform float xyPerspectiveBias1; + uniform vec3 shadow_tint; varying float adj_shadow_strength; varying float cosLight; @@ -432,7 +433,7 @@ void main(void) col.rgb = adjusted_night_ratio * col.rgb + // artificial light (1.0 - adjusted_night_ratio) * ( // natural light - col.rgb * (1.0 - shadow_int * (1.0 - shadow_color)) + // filtered texture color + col.rgb * (1.0 - shadow_int * (1.0 - shadow_color) * (1.0 - shadow_tint)) + // filtered texture color dayLight * shadow_color * shadow_int); // reflected filtered sunlight/moonlight } #endif @@ -448,7 +449,13 @@ void main(void) // Note: clarity = (1 - fogginess) float clarity = clamp(fogShadingParameter - fogShadingParameter * length(eyeVec) / fogDistance, 0.0, 1.0); - col = mix(fogColor, col, clarity); + float fogColorMax = max(max(fogColor.r, fogColor.g), fogColor.b); + // Prevent zero division. + if (fogColorMax < 0.0000001) fogColorMax = 1.0; + // For high clarity (light fog) we tint the fog color. + // For this to not make the fog color artificially dark we need to normalize using the + // fog color's brightest value. We then blend our base color with this to make the fog. + col = mix(fogColor * pow(fogColor / fogColorMax, vec4(2.0 * clarity)), col, clarity); col = vec4(col.rgb, base.a); gl_FragData[0] = col; diff --git a/client/shaders/volumetric_light/opengl_fragment.glsl b/client/shaders/volumetric_light/opengl_fragment.glsl index 9ed5fa9ba..001f59465 100644 --- a/client/shaders/volumetric_light/opengl_fragment.glsl +++ b/client/shaders/volumetric_light/opengl_fragment.glsl @@ -46,7 +46,9 @@ float sampleVolumetricLight(vec2 uv, vec3 lightVec, float rawDepth) if (min(samplepos.x, samplepos.y) > 0. && max(samplepos.x, samplepos.y) < 1.) result += texture2D(depthmap, samplepos).r < 1. ? 0.0 : 1.0; } - return result / samples; + // We use the depth map to approximate the effect of depth on the light intensity. + // The exponent was chosen based on aesthetic preference. + return result / samples * pow(texture2D(depthmap, uv).r, 128.0); } vec3 getDirectLightScatteringAtGround(vec3 v_LightDirection) diff --git a/doc/lua_api.md b/doc/lua_api.md index b06809aee..e7cc8a07f 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -8518,6 +8518,8 @@ child will follow movement and rotation of that bone. if set to zero the clouds are rendered flat. * `speed`: 2D cloud speed + direction in nodes per second (default `{x=0, z=-2}`). + * `shadow`: shadow color, applied to the base of the cloud + (default `#cccccc`). * `get_clouds()`: returns a table with the current cloud parameters as in `set_clouds`. * `override_day_night_ratio(ratio or nil)` @@ -8565,6 +8567,9 @@ child will follow movement and rotation of that bone. * `shadows` is a table that controls ambient shadows * `intensity` sets the intensity of the shadows from 0 (no shadows, default) to 1 (blackness) * This value has no effect on clients who have the "Dynamic Shadows" shader disabled. + * `tint` tints the shadows with the provided color, with RGB values ranging from 0 to 255. + (default `{r=0, g=0, b=0}`) + * This value has no effect on clients who have the "Dynamic Shadows" shader disabled. * `exposure` is a table that controls automatic exposure. The basic exposure factor equation is `e = 2^exposure_correction / clamp(luminance, 2^luminance_min, 2^luminance_max)` * `luminance_min` set the lower luminance boundary to use in the calculation (default: `-3.0`) diff --git a/src/client/clientevent.h b/src/client/clientevent.h index a53c007dd..acd375a4e 100644 --- a/src/client/clientevent.h +++ b/src/client/clientevent.h @@ -137,6 +137,7 @@ struct ClientEvent f32 density; u32 color_bright; u32 color_ambient; + u32 color_shadow; f32 height; f32 thickness; f32 speed_x; diff --git a/src/client/clientmap.cpp b/src/client/clientmap.cpp index 3cc3564bc..d608ae2f6 100644 --- a/src/client/clientmap.cpp +++ b/src/client/clientmap.cpp @@ -1209,11 +1209,22 @@ void ClientMap::renderMapShadows(video::IVideoDriver *driver, // Render all mesh buffers in order drawcall_count += draw_order.size(); + bool translucent_foliage = g_settings->getBool("enable_translucent_foliage"); + + video::E_MATERIAL_TYPE leaves_material = video::EMT_SOLID; + + // For translucent leaves, we want to use backface culling instead of frontface. + if (translucent_foliage) { + // this is the material leaves would use, compare to nodedef.cpp + auto* shdsrc = m_client->getShaderSource(); + const u32 leaves_shader = shdsrc->getShader("nodes_shader", TILE_MATERIAL_WAVING_LEAVES, NDT_ALLFACES); + leaves_material = shdsrc->getShaderInfo(leaves_shader).material; + } + for (auto &descriptor : draw_order) { if (!descriptor.m_reuse_material) { // override some material properties video::SMaterial local_material = descriptor.getMaterial(); - local_material.MaterialType = material.MaterialType; // do not override culling if the original material renders both back // and front faces in solid mode (e.g. plantlike) // Transparent plants would still render shadows only from one side, @@ -1222,6 +1233,11 @@ void ClientMap::renderMapShadows(video::IVideoDriver *driver, local_material.BackfaceCulling = material.BackfaceCulling; local_material.FrontfaceCulling = material.FrontfaceCulling; } + if (local_material.MaterialType == leaves_material && translucent_foliage) { + local_material.BackfaceCulling = true; + local_material.FrontfaceCulling = false; + } + local_material.MaterialType = material.MaterialType; local_material.BlendOperation = material.BlendOperation; driver->setMaterial(local_material); ++material_swaps; diff --git a/src/client/clouds.cpp b/src/client/clouds.cpp index a7154c2c7..96926f3e0 100644 --- a/src/client/clouds.cpp +++ b/src/client/clouds.cpp @@ -65,6 +65,8 @@ Clouds::Clouds(scene::ISceneManager* mgr, IShaderSource *ssrc, readSettings(); g_settings->registerChangedCallback("enable_3d_clouds", &cloud_3d_setting_changed, this); + g_settings->registerChangedCallback("soft_clouds", + &cloud_3d_setting_changed, this); updateBox(); @@ -76,6 +78,8 @@ Clouds::~Clouds() { g_settings->deregisterChangedCallback("enable_3d_clouds", &cloud_3d_setting_changed, this); + g_settings->deregisterChangedCallback("soft_clouds", + &cloud_3d_setting_changed, this); } void Clouds::OnRegisterSceneNode() @@ -141,15 +145,18 @@ void Clouds::updateMesh() // shader mixes the base color, set via ColorParam c_top_f = c_side_1_f = c_side_2_f = c_bottom_f = video::SColorf(1.0f, 1.0f, 1.0f, 1.0f); } - c_side_1_f.r *= 0.95f; - c_side_1_f.g *= 0.95f; - c_side_1_f.b *= 0.95f; - c_side_2_f.r *= 0.90f; - c_side_2_f.g *= 0.90f; - c_side_2_f.b *= 0.90f; - c_bottom_f.r *= 0.80f; - c_bottom_f.g *= 0.80f; - c_bottom_f.b *= 0.80f; + video::SColorf shadow = m_params.color_shadow; + + c_side_1_f.r *= shadow.r * 0.25f + 0.75f; + c_side_1_f.g *= shadow.g * 0.25f + 0.75f; + c_side_1_f.b *= shadow.b * 0.25f + 0.75f; + c_side_2_f.r *= shadow.r * 0.5f + 0.5f; + c_side_2_f.g *= shadow.g * 0.5f + 0.5f; + c_side_2_f.b *= shadow.b * 0.5f + 0.5f; + c_bottom_f.r *= shadow.r; + c_bottom_f.g *= shadow.g; + c_bottom_f.b *= shadow.b; + video::SColor c_top = c_top_f.toSColor(); video::SColor c_side_1 = c_side_1_f.toSColor(); video::SColor c_side_2 = c_side_2_f.toSColor(); @@ -221,13 +228,14 @@ void Clouds::updateMesh() const f32 ry = is3D() ? m_params.thickness * BS : 0.0f; const f32 rz = cloud_size / 2; - for(u32 i = 0; i < num_faces_to_draw; i++) + bool soft_clouds_enabled = g_settings->getBool("soft_clouds"); + for (u32 i = 0; i < num_faces_to_draw; i++) { - switch(i) + switch (i) { case 0: // top - for (video::S3DVertex &vertex : v) { - vertex.Normal.set(0,1,0); + for (video::S3DVertex& vertex : v) { + vertex.Normal.set(0, 1, 0); } v[0].Pos.set(-rx, ry,-rz); v[1].Pos.set(-rx, ry, rz); @@ -237,12 +245,20 @@ void Clouds::updateMesh() case 1: // back if (INAREA(xi, zi - 1, m_cloud_radius_i)) { u32 j = GETINDEX(xi, zi - 1, m_cloud_radius_i); - if(grid[j]) + if (grid[j]) continue; } - for (video::S3DVertex &vertex : v) { - vertex.Color = c_side_1; - vertex.Normal.set(0,0,-1); + if (soft_clouds_enabled) { + for (video::S3DVertex& vertex : v) { + vertex.Normal.set(0, 0, -1); + } + v[2].Color = c_bottom; + v[3].Color = c_bottom; + } else { + for (video::S3DVertex& vertex : v) { + vertex.Color = c_side_1; + vertex.Normal.set(0, 0, -1); + } } v[0].Pos.set(-rx, ry,-rz); v[1].Pos.set( rx, ry,-rz); @@ -251,28 +267,45 @@ void Clouds::updateMesh() break; case 2: //right if (INAREA(xi + 1, zi, m_cloud_radius_i)) { - u32 j = GETINDEX(xi+1, zi, m_cloud_radius_i); - if(grid[j]) + u32 j = GETINDEX(xi + 1, zi, m_cloud_radius_i); + if (grid[j]) continue; } - for (video::S3DVertex &vertex : v) { - vertex.Color = c_side_2; - vertex.Normal.set(1,0,0); + if (soft_clouds_enabled) { + for (video::S3DVertex& vertex : v) { + vertex.Normal.set(1, 0, 0); + } + v[2].Color = c_bottom; + v[3].Color = c_bottom; } - v[0].Pos.set( rx, ry,-rz); - v[1].Pos.set( rx, ry, rz); - v[2].Pos.set( rx, 0, rz); - v[3].Pos.set( rx, 0,-rz); + else { + for (video::S3DVertex& vertex : v) { + vertex.Color = c_side_2; + vertex.Normal.set(1, 0, 0); + } + } + v[0].Pos.set(rx, ry,-rz); + v[1].Pos.set(rx, ry, rz); + v[2].Pos.set(rx, 0, rz); + v[3].Pos.set(rx, 0,-rz); break; case 3: // front if (INAREA(xi, zi + 1, m_cloud_radius_i)) { u32 j = GETINDEX(xi, zi + 1, m_cloud_radius_i); - if(grid[j]) + if (grid[j]) continue; } - for (video::S3DVertex &vertex : v) { - vertex.Color = c_side_1; - vertex.Normal.set(0,0,-1); + if (soft_clouds_enabled) { + for (video::S3DVertex& vertex : v) { + vertex.Normal.set(0, 0, -1); + } + v[2].Color = c_bottom; + v[3].Color = c_bottom; + } else { + for (video::S3DVertex& vertex : v) { + vertex.Color = c_side_1; + vertex.Normal.set(0, 0, -1); + } } v[0].Pos.set( rx, ry, rz); v[1].Pos.set(-rx, ry, rz); @@ -280,14 +313,22 @@ void Clouds::updateMesh() v[3].Pos.set( rx, 0, rz); break; case 4: // left - if (INAREA(xi-1, zi, m_cloud_radius_i)) { - u32 j = GETINDEX(xi-1, zi, m_cloud_radius_i); - if(grid[j]) + if (INAREA(xi - 1, zi, m_cloud_radius_i)) { + u32 j = GETINDEX(xi - 1, zi, m_cloud_radius_i); + if (grid[j]) continue; } - for (video::S3DVertex &vertex : v) { - vertex.Color = c_side_2; - vertex.Normal.set(-1,0,0); + if (soft_clouds_enabled) { + for (video::S3DVertex& vertex : v) { + vertex.Normal.set(-1, 0, 0); + } + v[2].Color = c_bottom; + v[3].Color = c_bottom; + } else { + for (video::S3DVertex& vertex : v) { + vertex.Color = c_side_2; + vertex.Normal.set(-1, 0, 0); + } } v[0].Pos.set(-rx, ry, rz); v[1].Pos.set(-rx, ry,-rz); @@ -295,9 +336,9 @@ void Clouds::updateMesh() v[3].Pos.set(-rx, 0, rz); break; case 5: // bottom - for (video::S3DVertex &vertex : v) { + for (video::S3DVertex& vertex : v) { vertex.Color = c_bottom; - vertex.Normal.set(0,-1,0); + vertex.Normal.set(0, -1, 0); } v[0].Pos.set( rx, 0, rz); v[1].Pos.set(-rx, 0, rz); diff --git a/src/client/clouds.h b/src/client/clouds.h index acd4b0cfb..7193c03f9 100644 --- a/src/client/clouds.h +++ b/src/client/clouds.h @@ -109,6 +109,14 @@ public: m_params.color_ambient = color_ambient; } + void setColorShadow(video::SColor color_shadow) + { + if (m_params.color_shadow == color_shadow) + return; + m_params.color_shadow = color_shadow; + invalidateMesh(); + } + void setHeight(float height) { if (m_params.height == height) diff --git a/src/client/content_mapblock.cpp b/src/client/content_mapblock.cpp index f7852ad1c..2a1352139 100644 --- a/src/client/content_mapblock.cpp +++ b/src/client/content_mapblock.cpp @@ -83,7 +83,8 @@ MapblockMeshGenerator::MapblockMeshGenerator(MeshMakeData *input, MeshCollector meshmanip(mm), blockpos_nodes(data->m_blockpos * MAP_BLOCKSIZE), enable_mesh_cache(g_settings->getBool("enable_mesh_cache") && - !data->m_smooth_lighting) // Mesh cache is not supported with smooth lighting + !data->m_smooth_lighting), // Mesh cache is not supported with smooth lighting + smooth_liquids(g_settings->getBool("enable_water_reflections")) { } @@ -717,7 +718,7 @@ void MapblockMeshGenerator::drawLiquidSides() if (data->m_smooth_lighting) cur_node.color = blendLightColor(pos); pos += cur_node.origin; - vertices[j] = video::S3DVertex(pos.X, pos.Y, pos.Z, 0, 0, 0, cur_node.color, vertex.u, v); + vertices[j] = video::S3DVertex(pos.X, pos.Y, pos.Z, face.dir.X, face.dir.Y, face.dir.Z, cur_node.color, vertex.u, v); }; collector->append(cur_liquid.tile, vertices, 4, quad_indices, 6); } @@ -740,6 +741,19 @@ void MapblockMeshGenerator::drawLiquidTop() for (int i = 0; i < 4; i++) { int u = corner_resolve[i][0]; int w = corner_resolve[i][1]; + + if (smooth_liquids) { + int x = vertices[i].Pos.X > 0; + int z = vertices[i].Pos.Z > 0; + + f32 dx = 0.5f * (cur_liquid.neighbors[z][x].level - cur_liquid.neighbors[z][x + 1].level + + cur_liquid.neighbors[z + 1][x].level - cur_liquid.neighbors[z + 1][x + 1].level); + f32 dz = 0.5f * (cur_liquid.neighbors[z][x].level - cur_liquid.neighbors[z + 1][x].level + + cur_liquid.neighbors[z][x + 1].level - cur_liquid.neighbors[z + 1][x + 1].level); + + vertices[i].Normal = v3f(dx, 1., dz).normalize(); + } + vertices[i].Pos.Y += cur_liquid.corner_levels[w][u] * BS; if (data->m_smooth_lighting) vertices[i].Color = blendLightColor(vertices[i].Pos); @@ -779,6 +793,10 @@ void MapblockMeshGenerator::drawLiquidTop() vertex.TCoords += tcoord_center; vertex.TCoords += tcoord_translate; + + if (!smooth_liquids) { + vertex.Normal = v3f(dx, 1., dz).normalize(); + } } std::swap(vertices[0].TCoords, vertices[2].TCoords); diff --git a/src/client/content_mapblock.h b/src/client/content_mapblock.h index 730330a03..1c3060c83 100644 --- a/src/client/content_mapblock.h +++ b/src/client/content_mapblock.h @@ -134,6 +134,7 @@ private: f32 corner_levels[2][2]; }; LiquidData cur_liquid; + bool smooth_liquids = false; void prepareLiquidNodeDrawing(); void getLiquidNeighborhood(); diff --git a/src/client/game.cpp b/src/client/game.cpp index 33475f338..ed593abba 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -386,6 +386,8 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter CachedPixelShaderSetting m_minimap_yaw{"yawVec"}; CachedPixelShaderSetting m_camera_offset_pixel{"cameraOffset"}; CachedVertexShaderSetting m_camera_offset_vertex{"cameraOffset"}; + CachedPixelShaderSetting m_camera_position_pixel{ "cameraPosition" }; + CachedVertexShaderSetting m_camera_position_vertex{ "cameraPosition" }; CachedPixelShaderSetting m_texture0{"texture0"}; CachedPixelShaderSetting m_texture1{"texture1"}; CachedPixelShaderSetting m_texture2{"texture2"}; @@ -492,6 +494,10 @@ public: m_camera_offset_pixel.set(offset, services); m_camera_offset_vertex.set(offset, services); + v3f camera_position = m_client->getCamera()->getPosition(); + m_camera_position_pixel.set(camera_position, services); + m_camera_position_pixel.set(camera_position, services); + SamplerLayer_t tex_id; tex_id = 0; m_texture0.set(&tex_id, services); @@ -3184,6 +3190,7 @@ void Game::handleClientEvent_CloudParams(ClientEvent *event, CameraOrientation * clouds->setDensity(event->cloud_params.density); clouds->setColorBright(video::SColor(event->cloud_params.color_bright)); clouds->setColorAmbient(video::SColor(event->cloud_params.color_ambient)); + clouds->setColorShadow(video::SColor(event->cloud_params.color_shadow)); clouds->setHeight(event->cloud_params.height); clouds->setThickness(event->cloud_params.thickness); clouds->setSpeed(v2f(event->cloud_params.speed_x, event->cloud_params.speed_y)); @@ -4315,7 +4322,9 @@ void Game::updateShadows() float timeoftheday = getWickedTimeOfDay(in_timeofday); bool is_day = timeoftheday > 0.25 && timeoftheday < 0.75; bool is_shadow_visible = is_day ? sky->getSunVisible() : sky->getMoonVisible(); - shadow->setShadowIntensity(is_shadow_visible ? client->getEnv().getLocalPlayer()->getLighting().shadow_intensity : 0.0f); + const auto &lighting = client->getEnv().getLocalPlayer()->getLighting(); + shadow->setShadowIntensity(is_shadow_visible ? lighting.shadow_intensity : 0.0f); + shadow->setShadowTint(lighting.shadow_tint); timeoftheday = std::fmod(timeoftheday + 0.75f, 0.5f) + 0.25f; const float offset_constant = 10000.0f; diff --git a/src/client/shader.cpp b/src/client/shader.cpp index f43bc27dc..ad37ea4c1 100644 --- a/src/client/shader.cpp +++ b/src/client/shader.cpp @@ -689,6 +689,15 @@ ShaderInfo ShaderSource::generateShader(const std::string &name, if (g_settings->getBool("shadow_poisson_filter")) shaders_header << "#define POISSON_FILTER 1\n"; + if (g_settings->getBool("enable_water_reflections")) + shaders_header << "#define ENABLE_WATER_REFLECTIONS 1\n"; + + if (g_settings->getBool("enable_translucent_foliage")) + shaders_header << "#define ENABLE_TRANSLUCENT_FOLIAGE 1\n"; + + if (g_settings->getBool("enable_node_specular")) + shaders_header << "#define ENABLE_NODE_SPECULAR 1\n"; + s32 shadow_filter = g_settings->getS32("shadow_filters"); shaders_header << "#define SHADOW_FILTER " << shadow_filter << "\n"; diff --git a/src/client/shadows/dynamicshadowsrender.h b/src/client/shadows/dynamicshadowsrender.h index c4ffb39e2..d4437be68 100644 --- a/src/client/shadows/dynamicshadowsrender.h +++ b/src/client/shadows/dynamicshadowsrender.h @@ -94,9 +94,11 @@ public: bool is_active() const { return m_shadows_enabled && shadowMapTextureFinal != nullptr; } void setTimeOfDay(float isDay) { m_time_day = isDay; }; void setShadowIntensity(float shadow_intensity); + void setShadowTint(video::SColor shadow_tint) { m_shadow_tint = shadow_tint; } s32 getShadowSamples() const { return m_shadow_samples; } float getShadowStrength() const { return m_shadows_enabled ? m_shadow_strength : 0.0f; } + video::SColor getShadowTint() const { return m_shadow_tint; } float getTimeOfDay() const { return m_time_day; } f32 getPerspectiveBiasXY() { return m_perspective_bias_xy; } @@ -131,6 +133,7 @@ private: std::vector m_shadow_node_array; float m_shadow_strength; + video::SColor m_shadow_tint{ 255, 0, 0, 0 }; float m_shadow_strength_gamma; float m_shadow_map_max_distance; float m_shadow_map_texture_size; diff --git a/src/client/shadows/shadowsshadercallbacks.cpp b/src/client/shadows/shadowsshadercallbacks.cpp index 32d3e36be..fc4f73186 100644 --- a/src/client/shadows/shadowsshadercallbacks.cpp +++ b/src/client/shadows/shadowsshadercallbacks.cpp @@ -40,6 +40,9 @@ void ShadowConstantSetter::onSetConstants(video::IMaterialRendererServices *serv f32 ShadowStrength = shadow->getShadowStrength(); m_shadow_strength.set(&ShadowStrength, services); + video::SColor ShadowTint = shadow->getShadowTint(); + m_shadow_tint.set(ShadowTint, services); + f32 timeOfDay = shadow->getTimeOfDay(); m_time_of_day.set(&timeOfDay, services); diff --git a/src/client/shadows/shadowsshadercallbacks.h b/src/client/shadows/shadowsshadercallbacks.h index af83f021e..beac25d72 100644 --- a/src/client/shadows/shadowsshadercallbacks.h +++ b/src/client/shadows/shadowsshadercallbacks.h @@ -31,6 +31,7 @@ class ShadowConstantSetter : public IShaderConstantSetter CachedPixelShaderSetting m_light_direction{"v_LightDirection"}; CachedPixelShaderSetting m_texture_res{"f_textureresolution"}; CachedPixelShaderSetting m_shadow_strength{"f_shadow_strength"}; + CachedPixelShaderSetting m_shadow_tint{ "shadow_tint" }; CachedPixelShaderSetting m_time_of_day{"f_timeofday"}; CachedPixelShaderSetting m_shadowfar{"f_shadowfar"}; CachedPixelShaderSetting m_camera_pos{"CameraPos"}; diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index 8e2411df5..12946b06d 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -275,6 +275,7 @@ void set_default_settings() settings->setDefault("view_bobbing_amount", "1.0"); settings->setDefault("fall_bobbing_amount", "0.03"); settings->setDefault("enable_3d_clouds", "true"); + settings->setDefault("soft_clouds", "false"); settings->setDefault("cloud_radius", "12"); settings->setDefault("menu_clouds", "true"); settings->setDefault("translucent_liquids", "true"); @@ -335,6 +336,9 @@ void set_default_settings() settings->setDefault("bloom_intensity", "0.05"); settings->setDefault("bloom_radius", "1"); settings->setDefault("enable_volumetric_lighting", "false"); + settings->setDefault("enable_water_reflections", "false"); + settings->setDefault("enable_translucent_foliage", "false"); + settings->setDefault("enable_node_specular", "false"); // Effects Shadows settings->setDefault("enable_dynamic_shadows", "false"); diff --git a/src/lighting.h b/src/lighting.h index 262a48b5d..20f434112 100644 --- a/src/lighting.h +++ b/src/lighting.h @@ -18,7 +18,9 @@ with this program; if not, write to the Free Software Foundation, Inc., */ #pragma once +#include "SColor.h" +using namespace irr; /** * Parameters for automatic exposure compensation @@ -54,4 +56,5 @@ struct Lighting float shadow_intensity {0.0f}; float saturation {1.0f}; float volumetric_light_strength {0.0f}; + video::SColor shadow_tint; }; diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index a1bffbb93..5b7c2f527 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -1476,6 +1476,7 @@ void Client::handleCommand_CloudParams(NetworkPacket* pkt) f32 density; video::SColor color_bright; video::SColor color_ambient; + video::SColor color_shadow = video::SColor(255, 204, 204, 204); f32 height; f32 thickness; v2f speed; @@ -1483,6 +1484,10 @@ void Client::handleCommand_CloudParams(NetworkPacket* pkt) *pkt >> density >> color_bright >> color_ambient >> height >> thickness >> speed; + if (pkt->getRemainingBytes() >= 4) { + *pkt >> color_shadow; + } + ClientEvent *event = new ClientEvent(); event->type = CE_CLOUD_PARAMS; event->cloud_params.density = density; @@ -1491,6 +1496,7 @@ void Client::handleCommand_CloudParams(NetworkPacket* pkt) // we avoid using new() and delete() for no good reason event->cloud_params.color_bright = color_bright.color; event->cloud_params.color_ambient = color_ambient.color; + event->cloud_params.color_shadow = color_shadow.color; event->cloud_params.height = height; event->cloud_params.thickness = thickness; // same here: deconstruct to skip constructor @@ -1821,4 +1827,6 @@ void Client::handleCommand_SetLighting(NetworkPacket *pkt) } if (pkt->getRemainingBytes() >= 4) *pkt >> lighting.volumetric_light_strength; + if (pkt->getRemainingBytes() >= 4) + *pkt >> lighting.shadow_tint; } diff --git a/src/network/networkprotocol.h b/src/network/networkprotocol.h index 5af9859ae..85931c71b 100644 --- a/src/network/networkprotocol.h +++ b/src/network/networkprotocol.h @@ -229,10 +229,13 @@ with this program; if not, write to the Free Software Foundation, Inc., [bump for 5.9.1] PROTOCOL VERSION 46: Move default hotbar from client-side C++ to server-side builtin Lua + Add shadow tint to Lighting packets + Add shadow color to CloudParam packets [scheduled bump for 5.10.0] */ #define LATEST_PROTOCOL_VERSION 46 + #define LATEST_PROTOCOL_VERSION_STRING TOSTRING(LATEST_PROTOCOL_VERSION) // Server's supported network protocol range @@ -1176,4 +1179,4 @@ enum InteractAction : u8 INTERACT_PLACE, // 3: place block or item (to abovesurface) INTERACT_USE, // 4: use item INTERACT_ACTIVATE // 5: rightclick air ("activate") -}; +}; \ No newline at end of file diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index db7212897..d6d608aab 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -2448,6 +2448,10 @@ int ObjectRef::l_set_clouds(lua_State *L) if (!lua_isnil(L, -1)) read_color(L, -1, &cloud_params.color_ambient); lua_pop(L, 1); + lua_getfield(L, 2, "shadow"); + if (!lua_isnil(L, -1)) + read_color(L, -1, &cloud_params.color_shadow); + lua_pop(L, 1); cloud_params.height = getfloatfield_default(L, 2, "height", cloud_params.height); cloud_params.thickness = getfloatfield_default(L, 2, "thickness", cloud_params.thickness); @@ -2483,6 +2487,8 @@ int ObjectRef::l_get_clouds(lua_State *L) lua_setfield(L, -2, "color"); push_ARGB8(L, cloud_params.color_ambient); lua_setfield(L, -2, "ambient"); + push_ARGB8(L, cloud_params.color_shadow); + lua_setfield(L, -2, "shadow"); lua_pushnumber(L, cloud_params.height); lua_setfield(L, -2, "height"); lua_pushnumber(L, cloud_params.thickness); @@ -2611,6 +2617,8 @@ int ObjectRef::l_set_lighting(lua_State *L) lua_getfield(L, 2, "shadows"); if (lua_istable(L, -1)) { getfloatfield(L, -1, "intensity", lighting.shadow_intensity); + lua_getfield(L, -1, "tint"); + read_color(L, -1, &lighting.shadow_tint); } lua_pop(L, 1); // shadows @@ -2654,6 +2662,8 @@ int ObjectRef::l_get_lighting(lua_State *L) lua_newtable(L); // "shadows" lua_pushnumber(L, lighting.shadow_intensity); lua_setfield(L, -2, "intensity"); + push_ARGB8(L, lighting.shadow_tint); + lua_setfield(L, -2, "tint"); lua_setfield(L, -2, "shadows"); lua_pushnumber(L, lighting.saturation); lua_setfield(L, -2, "saturation"); diff --git a/src/server.cpp b/src/server.cpp index 6421fc175..4be3aa26a 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1843,7 +1843,7 @@ void Server::SendCloudParams(session_t peer_id, const CloudParams ¶ms) { NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id); pkt << params.density << params.color_bright << params.color_ambient - << params.height << params.thickness << params.speed; + << params.height << params.thickness << params.speed << params.color_shadow; Send(&pkt); } @@ -1873,7 +1873,7 @@ void Server::SendSetLighting(session_t peer_id, const Lighting &lighting) << lighting.exposure.speed_bright_dark << lighting.exposure.center_weight_power; - pkt << lighting.volumetric_light_strength; + pkt << lighting.volumetric_light_strength << lighting.shadow_tint; Send(&pkt); } diff --git a/src/skyparams.h b/src/skyparams.h index 2ff918f36..52a15810b 100644 --- a/src/skyparams.h +++ b/src/skyparams.h @@ -81,6 +81,7 @@ struct CloudParams float density; video::SColor color_bright; video::SColor color_ambient; + video::SColor color_shadow; float thickness; float height; v2f speed; @@ -160,6 +161,7 @@ public: clouds.density = 0.4f; clouds.color_bright = video::SColor(229, 240, 240, 255); clouds.color_ambient = video::SColor(255, 0, 0, 0); + clouds.color_shadow = video::SColor(255, 204, 204, 204); clouds.thickness = 16.0f; clouds.height = 120; clouds.speed = v2f(0.0f, -2.0f); From f65fe80e8120e1052ef4c00c423cd5038b4b71bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20=C3=85str=C3=B6m?= Date: Tue, 24 Sep 2024 22:25:34 +0200 Subject: [PATCH 56/67] Add minetest.bulk_swap_node (#15043) Co-authored-by: sfan5 --- builtin/emerge/env.lua | 2 ++ doc/lua_api.md | 2 ++ games/devtest/mods/benchmarks/init.lua | 33 ++++++++++++++++++++++++++ src/script/lua_api/l_env.cpp | 26 ++++++++++++++++++++ src/script/lua_api/l_env.h | 4 ++++ 5 files changed, 67 insertions(+) diff --git a/builtin/emerge/env.lua b/builtin/emerge/env.lua index 2b32a0339..5beb6285c 100644 --- a/builtin/emerge/env.lua +++ b/builtin/emerge/env.lua @@ -23,6 +23,8 @@ core.add_node = core.set_node -- we don't deal with metadata currently core.swap_node = core.set_node +core.bulk_swap_node = core.bulk_set_node + function core.remove_node(pos) return core.vmanip:set_node_at(pos, {name="air"}) end diff --git a/doc/lua_api.md b/doc/lua_api.md index e7cc8a07f..3a5f7e128 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -6145,6 +6145,8 @@ Environment access * `minetest.swap_node(pos, node)` * Swap node at position with another. * This keeps the metadata intact and will not run con-/destructor callbacks. +* `minetest.bulk_swap_node({pos1, pos2, pos3, ...}, node)` + * Equivalent to `minetest.swap_node` but in bulk. * `minetest.remove_node(pos)`: Remove a node * Equivalent to `minetest.set_node(pos, {name="air"})`, but a bit faster. * `minetest.get_node(pos)` diff --git a/games/devtest/mods/benchmarks/init.lua b/games/devtest/mods/benchmarks/init.lua index 1f5001c69..e3a4409a5 100644 --- a/games/devtest/mods/benchmarks/init.lua +++ b/games/devtest/mods/benchmarks/init.lua @@ -154,3 +154,36 @@ minetest.register_chatcommand("bench_bulk_get_node", { return true, msg end, }) + +minetest.register_chatcommand("bench_bulk_swap_node", { + params = "", + description = "Benchmark: Bulk-swap 99×99×99 stone nodes", + func = function(name, param) + local player = minetest.get_player_by_name(name) + if not player then + return false, "No player." + end + local pos_list = get_positions_cube(player:get_pos()) + + minetest.chat_send_player(name, "Benchmarking minetest.bulk_swap_node. Warming up ...") + + -- warm up because first execution otherwise becomes + -- significantly slower + minetest.bulk_swap_node(pos_list, {name = "mapgen_stone"}) + + minetest.chat_send_player(name, "Warming up finished, now benchmarking ...") + + local start_time = minetest.get_us_time() + for i=1,#pos_list do + minetest.swap_node(pos_list[i], {name = "mapgen_stone"}) + end + local middle_time = minetest.get_us_time() + minetest.bulk_swap_node(pos_list, {name = "mapgen_stone"}) + local end_time = minetest.get_us_time() + local msg = string.format("Benchmark results: minetest.swap_node loop: %.2f ms; minetest.bulk_swap_node: %.2f ms", + ((middle_time - start_time)) / 1000, + ((end_time - middle_time)) / 1000 + ) + return true, msg + end, +}) diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp index a024d7e42..125a352bc 100644 --- a/src/script/lua_api/l_env.cpp +++ b/src/script/lua_api/l_env.cpp @@ -253,6 +253,31 @@ int ModApiEnv::l_swap_node(lua_State *L) return 1; } +// bulk_swap_node([pos1, pos2, ...], node) +// pos = {x=num, y=num, z=num} +int ModApiEnv::l_bulk_swap_node(lua_State *L) +{ + GET_ENV_PTR; + + luaL_checktype(L, 1, LUA_TTABLE); + + s32 len = lua_objlen(L, 1); + + MapNode n = readnode(L, 2); + + // Do it + bool succeeded = true; + for (s32 i = 1; i <= len; i++) { + lua_rawgeti(L, 1, i); + if (!env->swapNode(read_v3s16(L, -1), n)) + succeeded = false; + lua_pop(L, 1); + } + + lua_pushboolean(L, succeeded); + return 1; +} + // get_node_raw(x, y, z) -> content, param1, param2, pos_ok int ModApiEnv::l_get_node_raw(lua_State *L) { @@ -1377,6 +1402,7 @@ void ModApiEnv::Initialize(lua_State *L, int top) API_FCT(bulk_set_node); API_FCT(add_node); API_FCT(swap_node); + API_FCT(bulk_swap_node); API_FCT(add_item); API_FCT(remove_node); API_FCT(get_node_raw); diff --git a/src/script/lua_api/l_env.h b/src/script/lua_api/l_env.h index b92a6f935..ba0f2eb61 100644 --- a/src/script/lua_api/l_env.h +++ b/src/script/lua_api/l_env.h @@ -65,6 +65,10 @@ private: // pos = {x=num, y=num, z=num} static int l_bulk_set_node(lua_State *L); + // bulk_swap_node([pos1, pos2, ...], node) + // pos = {x=num, y=num, z=num} + static int l_bulk_swap_node(lua_State *L); + static int l_add_node(lua_State *L); // remove_node(pos) From 3c48671076e7ae3d33b507b1f6d239a47ab6501a Mon Sep 17 00:00:00 2001 From: grorp Date: Tue, 24 Sep 2024 22:25:46 +0200 Subject: [PATCH 57/67] Fix -Winconsistent-missing-override in unit_sao.h (#15190) --- src/server/unit_sao.h | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/server/unit_sao.h b/src/server/unit_sao.h index c7f8c4aec..32b5dd30e 100644 --- a/src/server/unit_sao.h +++ b/src/server/unit_sao.h @@ -31,7 +31,7 @@ public: UnitSAO(ServerEnvironment *env, v3f pos); virtual ~UnitSAO() = default; - u16 getHP() const { return m_hp; } + u16 getHP() const override { return m_hp; } // Use a function, if isDead can be defined by other conditions bool isDead() const { return m_hp == 0; } @@ -59,39 +59,39 @@ public: { return itemgroup_get(getArmorGroups(), "immortal"); } - void setArmorGroups(const ItemGroupList &armor_groups); - const ItemGroupList &getArmorGroups() const; + void setArmorGroups(const ItemGroupList &armor_groups) override; + const ItemGroupList &getArmorGroups() const override; // Animation void setAnimation(v2f frame_range, float frame_speed, float frame_blend, - bool frame_loop); + bool frame_loop) override; void getAnimation(v2f *frame_range, float *frame_speed, float *frame_blend, - bool *frame_loop); - void setAnimationSpeed(float frame_speed); + bool *frame_loop) override; + void setAnimationSpeed(float frame_speed) override; // Bone position - void setBoneOverride(const std::string &bone, const BoneOverride &props); - BoneOverride getBoneOverride(const std::string &bone); + void setBoneOverride(const std::string &bone, const BoneOverride &props) override; + BoneOverride getBoneOverride(const std::string &bone) override; const std::unordered_map - &getBoneOverrides() const { return m_bone_override; }; + &getBoneOverrides() const override { return m_bone_override; }; // Attachments - ServerActiveObject *getParent() const; + ServerActiveObject *getParent() const override; inline bool isAttached() const { return m_attachment_parent_id != 0; } void setAttachment(object_t parent_id, const std::string &bone, v3f position, - v3f rotation, bool force_visible); + v3f rotation, bool force_visible) override; void getAttachment(object_t *parent_id, std::string *bone, v3f *position, - v3f *rotation, bool *force_visible) const; + v3f *rotation, bool *force_visible) const override; void clearChildAttachments() override; void addAttachmentChild(object_t child_id) override; void removeAttachmentChild(object_t child_id) override; - const std::unordered_set &getAttachmentChildIds() const { + const std::unordered_set &getAttachmentChildIds() const override { return m_attachment_child_ids; } // Object properties - ObjectProperties *accessObjectProperties(); - void notifyObjectPropertiesModified(); + ObjectProperties *accessObjectProperties() override; + void notifyObjectPropertiesModified() override; void sendOutdatedData(); // Update packets @@ -125,11 +125,11 @@ protected: object_t m_attachment_parent_id = 0; void clearAnyAttachments(); - virtual void onMarkedForDeactivation() { + virtual void onMarkedForDeactivation() override { ServerActiveObject::onMarkedForDeactivation(); clearAnyAttachments(); } - virtual void onMarkedForRemoval() { + virtual void onMarkedForRemoval() override { ServerActiveObject::onMarkedForRemoval(); clearAnyAttachments(); } From 526a2f7b8c45504088e194a83d54a19045227bbd Mon Sep 17 00:00:00 2001 From: grorp Date: Tue, 24 Sep 2024 22:37:44 +0200 Subject: [PATCH 58/67] Dehardcode the death formspec (#15155) Co-authored-by: Paul Ouellette --- builtin/client/death_formspec.lua | 15 ------------ builtin/client/init.lua | 1 - builtin/game/death_screen.lua | 31 +++++++++++++++++++++++++ builtin/game/init.lua | 1 + builtin/locale/__builtin.be.tr | 3 +++ builtin/locale/__builtin.bg.tr | 3 +++ builtin/locale/__builtin.ca.tr | 3 +++ builtin/locale/__builtin.cs.tr | 3 +++ builtin/locale/__builtin.cy.tr | 3 +++ builtin/locale/__builtin.da.tr | 3 +++ builtin/locale/__builtin.de.tr | 2 ++ builtin/locale/__builtin.el.tr | 3 +++ builtin/locale/__builtin.eo.tr | 2 ++ builtin/locale/__builtin.es.tr | 3 +++ builtin/locale/__builtin.et.tr | 3 +++ builtin/locale/__builtin.eu.tr | 3 +++ builtin/locale/__builtin.fi.tr | 3 +++ builtin/locale/__builtin.fil.tr | 3 +++ builtin/locale/__builtin.fr.tr | 2 ++ builtin/locale/__builtin.ga.tr | 3 +++ builtin/locale/__builtin.gl.tr | 3 +++ builtin/locale/__builtin.hu.tr | 3 +++ builtin/locale/__builtin.id.tr | 2 ++ builtin/locale/__builtin.it.tr | 2 ++ builtin/locale/__builtin.ja.tr | 3 +++ builtin/locale/__builtin.jbo.tr | 3 +++ builtin/locale/__builtin.jv.tr | 3 +++ builtin/locale/__builtin.ko.tr | 3 +++ builtin/locale/__builtin.kv.tr | 3 +++ builtin/locale/__builtin.ky.tr | 3 +++ builtin/locale/__builtin.lt.tr | 3 +++ builtin/locale/__builtin.lv.tr | 3 +++ builtin/locale/__builtin.lzh.tr | 3 +++ builtin/locale/__builtin.mn.tr | 3 +++ builtin/locale/__builtin.mr.tr | 3 +++ builtin/locale/__builtin.ms.tr | 2 ++ builtin/locale/__builtin.nb.tr | 3 +++ builtin/locale/__builtin.nl.tr | 3 +++ builtin/locale/__builtin.nn.tr | 3 +++ builtin/locale/__builtin.oc.tr | 3 +++ builtin/locale/__builtin.pl.tr | 3 +++ builtin/locale/__builtin.pt.tr | 3 +++ builtin/locale/__builtin.pt_BR.tr | 2 ++ builtin/locale/__builtin.ro.tr | 3 +++ builtin/locale/__builtin.ru.tr | 2 ++ builtin/locale/__builtin.sk.tr | 3 +++ builtin/locale/__builtin.sl.tr | 3 +++ builtin/locale/__builtin.sr_Cyrl.tr | 3 +++ builtin/locale/__builtin.sr_Latn.tr | 3 +++ builtin/locale/__builtin.sv.tr | 3 +++ builtin/locale/__builtin.sw.tr | 3 +++ builtin/locale/__builtin.tok.tr | 3 +++ builtin/locale/__builtin.tr.tr | 3 +++ builtin/locale/__builtin.tt.tr | 3 +++ builtin/locale/__builtin.uk.tr | 3 +++ builtin/locale/__builtin.vi.tr | 3 +++ builtin/locale/__builtin.zh_CN.tr | 3 +++ builtin/locale/__builtin.zh_TW.tr | 3 +++ doc/client_lua_api.md | 4 ---- doc/lua_api.md | 8 +++++++ src/client/client.cpp | 4 ++-- src/client/client.h | 4 ++-- src/client/clientevent.h | 9 +------- src/client/game.cpp | 25 ++++++-------------- src/network/clientopcodes.cpp | 4 ++-- src/network/clientpackethandler.cpp | 14 ++--------- src/network/networkprotocol.h | 17 ++++++++------ src/network/serveropcodes.cpp | 4 ++-- src/network/serverpackethandler.cpp | 27 ---------------------- src/script/cpp_api/s_client.cpp | 15 ------------ src/script/cpp_api/s_client.h | 1 - src/script/lua_api/l_client.cpp | 8 ------- src/script/lua_api/l_client.h | 3 --- src/script/lua_api/l_object.cpp | 6 ++--- src/server.cpp | 36 ----------------------------- src/server.h | 5 ---- src/server/clientiface.h | 2 +- src/server/player_sao.cpp | 15 ++++++++++++ src/server/player_sao.h | 1 + 79 files changed, 242 insertions(+), 172 deletions(-) delete mode 100644 builtin/client/death_formspec.lua create mode 100644 builtin/game/death_screen.lua create mode 100644 builtin/locale/__builtin.be.tr create mode 100644 builtin/locale/__builtin.bg.tr create mode 100644 builtin/locale/__builtin.ca.tr create mode 100644 builtin/locale/__builtin.cs.tr create mode 100644 builtin/locale/__builtin.cy.tr create mode 100644 builtin/locale/__builtin.da.tr create mode 100644 builtin/locale/__builtin.el.tr create mode 100644 builtin/locale/__builtin.es.tr create mode 100644 builtin/locale/__builtin.et.tr create mode 100644 builtin/locale/__builtin.eu.tr create mode 100644 builtin/locale/__builtin.fi.tr create mode 100644 builtin/locale/__builtin.fil.tr create mode 100644 builtin/locale/__builtin.ga.tr create mode 100644 builtin/locale/__builtin.gl.tr create mode 100644 builtin/locale/__builtin.hu.tr create mode 100644 builtin/locale/__builtin.ja.tr create mode 100644 builtin/locale/__builtin.jbo.tr create mode 100644 builtin/locale/__builtin.jv.tr create mode 100644 builtin/locale/__builtin.ko.tr create mode 100644 builtin/locale/__builtin.kv.tr create mode 100644 builtin/locale/__builtin.ky.tr create mode 100644 builtin/locale/__builtin.lt.tr create mode 100644 builtin/locale/__builtin.lv.tr create mode 100644 builtin/locale/__builtin.lzh.tr create mode 100644 builtin/locale/__builtin.mn.tr create mode 100644 builtin/locale/__builtin.mr.tr create mode 100644 builtin/locale/__builtin.nb.tr create mode 100644 builtin/locale/__builtin.nl.tr create mode 100644 builtin/locale/__builtin.nn.tr create mode 100644 builtin/locale/__builtin.oc.tr create mode 100644 builtin/locale/__builtin.pl.tr create mode 100644 builtin/locale/__builtin.pt.tr create mode 100644 builtin/locale/__builtin.ro.tr create mode 100644 builtin/locale/__builtin.sk.tr create mode 100644 builtin/locale/__builtin.sl.tr create mode 100644 builtin/locale/__builtin.sr_Cyrl.tr create mode 100644 builtin/locale/__builtin.sr_Latn.tr create mode 100644 builtin/locale/__builtin.sv.tr create mode 100644 builtin/locale/__builtin.sw.tr create mode 100644 builtin/locale/__builtin.tok.tr create mode 100644 builtin/locale/__builtin.tr.tr create mode 100644 builtin/locale/__builtin.tt.tr create mode 100644 builtin/locale/__builtin.uk.tr create mode 100644 builtin/locale/__builtin.vi.tr create mode 100644 builtin/locale/__builtin.zh_CN.tr create mode 100644 builtin/locale/__builtin.zh_TW.tr diff --git a/builtin/client/death_formspec.lua b/builtin/client/death_formspec.lua deleted file mode 100644 index c25c799ab..000000000 --- a/builtin/client/death_formspec.lua +++ /dev/null @@ -1,15 +0,0 @@ --- CSM death formspec. Only used when clientside modding is enabled, otherwise --- handled by the engine. - -core.register_on_death(function() - local formspec = "size[11,5.5]bgcolor[#320000b4;true]" .. - "label[4.85,1.35;" .. fgettext("You died") .. - "]button_exit[4,3;3,0.5;btn_respawn;".. fgettext("Respawn") .."]" - core.show_formspec("bultin:death", formspec) -end) - -core.register_on_formspec_input(function(formname, fields) - if formname == "bultin:death" then - core.send_respawn() - end -end) diff --git a/builtin/client/init.lua b/builtin/client/init.lua index 301a8050c..8d01c99a4 100644 --- a/builtin/client/init.lua +++ b/builtin/client/init.lua @@ -9,6 +9,5 @@ dofile(commonpath .. "mod_storage.lua") dofile(commonpath .. "chatcommands.lua") dofile(commonpath .. "information_formspecs.lua") dofile(clientpath .. "chatcommands.lua") -dofile(clientpath .. "death_formspec.lua") dofile(clientpath .. "misc.lua") assert(loadfile(commonpath .. "item_s.lua"))({}) -- Just for push/read node functions diff --git a/builtin/game/death_screen.lua b/builtin/game/death_screen.lua new file mode 100644 index 000000000..77f56aaff --- /dev/null +++ b/builtin/game/death_screen.lua @@ -0,0 +1,31 @@ +local F = core.formspec_escape +local S = core.get_translator("__builtin") + +function core.show_death_screen(player, _reason) + local fs = { + "formspec_version[1]", + "size[11,5.5,true]", + "bgcolor[#320000b4;true]", + "label[4.85,1.35;", F(S("You died")), "]", + "button_exit[4,3;3,0.5;btn_respawn;", F(S("Respawn")), "]", + } + core.show_formspec(player:get_player_name(), "__builtin:death", table.concat(fs, "")) +end + +core.register_on_dieplayer(function(player, reason) + core.show_death_screen(player, reason) +end) + +core.register_on_joinplayer(function(player) + if player:get_hp() == 0 then + core.show_death_screen(player, nil) + end +end) + +core.register_on_player_receive_fields(function(player, formname, fields) + if formname == "__builtin:death" and fields.quit and player:get_hp() == 0 then + player:respawn() + core.log("action", player:get_player_name() .. " respawns at " .. + player:get_pos():to_string()) + end +end) diff --git a/builtin/game/init.lua b/builtin/game/init.lua index 4e16c686d..b3c64e729 100644 --- a/builtin/game/init.lua +++ b/builtin/game/init.lua @@ -38,6 +38,7 @@ dofile(gamepath .. "forceloading.lua") dofile(gamepath .. "hud.lua") dofile(gamepath .. "knockback.lua") dofile(gamepath .. "async.lua") +dofile(gamepath .. "death_screen.lua") core.after(0, builtin_shared.cache_content_ids) diff --git a/builtin/locale/__builtin.be.tr b/builtin/locale/__builtin.be.tr new file mode 100644 index 000000000..bd8ea999e --- /dev/null +++ b/builtin/locale/__builtin.be.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Вы загінулі +Respawn=Адрадзіцца diff --git a/builtin/locale/__builtin.bg.tr b/builtin/locale/__builtin.bg.tr new file mode 100644 index 000000000..43fe8f31e --- /dev/null +++ b/builtin/locale/__builtin.bg.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Умряхте +Respawn=Прераждане diff --git a/builtin/locale/__builtin.ca.tr b/builtin/locale/__builtin.ca.tr new file mode 100644 index 000000000..5cde155f9 --- /dev/null +++ b/builtin/locale/__builtin.ca.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Has mort +Respawn=Reaparèixer diff --git a/builtin/locale/__builtin.cs.tr b/builtin/locale/__builtin.cs.tr new file mode 100644 index 000000000..4f4b592e4 --- /dev/null +++ b/builtin/locale/__builtin.cs.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Zemřel jsi +Respawn=Oživit diff --git a/builtin/locale/__builtin.cy.tr b/builtin/locale/__builtin.cy.tr new file mode 100644 index 000000000..372da1a89 --- /dev/null +++ b/builtin/locale/__builtin.cy.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Buest ti farw +Respawn=Atgyfodi diff --git a/builtin/locale/__builtin.da.tr b/builtin/locale/__builtin.da.tr new file mode 100644 index 000000000..c34eceeb9 --- /dev/null +++ b/builtin/locale/__builtin.da.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Du døde +Respawn=Genopstå diff --git a/builtin/locale/__builtin.de.tr b/builtin/locale/__builtin.de.tr index 0552ef88b..3665a3f54 100644 --- a/builtin/locale/__builtin.de.tr +++ b/builtin/locale/__builtin.de.tr @@ -244,3 +244,5 @@ A total of @1 sample(s) were taken.=Es wurden insgesamt @1 Datenpunkt(e) aufgeze The output is limited to '@1'.=Die Ausgabe ist beschränkt auf „@1“. Saving of profile failed: @1=Speichern des Profils fehlgeschlagen: @1 Profile saved to @1=Profil abgespeichert nach @1 +You died=Sie sind gestorben +Respawn=Wiederbeleben diff --git a/builtin/locale/__builtin.el.tr b/builtin/locale/__builtin.el.tr new file mode 100644 index 000000000..c14180a62 --- /dev/null +++ b/builtin/locale/__builtin.el.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Πέθανες +Respawn=Επανεμφάνηση diff --git a/builtin/locale/__builtin.eo.tr b/builtin/locale/__builtin.eo.tr index c3fec6c37..f1fe5333b 100644 --- a/builtin/locale/__builtin.eo.tr +++ b/builtin/locale/__builtin.eo.tr @@ -244,3 +244,5 @@ A total of @1 sample(s) were taken.=Sume @1 ekzemplero(j) konserviĝis. The output is limited to '@1'.=La eligo estas limigita al «@1». Saving of profile failed: @1=Konservado de profilo malsukcesis: @1 Profile saved to @1=Profilo konservita al @1 +You died=Vi mortis +Respawn=Renaskiĝi diff --git a/builtin/locale/__builtin.es.tr b/builtin/locale/__builtin.es.tr new file mode 100644 index 000000000..3c4a66933 --- /dev/null +++ b/builtin/locale/__builtin.es.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Has muerto +Respawn=Reaparecer diff --git a/builtin/locale/__builtin.et.tr b/builtin/locale/__builtin.et.tr new file mode 100644 index 000000000..e0745c24a --- /dev/null +++ b/builtin/locale/__builtin.et.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Said surma +Respawn=Ärka ellu diff --git a/builtin/locale/__builtin.eu.tr b/builtin/locale/__builtin.eu.tr new file mode 100644 index 000000000..77f510855 --- /dev/null +++ b/builtin/locale/__builtin.eu.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Hil zara +Respawn=Birsortu diff --git a/builtin/locale/__builtin.fi.tr b/builtin/locale/__builtin.fi.tr new file mode 100644 index 000000000..f7c0ee038 --- /dev/null +++ b/builtin/locale/__builtin.fi.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Kuolit +Respawn=Synny uudelleen diff --git a/builtin/locale/__builtin.fil.tr b/builtin/locale/__builtin.fil.tr new file mode 100644 index 000000000..0755234a1 --- /dev/null +++ b/builtin/locale/__builtin.fil.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Namatay ka +Respawn=Mag-respawn diff --git a/builtin/locale/__builtin.fr.tr b/builtin/locale/__builtin.fr.tr index 6c3a244dc..d36574afd 100644 --- a/builtin/locale/__builtin.fr.tr +++ b/builtin/locale/__builtin.fr.tr @@ -244,3 +244,5 @@ A total of @1 sample(s) were taken.=@1 échantillons ont été collectés. The output is limited to '@1'.=La sortie est limitée à '@1'. Saving of profile failed: @1=La sauvegarde du profil a échoué : @1 Profile saved to @1=Le profil a été sauvegardé dans @1 +You died=Vous êtes mort +Respawn=Réapparaître diff --git a/builtin/locale/__builtin.ga.tr b/builtin/locale/__builtin.ga.tr new file mode 100644 index 000000000..e19959b10 --- /dev/null +++ b/builtin/locale/__builtin.ga.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Fuair tú bás +Respawn=Athsceith diff --git a/builtin/locale/__builtin.gl.tr b/builtin/locale/__builtin.gl.tr new file mode 100644 index 000000000..7f692f633 --- /dev/null +++ b/builtin/locale/__builtin.gl.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Morreches +Respawn=Reaparecer diff --git a/builtin/locale/__builtin.hu.tr b/builtin/locale/__builtin.hu.tr new file mode 100644 index 000000000..d7eebf7a0 --- /dev/null +++ b/builtin/locale/__builtin.hu.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Meghaltál +Respawn=Újraéledés diff --git a/builtin/locale/__builtin.id.tr b/builtin/locale/__builtin.id.tr index a541b0f8c..a7eba8c1c 100644 --- a/builtin/locale/__builtin.id.tr +++ b/builtin/locale/__builtin.id.tr @@ -244,3 +244,5 @@ A total of @1 sample(s) were taken.=Total @1 sampel yang diambil. The output is limited to '@1'.=Keluaran dibatasi ke '@1'. Saving of profile failed: @1=Penyimpanan profil gagal: @1 Profile saved to @1=Profil disimpan ke @1 +You died=Anda mati +Respawn=Bangkit kembali diff --git a/builtin/locale/__builtin.it.tr b/builtin/locale/__builtin.it.tr index aecb80a9a..24cf38104 100644 --- a/builtin/locale/__builtin.it.tr +++ b/builtin/locale/__builtin.it.tr @@ -245,3 +245,5 @@ A total of @1 sample(s) were taken.=Son stati ottenuti campioni per un totale di The output is limited to '@1'.=L'output è limitato a '@1'. Saving of profile failed: @1=Errore nel salvare il profilo: @1 Profile saved to @1=Profilo salvato in @1 +You died=Sei morto +Respawn=Rinasci diff --git a/builtin/locale/__builtin.ja.tr b/builtin/locale/__builtin.ja.tr new file mode 100644 index 000000000..1138edddd --- /dev/null +++ b/builtin/locale/__builtin.ja.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=死んでしまった +Respawn=リスポーン diff --git a/builtin/locale/__builtin.jbo.tr b/builtin/locale/__builtin.jbo.tr new file mode 100644 index 000000000..fe492bcdb --- /dev/null +++ b/builtin/locale/__builtin.jbo.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=.i do morsi +Respawn=tolcanci diff --git a/builtin/locale/__builtin.jv.tr b/builtin/locale/__builtin.jv.tr new file mode 100644 index 000000000..282cc5476 --- /dev/null +++ b/builtin/locale/__builtin.jv.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Panjenengan pejah +Respawn=Bangkit Malilh diff --git a/builtin/locale/__builtin.ko.tr b/builtin/locale/__builtin.ko.tr new file mode 100644 index 000000000..0d5d35a90 --- /dev/null +++ b/builtin/locale/__builtin.ko.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=사망했습니다 +Respawn=리스폰 diff --git a/builtin/locale/__builtin.kv.tr b/builtin/locale/__builtin.kv.tr new file mode 100644 index 000000000..f985d2ac4 --- /dev/null +++ b/builtin/locale/__builtin.kv.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Кулінныд +Respawn=Ловзьыны diff --git a/builtin/locale/__builtin.ky.tr b/builtin/locale/__builtin.ky.tr new file mode 100644 index 000000000..9ad468aa0 --- /dev/null +++ b/builtin/locale/__builtin.ky.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Сиз өлдүңүз. +Respawn=Кайтадан жаралуу diff --git a/builtin/locale/__builtin.lt.tr b/builtin/locale/__builtin.lt.tr new file mode 100644 index 000000000..cc613162c --- /dev/null +++ b/builtin/locale/__builtin.lt.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Jūs numirėte +Respawn=Prisikelti diff --git a/builtin/locale/__builtin.lv.tr b/builtin/locale/__builtin.lv.tr new file mode 100644 index 000000000..1da1fe3d8 --- /dev/null +++ b/builtin/locale/__builtin.lv.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Jūs nomirāt +Respawn=Atdzīvoties diff --git a/builtin/locale/__builtin.lzh.tr b/builtin/locale/__builtin.lzh.tr new file mode 100644 index 000000000..1af6aba98 --- /dev/null +++ b/builtin/locale/__builtin.lzh.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=尔死矣 +Respawn=复生 diff --git a/builtin/locale/__builtin.mn.tr b/builtin/locale/__builtin.mn.tr new file mode 100644 index 000000000..dd9a3465b --- /dev/null +++ b/builtin/locale/__builtin.mn.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Та үхсэн +Respawn=Дахин төрөх diff --git a/builtin/locale/__builtin.mr.tr b/builtin/locale/__builtin.mr.tr new file mode 100644 index 000000000..e4fcfb9b1 --- /dev/null +++ b/builtin/locale/__builtin.mr.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=तू मेलास +Respawn=पुनर्जन्म diff --git a/builtin/locale/__builtin.ms.tr b/builtin/locale/__builtin.ms.tr index ebf794e97..65ac557bf 100644 --- a/builtin/locale/__builtin.ms.tr +++ b/builtin/locale/__builtin.ms.tr @@ -244,3 +244,5 @@ A total of @1 sample(s) were taken.=Sebanyak @1 sampel telah diambil secara kese The output is limited to '@1'.=Output dihadkan kepada '@1'. Saving of profile failed: @1=Penyimpanan profil telah gagal: @1 Profile saved to @1=Profil telah disimpan ke @1 +You died=Anda telah meninggal +Respawn=Jelma semula diff --git a/builtin/locale/__builtin.nb.tr b/builtin/locale/__builtin.nb.tr new file mode 100644 index 000000000..b02a2d282 --- /dev/null +++ b/builtin/locale/__builtin.nb.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Du døde +Respawn=Gjenoppstå diff --git a/builtin/locale/__builtin.nl.tr b/builtin/locale/__builtin.nl.tr new file mode 100644 index 000000000..bd23c04b0 --- /dev/null +++ b/builtin/locale/__builtin.nl.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Je bent gestorven +Respawn=Herboren worden diff --git a/builtin/locale/__builtin.nn.tr b/builtin/locale/__builtin.nn.tr new file mode 100644 index 000000000..240191f73 --- /dev/null +++ b/builtin/locale/__builtin.nn.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Du døydde +Respawn=Kom opp att diff --git a/builtin/locale/__builtin.oc.tr b/builtin/locale/__builtin.oc.tr new file mode 100644 index 000000000..34b6577ad --- /dev/null +++ b/builtin/locale/__builtin.oc.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Setz mòrt·a +Respawn=Tornar diff --git a/builtin/locale/__builtin.pl.tr b/builtin/locale/__builtin.pl.tr new file mode 100644 index 000000000..ec0a9b7c1 --- /dev/null +++ b/builtin/locale/__builtin.pl.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Nie żyjesz +Respawn=Wróć do gry diff --git a/builtin/locale/__builtin.pt.tr b/builtin/locale/__builtin.pt.tr new file mode 100644 index 000000000..fbdb461e5 --- /dev/null +++ b/builtin/locale/__builtin.pt.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Você morreu +Respawn=Renascer diff --git a/builtin/locale/__builtin.pt_BR.tr b/builtin/locale/__builtin.pt_BR.tr index e12e9fae8..e48425bda 100644 --- a/builtin/locale/__builtin.pt_BR.tr +++ b/builtin/locale/__builtin.pt_BR.tr @@ -244,3 +244,5 @@ A total of @1 sample(s) were taken.=Um total de @1 amostra(s) foi coletada. The output is limited to '@1'.=A saída é limitada a '@1'. Saving of profile failed: @1=Falha ao salvar o perfil: @1 Profile saved to @1=Perfil salvo em @1 +You died=Você morreu +Respawn=Reviver diff --git a/builtin/locale/__builtin.ro.tr b/builtin/locale/__builtin.ro.tr new file mode 100644 index 000000000..7ff5e3c38 --- /dev/null +++ b/builtin/locale/__builtin.ro.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Ai murit +Respawn=Reînviere diff --git a/builtin/locale/__builtin.ru.tr b/builtin/locale/__builtin.ru.tr index d43fbc589..863cdd638 100644 --- a/builtin/locale/__builtin.ru.tr +++ b/builtin/locale/__builtin.ru.tr @@ -244,3 +244,5 @@ A total of @1 sample(s) were taken.=Всего было взято @1 образ The output is limited to '@1'.=Вывод ограничен значением '@1'. Saving of profile failed: @1=Не удалось сохранить данные профилирования: @1 Profile saved to @1=Данные профилирования сохранены в @1 +You died=Вы умерли +Respawn=Возродиться diff --git a/builtin/locale/__builtin.sk.tr b/builtin/locale/__builtin.sk.tr new file mode 100644 index 000000000..e9e93f6a3 --- /dev/null +++ b/builtin/locale/__builtin.sk.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Zomrel si +Respawn=Oživiť diff --git a/builtin/locale/__builtin.sl.tr b/builtin/locale/__builtin.sl.tr new file mode 100644 index 000000000..6dc77c3b2 --- /dev/null +++ b/builtin/locale/__builtin.sl.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Umrl si +Respawn=Ponovno oživi diff --git a/builtin/locale/__builtin.sr_Cyrl.tr b/builtin/locale/__builtin.sr_Cyrl.tr new file mode 100644 index 000000000..68551e77a --- /dev/null +++ b/builtin/locale/__builtin.sr_Cyrl.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Умро си +Respawn=Врати се у живот diff --git a/builtin/locale/__builtin.sr_Latn.tr b/builtin/locale/__builtin.sr_Latn.tr new file mode 100644 index 000000000..4adc496b4 --- /dev/null +++ b/builtin/locale/__builtin.sr_Latn.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Umro/la si. +Respawn=Vrati se u zivot diff --git a/builtin/locale/__builtin.sv.tr b/builtin/locale/__builtin.sv.tr new file mode 100644 index 000000000..115014506 --- /dev/null +++ b/builtin/locale/__builtin.sv.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Du dog +Respawn=Återuppstå diff --git a/builtin/locale/__builtin.sw.tr b/builtin/locale/__builtin.sw.tr new file mode 100644 index 000000000..92aa1f3e1 --- /dev/null +++ b/builtin/locale/__builtin.sw.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Umekufa. +Respawn=Respawn diff --git a/builtin/locale/__builtin.tok.tr b/builtin/locale/__builtin.tok.tr new file mode 100644 index 000000000..14d131d6a --- /dev/null +++ b/builtin/locale/__builtin.tok.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=sina moli +Respawn=o kama sin diff --git a/builtin/locale/__builtin.tr.tr b/builtin/locale/__builtin.tr.tr new file mode 100644 index 000000000..dafec5630 --- /dev/null +++ b/builtin/locale/__builtin.tr.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Öldün +Respawn=Yeniden Canlan diff --git a/builtin/locale/__builtin.tt.tr b/builtin/locale/__builtin.tt.tr new file mode 100644 index 000000000..a162cd9b7 --- /dev/null +++ b/builtin/locale/__builtin.tt.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Сез үлдегез +Respawn=Тергезелергә diff --git a/builtin/locale/__builtin.uk.tr b/builtin/locale/__builtin.uk.tr new file mode 100644 index 000000000..e82a10bde --- /dev/null +++ b/builtin/locale/__builtin.uk.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Ви загинули +Respawn=Відродитися diff --git a/builtin/locale/__builtin.vi.tr b/builtin/locale/__builtin.vi.tr new file mode 100644 index 000000000..53caac93c --- /dev/null +++ b/builtin/locale/__builtin.vi.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=Bạn đã bị chết +Respawn=Hồi sinh diff --git a/builtin/locale/__builtin.zh_CN.tr b/builtin/locale/__builtin.zh_CN.tr new file mode 100644 index 000000000..5b1077429 --- /dev/null +++ b/builtin/locale/__builtin.zh_CN.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=您已死亡 +Respawn=重生 diff --git a/builtin/locale/__builtin.zh_TW.tr b/builtin/locale/__builtin.zh_TW.tr new file mode 100644 index 000000000..5b1077429 --- /dev/null +++ b/builtin/locale/__builtin.zh_TW.tr @@ -0,0 +1,3 @@ +# textdomain: __builtin +You died=您已死亡 +Respawn=重生 diff --git a/doc/client_lua_api.md b/doc/client_lua_api.md index 08d0317ab..cd651f1b3 100644 --- a/doc/client_lua_api.md +++ b/doc/client_lua_api.md @@ -338,8 +338,6 @@ Call these functions only at load time! is checked to see if the command exists, but after the input is parsed. * Return `true` to mark the command as handled, which means that the default handlers will be prevented. -* `minetest.register_on_death(function())` - * Called when the local player dies * `minetest.register_on_hp_modification(function(hp))` * Called when server modified player's HP * `minetest.register_on_damage_taken(function(hp))` @@ -487,8 +485,6 @@ Call these functions only at load time! * Returns `false` if the client is already disconnecting otherwise returns `true`. * `minetest.get_server_info()` * Returns [server info](#server-info). -* `minetest.send_respawn()` - * Sends a respawn request to the server. ### Storage API * `minetest.get_mod_storage()`: diff --git a/doc/lua_api.md b/doc/lua_api.md index 3a5f7e128..66a83542e 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -5869,6 +5869,7 @@ Call these functions only at load time! * `minetest.register_on_dieplayer(function(ObjectRef, reason))` * Called when a player dies * `reason`: a PlayerHPChangeReason table, see register_on_player_hpchange + * For customizing the death screen, see `minetest.show_death_screen`. * `minetest.register_on_respawnplayer(function(ObjectRef))` * Called when player is to be respawned * Called _before_ repositioning of player occurs @@ -6573,6 +6574,13 @@ Formspec * `"INV"`: something failed * `"CHG"`: has been changed * `"VAL"`: not changed +* `minetest.show_death_screen(player, reason)` + * Called when the death screen should be shown. + * `player` is an ObjectRef, `reason` is a PlayerHPChangeReason table or nil. + * By default, this shows a simple formspec with the option to respawn. + Respawning is done via `ObjectRef:respawn`. + * You can override this to show a custom death screen. + * For general death handling, use `minetest.register_on_dieplayer` instead. Item handling ------------- diff --git a/src/client/client.cpp b/src/client/client.cpp index b14ef7004..1a2f51db9 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -1359,9 +1359,9 @@ void Client::sendDamage(u16 damage) Send(&pkt); } -void Client::sendRespawn() +void Client::sendRespawnLegacy() { - NetworkPacket pkt(TOSERVER_RESPAWN, 0); + NetworkPacket pkt(TOSERVER_RESPAWN_LEGACY, 0); Send(&pkt); } diff --git a/src/client/client.h b/src/client/client.h index adbe7a70d..f9f77ede4 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -194,7 +194,7 @@ public: void handleCommand_Breath(NetworkPacket* pkt); void handleCommand_MovePlayer(NetworkPacket* pkt); void handleCommand_MovePlayerRel(NetworkPacket* pkt); - void handleCommand_DeathScreen(NetworkPacket* pkt); + void handleCommand_DeathScreenLegacy(NetworkPacket* pkt); void handleCommand_AnnounceMedia(NetworkPacket* pkt); void handleCommand_Media(NetworkPacket* pkt); void handleCommand_NodeDef(NetworkPacket* pkt); @@ -249,7 +249,7 @@ public: void sendChangePassword(const std::string &oldpassword, const std::string &newpassword); void sendDamage(u16 damage); - void sendRespawn(); + void sendRespawnLegacy(); void sendReady(); void sendHaveMedia(const std::vector &tokens); void sendUpdateClientInfo(const ClientDynamicInfo &info); diff --git a/src/client/clientevent.h b/src/client/clientevent.h index acd375a4e..8c505786b 100644 --- a/src/client/clientevent.h +++ b/src/client/clientevent.h @@ -35,7 +35,7 @@ enum ClientEventType : u8 CE_NONE, CE_PLAYER_DAMAGE, CE_PLAYER_FORCE_MOVE, - CE_DEATHSCREEN, + CE_DEATHSCREEN_LEGACY, CE_SHOW_FORMSPEC, CE_SHOW_LOCAL_FORMSPEC, CE_SPAWN_PARTICLE, @@ -96,13 +96,6 @@ struct ClientEvent f32 yaw; } player_force_move; struct - { - bool set_camera_point_target; - f32 camera_point_target_x; - f32 camera_point_target_y; - f32 camera_point_target_z; - } deathscreen; - struct { std::string *formspec; std::string *formname; diff --git a/src/client/game.cpp b/src/client/game.cpp index ed593abba..6cbf54f5a 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -186,7 +186,7 @@ struct LocalFormspecHandler : public TextDest assert(m_client != nullptr); if (fields.find("quit") != fields.end()) - m_client->sendRespawn(); + m_client->sendRespawnLegacy(); return; } @@ -837,7 +837,7 @@ private: bool disable_camera_update = false; }; - void showDeathFormspec(); + void showDeathFormspecLegacy(); void showPauseMenu(); void pauseAnimation(); @@ -847,7 +847,7 @@ private: void handleClientEvent_None(ClientEvent *event, CameraOrientation *cam); void handleClientEvent_PlayerDamage(ClientEvent *event, CameraOrientation *cam); void handleClientEvent_PlayerForceMove(ClientEvent *event, CameraOrientation *cam); - void handleClientEvent_Deathscreen(ClientEvent *event, CameraOrientation *cam); + void handleClientEvent_DeathscreenLegacy(ClientEvent *event, CameraOrientation *cam); void handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation *cam); void handleClientEvent_ShowLocalFormSpec(ClientEvent *event, CameraOrientation *cam); void handleClientEvent_HandleParticleEvent(ClientEvent *event, @@ -2854,7 +2854,7 @@ const ClientEventHandler Game::clientEventHandler[CLIENTEVENT_MAX] = { {&Game::handleClientEvent_None}, {&Game::handleClientEvent_PlayerDamage}, {&Game::handleClientEvent_PlayerForceMove}, - {&Game::handleClientEvent_Deathscreen}, + {&Game::handleClientEvent_DeathscreenLegacy}, {&Game::handleClientEvent_ShowFormSpec}, {&Game::handleClientEvent_ShowLocalFormSpec}, {&Game::handleClientEvent_HandleParticleEvent}, @@ -2910,20 +2910,9 @@ void Game::handleClientEvent_PlayerForceMove(ClientEvent *event, CameraOrientati cam->camera_pitch = event->player_force_move.pitch; } -void Game::handleClientEvent_Deathscreen(ClientEvent *event, CameraOrientation *cam) +void Game::handleClientEvent_DeathscreenLegacy(ClientEvent *event, CameraOrientation *cam) { - // If client scripting is enabled, deathscreen is handled by CSM code in - // builtin/client/init.lua - if (client->modsLoaded()) - client->getScript()->on_death(); - else - showDeathFormspec(); - - /* Handle visualization */ - LocalPlayer *player = client->getEnv().getLocalPlayer(); - runData.damage_flash = 0; - player->hurt_tilt_timer = 0; - player->hurt_tilt_strength = 0; + showDeathFormspecLegacy(); } void Game::handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation *cam) @@ -4468,7 +4457,7 @@ void Game::readSettings() ****************************************************************************/ /****************************************************************************/ -void Game::showDeathFormspec() +void Game::showDeathFormspecLegacy() { static std::string formspec_str = std::string("formspec_version[1]") + diff --git a/src/network/clientopcodes.cpp b/src/network/clientopcodes.cpp index d426d3fe7..7d0840754 100644 --- a/src/network/clientopcodes.cpp +++ b/src/network/clientopcodes.cpp @@ -81,7 +81,7 @@ const ToClientCommandHandler toClientCommandTable[TOCLIENT_NUM_MSG_TYPES] = { "TOCLIENT_MOVE_PLAYER", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_MovePlayer }, // 0x34 { "TOCLIENT_ACCESS_DENIED_LEGACY", TOCLIENT_STATE_NOT_CONNECTED, &Client::handleCommand_AccessDenied }, // 0x35 { "TOCLIENT_FOV", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_Fov }, // 0x36 - { "TOCLIENT_DEATHSCREEN", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_DeathScreen }, // 0x37 + { "TOCLIENT_DEATHSCREEN_LEGACY", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_DeathScreenLegacy }, // 0x37 { "TOCLIENT_MEDIA", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_Media }, // 0x38 null_command_handler, { "TOCLIENT_NODEDEF", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_NodeDef }, // 0x3a @@ -198,7 +198,7 @@ const ServerCommandFactory serverCommandFactoryTable[TOSERVER_NUM_MSG_TYPES] = { "TOSERVER_DAMAGE", 0, true }, // 0x35 null_command_factory, // 0x36 { "TOSERVER_PLAYERITEM", 0, true }, // 0x37 - { "TOSERVER_RESPAWN", 0, true }, // 0x38 + { "TOSERVER_RESPAWN_LEGACY", 0, true }, // 0x38 { "TOSERVER_INTERACT", 0, true }, // 0x39 { "TOSERVER_REMOVED_SOUNDS", 2, true }, // 0x3a { "TOSERVER_NODEMETA_FIELDS", 0, true }, // 0x3b diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index 5b7c2f527..2716879f4 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -653,20 +653,10 @@ void Client::handleCommand_MovePlayerRel(NetworkPacket *pkt) player->addPosition(added_pos); } -void Client::handleCommand_DeathScreen(NetworkPacket* pkt) +void Client::handleCommand_DeathScreenLegacy(NetworkPacket* pkt) { - bool set_camera_point_target; - v3f camera_point_target; - - *pkt >> set_camera_point_target; - *pkt >> camera_point_target; - ClientEvent *event = new ClientEvent(); - event->type = CE_DEATHSCREEN; - event->deathscreen.set_camera_point_target = set_camera_point_target; - event->deathscreen.camera_point_target_x = camera_point_target.X; - event->deathscreen.camera_point_target_y = camera_point_target.Y; - event->deathscreen.camera_point_target_z = camera_point_target.Z; + event->type = CE_DEATHSCREEN_LEGACY; m_client_event_queue.push(event); } diff --git a/src/network/networkprotocol.h b/src/network/networkprotocol.h index 85931c71b..cae2a3291 100644 --- a/src/network/networkprotocol.h +++ b/src/network/networkprotocol.h @@ -231,6 +231,12 @@ with this program; if not, write to the Free Software Foundation, Inc., Move default hotbar from client-side C++ to server-side builtin Lua Add shadow tint to Lighting packets Add shadow color to CloudParam packets + Move death screen to server and make it a regular formspec + The server no longer triggers the hardcoded client-side death + formspec, but the client still supports it for compatibility with + old servers. + Rename TOCLIENT_DEATHSCREEN to TOCLIENT_DEATHSCREEN_LEGACY + Rename TOSERVER_RESPAWN to TOSERVER_RESPAWN_LEGACY [scheduled bump for 5.10.0] */ @@ -391,10 +397,10 @@ enum ToClientCommand : u16 f32 transition_time */ - TOCLIENT_DEATHSCREEN = 0x37, + TOCLIENT_DEATHSCREEN_LEGACY = 0x37, /* - u8 bool set camera point target - v3f1000 camera point target (to point the death cause or whatever) + u8 bool unused + v3f1000 unused */ TOCLIENT_MEDIA = 0x38, @@ -1002,10 +1008,7 @@ enum ToServerCommand : u16 [2] u16 item */ - TOSERVER_RESPAWN = 0x38, - /* - u16 TOSERVER_RESPAWN - */ + TOSERVER_RESPAWN_LEGACY = 0x38, TOSERVER_INTERACT = 0x39, /* diff --git a/src/network/serveropcodes.cpp b/src/network/serveropcodes.cpp index 1cb413492..4b87c3fbe 100644 --- a/src/network/serveropcodes.cpp +++ b/src/network/serveropcodes.cpp @@ -82,7 +82,7 @@ const ToServerCommandHandler toServerCommandTable[TOSERVER_NUM_MSG_TYPES] = { "TOSERVER_DAMAGE", TOSERVER_STATE_INGAME, &Server::handleCommand_Damage }, // 0x35 null_command_handler, // 0x36 { "TOSERVER_PLAYERITEM", TOSERVER_STATE_INGAME, &Server::handleCommand_PlayerItem }, // 0x37 - { "TOSERVER_RESPAWN", TOSERVER_STATE_INGAME, &Server::handleCommand_Respawn }, // 0x38 + null_command_handler, // 0x38 { "TOSERVER_INTERACT", TOSERVER_STATE_INGAME, &Server::handleCommand_Interact }, // 0x39 { "TOSERVER_REMOVED_SOUNDS", TOSERVER_STATE_INGAME, &Server::handleCommand_RemovedSounds }, // 0x3a { "TOSERVER_NODEMETA_FIELDS", TOSERVER_STATE_INGAME, &Server::handleCommand_NodeMetaFields }, // 0x3b @@ -181,7 +181,7 @@ const ClientCommandFactory clientCommandFactoryTable[TOCLIENT_NUM_MSG_TYPES] = { "TOCLIENT_MOVE_PLAYER", 0, true }, // 0x34 null_command_factory, // 0x35 { "TOCLIENT_FOV", 0, true }, // 0x36 - { "TOCLIENT_DEATHSCREEN", 0, true }, // 0x37 + null_command_factory, // 0x37 { "TOCLIENT_MEDIA", 2, true }, // 0x38 null_command_factory, // 0x39 { "TOCLIENT_NODEDEF", 0, true }, // 0x3A diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp index 7d8555c8e..c17d32e41 100644 --- a/src/network/serverpackethandler.cpp +++ b/src/network/serverpackethandler.cpp @@ -858,33 +858,6 @@ void Server::handleCommand_PlayerItem(NetworkPacket* pkt) playersao->getPlayer()->setWieldIndex(item); } -void Server::handleCommand_Respawn(NetworkPacket* pkt) -{ - session_t peer_id = pkt->getPeerId(); - RemotePlayer *player = m_env->getPlayer(peer_id); - if (player == NULL) { - errorstream << - "Server::ProcessData(): Canceling: No player for peer_id=" << - peer_id << " disconnecting peer!" << std::endl; - DisconnectPeer(peer_id); - return; - } - - PlayerSAO *playersao = player->getPlayerSAO(); - assert(playersao); - - if (!playersao->isDead()) - return; - - RespawnPlayer(peer_id); - - actionstream << player->getName() << " respawns at " - << (playersao->getBasePosition() / BS) << std::endl; - - // ActiveObject is added to environment in AsyncRunStep after - // the previous addition has been successfully removed -} - bool Server::checkInteractDistance(RemotePlayer *player, const f32 d, const std::string &what) { ItemStack selected_item, hand_item; diff --git a/src/script/cpp_api/s_client.cpp b/src/script/cpp_api/s_client.cpp index 6faa0695c..78d0ec44d 100644 --- a/src/script/cpp_api/s_client.cpp +++ b/src/script/cpp_api/s_client.cpp @@ -125,21 +125,6 @@ void ScriptApiClient::on_hp_modification(int32_t newhp) } } -void ScriptApiClient::on_death() -{ - SCRIPTAPI_PRECHECKHEADER - - // Get registered shutdown hooks - lua_getglobal(L, "core"); - lua_getfield(L, -1, "registered_on_death"); - // Call callbacks - try { - runCallbacks(0, RUN_CALLBACKS_MODE_FIRST); - } catch (LuaError &e) { - getClient()->setFatalError(e); - } -} - void ScriptApiClient::environment_step(float dtime) { SCRIPTAPI_PRECHECKHEADER diff --git a/src/script/cpp_api/s_client.h b/src/script/cpp_api/s_client.h index 8a5523d0d..74cc0d898 100644 --- a/src/script/cpp_api/s_client.h +++ b/src/script/cpp_api/s_client.h @@ -49,7 +49,6 @@ public: void on_damage_taken(int32_t damage_amount); void on_hp_modification(int32_t newhp); - void on_death(); void environment_step(float dtime); void on_formspec_input(const std::string &formname, const StringMap &fields); diff --git a/src/script/lua_api/l_client.cpp b/src/script/lua_api/l_client.cpp index da19ed0ea..3bd9fc04d 100644 --- a/src/script/lua_api/l_client.cpp +++ b/src/script/lua_api/l_client.cpp @@ -157,13 +157,6 @@ int ModApiClient::l_show_formspec(lua_State *L) return 1; } -// send_respawn() -int ModApiClient::l_send_respawn(lua_State *L) -{ - getClient(L)->sendRespawn(); - return 0; -} - // disconnect() int ModApiClient::l_disconnect(lua_State *L) { @@ -348,7 +341,6 @@ void ModApiClient::Initialize(lua_State *L, int top) API_FCT(clear_out_chat_queue); API_FCT(get_player_names); API_FCT(show_formspec); - API_FCT(send_respawn); API_FCT(gettext); API_FCT(get_node_or_nil); API_FCT(disconnect); diff --git a/src/script/lua_api/l_client.h b/src/script/lua_api/l_client.h index e960dc4cf..d726bc8a3 100644 --- a/src/script/lua_api/l_client.h +++ b/src/script/lua_api/l_client.h @@ -51,9 +51,6 @@ private: // show_formspec(name, formspec) static int l_show_formspec(lua_State *L); - // send_respawn() - static int l_send_respawn(lua_State *L); - // disconnect() static int l_disconnect(lua_State *L); diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index d6d608aab..ebd1bde71 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -2693,11 +2693,11 @@ int ObjectRef::l_respawn(lua_State *L) { NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkObject(L, 1); - RemotePlayer *player = getplayer(ref); - if (player == nullptr) + auto *psao = getplayersao(ref); + if (psao == nullptr) return 0; - getServer(L)->RespawnPlayer(player->getPeerId()); + psao->respawn(); lua_pushboolean(L, true); return 1; } diff --git a/src/server.cpp b/src/server.cpp index 4be3aa26a..fe3dc8516 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1159,10 +1159,6 @@ PlayerSAO* Server::StageTwoClientInit(session_t peer_id) // Send HP SendPlayerHP(playersao, false); - // Send death screen - if (playersao->isDead()) - SendDeathscreen(peer_id, false, v3f(0,0,0)); - // Send Breath SendPlayerBreath(playersao); @@ -1405,14 +1401,6 @@ void Server::SendAccessDenied(session_t peer_id, AccessDeniedCode reason, Send(&pkt); } -void Server::SendDeathscreen(session_t peer_id, bool set_camera_point_target, - v3f camera_point_target) -{ - NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id); - pkt << set_camera_point_target << camera_point_target; - Send(&pkt); -} - void Server::SendItemDef(session_t peer_id, IItemDefManager *itemdef, u16 protocol_version) { @@ -2803,32 +2791,8 @@ void Server::HandlePlayerDeath(PlayerSAO *playersao, const PlayerHPChangeReason // Trigger scripted stuff m_script->on_dieplayer(playersao, reason); - - SendDeathscreen(playersao->getPeerID(), false, v3f(0,0,0)); } -void Server::RespawnPlayer(session_t peer_id) -{ - PlayerSAO *playersao = getPlayerSAO(peer_id); - assert(playersao); - - infostream << "Server::RespawnPlayer(): Player " - << playersao->getPlayer()->getName() - << " respawns" << std::endl; - - const auto *prop = playersao->accessObjectProperties(); - playersao->setHP(prop->hp_max, - PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN)); - playersao->setBreath(prop->breath_max); - - bool repositioned = m_script->on_respawnplayer(playersao); - if (!repositioned) { - // setPos will send the new position to client - playersao->setPos(findSpawnPos()); - } -} - - void Server::DenySudoAccess(session_t peer_id) { NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id); diff --git a/src/server.h b/src/server.h index 58805c667..5f6086cde 100644 --- a/src/server.h +++ b/src/server.h @@ -193,7 +193,6 @@ public: void handleCommand_ChatMessage(NetworkPacket* pkt); void handleCommand_Damage(NetworkPacket* pkt); void handleCommand_PlayerItem(NetworkPacket* pkt); - void handleCommand_Respawn(NetworkPacket* pkt); void handleCommand_Interact(NetworkPacket* pkt); void handleCommand_RemovedSounds(NetworkPacket* pkt); void handleCommand_NodeMetaFields(NetworkPacket* pkt); @@ -356,8 +355,6 @@ public: void setLighting(RemotePlayer *player, const Lighting &lighting); - void RespawnPlayer(session_t peer_id); - /* con::PeerHandler implementation. */ void peerAdded(con::IPeer *peer); void deletingPeer(con::IPeer *peer, bool timeout); @@ -486,8 +483,6 @@ private: void SendBreath(session_t peer_id, u16 breath); void SendAccessDenied(session_t peer_id, AccessDeniedCode reason, std::string_view custom_reason, bool reconnect = false); - void SendDeathscreen(session_t peer_id, bool set_camera_point_target, - v3f camera_point_target); void SendItemDef(session_t peer_id, IItemDefManager *itemdef, u16 protocol_version); void SendNodeDef(session_t peer_id, const NodeDefManager *nodedef, u16 protocol_version); diff --git a/src/server/clientiface.h b/src/server/clientiface.h index f930e7f3e..3f5ba6434 100644 --- a/src/server/clientiface.h +++ b/src/server/clientiface.h @@ -126,7 +126,7 @@ class EmergeManager; | TOCLIENT_INVENTORY | | | | | TOCLIENT_HP (opt) | \-----------------/ | | TOCLIENT_BREATH | | -| TOCLIENT_DEATHSCREEN | | +| TOCLIENT_DEATHSCREEN_LEGACY | | +-----------------------------+ | | | v | diff --git a/src/server/player_sao.cpp b/src/server/player_sao.cpp index 11922b2c6..30c41bb1e 100644 --- a/src/server/player_sao.cpp +++ b/src/server/player_sao.cpp @@ -558,6 +558,21 @@ void PlayerSAO::setBreath(const u16 breath, bool send) m_env->getGameDef()->SendPlayerBreath(this); } +void PlayerSAO::respawn() +{ + infostream << "PlayerSAO::respawn(): Player " << m_player->getName() + << " respawns" << std::endl; + + setHP(m_prop.hp_max, PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN)); + setBreath(m_prop.breath_max); + + bool repositioned = m_env->getScriptIface()->on_respawnplayer(this); + if (!repositioned) { + // setPos will send the new position to client + setPos(m_env->getGameDef()->findSpawnPos()); + } +} + Inventory *PlayerSAO::getInventory() const { return m_player ? &m_player->inventory : nullptr; diff --git a/src/server/player_sao.h b/src/server/player_sao.h index 95bd1d109..487e37957 100644 --- a/src/server/player_sao.h +++ b/src/server/player_sao.h @@ -124,6 +124,7 @@ public: void setHPRaw(u16 hp) { m_hp = hp; } u16 getBreath() const { return m_breath; } void setBreath(const u16 breath, bool send = true); + void respawn(); /* Inventory interface From 588a0f83e9dffd86b612445a1494e205b5d78a2e Mon Sep 17 00:00:00 2001 From: sfan5 Date: Wed, 11 Sep 2024 19:17:08 +0200 Subject: [PATCH 59/67] Divorce map database locking from env lock (#15151) --- src/emerge.cpp | 68 ++++++++++++++++--- src/emerge.h | 8 +++ src/emerge_internal.h | 22 ++++-- src/main.cpp | 3 +- src/servermap.cpp | 152 ++++++++++++++++++++++++------------------ src/servermap.h | 34 ++++++++-- 6 files changed, 197 insertions(+), 90 deletions(-) diff --git a/src/emerge.cpp b/src/emerge.cpp index 425e294b8..f66b78909 100644 --- a/src/emerge.cpp +++ b/src/emerge.cpp @@ -31,6 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "filesys.h" #include "log.h" #include "servermap.h" +#include "database/database.h" #include "mapblock.h" #include "mapgen/mg_biome.h" #include "mapgen/mg_ore.h" @@ -185,10 +186,22 @@ SchematicManager *EmergeManager::getWritableSchematicManager() return schemmgr; } +void EmergeManager::initMap(MapDatabaseAccessor *holder) +{ + FATAL_ERROR_IF(m_db, "Map database already initialized."); + assert(holder->dbase); + m_db = holder; +} + +void EmergeManager::resetMap() +{ + FATAL_ERROR_IF(m_threads_active, "Threads are still active."); + m_db = nullptr; +} void EmergeManager::initMapgens(MapgenParams *params) { - FATAL_ERROR_IF(!m_mapgens.empty(), "Mapgen already initialised."); + FATAL_ERROR_IF(!m_mapgens.empty(), "Mapgen already initialized."); mgparams = params; @@ -466,7 +479,7 @@ void EmergeThread::signal() } -bool EmergeThread::pushBlock(const v3s16 &pos) +bool EmergeThread::pushBlock(v3s16 pos) { m_block_queue.push(pos); return true; @@ -491,7 +504,7 @@ void EmergeThread::cancelPendingItems() } -void EmergeThread::runCompletionCallbacks(const v3s16 &pos, EmergeAction action, +void EmergeThread::runCompletionCallbacks(v3s16 pos, EmergeAction action, const EmergeCallbackList &callbacks) { m_emerge->reportCompletedEmerge(action); @@ -524,21 +537,36 @@ bool EmergeThread::popBlockEmerge(v3s16 *pos, BlockEmergeData *bedata) } -EmergeAction EmergeThread::getBlockOrStartGen( - const v3s16 &pos, bool allow_gen, MapBlock **block, BlockMakeData *bmdata) +EmergeAction EmergeThread::getBlockOrStartGen(const v3s16 pos, bool allow_gen, + const std::string *from_db, MapBlock **block, BlockMakeData *bmdata) { MutexAutoLock envlock(m_server->m_env_mutex); + auto block_ok = [] (MapBlock *b) { + return b && b->isGenerated(); + }; + // 1). Attempt to fetch block from memory *block = m_map->getBlockNoCreateNoEx(pos); if (*block) { - if ((*block)->isGenerated()) + if (block_ok(*block)) { + // if we just read it from the db but the block exists that means + // someone else was faster. don't touch it to prevent data loss. + if (from_db) + verbosestream << "getBlockOrStartGen: block loading raced" << std::endl; return EMERGE_FROM_MEMORY; + } } else { - // 2). Attempt to load block from disk if it was not in the memory - *block = m_map->loadBlock(pos); - if (*block && (*block)->isGenerated()) + if (!from_db) { + // 2). We should attempt loading it return EMERGE_FROM_DISK; + } + // 2). Second invocation, we have the data + if (!from_db->empty()) { + *block = m_map->loadBlock(*from_db, pos); + if (block_ok(*block)) + return EMERGE_FROM_DISK; + } } // 3). Attempt to start generation @@ -643,7 +671,8 @@ void *EmergeThread::run() BEGIN_DEBUG_EXCEPTION_HANDLER v3s16 pos; - std::map modified_blocks; + std::map modified_blocks; + std::string databuf; m_map = &m_server->m_env->getServerMap(); m_emerge = m_server->getEmergeManager(); @@ -669,13 +698,30 @@ void *EmergeThread::run() continue; } + g_profiler->add(m_name + ": processed [#]", 1); + if (blockpos_over_max_limit(pos)) continue; bool allow_gen = bedata.flags & BLOCK_EMERGE_ALLOW_GEN; EMERGE_DBG_OUT("pos=" << pos << " allow_gen=" << allow_gen); - action = getBlockOrStartGen(pos, allow_gen, &block, &bmdata); + action = getBlockOrStartGen(pos, allow_gen, nullptr, &block, &bmdata); + + /* Try to load it */ + if (action == EMERGE_FROM_DISK) { + auto &m_db = *m_emerge->m_db; + { + ScopeProfiler sp(g_profiler, "EmergeThread: load block - async (sum)"); + MutexAutoLock dblock(m_db.mutex); + m_db.loadBlock(pos, databuf); + } + // actually load it, then decide again + action = getBlockOrStartGen(pos, allow_gen, &databuf, &block, &bmdata); + databuf.clear(); + } + + /* Generate it */ if (action == EMERGE_GENERATED) { bool error = false; m_trans_liquid = &bmdata.transforming_liquid; diff --git a/src/emerge.h b/src/emerge.h index d7f018feb..4e0f738d8 100644 --- a/src/emerge.h +++ b/src/emerge.h @@ -46,6 +46,7 @@ class DecorationManager; class SchematicManager; class Server; class ModApiMapgen; +struct MapDatabaseAccessor; // Structure containing inputs/outputs for chunk generation struct BlockMakeData { @@ -173,6 +174,10 @@ public: SchematicManager *getWritableSchematicManager(); void initMapgens(MapgenParams *mgparams); + /// @param holder non-owned reference that must stay alive + void initMap(MapDatabaseAccessor *holder); + /// resets the reference + void resetMap(); void startThreads(); void stopThreads(); @@ -206,6 +211,9 @@ private: std::vector m_threads; bool m_threads_active = false; + // The map database + MapDatabaseAccessor *m_db = nullptr; + std::mutex m_queue_mutex; std::map m_blocks_enqueued; std::unordered_map m_peer_queue_count; diff --git a/src/emerge_internal.h b/src/emerge_internal.h index 439c8227b..08e36778d 100644 --- a/src/emerge_internal.h +++ b/src/emerge_internal.h @@ -40,7 +40,7 @@ class EmergeScripting; class EmergeThread : public Thread { public: bool enable_mapgen_debug_info; - int id; + const int id; // Index of this thread EmergeThread(Server *server, int ethreadid); ~EmergeThread() = default; @@ -49,7 +49,7 @@ public: void signal(); // Requires queue mutex held - bool pushBlock(const v3s16 &pos); + bool pushBlock(v3s16 pos); void cancelPendingItems(); @@ -59,7 +59,7 @@ public: protected: void runCompletionCallbacks( - const v3s16 &pos, EmergeAction action, + v3s16 pos, EmergeAction action, const EmergeCallbackList &callbacks); private: @@ -79,8 +79,20 @@ private: bool popBlockEmerge(v3s16 *pos, BlockEmergeData *bedata); - EmergeAction getBlockOrStartGen( - const v3s16 &pos, bool allow_gen, MapBlock **block, BlockMakeData *data); + /** + * Try to get a block from memory and decide what to do. + * + * @param pos block position + * @param from_db serialized block data, optional + * (for second call after EMERGE_FROM_DISK was returned) + * @param allow_gen allow invoking mapgen? + * @param block output pointer for block + * @param data info for mapgen + * @return what to do for this block + */ + EmergeAction getBlockOrStartGen(v3s16 pos, bool allow_gen, + const std::string *from_db, MapBlock **block, BlockMakeData *data); + MapBlock *finishGen(v3s16 pos, BlockMakeData *bmdata, std::map *modified_blocks); diff --git a/src/main.cpp b/src/main.cpp index 30db81aa9..9f737b86d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1278,8 +1278,7 @@ static bool recompress_map_database(const GameParams &game_params, const Setting { MapBlock mb(v3s16(0,0,0), &server); - u8 ver = readU8(iss); - mb.deSerialize(iss, ver, true); + ServerMap::deSerializeBlock(&mb, iss); oss.str(""); oss.clear(); diff --git a/src/servermap.cpp b/src/servermap.cpp index 0248497c1..f57e5b5e4 100644 --- a/src/servermap.cpp +++ b/src/servermap.cpp @@ -51,6 +51,18 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "database/database-postgresql.h" #endif +/* + Helpers +*/ + +void MapDatabaseAccessor::loadBlock(v3s16 blockpos, std::string &ret) +{ + ret.clear(); + dbase->loadBlock(blockpos, &ret); + if (ret.empty() && dbase_ro) + dbase_ro->loadBlock(blockpos, &ret); +} + /* ServerMap */ @@ -67,7 +79,7 @@ ServerMap::ServerMap(const std::string &savedir, IGameDef *gamedef, emerge->map_settings_mgr = &settings_mgr; /* - Try to load map; if not found, create a new one. + Try to open map; if not found, create a new one. */ // Determine which database backend to use @@ -79,10 +91,10 @@ ServerMap::ServerMap(const std::string &savedir, IGameDef *gamedef, conf.set("backend", "sqlite3"); } std::string backend = conf.get("backend"); - dbase = createDatabase(backend, savedir, conf); + m_db.dbase = createDatabase(backend, savedir, conf); if (conf.exists("readonly_backend")) { std::string readonly_dir = savedir + DIR_DELIM + "readonly"; - dbase_ro = createDatabase(conf.get("readonly_backend"), readonly_dir, conf); + m_db.dbase_ro = createDatabase(conf.get("readonly_backend"), readonly_dir, conf); } if (!conf.updateConfigFile(conf_path.c_str())) errorstream << "ServerMap::ServerMap(): Failed to update world.mt!" << std::endl; @@ -90,6 +102,9 @@ ServerMap::ServerMap(const std::string &savedir, IGameDef *gamedef, m_savedir = savedir; m_map_saving_enabled = false; + // Inform EmergeManager of db handles + m_emerge->initMap(&m_db); + m_save_time_counter = mb->addCounter( "minetest_map_save_time", "Time spent saving blocks (in microseconds)"); m_save_count_counter = mb->addCounter( @@ -159,11 +174,15 @@ ServerMap::~ServerMap() << ", exception: " << e.what() << std::endl; } - /* - Close database if it was opened - */ - delete dbase; - delete dbase_ro; + m_emerge->resetMap(); + + { + MutexAutoLock dblock(m_db.mutex); + delete m_db.dbase; + m_db.dbase = nullptr; + delete m_db.dbase_ro; + m_db.dbase_ro = nullptr; + } deleteDetachedBlocks(); } @@ -547,9 +566,10 @@ void ServerMap::save(ModifiedState save_level) void ServerMap::listAllLoadableBlocks(std::vector &dst) { - dbase->listAllLoadableBlocks(dst); - if (dbase_ro) - dbase_ro->listAllLoadableBlocks(dst); + MutexAutoLock dblock(m_db.mutex); + m_db.dbase->listAllLoadableBlocks(dst); + if (m_db.dbase_ro) + m_db.dbase_ro->listAllLoadableBlocks(dst); } void ServerMap::listAllLoadedBlocks(std::vector &dst) @@ -597,17 +617,21 @@ MapDatabase *ServerMap::createDatabase( void ServerMap::beginSave() { - dbase->beginSave(); + MutexAutoLock dblock(m_db.mutex); + m_db.dbase->beginSave(); } void ServerMap::endSave() { - dbase->endSave(); + MutexAutoLock dblock(m_db.mutex); + m_db.dbase->endSave(); } bool ServerMap::saveBlock(MapBlock *block) { - return saveBlock(block, dbase, m_map_compression_level); + // FIXME: serialization happens under mutex + MutexAutoLock dblock(m_db.mutex); + return saveBlock(block, m_db.dbase, m_map_compression_level); } bool ServerMap::saveBlock(MapBlock *block, MapDatabase *db, int compression_level) @@ -634,18 +658,27 @@ bool ServerMap::saveBlock(MapBlock *block, MapDatabase *db, int compression_leve return ret; } -void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load) +void ServerMap::deSerializeBlock(MapBlock *block, std::istream &is) { + ScopeProfiler sp(g_profiler, "ServerMap: deSer block", SPT_AVG, PRECISION_MICRO); + + u8 version = readU8(is); + if (is.fail()) + throw SerializationError("Failed to read MapBlock version"); + + block->deSerialize(is, version, true); +} + +MapBlock *ServerMap::loadBlock(const std::string &blob, v3s16 p3d, bool save_after_load) +{ + ScopeProfiler sp(g_profiler, "ServerMap: load block", SPT_AVG, PRECISION_MICRO); + MapBlock *block = nullptr; + bool created_new = false; + try { - std::istringstream is(*blob, std::ios_base::binary); + v2s16 p2d(p3d.X, p3d.Z); + MapSector *sector = createSector(p2d); - u8 version = readU8(is); - - if(is.fail()) - throw SerializationError("ServerMap::loadBlock(): Failed" - " to read MapBlock version"); - - MapBlock *block = nullptr; std::unique_ptr block_created_new; block = sector->getBlockNoCreateNoEx(p3d.Y); if (!block) { @@ -654,31 +687,16 @@ void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool } { - ScopeProfiler sp(g_profiler, "ServerMap: deSer block", SPT_AVG, PRECISION_MICRO); - block->deSerialize(is, version, true); + std::istringstream iss(blob, std::ios_base::binary); + deSerializeBlock(block, iss); } // If it's a new block, insert it to the map if (block_created_new) { sector->insertBlock(std::move(block_created_new)); - ReflowScan scanner(this, m_emerge->ndef); - scanner.scan(block, &m_transforming_liquid); + created_new = true; } - - /* - Save blocks loaded in old format in new format - */ - - //if(version < SER_FMT_VER_HIGHEST_READ || save_after_load) - // Only save if asked to; no need to update version - if(save_after_load) - saveBlock(block); - - // We just loaded it from, so it's up-to-date. - block->resetModified(); - } - catch(SerializationError &e) - { + } catch (SerializationError &e) { errorstream<<"Invalid block data in database" <<" ("<ndef); + scanner.scan(block, &m_transforming_liquid); - std::string ret; - dbase->loadBlock(blockpos, &ret); - if (!ret.empty()) { - loadBlock(&ret, blockpos, createSector(p2d), false); - } else if (dbase_ro) { - dbase_ro->loadBlock(blockpos, &ret); - if (!ret.empty()) { - loadBlock(&ret, blockpos, createSector(p2d), false); - } - } else { - return NULL; - } - - MapBlock *block = getBlockNoCreateNoEx(blockpos); - if (created_new && (block != NULL)) { std::map modified_blocks; // Fix lighting if necessary voxalgo::update_block_border_lighting(this, block, modified_blocks); if (!modified_blocks.empty()) { - //Modified lighting, send event MapEditEvent event; event.type = MEET_OTHER; event.setModifiedBlocks(modified_blocks); dispatchEvent(event); } } + + if (save_after_load) + saveBlock(block); + + // We just loaded it, so it's up-to-date. + block->resetModified(); + return block; } +MapBlock* ServerMap::loadBlock(v3s16 blockpos) +{ + std::string data; + { + ScopeProfiler sp(g_profiler, "ServerMap: load block - sync (sum)"); + MutexAutoLock dblock(m_db.mutex); + m_db.loadBlock(blockpos, data); + } + + if (!data.empty()) + return loadBlock(data, blockpos); + return getBlockNoCreateNoEx(blockpos); +} + bool ServerMap::deleteBlock(v3s16 blockpos) { - if (!dbase->deleteBlock(blockpos)) + MutexAutoLock dblock(m_db.mutex); + if (!m_db.dbase->deleteBlock(blockpos)) return false; MapBlock *block = getBlockNoCreateNoEx(blockpos); diff --git a/src/servermap.h b/src/servermap.h index 7a8a84b9b..3a2102668 100644 --- a/src/servermap.h +++ b/src/servermap.h @@ -33,9 +33,22 @@ class IRollbackManager; class EmergeManager; class ServerEnvironment; struct BlockMakeData; - class MetricsBackend; +// TODO: this could wrap all calls to MapDatabase, including locking +struct MapDatabaseAccessor { + /// Lock, to be taken for any operation + std::mutex mutex; + /// Main database + MapDatabase *dbase = nullptr; + /// Fallback database for read operations + MapDatabase *dbase_ro = nullptr; + + /// Load a block, taking dbase_ro into account. + /// @note call locked + void loadBlock(v3s16 blockpos, std::string &ret); +}; + /* ServerMap @@ -75,7 +88,7 @@ public: MapBlock *createBlock(v3s16 p); /* - Forcefully get a block from somewhere. + Forcefully get a block from somewhere (blocking!). - Memory - Load from disk - Create blank filled with CONTENT_IGNORE @@ -114,9 +127,16 @@ public: bool saveBlock(MapBlock *block) override; static bool saveBlock(MapBlock *block, MapDatabase *db, int compression_level = -1); - MapBlock* loadBlock(v3s16 p); - // Database version - void loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load=false); + + // Load block in a synchronous fashion + MapBlock *loadBlock(v3s16 p); + /// Load a block that was already read from disk. Used by EmergeManager. + /// @return non-null block (but can be blank) + MapBlock *loadBlock(const std::string &blob, v3s16 p, bool save_after_load=false); + + // Helper for deserializing blocks from disk + // @throws SerializationError + static void deSerializeBlock(MapBlock *block, std::istream &is); // Blocks are removed from the map but not deleted from memory until // deleteDetachedBlocks() is called, since pointers to them may still exist @@ -185,8 +205,8 @@ private: This is reset to false when written on disk. */ bool m_map_metadata_changed = true; - MapDatabase *dbase = nullptr; - MapDatabase *dbase_ro = nullptr; + + MapDatabaseAccessor m_db; // Map metrics MetricGaugePtr m_loaded_blocks_gauge; From 0220d0d4928f7473ea4bbe6b7537cd45ae877ee5 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sun, 15 Sep 2024 21:25:03 +0200 Subject: [PATCH 60/67] Encapsulate envlock --- src/emerge.cpp | 6 +++--- src/script/lua_api/l_env.cpp | 2 +- src/server.cpp | 31 +++++++++++++++---------------- src/server.h | 14 ++++++++++++-- 4 files changed, 31 insertions(+), 22 deletions(-) diff --git a/src/emerge.cpp b/src/emerge.cpp index f66b78909..2d0f67505 100644 --- a/src/emerge.cpp +++ b/src/emerge.cpp @@ -540,7 +540,7 @@ bool EmergeThread::popBlockEmerge(v3s16 *pos, BlockEmergeData *bedata) EmergeAction EmergeThread::getBlockOrStartGen(const v3s16 pos, bool allow_gen, const std::string *from_db, MapBlock **block, BlockMakeData *bmdata) { - MutexAutoLock envlock(m_server->m_env_mutex); + Server::EnvAutoLock envlock(m_server); auto block_ok = [] (MapBlock *b) { return b && b->isGenerated(); @@ -581,7 +581,7 @@ EmergeAction EmergeThread::getBlockOrStartGen(const v3s16 pos, bool allow_gen, MapBlock *EmergeThread::finishGen(v3s16 pos, BlockMakeData *bmdata, std::map *modified_blocks) { - MutexAutoLock envlock(m_server->m_env_mutex); + Server::EnvAutoLock envlock(m_server); ScopeProfiler sp(g_profiler, "EmergeThread: after Mapgen::makeChunk", SPT_AVG); @@ -762,7 +762,7 @@ void *EmergeThread::run() MapEditEvent event; event.type = MEET_OTHER; event.setModifiedBlocks(modified_blocks); - MutexAutoLock envlock(m_server->m_env_mutex); + Server::EnvAutoLock envlock(m_server); m_map->dispatchEvent(event); } modified_blocks.clear(); diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp index 125a352bc..726300b07 100644 --- a/src/script/lua_api/l_env.cpp +++ b/src/script/lua_api/l_env.cpp @@ -160,7 +160,7 @@ void LuaEmergeAreaCallback(v3s16 blockpos, EmergeAction action, void *param) // state must be protected by envlock Server *server = state->script->getServer(); - MutexAutoLock envlock(server->m_env_mutex); + Server::EnvAutoLock envlock(server); state->refcount--; diff --git a/src/server.cpp b/src/server.cpp index fe3dc8516..8a45d7369 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -353,7 +353,7 @@ Server::~Server() m_emerge->stopThreads(); if (m_env) { - MutexAutoLock envlock(m_env_mutex); + EnvAutoLock envlock(this); infostream << "Server: Executing shutdown hooks" << std::endl; try { @@ -461,7 +461,7 @@ void Server::init() } //lock environment - MutexAutoLock envlock(m_env_mutex); + EnvAutoLock envlock(this); // Create the Map (loads map_meta.txt, overriding configured mapgen params) auto startup_server_map = std::make_unique(m_path_world, this, @@ -653,7 +653,7 @@ void Server::AsyncRunStep(float dtime, bool initial_step) } { - MutexAutoLock lock(m_env_mutex); + EnvAutoLock lock(this); float max_lag = m_env->getMaxLagEstimate(); constexpr float lag_warn_threshold = 2.0f; @@ -686,7 +686,7 @@ void Server::AsyncRunStep(float dtime, bool initial_step) static const float map_timer_and_unload_dtime = 2.92; if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime)) { - MutexAutoLock lock(m_env_mutex); + EnvAutoLock lock(this); // Run Map's timers and unload unused data ScopeProfiler sp(g_profiler, "Server: map timer and unload"); m_env->getMap().timerUpdate(map_timer_and_unload_dtime, @@ -704,7 +704,7 @@ void Server::AsyncRunStep(float dtime, bool initial_step) */ if (m_admin_chat) { if (!m_admin_chat->command_queue.empty()) { - MutexAutoLock lock(m_env_mutex); + EnvAutoLock lock(this); while (!m_admin_chat->command_queue.empty()) { ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx(); handleChatInterfaceEvent(evt); @@ -725,7 +725,7 @@ void Server::AsyncRunStep(float dtime, bool initial_step) { m_liquid_transform_timer -= m_liquid_transform_every; - MutexAutoLock lock(m_env_mutex); + EnvAutoLock lock(this); ScopeProfiler sp(g_profiler, "Server: liquid transform"); @@ -786,7 +786,7 @@ void Server::AsyncRunStep(float dtime, bool initial_step) */ { //infostream<<"Server: Checking added and deleted active objects"<getFloat("server_map_save_interval"); if (counter >= save_interval) { counter = 0.0; - MutexAutoLock lock(m_env_mutex); + EnvAutoLock lock(this); ScopeProfiler sp(g_profiler, "Server: map saving (sum)"); @@ -1191,7 +1191,7 @@ inline void Server::handleCommand(NetworkPacket *pkt) void Server::ProcessData(NetworkPacket *pkt) { // Environment is locked first. - MutexAutoLock envlock(m_env_mutex); + EnvAutoLock envlock(this); ScopeProfiler sp(g_profiler, "Server: Process network packet (sum)"); u32 peer_id = pkt->getPeerId(); @@ -2363,8 +2363,7 @@ void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver, void Server::SendBlocks(float dtime) { - MutexAutoLock envlock(m_env_mutex); - //TODO check if one big lock could be faster then multiple small ones + EnvAutoLock envlock(this); std::vector queue; @@ -2695,7 +2694,7 @@ void Server::sendRequestedMedia(session_t peer_id, void Server::stepPendingDynMediaCallbacks(float dtime) { - MutexAutoLock lock(m_env_mutex); + EnvAutoLock lock(this); for (auto it = m_pending_dyn_media.begin(); it != m_pending_dyn_media.end();) { it->second.expiry_timer -= dtime; @@ -2914,7 +2913,7 @@ void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason) } } { - MutexAutoLock env_lock(m_env_mutex); + EnvAutoLock envlock(this); m_clients.DeleteClient(peer_id); } } @@ -4107,7 +4106,7 @@ Translations *Server::getTranslationLanguage(const std::string &lang_code) std::unordered_map Server::getMediaList() { - MutexAutoLock env_lock(m_env_mutex); + EnvAutoLock envlock(this); std::unordered_map ret; for (auto &it : m_media) { diff --git a/src/server.h b/src/server.h index 5f6086cde..51d52d443 100644 --- a/src/server.h +++ b/src/server.h @@ -424,8 +424,14 @@ public: // Bind address Address m_bind_addr; - // Environment mutex (envlock) - std::mutex m_env_mutex; + // Public helper for taking the envlock in a scope + class EnvAutoLock { + public: + EnvAutoLock(Server *server): m_lock(server->m_env_mutex) {} + + private: + MutexAutoLock m_lock; + }; protected: /* Do not add more members here, this is only required to make unit tests work. */ @@ -600,6 +606,10 @@ private: /* Variables */ + + // Environment mutex (envlock) + std::mutex m_env_mutex; + // World directory std::string m_path_world; std::string m_path_mod_data; From 5f308deb50133e4d42ec2920cd98c1d3797fa58f Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sun, 15 Sep 2024 22:16:05 +0200 Subject: [PATCH 61/67] Switch env lock to fair mutex implementation --- src/server.h | 5 ++-- src/threading/ordered_mutex.h | 46 +++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 src/threading/ordered_mutex.h diff --git a/src/server.h b/src/server.h index 51d52d443..6b48d929d 100644 --- a/src/server.h +++ b/src/server.h @@ -35,6 +35,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "util/metricsbackend.h" #include "serverenvironment.h" #include "server/clientiface.h" +#include "threading/ordered_mutex.h" #include "chatmessage.h" #include "sound.h" #include "translation.h" @@ -430,7 +431,7 @@ public: EnvAutoLock(Server *server): m_lock(server->m_env_mutex) {} private: - MutexAutoLock m_lock; + std::lock_guard m_lock; }; protected: @@ -608,7 +609,7 @@ private: */ // Environment mutex (envlock) - std::mutex m_env_mutex; + ordered_mutex m_env_mutex; // World directory std::string m_path_world; diff --git a/src/threading/ordered_mutex.h b/src/threading/ordered_mutex.h new file mode 100644 index 000000000..f7fb4d309 --- /dev/null +++ b/src/threading/ordered_mutex.h @@ -0,0 +1,46 @@ +// Minetest +// SPDX-License-Identifier: LGPL-2.1-or-later + +#pragma once + +#include +#include + +/* + Fair mutex based on ticketing approach. + Satisfies `Mutex` C++11 requirements. +*/ +class ordered_mutex { +public: + ordered_mutex() : next_ticket(0), counter(0) {} + + void lock() + { + std::unique_lock autolock(cv_lock); + const auto ticket = next_ticket++; + cv.wait(autolock, [&] { return counter == ticket; }); + } + + bool try_lock() + { + std::lock_guard autolock(cv_lock); + if (counter != next_ticket) + return false; + next_ticket++; + return true; + } + + void unlock() + { + { + std::lock_guard autolock(cv_lock); + counter++; + } + cv.notify_all(); // intentionally outside lock + } + +private: + std::condition_variable cv; + std::mutex cv_lock; + uint_fast32_t next_ticket, counter; +}; From c1ea49940b678c1158167ff3dccee85a9e0df769 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sun, 15 Sep 2024 23:06:03 +0200 Subject: [PATCH 62/67] Add questionable workaround for env lock contention --- src/emerge.cpp | 8 +++++++ src/emerge.h | 1 + src/server.cpp | 54 ++++++++++++++++++++++++++++++++++++++++-- src/server.h | 5 ++-- src/util/timetaker.cpp | 2 +- 5 files changed, 65 insertions(+), 5 deletions(-) diff --git a/src/emerge.cpp b/src/emerge.cpp index 2d0f67505..788e2b745 100644 --- a/src/emerge.cpp +++ b/src/emerge.cpp @@ -316,6 +316,12 @@ bool EmergeManager::enqueueBlockEmergeEx( } +size_t EmergeManager::getQueueSize() +{ + MutexAutoLock queuelock(m_queue_mutex); + return m_blocks_enqueued.size(); +} + bool EmergeManager::isBlockInQueue(v3s16 pos) { MutexAutoLock queuelock(m_queue_mutex); @@ -540,7 +546,9 @@ bool EmergeThread::popBlockEmerge(v3s16 *pos, BlockEmergeData *bedata) EmergeAction EmergeThread::getBlockOrStartGen(const v3s16 pos, bool allow_gen, const std::string *from_db, MapBlock **block, BlockMakeData *bmdata) { + //TimeTaker tt("", nullptr, PRECISION_MICRO); Server::EnvAutoLock envlock(m_server); + //g_profiler->avg("EmergeThread: lock wait time [us]", tt.stop()); auto block_ok = [] (MapBlock *b) { return b && b->isGenerated(); diff --git a/src/emerge.h b/src/emerge.h index 4e0f738d8..cbdcc4c7c 100644 --- a/src/emerge.h +++ b/src/emerge.h @@ -196,6 +196,7 @@ public: EmergeCompletionCallback callback, void *callback_param); + size_t getQueueSize(); bool isBlockInQueue(v3s16 pos); Mapgen *getCurrentMapgen(); diff --git a/src/server.cpp b/src/server.cpp index 8a45d7369..ddafa6312 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -133,9 +133,13 @@ void *ServerThread::run() u64 t0 = porting::getTimeUs(); - const Server::StepSettings step_settings = m_server->getStepSettings(); + const auto step_settings = m_server->getStepSettings(); try { + // see explanation inside + if (dtime > step_settings.steplen) + m_server->yieldToOtherThreads(dtime); + m_server->AsyncRunStep(step_settings.pause ? 0.0f : dtime); const float remaining_time = step_settings.steplen @@ -655,7 +659,7 @@ void Server::AsyncRunStep(float dtime, bool initial_step) { EnvAutoLock lock(this); float max_lag = m_env->getMaxLagEstimate(); - constexpr float lag_warn_threshold = 2.0f; + constexpr float lag_warn_threshold = 1.0f; // Decrease value gradually, halve it every minute. if (m_max_lag_decrease.step(dtime, 0.5f)) { @@ -1113,6 +1117,52 @@ void Server::Receive(float timeout) } } +void Server::yieldToOtherThreads(float dtime) +{ + /* + * Problem: the server thread and emerge thread compete for the envlock. + * While the emerge thread needs it just once or twice for every processed item + * the server thread uses it much more generously. + * This is usually not a problem as the server sleeps between steps, which leaves + * enough chance. But if the server is overloaded it's busy all the time and + * - even with a fair envlock - the emerge thread can't get up to speed. + * This generally has a much worse impact on gameplay than server lag itself + * ever would. + * + * Workaround: If we detect that the server is overloaded, introduce some careful + * artificial sleeps to leave the emerge threads enough chance to do their job. + * + * In the future the emerge code should be reworked to exclusively use a result + * queue, thereby avoiding this problem (and terrible workaround). + */ + + // don't activate workaround too quickly + constexpr size_t MIN_EMERGE_QUEUE_SIZE = 32; + const size_t qs_initial = m_emerge->getQueueSize(); + if (qs_initial < MIN_EMERGE_QUEUE_SIZE) + return; + + // give the thread a chance to run for every 28ms (on average) + // this was experimentally determined + const float QUANTUM = 28.0f / 1000; + // put an upper limit to not cause too much lag, also so this doesn't become self-sustaining + const int SLEEP_MAX = 10; + + int sleep_count = std::clamp(dtime / QUANTUM, 1, SLEEP_MAX); + + ScopeProfiler sp(g_profiler, "Server::yieldTo...() sleep", SPT_AVG); + size_t qs = qs_initial; + while (sleep_count-- > 0) { + sleep_ms(1); + // abort if we don't make progress + size_t qs2 = m_emerge->getQueueSize(); + if (qs2 >= qs || qs2 == 0) + break; + qs = qs2; + } + g_profiler->avg("Server::yieldTo...() progress [#]", qs_initial - qs); +} + PlayerSAO* Server::StageTwoClientInit(session_t peer_id) { std::string playername; diff --git a/src/server.h b/src/server.h index 6b48d929d..57b543c11 100644 --- a/src/server.h +++ b/src/server.h @@ -167,9 +167,12 @@ public: // Actual processing is done in another thread. // This just checks if there was an error in that thread. void step(); + // This is run by ServerThread and does the actual processing void AsyncRunStep(float dtime, bool initial_step = false); void Receive(float timeout); + void yieldToOtherThreads(float dtime); + PlayerSAO* StageTwoClientInit(session_t peer_id); /* @@ -602,8 +605,6 @@ private: */ PlayerSAO *emergePlayer(const char *name, session_t peer_id, u16 proto_version); - void handlePeerChanges(); - /* Variables */ diff --git a/src/util/timetaker.cpp b/src/util/timetaker.cpp index a18d813ba..47d8ab83a 100644 --- a/src/util/timetaker.cpp +++ b/src/util/timetaker.cpp @@ -35,7 +35,7 @@ u64 TimeTaker::stop(bool quiet) if (m_result != nullptr) { (*m_result) += dtime; } else { - if (!quiet) { + if (!quiet && !m_name.empty()) { infostream << m_name << " took " << dtime << TimePrecision_units[m_precision] << std::endl; } From d08d34d80338aaad2fe963c10b081ee32676561a Mon Sep 17 00:00:00 2001 From: sfence Date: Thu, 26 Sep 2024 17:32:55 +0200 Subject: [PATCH 63/67] ABM without_neighbors (#14116) --- builtin/game/features.lua | 1 + doc/lua_api.md | 7 ++ games/devtest/mods/testabms/README.md | 6 ++ games/devtest/mods/testabms/after_node.lua | 12 +++ games/devtest/mods/testabms/chances.lua | 56 ++++++++++ games/devtest/mods/testabms/init.lua | 7 ++ games/devtest/mods/testabms/intervals.lua | 56 ++++++++++ games/devtest/mods/testabms/min_max.lua | 58 ++++++++++ games/devtest/mods/testabms/mod.conf | 2 + games/devtest/mods/testabms/neighbors.lua | 99 ++++++++++++++++++ .../testabms/textures/testabms_after_node.png | Bin 0 -> 179 bytes .../testabms/textures/testabms_wait_node.png | Bin 0 -> 183 bytes src/script/cpp_api/s_env.cpp | 17 ++- src/serverenvironment.cpp | 27 ++++- src/serverenvironment.h | 3 + src/unittest/test_servermodmanager.cpp | 2 +- 16 files changed, 347 insertions(+), 6 deletions(-) create mode 100644 games/devtest/mods/testabms/README.md create mode 100644 games/devtest/mods/testabms/after_node.lua create mode 100644 games/devtest/mods/testabms/chances.lua create mode 100644 games/devtest/mods/testabms/init.lua create mode 100644 games/devtest/mods/testabms/intervals.lua create mode 100644 games/devtest/mods/testabms/min_max.lua create mode 100644 games/devtest/mods/testabms/mod.conf create mode 100644 games/devtest/mods/testabms/neighbors.lua create mode 100644 games/devtest/mods/testabms/textures/testabms_after_node.png create mode 100644 games/devtest/mods/testabms/textures/testabms_wait_node.png diff --git a/builtin/game/features.lua b/builtin/game/features.lua index 81b291e6c..10884497c 100644 --- a/builtin/game/features.lua +++ b/builtin/game/features.lua @@ -44,6 +44,7 @@ core.features = { override_item_remove_fields = true, hotbar_hud_element = true, bulk_lbms = true, + abm_without_neighbors = true, } function core.has_feature(arg) diff --git a/doc/lua_api.md b/doc/lua_api.md index 66a83542e..4c436b1d2 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -5524,6 +5524,8 @@ Utilities hotbar_hud_element = true, -- Bulk LBM support (5.10.0) bulk_lbms = true, + -- ABM supports field without_neighbors (5.10.0) + abm_without_neighbors = true, } ``` @@ -9106,6 +9108,11 @@ Used by `minetest.register_abm`. -- If left out or empty, any neighbor will do. -- `group:groupname` can also be used here. + without_neighbors = {"default:lava_source", "default:lava_flowing"}, + -- Only apply `action` to nodes that have no one of these neighbors. + -- If left out or empty, it has no effect. + -- `group:groupname` can also be used here. + interval = 10.0, -- Operation interval in seconds diff --git a/games/devtest/mods/testabms/README.md b/games/devtest/mods/testabms/README.md new file mode 100644 index 000000000..60fa6d656 --- /dev/null +++ b/games/devtest/mods/testabms/README.md @@ -0,0 +1,6 @@ +# Test ABMs + +This mod contains a nodes and related ABM actions. +By placing these nodes, you can test basic ABM behaviours. + +There are separate tests for ABM `chance`, `interval`, `min_y`, `max_y`, `neighbor` and `without_neighbor` fields. diff --git a/games/devtest/mods/testabms/after_node.lua b/games/devtest/mods/testabms/after_node.lua new file mode 100644 index 000000000..64cdfb484 --- /dev/null +++ b/games/devtest/mods/testabms/after_node.lua @@ -0,0 +1,12 @@ + +local S = minetest.get_translator("testnodes") + +-- After ABM node +minetest.register_node("testabms:after_abm", { + description = S("After ABM processed node."), + drawtype = "normal", + tiles = { "testabms_after_node.png" }, + + groups = { dig_immediate = 3 }, +}) + diff --git a/games/devtest/mods/testabms/chances.lua b/games/devtest/mods/testabms/chances.lua new file mode 100644 index 000000000..95f416b45 --- /dev/null +++ b/games/devtest/mods/testabms/chances.lua @@ -0,0 +1,56 @@ +-- test ABMs with different chances + +local S = minetest.get_translator("testnodes") + +-- ABM chance 5 node +minetest.register_node("testabms:chance_5", { + description = S("Node for test ABM chance_5"), + drawtype = "normal", + tiles = { "testabms_wait_node.png" }, + + groups = { dig_immediate = 3 }, + + on_construct = function (pos) + local meta = minetest.get_meta(pos) + meta:set_string("infotext", "Waiting for ABM testabms:chance_5") + end, +}) + +minetest.register_abm({ + label = "testabms:chance_5", + nodenames = "testabms:chance_5", + interval = 10, + chance = 5, + action = function (pos) + minetest.swap_node(pos, {name="testabms:after_abm"}) + local meta = minetest.get_meta(pos) + meta:set_string("infotext", "ABM testabsm:chance_5 changed this node.") + end +}) + +-- ABM chance 20 node +minetest.register_node("testabms:chance_20", { + description = S("Node for test ABM chance_20"), + drawtype = "normal", + tiles = { "testabms_wait_node.png" }, + + groups = { dig_immediate = 3 }, + + on_construct = function (pos) + local meta = minetest.get_meta(pos) + meta:set_string("infotext", "Waiting for ABM testabms:chance_20") + end, +}) + +minetest.register_abm({ + label = "testabms:chance_20", + nodenames = "testabms:chance_20", + interval = 10, + chance = 20, + action = function (pos) + minetest.swap_node(pos, {name="testabms:after_abm"}) + local meta = minetest.get_meta(pos) + meta:set_string("infotext", "ABM testabsm:chance_20 changed this node.") + end +}) + diff --git a/games/devtest/mods/testabms/init.lua b/games/devtest/mods/testabms/init.lua new file mode 100644 index 000000000..7830d8436 --- /dev/null +++ b/games/devtest/mods/testabms/init.lua @@ -0,0 +1,7 @@ +local path = minetest.get_modpath(minetest.get_current_modname()) + +dofile(path.."/after_node.lua") +dofile(path.."/chances.lua") +dofile(path.."/intervals.lua") +dofile(path.."/min_max.lua") +dofile(path.."/neighbors.lua") diff --git a/games/devtest/mods/testabms/intervals.lua b/games/devtest/mods/testabms/intervals.lua new file mode 100644 index 000000000..57b58faa5 --- /dev/null +++ b/games/devtest/mods/testabms/intervals.lua @@ -0,0 +1,56 @@ +-- test ABMs with different interval + +local S = minetest.get_translator("testnodes") + +-- ABM inteval 1 node +minetest.register_node("testabms:interval_1", { + description = S("Node for test ABM interval_1"), + drawtype = "normal", + tiles = { "testabms_wait_node.png" }, + + groups = { dig_immediate = 3 }, + + on_construct = function (pos) + local meta = minetest.get_meta(pos) + meta:set_string("infotext", "Waiting for ABM testabms:interval_1") + end, +}) + +minetest.register_abm({ + label = "testabms:interval_1", + nodenames = "testabms:interval_1", + interval = 1, + chance = 1, + action = function (pos) + minetest.swap_node(pos, {name="testabms:after_abm"}) + local meta = minetest.get_meta(pos) + meta:set_string("infotext", "ABM testabsm:interval_1 changed this node.") + end +}) + +-- ABM interval 60 node +minetest.register_node("testabms:interval_60", { + description = S("Node for test ABM interval_60"), + drawtype = "normal", + tiles = { "testabms_wait_node.png" }, + + groups = { dig_immediate = 3 }, + + on_construct = function (pos) + local meta = minetest.get_meta(pos) + meta:set_string("infotext", "Waiting for ABM testabms:interval_60") + end, +}) + +minetest.register_abm({ + label = "testabms:interval_60", + nodenames = "testabms:interval_60", + interval = 60, + chance = 1, + action = function (pos) + minetest.swap_node(pos, {name="testabms:after_abm"}) + local meta = minetest.get_meta(pos) + meta:set_string("infotext", "ABM testabsm:interval_60 changed this node.") + end +}) + diff --git a/games/devtest/mods/testabms/min_max.lua b/games/devtest/mods/testabms/min_max.lua new file mode 100644 index 000000000..62f1ccd53 --- /dev/null +++ b/games/devtest/mods/testabms/min_max.lua @@ -0,0 +1,58 @@ +-- test ABMs with min_y and max_y + +local S = minetest.get_translator("testnodes") + +-- ABM min_y node +minetest.register_node("testabms:min_y", { + description = S("Node for test ABM min_y."), + drawtype = "normal", + tiles = { "testabms_wait_node.png" }, + + groups = { dig_immediate = 3 }, + + on_construct = function (pos) + local meta = minetest.get_meta(pos) + meta:set_string("infotext", "Waiting for ABM testabms:min_y at y "..pos.y.." with min_y = 0") + end, +}) + +minetest.register_abm({ + label = "testabms:min_y", + nodenames = "testabms:min_y", + interval = 10, + chance = 1, + min_y = 0, + action = function (pos) + minetest.swap_node(pos, {name="testabms:after_abm"}) + local meta = minetest.get_meta(pos) + meta:set_string("infotext", "ABM testabsm:min_y changed this node.") + end +}) + +-- ABM max_y node +minetest.register_node("testabms:max_y", { + description = S("Node for test ABM max_y."), + drawtype = "normal", + tiles = { "testabms_wait_node.png" }, + + groups = { dig_immediate = 3 }, + + on_construct = function (pos) + local meta = minetest.get_meta(pos) + meta:set_string("infotext", "Waiting for ABM testabms:max_y at y "..pos.y.." with max_y = 0") + end, +}) + +minetest.register_abm({ + label = "testabms:max_y", + nodenames = "testabms:max_y", + interval = 10, + chance = 1, + max_y = 0, + action = function (pos) + minetest.swap_node(pos, {name="testabms:after_abm"}) + local meta = minetest.get_meta(pos) + meta:set_string("infotext", "ABM testabsm:max_y changed this node.") + end +}) + diff --git a/games/devtest/mods/testabms/mod.conf b/games/devtest/mods/testabms/mod.conf new file mode 100644 index 000000000..ad74cd2ed --- /dev/null +++ b/games/devtest/mods/testabms/mod.conf @@ -0,0 +1,2 @@ +name = testabms +description = Contains some nodes for test ABMs. diff --git a/games/devtest/mods/testabms/neighbors.lua b/games/devtest/mods/testabms/neighbors.lua new file mode 100644 index 000000000..42ce47dff --- /dev/null +++ b/games/devtest/mods/testabms/neighbors.lua @@ -0,0 +1,99 @@ +-- test ABMs with neighbor and without_neighbor + +local S = minetest.get_translator("testnodes") + +-- ABM required neighbor +minetest.register_node("testabms:required_neighbor", { + description = S("Node for test ABM required_neighbor.") .. "\n" + .. S("Sensitive neighbor node is testnodes:normal."), + drawtype = "normal", + tiles = { "testabms_wait_node.png" }, + + groups = { dig_immediate = 3 }, + + on_construct = function (pos) + local meta = minetest.get_meta(pos) + meta:set_string("infotext", + "Waiting for ABM testabms:required_neighbor " + .. "(normal drawtype testnode sensitive)") + end, +}) + +minetest.register_abm({ + label = "testabms:required_neighbor", + nodenames = "testabms:required_neighbor", + neighbors = {"testnodes:normal"}, + interval = 1, + chance = 1, + action = function (pos) + minetest.swap_node(pos, {name="testabms:after_abm"}) + local meta = minetest.get_meta(pos) + meta:set_string("infotext", + "ABM testabsm:required_neighbor changed this node.") + end +}) + +-- ABM missing neighbor node +minetest.register_node("testabms:missing_neighbor", { + description = S("Node for test ABM missing_neighbor.") .. "\n" + .. S("Sensitive neighbor node is testnodes:normal."), + drawtype = "normal", + tiles = { "testabms_wait_node.png" }, + + groups = { dig_immediate = 3 }, + + on_construct = function (pos) + local meta = minetest.get_meta(pos) + meta:set_string("infotext", + "Waiting for ABM testabms:missing_neighbor" + .. " (normal drawtype testnode sensitive)") + end, +}) + +minetest.register_abm({ + label = "testabms:missing_neighbor", + nodenames = "testabms:missing_neighbor", + without_neighbors = {"testnodes:normal"}, + interval = 1, + chance = 1, + action = function (pos) + minetest.swap_node(pos, {name="testabms:after_abm"}) + local meta = minetest.get_meta(pos) + meta:set_string("infotext", + "ABM testabsm:missing_neighbor changed this node.") + end +}) + +-- ABM required and missing neighbor node +minetest.register_node("testabms:required_missing_neighbor", { + description = S("Node for test ABM required_missing_neighbor.") .. "\n" + .. S("Sensitive neighbor nodes are testnodes:normal and testnodes:glasslike."), + drawtype = "normal", + tiles = { "testabms_wait_node.png" }, + + groups = { dig_immediate = 3 }, + + on_construct = function (pos) + local meta = minetest.get_meta(pos) + meta:set_string("infotext", + "Waiting for ABM testabms:required_missing_neighbor" + .. " (wint normal drawtype testnode and no glasslike" + .. " drawtype testnode sensitive)") + end, +}) + +minetest.register_abm({ + label = "testabms:required_missing_neighbor", + nodenames = "testabms:required_missing_neighbor", + neighbors = {"testnodes:normal"}, + without_neighbors = {"testnodes:glasslike"}, + interval = 1, + chance = 1, + action = function (pos) + minetest.swap_node(pos, {name="testabms:after_abm"}) + local meta = minetest.get_meta(pos) + meta:set_string("infotext", + "ABM testabsm:required_missing_neighbor changed this node.") + end +}) + diff --git a/games/devtest/mods/testabms/textures/testabms_after_node.png b/games/devtest/mods/testabms/textures/testabms_after_node.png new file mode 100644 index 0000000000000000000000000000000000000000..dab87594b998dde660a623a10cb6e8fe9a1a8b74 GIT binary patch literal 179 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#VfSXm-H;@Q#K(^opENwkdiDLntV2h`_qQKreZkP3#AD~DpHR%m*I>YK zwjGT(@8;C;|3_=v}$Oz_?mj^GY`-UXGp4=yt@ Y%$;W#T>IM27-%blr>mdKI;Vst0G7r(4*&oF literal 0 HcmV?d00001 diff --git a/games/devtest/mods/testabms/textures/testabms_wait_node.png b/games/devtest/mods/testabms/textures/testabms_wait_node.png new file mode 100644 index 0000000000000000000000000000000000000000..a9bd9a36f78fdc973c949fb4b9ded1d444215edd GIT binary patch literal 183 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vfj|2BG;e?M9j;d3T7>A%)9PS@tiKNgrtl`-%3-M7kz|#}Bta^XmL%oFUpD#X->OMTD=4o-qQx2oT_|ManSMX`=ZSV<~ e)wuhgoj>ufCtviv(>g$#89ZJ6T-G@yGywp@vqLce literal 0 HcmV?d00001 diff --git a/src/script/cpp_api/s_env.cpp b/src/script/cpp_api/s_env.cpp index deac90f3c..007622d52 100644 --- a/src/script/cpp_api/s_env.cpp +++ b/src/script/cpp_api/s_env.cpp @@ -34,10 +34,11 @@ with this program; if not, write to the Free Software Foundation, Inc., class LuaABM : public ActiveBlockModifier { private: - int m_id; + const int m_id; std::vector m_trigger_contents; std::vector m_required_neighbors; + std::vector m_without_neighbors; float m_trigger_interval; u32 m_trigger_chance; bool m_simple_catch_up; @@ -47,11 +48,13 @@ public: LuaABM(int id, const std::vector &trigger_contents, const std::vector &required_neighbors, + const std::vector &without_neighbors, float trigger_interval, u32 trigger_chance, bool simple_catch_up, s16 min_y, s16 max_y): m_id(id), m_trigger_contents(trigger_contents), m_required_neighbors(required_neighbors), + m_without_neighbors(without_neighbors), m_trigger_interval(trigger_interval), m_trigger_chance(trigger_chance), m_simple_catch_up(simple_catch_up), @@ -67,6 +70,10 @@ public: { return m_required_neighbors; } + virtual const std::vector &getWithoutNeighbors() const + { + return m_without_neighbors; + } virtual float getTriggerInterval() { return m_trigger_interval; @@ -230,6 +237,11 @@ void ScriptApiEnv::readABMs() read_nodenames(L, -1, required_neighbors); lua_pop(L, 1); + std::vector without_neighbors; + lua_getfield(L, current_abm, "without_neighbors"); + read_nodenames(L, -1, without_neighbors); + lua_pop(L, 1); + float trigger_interval = 10.0; getfloatfield(L, current_abm, "interval", trigger_interval); @@ -250,7 +262,8 @@ void ScriptApiEnv::readABMs() lua_pop(L, 1); LuaABM *abm = new LuaABM(id, trigger_contents, required_neighbors, - trigger_interval, trigger_chance, simple_catch_up, min_y, max_y); + without_neighbors, trigger_interval, trigger_chance, + simple_catch_up, min_y, max_y); env->addActiveBlockModifier(abm); diff --git a/src/serverenvironment.cpp b/src/serverenvironment.cpp index ac627dd50..813184de1 100644 --- a/src/serverenvironment.cpp +++ b/src/serverenvironment.cpp @@ -827,6 +827,7 @@ struct ActiveABM { ActiveBlockModifier *abm; std::vector required_neighbors; + std::vector without_neighbors; int chance; s16 min_y, max_y; }; @@ -885,6 +886,10 @@ public: ndef->getIds(s, aabm.required_neighbors); SORT_AND_UNIQUE(aabm.required_neighbors); + for (const auto &s : abm->getWithoutNeighbors()) + ndef->getIds(s, aabm.without_neighbors); + SORT_AND_UNIQUE(aabm.without_neighbors); + // Trigger contents std::vector ids; for (const auto &s : abm->getTriggerContents()) @@ -996,8 +1001,11 @@ public: continue; // Check neighbors - if (!aabm.required_neighbors.empty()) { + const bool check_required_neighbors = !aabm.required_neighbors.empty(); + const bool check_without_neighbors = !aabm.without_neighbors.empty(); + if (check_required_neighbors || check_without_neighbors) { v3s16 p1; + bool have_required = false; for(p1.X = p0.X-1; p1.X <= p0.X+1; p1.X++) for(p1.Y = p0.Y-1; p1.Y <= p0.Y+1; p1.Y++) for(p1.Z = p0.Z-1; p1.Z <= p0.Z+1; p1.Z++) @@ -1015,12 +1023,25 @@ public: MapNode n = map->getNode(p1 + block->getPosRelative()); c = n.getContent(); } - if (CONTAINS(aabm.required_neighbors, c)) - goto neighbor_found; + if (check_required_neighbors && !have_required) { + if (CONTAINS(aabm.required_neighbors, c)) { + if (!check_without_neighbors) + goto neighbor_found; + have_required = true; + } + } + if (check_without_neighbors) { + if (CONTAINS(aabm.without_neighbors, c)) + goto neighbor_invalid; + } } + if (have_required || !check_required_neighbors) + goto neighbor_found; // No required neighbor found + neighbor_invalid: continue; } + neighbor_found: abms_run++; diff --git a/src/serverenvironment.h b/src/serverenvironment.h index d20cc0b3f..0b00fac91 100644 --- a/src/serverenvironment.h +++ b/src/serverenvironment.h @@ -63,6 +63,9 @@ public: // Set of required neighbors (trigger doesn't happen if none are found) // Empty = do not check neighbors virtual const std::vector &getRequiredNeighbors() const = 0; + // Set of without neighbors (trigger doesn't happen if any are found) + // Empty = do not check neighbors + virtual const std::vector &getWithoutNeighbors() const = 0; // Trigger interval in seconds virtual float getTriggerInterval() = 0; // Random chance of (1 / return value), 0 is disallowed diff --git a/src/unittest/test_servermodmanager.cpp b/src/unittest/test_servermodmanager.cpp index f26734ab3..03fdc7042 100644 --- a/src/unittest/test_servermodmanager.cpp +++ b/src/unittest/test_servermodmanager.cpp @@ -122,7 +122,7 @@ void TestServerModManager::testGetMods() ServerModManager sm(m_worlddir); const auto &mods = sm.getMods(); // `ls ./games/devtest/mods | wc -l` + 1 (test mod) - UASSERTEQ(std::size_t, mods.size(), 32 + 1); + UASSERTEQ(std::size_t, mods.size(), 33 + 1); // Ensure we found basenodes mod (part of devtest) // and test_mod (for testing MINETEST_MOD_PATH). From 65ec371b7849606e7a8b6bf31e75d7c210ce7035 Mon Sep 17 00:00:00 2001 From: DragonWrangler1 <146014546+DragonWrangler1@users.noreply.github.com> Date: Thu, 26 Sep 2024 08:34:16 -0700 Subject: [PATCH 64/67] Allow `allfaces` drawtypes to have 6 textures (#15175) --- doc/lua_api.md | 3 ++- games/devtest/mods/testnodes/drawtypes.lua | 17 +++++++++++++++++ src/client/content_mapblock.cpp | 18 +++++++++++------- 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/doc/lua_api.md b/doc/lua_api.md index 4c436b1d2..7623c1c5d 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -1470,7 +1470,8 @@ Look for examples in `games/devtest` or `games/minetest_game`. 'Connected Glass'. * `allfaces` * Often used for partially-transparent nodes. - * External and internal sides of textures are visible. + * External sides of textures, and unlike other drawtypes, the external sides + of other blocks, are visible from the inside. * `allfaces_optional` * Often used for leaves nodes. * This switches between `normal`, `glasslike` and `allfaces` according to diff --git a/games/devtest/mods/testnodes/drawtypes.lua b/games/devtest/mods/testnodes/drawtypes.lua index 087d09eff..4a657b739 100644 --- a/games/devtest/mods/testnodes/drawtypes.lua +++ b/games/devtest/mods/testnodes/drawtypes.lua @@ -98,6 +98,23 @@ minetest.register_node("testnodes:allfaces", { groups = { dig_immediate = 3 }, }) +minetest.register_node("testnodes:allfaces_6", { + description = S("\"allfaces 6 Textures\" Drawtype Test Node").."\n".. + S("Transparent node with visible internal backfaces"), + drawtype = "allfaces", + paramtype = "light", + tiles = { + "testnodes_allfaces.png^[colorize:red", + "testnodes_allfaces.png^[colorize:orange", + "testnodes_allfaces.png^[colorize:yellow", + "testnodes_allfaces.png^[colorize:green", + "testnodes_allfaces.png^[colorize:blue", + "testnodes_allfaces.png^[colorize:purple" + }, + + groups = { dig_immediate = 3 }, +}) + local allfaces_optional_tooltip = "".. S("Rendering depends on 'leaves_style' setting:").."\n".. S("* 'fancy': transparent with visible internal backfaces").."\n".. diff --git a/src/client/content_mapblock.cpp b/src/client/content_mapblock.cpp index 2a1352139..6ce3ca0f4 100644 --- a/src/client/content_mapblock.cpp +++ b/src/client/content_mapblock.cpp @@ -1016,13 +1016,6 @@ void MapblockMeshGenerator::drawGlasslikeFramedNode() } } -void MapblockMeshGenerator::drawAllfacesNode() -{ - static const aabb3f box(-BS / 2, -BS / 2, -BS / 2, BS / 2, BS / 2, BS / 2); - useTile(0, 0, 0); - drawAutoLightedCuboid(box); -} - void MapblockMeshGenerator::drawTorchlikeNode() { u8 wall = cur_node.n.getWallMounted(nodedef); @@ -1545,6 +1538,17 @@ namespace { }; } +void MapblockMeshGenerator::drawAllfacesNode() +{ + static const aabb3f box(-BS / 2, -BS / 2, -BS / 2, BS / 2, BS / 2, BS / 2); + TileSpec tiles[6]; + for (int face = 0; face < 6; face++) + getTile(nodebox_tile_dirs[face], &tiles[face]); + if (data->m_smooth_lighting) + getSmoothLightFrame(); + drawAutoLightedCuboid(box, nullptr, tiles, 6); +} + void MapblockMeshGenerator::drawNodeboxNode() { TileSpec tiles[6]; From fbb0e82679b35366ae72db42d357b5439d72f9d6 Mon Sep 17 00:00:00 2001 From: grorp Date: Fri, 27 Sep 2024 11:08:35 +0200 Subject: [PATCH 65/67] Fix uninitialized shadow tint regression from #14610 (#15197) * Fix uninitialized shadow tint This resulted in shadows having a different, random color each time I started a game * Fix formatting mistakes from the same PR --- src/lighting.h | 2 +- src/network/networkprotocol.h | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/lighting.h b/src/lighting.h index 20f434112..fbf10b1c9 100644 --- a/src/lighting.h +++ b/src/lighting.h @@ -56,5 +56,5 @@ struct Lighting float shadow_intensity {0.0f}; float saturation {1.0f}; float volumetric_light_strength {0.0f}; - video::SColor shadow_tint; + video::SColor shadow_tint {255, 0, 0, 0}; }; diff --git a/src/network/networkprotocol.h b/src/network/networkprotocol.h index cae2a3291..aeb827608 100644 --- a/src/network/networkprotocol.h +++ b/src/network/networkprotocol.h @@ -229,7 +229,7 @@ with this program; if not, write to the Free Software Foundation, Inc., [bump for 5.9.1] PROTOCOL VERSION 46: Move default hotbar from client-side C++ to server-side builtin Lua - Add shadow tint to Lighting packets + Add shadow tint to Lighting packets Add shadow color to CloudParam packets Move death screen to server and make it a regular formspec The server no longer triggers the hardcoded client-side death @@ -241,7 +241,6 @@ with this program; if not, write to the Free Software Foundation, Inc., */ #define LATEST_PROTOCOL_VERSION 46 - #define LATEST_PROTOCOL_VERSION_STRING TOSTRING(LATEST_PROTOCOL_VERSION) // Server's supported network protocol range @@ -1182,4 +1181,4 @@ enum InteractAction : u8 INTERACT_PLACE, // 3: place block or item (to abovesurface) INTERACT_USE, // 4: use item INTERACT_ACTIVATE // 5: rightclick air ("activate") -}; \ No newline at end of file +}; From 610ddaba7ce23248ec898ac68c44ca62c0ad73b4 Mon Sep 17 00:00:00 2001 From: sfence Date: Fri, 27 Sep 2024 21:34:52 +0200 Subject: [PATCH 66/67] Allow detection of damage greater than HP (#15160) Co-authored-by: Gregor Parzefall --- doc/lua_api.md | 5 ++ games/devtest/mods/unittests/player.lua | 78 +++++++++++++++++++++---- src/server/player_sao.cpp | 9 +-- 3 files changed, 77 insertions(+), 15 deletions(-) diff --git a/doc/lua_api.md b/doc/lua_api.md index 7623c1c5d..9c888ff13 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -5850,8 +5850,13 @@ Call these functions only at load time! * `clicker`: ObjectRef - Object that acted upon `player`, may or may not be a player * `minetest.register_on_player_hpchange(function(player, hp_change, reason), modifier)` * Called when the player gets damaged or healed + * When `hp == 0`, damage doesn't trigger this callback. + * When `hp == hp_max`, healing does still trigger this callback. * `player`: ObjectRef of the player * `hp_change`: the amount of change. Negative when it is damage. + * Historically, the new HP value was clamped to [0, 65535] before + calculating the HP change. This clamping has been removed as of + Minetest 5.10.0 * `reason`: a PlayerHPChangeReason table. * The `type` field will have one of the following values: * `set_hp`: A mod or the engine called `set_hp` without diff --git a/games/devtest/mods/unittests/player.lua b/games/devtest/mods/unittests/player.lua index 7650d5f57..f8945f320 100644 --- a/games/devtest/mods/unittests/player.lua +++ b/games/devtest/mods/unittests/player.lua @@ -42,41 +42,97 @@ unittests.register("test_hpchangereason", run_hpchangereason_tests, {player=true -- local expected_diff = nil +local hpchange_counter = 0 +local die_counter = 0 core.register_on_player_hpchange(function(player, hp_change, reason) if expected_diff then assert(hp_change == expected_diff) + hpchange_counter = hpchange_counter + 1 end end) +core.register_on_dieplayer(function() + die_counter = die_counter + 1 +end) + +local function hp_diference_test(player, hp_max) + assert(hp_max >= 22) -local function run_hp_difference_tests(player) local old_hp = player:get_hp() local old_hp_max = player:get_properties().hp_max - expected_diff = nil - player:set_properties({hp_max = 30}) - player:set_hp(22) + hpchange_counter = 0 + die_counter = 0 - -- final HP value is clamped to >= 0 before difference calculation - expected_diff = -22 + expected_diff = nil + player:set_properties({hp_max = hp_max}) + player:set_hp(22) + assert(player:get_hp() == 22) + assert(hpchange_counter == 0) + assert(die_counter == 0) + + -- HP difference is not clamped + expected_diff = -25 player:set_hp(-3) - -- and actual final HP value is clamped to >= 0 too + -- actual final HP value is clamped to >= 0 assert(player:get_hp() == 0) + assert(hpchange_counter == 1) + assert(die_counter == 1) expected_diff = 22 player:set_hp(22) assert(player:get_hp() == 22) + assert(hpchange_counter == 2) + assert(die_counter == 1) - -- final HP value is clamped to <= U16_MAX before difference calculation - expected_diff = 65535 - 22 + -- Integer overflow is prevented + -- so result is S32_MIN, not S32_MIN - 22 + expected_diff = -2147483648 + player:set_hp(-2147483648) + -- actual final HP value is clamped to >= 0 + assert(player:get_hp() == 0) + assert(hpchange_counter == 3) + assert(die_counter == 2) + + -- Damage is ignored if player is already dead (hp == 0) + expected_diff = "never equal" + player:set_hp(-11) + assert(player:get_hp() == 0) + -- no on_player_hpchange or on_dieplayer call expected + assert(hpchange_counter == 3) + assert(die_counter == 2) + + expected_diff = 11 + player:set_hp(11) + assert(player:get_hp() == 11) + assert(hpchange_counter == 4) + assert(die_counter == 2) + + -- HP difference is not clamped + expected_diff = 1000000 - 11 player:set_hp(1000000) - -- and actual final HP value is clamped to <= hp_max - assert(player:get_hp() == 30) + -- actual final HP value is clamped to <= hp_max + assert(player:get_hp() == hp_max) + assert(hpchange_counter == 5) + assert(die_counter == 2) + + -- "Healing" is not ignored when hp == hp_max + expected_diff = 80000 - hp_max + player:set_hp(80000) + assert(player:get_hp() == hp_max) + -- on_player_hpchange_call expected + assert(hpchange_counter == 6) + assert(die_counter == 2) expected_diff = nil player:set_properties({hp_max = old_hp_max}) player:set_hp(old_hp) core.close_formspec(player:get_player_name(), "") -- hide death screen end +local function run_hp_difference_tests(player) + hp_diference_test(player, 22) + hp_diference_test(player, 30) + hp_diference_test(player, 65535) -- U16_MAX +end unittests.register("test_hp_difference", run_hp_difference_tests, {player=true}) -- diff --git a/src/server/player_sao.cpp b/src/server/player_sao.cpp index 30c41bb1e..61d328ca7 100644 --- a/src/server/player_sao.cpp +++ b/src/server/player_sao.cpp @@ -519,12 +519,13 @@ void PlayerSAO::rightClick(ServerActiveObject *clicker) void PlayerSAO::setHP(s32 target_hp, const PlayerHPChangeReason &reason, bool from_client) { - target_hp = rangelim(target_hp, 0, U16_MAX); - - if (target_hp == m_hp) + if (target_hp == m_hp || (m_hp == 0 && target_hp < 0)) return; // Nothing to do - s32 hp_change = m_env->getScriptIface()->on_player_hpchange(this, target_hp - (s32)m_hp, reason); + // Protect against overflow. + s32 hp_change = std::max((s64)target_hp - (s64)m_hp, S32_MIN); + + hp_change = m_env->getScriptIface()->on_player_hpchange(this, hp_change, reason); hp_change = std::min(hp_change, U16_MAX); // Protect against overflow s32 hp = (s32)m_hp + hp_change; From 700fbc803d7fb393863074beb9e6c86e6883f003 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Wed, 25 Sep 2024 23:24:30 +0200 Subject: [PATCH 67/67] Minor improvements to metadata handling --- src/itemstackmetadata.cpp | 4 ++-- src/nodemetadata.cpp | 19 ++++++++++--------- src/nodemetadata.h | 5 ++++- src/script/lua_api/l_itemstackmeta.cpp | 6 +----- src/script/lua_api/l_nodemeta.cpp | 21 +++++++++++++-------- src/script/lua_api/l_playermeta.cpp | 5 +---- 6 files changed, 31 insertions(+), 29 deletions(-) diff --git a/src/itemstackmetadata.cpp b/src/itemstackmetadata.cpp index be1715e1a..a2fc67c46 100644 --- a/src/itemstackmetadata.cpp +++ b/src/itemstackmetadata.cpp @@ -89,11 +89,11 @@ void ItemStackMetadata::deSerialize(std::istream &is) while (!fnd.at_end()) { std::string name = fnd.next(DESERIALIZE_KV_DELIM_STR); std::string var = fnd.next(DESERIALIZE_PAIR_DELIM_STR); - m_stringvars[name] = var; + m_stringvars[name] = std::move(var); } } else { // BACKWARDS COMPATIBILITY - m_stringvars[""] = in; + m_stringvars[""] = std::move(in); } } updateToolCapabilities(); diff --git a/src/nodemetadata.cpp b/src/nodemetadata.cpp index a11503ebe..a86db15ad 100644 --- a/src/nodemetadata.cpp +++ b/src/nodemetadata.cpp @@ -62,14 +62,14 @@ void NodeMetadata::serialize(std::ostream &os, u8 version, bool disk) const void NodeMetadata::deSerialize(std::istream &is, u8 version) { clear(); - int num_vars = readU32(is); - for(int i=0; i= 2) { if (readU8(is) == 1) - markPrivate(name, true); + m_privatevars.insert(name); } } @@ -89,12 +89,12 @@ bool NodeMetadata::empty() const } -void NodeMetadata::markPrivate(const std::string &name, bool set) +bool NodeMetadata::markPrivate(const std::string &name, bool set) { if (set) - m_privatevars.insert(name); + return m_privatevars.insert(name).second; else - m_privatevars.erase(name); + return m_privatevars.erase(name) > 0; } int NodeMetadata::countNonPrivate() const @@ -144,6 +144,8 @@ void NodeMetadataList::serialize(std::ostream &os, u8 blockver, bool disk, writeS16(os, p.Z); } else { // Serialize positions within a mapblock + static_assert(MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE <= U16_MAX, + "position too big to serialize"); u16 p16 = (p.Z * MAP_BLOCKSIZE + p.Y) * MAP_BLOCKSIZE + p.X; writeU16(os, p16); } @@ -246,8 +248,7 @@ void NodeMetadataList::set(v3s16 p, NodeMetadata *d) void NodeMetadataList::clear() { if (m_is_metadata_owner) { - NodeMetadataMap::const_iterator it; - for (it = m_data.begin(); it != m_data.end(); ++it) + for (auto it = m_data.begin(); it != m_data.end(); ++it) delete it->second; } m_data.clear(); diff --git a/src/nodemetadata.h b/src/nodemetadata.h index da277aabd..3c2a67f53 100644 --- a/src/nodemetadata.h +++ b/src/nodemetadata.h @@ -57,7 +57,10 @@ public: { return m_privatevars.count(name) != 0; } - void markPrivate(const std::string &name, bool set); + + /// Marks a key as private. + /// @return metadata modified? + bool markPrivate(const std::string &name, bool set); private: int countNonPrivate() const; diff --git a/src/script/lua_api/l_itemstackmeta.cpp b/src/script/lua_api/l_itemstackmeta.cpp index ebabf7bae..730fab3b4 100644 --- a/src/script/lua_api/l_itemstackmeta.cpp +++ b/src/script/lua_api/l_itemstackmeta.cpp @@ -41,7 +41,7 @@ void ItemStackMetaRef::clearMeta() void ItemStackMetaRef::reportMetadataChange(const std::string *name) { - // TODO + // nothing to do } // Exported functions @@ -89,7 +89,6 @@ ItemStackMetaRef::~ItemStackMetaRef() void ItemStackMetaRef::create(lua_State *L, LuaItemStack *istack) { ItemStackMetaRef *o = new ItemStackMetaRef(istack); - //infostream<<"NodeMetaRef::create: o="<(getmeta(false)); + bool is_private_change = meta && name && meta->isPrivate(*name); + // If the metadata is now empty, get rid of it if (meta && meta->empty()) { clearMeta(); @@ -67,7 +69,7 @@ void NodeMetaRef::reportMetadataChange(const std::string *name) MapEditEvent event; event.type = MEET_BLOCK_NODE_METADATA_CHANGED; event.setPositionModified(m_p); - event.is_private_change = name && meta && meta->isPrivate(*name); + event.is_private_change = is_private_change; m_env->getMap().dispatchEvent(event); } @@ -94,21 +96,24 @@ int NodeMetaRef::l_mark_as_private(lua_State *L) NodeMetaRef *ref = checkObject(L, 1); NodeMetadata *meta = dynamic_cast(ref->getmeta(true)); - assert(meta); + if (!meta) + return 0; + bool modified = false; if (lua_istable(L, 2)) { lua_pushnil(L); while (lua_next(L, 2) != 0) { // key at index -2 and value at index -1 luaL_checktype(L, -1, LUA_TSTRING); - meta->markPrivate(readParam(L, -1), true); + modified |= meta->markPrivate(readParam(L, -1), true); // removes value, keeps key for next iteration lua_pop(L, 1); } } else if (lua_isstring(L, 2)) { - meta->markPrivate(readParam(L, 2), true); + modified |= meta->markPrivate(readParam(L, 2), true); } - ref->reportMetadataChange(); + if (modified) + ref->reportMetadataChange(); return 0; } @@ -145,12 +150,13 @@ bool NodeMetaRef::handleFromTable(lua_State *L, int table, IMetadata *_meta) Inventory *inv = meta->getInventory(); lua_getfield(L, table, "inventory"); if (lua_istable(L, -1)) { + auto *gamedef = getGameDef(L); int inventorytable = lua_gettop(L); lua_pushnil(L); while (lua_next(L, inventorytable) != 0) { // key at index -2 and value at index -1 - std::string name = luaL_checkstring(L, -2); - read_inventory_list(L, -1, inv, name.c_str(), getServer(L)); + const char *name = luaL_checkstring(L, -2); + read_inventory_list(L, -1, inv, name, gamedef); lua_pop(L, 1); // Remove value, keep key for next iteration } lua_pop(L, 1); @@ -177,7 +183,6 @@ NodeMetaRef::NodeMetaRef(IMetadata *meta): void NodeMetaRef::create(lua_State *L, v3s16 p, ServerEnvironment *env) { NodeMetaRef *o = new NodeMetaRef(p, env); - //infostream<<"NodeMetaRef::create: o="<