From 604fb2b738c1f369c608b7f3b778034bf3dc2725 Mon Sep 17 00:00:00 2001 From: x2048 Date: Fri, 20 May 2022 22:33:52 +0200 Subject: [PATCH 01/13] Fix lighting of the wield mesh (#12341) * Assign node light to player before final color blend. Fixes day/night lightbank ratio for wield meshes * Update wield mesh light when changing mesh --- src/client/camera.cpp | 10 +++++++--- src/client/camera.h | 3 +++ src/client/clientenvironment.cpp | 1 + 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/client/camera.cpp b/src/client/camera.cpp index d1f19adb3..7cc9cb6e8 100644 --- a/src/client/camera.cpp +++ b/src/client/camera.cpp @@ -47,7 +47,8 @@ with this program; if not, write to the Free Software Foundation, Inc., Camera::Camera(MapDrawControl &draw_control, Client *client, RenderingEngine *rendering_engine): m_draw_control(draw_control), - m_client(client) + m_client(client), + m_player_light_color(0xFFFFFFFF) { auto smgr = rendering_engine->get_scene_manager(); // note: making the camera node a child of the player node @@ -153,8 +154,10 @@ void Camera::step(f32 dtime) bool was_under_zero = m_wield_change_timer < 0; m_wield_change_timer = MYMIN(m_wield_change_timer + dtime, 0.125); - if (m_wield_change_timer >= 0 && was_under_zero) + if (m_wield_change_timer >= 0 && was_under_zero) { m_wieldnode->setItem(m_wield_item_next, m_client); + m_wieldnode->setNodeLightColor(m_player_light_color); + } if (m_view_bobbing_state != 0) { @@ -555,7 +558,8 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 tool_reload_ratio) m_wieldnode->setPosition(wield_position); m_wieldnode->setRotation(wield_rotation); - m_wieldnode->setNodeLightColor(player->light_color); + m_player_light_color = player->light_color; + m_wieldnode->setNodeLightColor(m_player_light_color); // Set render distance updateViewingRange(); diff --git a/src/client/camera.h b/src/client/camera.h index 403d6024c..cbf248d97 100644 --- a/src/client/camera.h +++ b/src/client/camera.h @@ -264,4 +264,7 @@ private: std::list m_nametags; bool m_show_nametag_backgrounds; + + // Last known light color of the player + video::SColor m_player_light_color; }; diff --git a/src/client/clientenvironment.cpp b/src/client/clientenvironment.cpp index 448af36c6..183a95007 100644 --- a/src/client/clientenvironment.cpp +++ b/src/client/clientenvironment.cpp @@ -305,6 +305,7 @@ void ClientEnvironment::step(float dtime) node_at_lplayer = m_map->getNode(p); u16 light = getInteriorLight(node_at_lplayer, 0, m_client->ndef()); + lplayer->light_color = encode_light(light, 0); // this transfers light.alpha final_color_blend(&lplayer->light_color, light, day_night_ratio); } From a4ef62f5b215fe0f23e3e50672f1538854db4ed9 Mon Sep 17 00:00:00 2001 From: x2048 Date: Fri, 20 May 2022 22:35:03 +0200 Subject: [PATCH 02/13] Fix lighting of upright_sprite entities (#12336) Use MeshNode materials to set the light since ReadOnlyMaterials is now false --- src/client/content_cao.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/client/content_cao.cpp b/src/client/content_cao.cpp index d89bb53b3..9c3e5aa05 100644 --- a/src/client/content_cao.cpp +++ b/src/client/content_cao.cpp @@ -905,12 +905,8 @@ void GenericCAO::setNodeLight(const video::SColor &light_color) if (m_prop.visual == "upright_sprite") { if (!m_meshnode) return; - - scene::IMesh *mesh = m_meshnode->getMesh(); - for (u32 i = 0; i < mesh->getMeshBufferCount(); ++i) { - scene::IMeshBuffer *buf = mesh->getMeshBuffer(i); - buf->getMaterial().EmissiveColor = light_color; - } + for (u32 i = 0; i < m_meshnode->getMaterialCount(); ++i) + m_meshnode->getMaterial(i).EmissiveColor = light_color; } else { scene::ISceneNode *node = getSceneNode(); if (!node) From dc45b85a543b4c8ad72f69a554ecfe7f0a60c533 Mon Sep 17 00:00:00 2001 From: x2048 Date: Sat, 21 May 2022 16:49:30 +0200 Subject: [PATCH 03/13] Improve shadow filters (#12195) * Rewrite shadow filtering for the new distortion * Calculate penumbra radius using a single sample * Avoid peter-panning effect due to filtering of short shadows * Add adaptive filter quality for soft shadows * Avoid sharp shadows on surfaces without normals (e.g. plants) * Increase default and maximum soft shadow radius * Make line numbers in shader errors match the code --- builtin/settingtypes.txt | 4 +- .../shaders/nodes_shader/opengl_fragment.glsl | 166 ++++++----------- .../shaders/nodes_shader/opengl_vertex.glsl | 2 + .../object_shader/opengl_fragment.glsl | 170 +++++++----------- .../shaders/object_shader/opengl_vertex.glsl | 2 + src/client/clientmap.cpp | 2 + src/client/shader.cpp | 2 + src/client/shadows/dynamicshadowsrender.cpp | 1 + src/defaultsettings.cpp | 2 +- 9 files changed, 131 insertions(+), 220 deletions(-) diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt index ff69d9741..3f6f6c9fc 100644 --- a/builtin/settingtypes.txt +++ b/builtin/settingtypes.txt @@ -631,8 +631,8 @@ shadow_update_frames (Map shadows update frames) int 8 1 16 # Set the soft shadow radius size. # Lower values mean sharper shadows, bigger values mean softer shadows. -# Minimum value: 1.0; maximum value: 10.0 -shadow_soft_radius (Soft shadow radius) float 1.0 1.0 10.0 +# Minimum value: 1.0; maximum value: 15.0 +shadow_soft_radius (Soft shadow radius) float 5.0 1.0 15.0 # Set the tilt of Sun/Moon orbit in degrees. # Value of 0 means no tilt / vertical orbit. diff --git a/client/shaders/nodes_shader/opengl_fragment.glsl b/client/shaders/nodes_shader/opengl_fragment.glsl index 8110f6fd3..c4b947e72 100644 --- a/client/shaders/nodes_shader/opengl_fragment.glsl +++ b/client/shaders/nodes_shader/opengl_fragment.glsl @@ -25,6 +25,7 @@ uniform float animationTimer; varying float cosLight; varying float f_normal_length; varying vec3 shadow_position; + varying float perspective_factor; #endif @@ -116,23 +117,16 @@ float getHardShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance #if SHADOW_FILTER == 2 - #define PCFBOUND 3.5 - #define PCFSAMPLES 64.0 + #define PCFBOUND 2.0 // 5x5 + #define PCFSAMPLES 25 #elif SHADOW_FILTER == 1 - #define PCFBOUND 1.5 - #if defined(POISSON_FILTER) - #define PCFSAMPLES 32.0 - #else - #define PCFSAMPLES 16.0 - #endif + #define PCFBOUND 1.0 // 3x3 + #define PCFSAMPLES 9 #else #define PCFBOUND 0.0 - #if defined(POISSON_FILTER) - #define PCFSAMPLES 4.0 - #else - #define PCFSAMPLES 1.0 - #endif + #define PCFSAMPLES 1 #endif + #ifdef COLORED_SHADOWS float getHardShadowDepth(sampler2D shadowsampler, vec2 smTexCoord, float realDistance) { @@ -149,59 +143,31 @@ float getHardShadowDepth(sampler2D shadowsampler, vec2 smTexCoord, float realDis } #endif -float getBaseLength(vec2 smTexCoord) -{ - float l = length(2.0 * smTexCoord.xy - 1.0 - CameraPos.xy); // length in texture coords - return xyPerspectiveBias1 / (1.0 / l - xyPerspectiveBias0); // return to undistorted coords -} +#define BASEFILTERRADIUS 1.0 -float getDeltaPerspectiveFactor(float l) +float getPenumbraRadius(sampler2D shadowsampler, vec2 smTexCoord, float realDistance) { - return 0.04 * pow(512.0 / f_textureresolution, 0.4) / (xyPerspectiveBias0 * l + xyPerspectiveBias1); // original distortion factor, divided by 10 -} - -float getPenumbraRadius(sampler2D shadowsampler, vec2 smTexCoord, float realDistance, float multiplier) -{ - float baseLength = getBaseLength(smTexCoord); - float perspectiveFactor; - // Return fast if sharp shadows are requested - if (PCFBOUND == 0.0) + if (PCFBOUND == 0.0 || SOFTSHADOWRADIUS <= 0.0) return 0.0; - if (SOFTSHADOWRADIUS <= 1.0) { - perspectiveFactor = getDeltaPerspectiveFactor(baseLength); - return max(2 * length(smTexCoord.xy) * 2048 / f_textureresolution / pow(perspectiveFactor, 3), SOFTSHADOWRADIUS); - } - vec2 clampedpos; - float texture_size = 1.0 / (2048 /*f_textureresolution*/ * 0.5); float y, x; - float depth = 0.0; - float pointDepth; - float maxRadius = SOFTSHADOWRADIUS * 5.0 * multiplier; + float depth = getHardShadowDepth(shadowsampler, smTexCoord.xy, realDistance); + // A factor from 0 to 1 to reduce blurring of short shadows + float sharpness_factor = 1.0; + // conversion factor from shadow depth to blur radius + float depth_to_blur = f_shadowfar / SOFTSHADOWRADIUS / xyPerspectiveBias0; + if (depth > 0.0 && f_normal_length > 0.0) + // 5 is empirical factor that controls how fast shadow loses sharpness + sharpness_factor = clamp(5 * depth * depth_to_blur, 0.0, 1.0); + depth = 0.0; - float bound = clamp(PCFBOUND * (1 - baseLength), 0.0, PCFBOUND); - int n = 0; + float world_to_texture = xyPerspectiveBias1 / perspective_factor / perspective_factor + * f_textureresolution / 2.0 / f_shadowfar; + float world_radius = 0.2; // shadow blur radius in world float coordinates, e.g. 0.2 = 0.02 of one node - for (y = -bound; y <= bound; y += 1.0) - for (x = -bound; x <= bound; x += 1.0) { - clampedpos = vec2(x,y); - perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * maxRadius); - clampedpos = clampedpos * texture_size * perspectiveFactor * maxRadius * perspectiveFactor + smTexCoord.xy; - - pointDepth = getHardShadowDepth(shadowsampler, clampedpos.xy, realDistance); - if (pointDepth > -0.01) { - depth += pointDepth; - n += 1; - } - } - - depth = depth / n; - depth = pow(clamp(depth, 0.0, 1000.0), 1.6) / 0.001; - - perspectiveFactor = getDeltaPerspectiveFactor(baseLength); - return max(length(smTexCoord.xy) * 2 * 2048 / f_textureresolution / pow(perspectiveFactor, 3), depth * maxRadius); + return max(BASEFILTERRADIUS * f_textureresolution / 4096.0, sharpness_factor * world_radius * world_to_texture * SOFTSHADOWRADIUS); } #ifdef POISSON_FILTER @@ -276,26 +242,23 @@ const vec2[64] poissonDisk = vec2[64]( vec4 getShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance) { - vec2 clampedpos; - vec4 visibility = vec4(0.0); - float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance, 1.5); // scale to align with PCF + float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance); if (radius < 0.1) { // we are in the middle of even brightness, no need for filtering return getHardShadowColor(shadowsampler, smTexCoord.xy, realDistance); } - float baseLength = getBaseLength(smTexCoord); - float perspectiveFactor; + vec2 clampedpos; + vec4 visibility = vec4(0.0); + float scale_factor = radius / f_textureresolution; - float texture_size = 1.0 / (f_textureresolution * 0.5); - int samples = int(clamp(PCFSAMPLES * (1 - baseLength) * (1 - baseLength), PCFSAMPLES / 4, PCFSAMPLES)); + int samples = (1 + 1 * int(SOFTSHADOWRADIUS > 1.0)) * PCFSAMPLES; // scale max samples for the soft shadows + samples = int(clamp(pow(4.0 * radius + 1.0, 2.0), 1.0, float(samples))); int init_offset = int(floor(mod(((smTexCoord.x * 34.0) + 1.0) * smTexCoord.y, 64.0-samples))); int end_offset = int(samples) + init_offset; for (int x = init_offset; x < end_offset; x++) { - clampedpos = poissonDisk[x]; - perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * radius); - clampedpos = clampedpos * texture_size * perspectiveFactor * radius * perspectiveFactor + smTexCoord.xy; + clampedpos = poissonDisk[x] * scale_factor + smTexCoord.xy; visibility += getHardShadowColor(shadowsampler, clampedpos.xy, realDistance); } @@ -306,26 +269,23 @@ vec4 getShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance) { - vec2 clampedpos; - float visibility = 0.0; - float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance, 1.5); // scale to align with PCF + float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance); if (radius < 0.1) { // we are in the middle of even brightness, no need for filtering return getHardShadow(shadowsampler, smTexCoord.xy, realDistance); } - float baseLength = getBaseLength(smTexCoord); - float perspectiveFactor; + vec2 clampedpos; + float visibility = 0.0; + float scale_factor = radius / f_textureresolution; - float texture_size = 1.0 / (f_textureresolution * 0.5); - int samples = int(clamp(PCFSAMPLES * (1 - baseLength) * (1 - baseLength), PCFSAMPLES / 4, PCFSAMPLES)); + int samples = (1 + 1 * int(SOFTSHADOWRADIUS > 1.0)) * PCFSAMPLES; // scale max samples for the soft shadows + samples = int(clamp(pow(4.0 * radius + 1.0, 2.0), 1.0, float(samples))); int init_offset = int(floor(mod(((smTexCoord.x * 34.0) + 1.0) * smTexCoord.y, 64.0-samples))); int end_offset = int(samples) + init_offset; for (int x = init_offset; x < end_offset; x++) { - clampedpos = poissonDisk[x]; - perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * radius); - clampedpos = clampedpos * texture_size * perspectiveFactor * radius * perspectiveFactor + smTexCoord.xy; + clampedpos = poissonDisk[x] * scale_factor + smTexCoord.xy; visibility += getHardShadow(shadowsampler, clampedpos.xy, realDistance); } @@ -341,65 +301,57 @@ float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance) vec4 getShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance) { - vec2 clampedpos; - vec4 visibility = vec4(0.0); - float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance, 1.0); + float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance); if (radius < 0.1) { // we are in the middle of even brightness, no need for filtering return getHardShadowColor(shadowsampler, smTexCoord.xy, realDistance); } - float baseLength = getBaseLength(smTexCoord); - float perspectiveFactor; - - float texture_size = 1.0 / (f_textureresolution * 0.5); - float y, x; - float bound = clamp(PCFBOUND * (1 - baseLength), PCFBOUND / 2, PCFBOUND); - int n = 0; + vec2 clampedpos; + vec4 visibility = vec4(0.0); + float x, y; + float bound = (1 + 0.5 * int(SOFTSHADOWRADIUS > 1.0)) * PCFBOUND; // scale max bound for soft shadows + bound = clamp(0.5 * (4.0 * radius - 1.0), 0.5, bound); + float scale_factor = radius / bound / f_textureresolution; + float n = 0.0; // basic PCF filter for (y = -bound; y <= bound; y += 1.0) for (x = -bound; x <= bound; x += 1.0) { - clampedpos = vec2(x,y); // screen offset - perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * radius / bound); - clampedpos = clampedpos * texture_size * perspectiveFactor * radius * perspectiveFactor / bound + smTexCoord.xy; // both dx,dy and radius are adjusted + clampedpos = vec2(x,y) * scale_factor + smTexCoord.xy; visibility += getHardShadowColor(shadowsampler, clampedpos.xy, realDistance); - n += 1; + n += 1.0; } - return visibility / n; + return visibility / max(n, 1.0); } #else float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance) { - vec2 clampedpos; - float visibility = 0.0; - float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance, 1.0); + float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance); if (radius < 0.1) { // we are in the middle of even brightness, no need for filtering return getHardShadow(shadowsampler, smTexCoord.xy, realDistance); } - float baseLength = getBaseLength(smTexCoord); - float perspectiveFactor; - - float texture_size = 1.0 / (f_textureresolution * 0.5); - float y, x; - float bound = clamp(PCFBOUND * (1 - baseLength), PCFBOUND / 2, PCFBOUND); - int n = 0; + vec2 clampedpos; + float visibility = 0.0; + float x, y; + float bound = (1 + 0.5 * int(SOFTSHADOWRADIUS > 1.0)) * PCFBOUND; // scale max bound for soft shadows + bound = clamp(0.5 * (4.0 * radius - 1.0), 0.5, bound); + float scale_factor = radius / bound / f_textureresolution; + float n = 0.0; // basic PCF filter for (y = -bound; y <= bound; y += 1.0) for (x = -bound; x <= bound; x += 1.0) { - clampedpos = vec2(x,y); // screen offset - perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * radius / bound); - clampedpos = clampedpos * texture_size * perspectiveFactor * radius * perspectiveFactor / bound + smTexCoord.xy; // both dx,dy and radius are adjusted + clampedpos = vec2(x,y) * scale_factor + smTexCoord.xy; visibility += getHardShadow(shadowsampler, clampedpos.xy, realDistance); - n += 1; + n += 1.0; } - return visibility / n; + return visibility / max(n, 1.0); } #endif diff --git a/client/shaders/nodes_shader/opengl_vertex.glsl b/client/shaders/nodes_shader/opengl_vertex.glsl index 3ea0faa36..d1fba2830 100644 --- a/client/shaders/nodes_shader/opengl_vertex.glsl +++ b/client/shaders/nodes_shader/opengl_vertex.glsl @@ -39,6 +39,7 @@ centroid varying vec2 varTexCoord; varying float adj_shadow_strength; varying float f_normal_length; varying vec3 shadow_position; + varying float perspective_factor; #endif @@ -253,6 +254,7 @@ void main(void) shadow_position = applyPerspectiveDistortion(m_ShadowViewProj * mWorld * (inVertexPosition + vec4(normalOffsetScale * nNormal, 0.0))).xyz; shadow_position.z -= z_bias; + perspective_factor = pFactor; if (f_timeofday < 0.2) { adj_shadow_strength = f_shadow_strength * 0.5 * diff --git a/client/shaders/object_shader/opengl_fragment.glsl b/client/shaders/object_shader/opengl_fragment.glsl index 7baf5826f..1fefc764b 100644 --- a/client/shaders/object_shader/opengl_fragment.glsl +++ b/client/shaders/object_shader/opengl_fragment.glsl @@ -1,6 +1,5 @@ uniform sampler2D baseTexture; -uniform vec4 emissiveColor; uniform vec3 dayLight; uniform vec4 skyBgColor; uniform float fogDistance; @@ -26,6 +25,7 @@ uniform float animationTimer; varying float cosLight; varying float f_normal_length; varying vec3 shadow_position; + varying float perspective_factor; #endif @@ -119,23 +119,16 @@ float getHardShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance #if SHADOW_FILTER == 2 - #define PCFBOUND 3.5 - #define PCFSAMPLES 64.0 + #define PCFBOUND 2.0 // 5x5 + #define PCFSAMPLES 25 #elif SHADOW_FILTER == 1 - #define PCFBOUND 1.5 - #if defined(POISSON_FILTER) - #define PCFSAMPLES 32.0 - #else - #define PCFSAMPLES 16.0 - #endif + #define PCFBOUND 1.0 // 3x3 + #define PCFSAMPLES 9 #else #define PCFBOUND 0.0 - #if defined(POISSON_FILTER) - #define PCFSAMPLES 4.0 - #else - #define PCFSAMPLES 1.0 - #endif + #define PCFSAMPLES 1 #endif + #ifdef COLORED_SHADOWS float getHardShadowDepth(sampler2D shadowsampler, vec2 smTexCoord, float realDistance) { @@ -152,59 +145,31 @@ float getHardShadowDepth(sampler2D shadowsampler, vec2 smTexCoord, float realDis } #endif -float getBaseLength(vec2 smTexCoord) -{ - float l = length(2.0 * smTexCoord.xy - 1.0 - CameraPos.xy); // length in texture coords - return xyPerspectiveBias1 / (1.0 / l - xyPerspectiveBias0); // return to undistorted coords -} +#define BASEFILTERRADIUS 1.0 -float getDeltaPerspectiveFactor(float l) +float getPenumbraRadius(sampler2D shadowsampler, vec2 smTexCoord, float realDistance) { - return 0.04 * pow(512.0 / f_textureresolution, 0.4) / (xyPerspectiveBias0 * l + xyPerspectiveBias1); // original distortion factor, divided by 10 -} - -float getPenumbraRadius(sampler2D shadowsampler, vec2 smTexCoord, float realDistance, float multiplier) -{ - float baseLength = getBaseLength(smTexCoord); - float perspectiveFactor; - // Return fast if sharp shadows are requested - if (PCFBOUND == 0.0) + if (PCFBOUND == 0.0 || SOFTSHADOWRADIUS <= 0.0) return 0.0; - if (SOFTSHADOWRADIUS <= 1.0) { - perspectiveFactor = getDeltaPerspectiveFactor(baseLength); - return max(2 * length(smTexCoord.xy) * 2048 / f_textureresolution / pow(perspectiveFactor, 3), SOFTSHADOWRADIUS); - } - vec2 clampedpos; - float texture_size = 1.0 / (2048 /*f_textureresolution*/ * 0.5); float y, x; - float depth = 0.0; - float pointDepth; - float maxRadius = SOFTSHADOWRADIUS * 5.0 * multiplier; + float depth = getHardShadowDepth(shadowsampler, smTexCoord.xy, realDistance); + // A factor from 0 to 1 to reduce blurring of short shadows + float sharpness_factor = 1.0; + // conversion factor from shadow depth to blur radius + float depth_to_blur = f_shadowfar / SOFTSHADOWRADIUS / xyPerspectiveBias0; + if (depth > 0.0 && f_normal_length > 0.0) + // 5 is empirical factor that controls how fast shadow loses sharpness + sharpness_factor = clamp(5 * depth * depth_to_blur, 0.0, 1.0); + depth = 0.0; - float bound = clamp(PCFBOUND * (1 - baseLength), 0.0, PCFBOUND); - int n = 0; + float world_to_texture = xyPerspectiveBias1 / perspective_factor / perspective_factor + * f_textureresolution / 2.0 / f_shadowfar; + float world_radius = 0.2; // shadow blur radius in world float coordinates, e.g. 0.2 = 0.02 of one node - for (y = -bound; y <= bound; y += 1.0) - for (x = -bound; x <= bound; x += 1.0) { - clampedpos = vec2(x,y); - perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * maxRadius); - clampedpos = clampedpos * texture_size * perspectiveFactor * maxRadius * perspectiveFactor + smTexCoord.xy; - - pointDepth = getHardShadowDepth(shadowsampler, clampedpos.xy, realDistance); - if (pointDepth > -0.01) { - depth += pointDepth; - n += 1; - } - } - - depth = depth / n; - depth = pow(clamp(depth, 0.0, 1000.0), 1.6) / 0.001; - - perspectiveFactor = getDeltaPerspectiveFactor(baseLength); - return max(length(smTexCoord.xy) * 2 * 2048 / f_textureresolution / pow(perspectiveFactor, 3), depth * maxRadius); + return max(BASEFILTERRADIUS * f_textureresolution / 4096.0, sharpness_factor * world_radius * world_to_texture * SOFTSHADOWRADIUS); } #ifdef POISSON_FILTER @@ -279,26 +244,23 @@ const vec2[64] poissonDisk = vec2[64]( vec4 getShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance) { - vec2 clampedpos; - vec4 visibility = vec4(0.0); - float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance, 1.5); // scale to align with PCF + float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance); if (radius < 0.1) { // we are in the middle of even brightness, no need for filtering return getHardShadowColor(shadowsampler, smTexCoord.xy, realDistance); } - float baseLength = getBaseLength(smTexCoord); - float perspectiveFactor; + vec2 clampedpos; + vec4 visibility = vec4(0.0); + float scale_factor = radius / f_textureresolution; - float texture_size = 1.0 / (f_textureresolution * 0.5); - int samples = int(clamp(PCFSAMPLES * (1 - baseLength) * (1 - baseLength), PCFSAMPLES / 4, PCFSAMPLES)); + int samples = (1 + 1 * int(SOFTSHADOWRADIUS > 1.0)) * PCFSAMPLES; // scale max samples for the soft shadows + samples = int(clamp(pow(4.0 * radius + 1.0, 2.0), 1.0, float(samples))); int init_offset = int(floor(mod(((smTexCoord.x * 34.0) + 1.0) * smTexCoord.y, 64.0-samples))); int end_offset = int(samples) + init_offset; for (int x = init_offset; x < end_offset; x++) { - clampedpos = poissonDisk[x]; - perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * radius); - clampedpos = clampedpos * texture_size * perspectiveFactor * radius * perspectiveFactor + smTexCoord.xy; + clampedpos = poissonDisk[x] * scale_factor + smTexCoord.xy; visibility += getHardShadowColor(shadowsampler, clampedpos.xy, realDistance); } @@ -309,26 +271,23 @@ vec4 getShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance) { - vec2 clampedpos; - float visibility = 0.0; - float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance, 1.5); // scale to align with PCF + float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance); if (radius < 0.1) { // we are in the middle of even brightness, no need for filtering return getHardShadow(shadowsampler, smTexCoord.xy, realDistance); } - float baseLength = getBaseLength(smTexCoord); - float perspectiveFactor; + vec2 clampedpos; + float visibility = 0.0; + float scale_factor = radius / f_textureresolution; - float texture_size = 1.0 / (f_textureresolution * 0.5); - int samples = int(clamp(PCFSAMPLES * (1 - baseLength) * (1 - baseLength), PCFSAMPLES / 4, PCFSAMPLES)); + int samples = (1 + 1 * int(SOFTSHADOWRADIUS > 1.0)) * PCFSAMPLES; // scale max samples for the soft shadows + samples = int(clamp(pow(4.0 * radius + 1.0, 2.0), 1.0, float(samples))); int init_offset = int(floor(mod(((smTexCoord.x * 34.0) + 1.0) * smTexCoord.y, 64.0-samples))); int end_offset = int(samples) + init_offset; for (int x = init_offset; x < end_offset; x++) { - clampedpos = poissonDisk[x]; - perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * radius); - clampedpos = clampedpos * texture_size * perspectiveFactor * radius * perspectiveFactor + smTexCoord.xy; + clampedpos = poissonDisk[x] * scale_factor + smTexCoord.xy; visibility += getHardShadow(shadowsampler, clampedpos.xy, realDistance); } @@ -344,65 +303,57 @@ float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance) vec4 getShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance) { - vec2 clampedpos; - vec4 visibility = vec4(0.0); - float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance, 1.0); + float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance); if (radius < 0.1) { // we are in the middle of even brightness, no need for filtering return getHardShadowColor(shadowsampler, smTexCoord.xy, realDistance); } - float baseLength = getBaseLength(smTexCoord); - float perspectiveFactor; - - float texture_size = 1.0 / (f_textureresolution * 0.5); - float y, x; - float bound = clamp(PCFBOUND * (1 - baseLength), PCFBOUND / 2, PCFBOUND); - int n = 0; + vec2 clampedpos; + vec4 visibility = vec4(0.0); + float x, y; + float bound = (1 + 0.5 * int(SOFTSHADOWRADIUS > 1.0)) * PCFBOUND; // scale max bound for soft shadows + bound = clamp(0.5 * (4.0 * radius - 1.0), 0.5, bound); + float scale_factor = radius / bound / f_textureresolution; + float n = 0.0; // basic PCF filter for (y = -bound; y <= bound; y += 1.0) for (x = -bound; x <= bound; x += 1.0) { - clampedpos = vec2(x,y); // screen offset - perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * radius / bound); - clampedpos = clampedpos * texture_size * perspectiveFactor * radius * perspectiveFactor / bound + smTexCoord.xy; // both dx,dy and radius are adjusted + clampedpos = vec2(x,y) * scale_factor + smTexCoord.xy; visibility += getHardShadowColor(shadowsampler, clampedpos.xy, realDistance); - n += 1; + n += 1.0; } - return visibility / n; + return visibility / max(n, 1.0); } #else float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance) { - vec2 clampedpos; - float visibility = 0.0; - float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance, 1.0); + float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance); if (radius < 0.1) { // we are in the middle of even brightness, no need for filtering return getHardShadow(shadowsampler, smTexCoord.xy, realDistance); } - float baseLength = getBaseLength(smTexCoord); - float perspectiveFactor; - - float texture_size = 1.0 / (f_textureresolution * 0.5); - float y, x; - float bound = clamp(PCFBOUND * (1 - baseLength), PCFBOUND / 2, PCFBOUND); - int n = 0; + vec2 clampedpos; + float visibility = 0.0; + float x, y; + float bound = (1 + 0.5 * int(SOFTSHADOWRADIUS > 1.0)) * PCFBOUND; // scale max bound for soft shadows + bound = clamp(0.5 * (4.0 * radius - 1.0), 0.5, bound); + float scale_factor = radius / bound / f_textureresolution; + float n = 0.0; // basic PCF filter for (y = -bound; y <= bound; y += 1.0) for (x = -bound; x <= bound; x += 1.0) { - clampedpos = vec2(x,y); // screen offset - perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * radius / bound); - clampedpos = clampedpos * texture_size * perspectiveFactor * radius * perspectiveFactor / bound + smTexCoord.xy; // both dx,dy and radius are adjusted + clampedpos = vec2(x,y) * scale_factor + smTexCoord.xy; visibility += getHardShadow(shadowsampler, clampedpos.xy, realDistance); - n += 1; + n += 1.0; } - return visibility / n; + return visibility / max(n, 1.0); } #endif @@ -489,7 +440,6 @@ void main(void) shadow_color = visibility.gba; #else if (cosLight > 0.0 || f_normal_length < 1e-3) - if (cosLight > 0.0) shadow_int = getShadow(ShadowMapSampler, posLightSpace.xy, posLightSpace.z); else shadow_int = 1.0; @@ -540,6 +490,6 @@ void main(void) - fogShadingParameter * length(eyeVec) / fogDistance, 0.0, 1.0); col = mix(skyBgColor, col, clarity); col = vec4(col.rgb, base.a); - + gl_FragColor = col; } diff --git a/client/shaders/object_shader/opengl_vertex.glsl b/client/shaders/object_shader/opengl_vertex.glsl index 6dc25f854..dc9c70cdf 100644 --- a/client/shaders/object_shader/opengl_vertex.glsl +++ b/client/shaders/object_shader/opengl_vertex.glsl @@ -30,6 +30,7 @@ centroid varying vec2 varTexCoord; varying float adj_shadow_strength; varying float f_normal_length; varying vec3 shadow_position; + varying float perspective_factor; #endif varying vec3 eyeVec; @@ -162,6 +163,7 @@ void main(void) shadow_position = applyPerspectiveDistortion(m_ShadowViewProj * mWorld * (inVertexPosition + vec4(normalOffsetScale * nNormal, 0.0))).xyz; shadow_position.z -= z_bias; + perspective_factor = pFactor; if (f_timeofday < 0.2) { adj_shadow_strength = f_shadow_strength * 0.5 * diff --git a/src/client/clientmap.cpp b/src/client/clientmap.cpp index 10967c0cb..46cb115aa 100644 --- a/src/client/clientmap.cpp +++ b/src/client/clientmap.cpp @@ -489,6 +489,8 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) // Do not enable filter on shadow texture to avoid visual artifacts // with colored shadows. // Filtering is done in shader code anyway + layer.BilinearFilter = false; + layer.AnisotropicFilter = false; layer.TrilinearFilter = false; } driver->setMaterial(material); diff --git a/src/client/shader.cpp b/src/client/shader.cpp index bbb872761..009a4b3d7 100644 --- a/src/client/shader.cpp +++ b/src/client/shader.cpp @@ -771,6 +771,8 @@ ShaderInfo ShaderSource::generateShader(const std::string &name, shaders_header << "#define SOFTSHADOWRADIUS " << shadow_soft_radius << "\n"; } + shaders_header << "#line 0\n"; // reset the line counter for meaningful diagnostics + std::string common_header = shaders_header.str(); std::string vertex_shader = m_sourcecache.getOrLoad(name, "opengl_vertex.glsl"); diff --git a/src/client/shadows/dynamicshadowsrender.cpp b/src/client/shadows/dynamicshadowsrender.cpp index 07dc6daf2..c13cfe252 100644 --- a/src/client/shadows/dynamicshadowsrender.cpp +++ b/src/client/shadows/dynamicshadowsrender.cpp @@ -670,6 +670,7 @@ std::string ShadowRenderer::readShaderFile(const std::string &path) std::string prefix; if (m_shadow_map_colored) prefix.append("#define COLORED_SHADOWS 1\n"); + prefix.append("#line 0\n"); std::string content; fs::ReadFile(path, content); diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index 11d52efd3..0087f8d48 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -274,7 +274,7 @@ void set_default_settings() settings->setDefault("shadow_filters", "1"); settings->setDefault("shadow_poisson_filter", "true"); settings->setDefault("shadow_update_frames", "8"); - settings->setDefault("shadow_soft_radius", "1.0"); + settings->setDefault("shadow_soft_radius", "5.0"); settings->setDefault("shadow_sky_body_orbit_tilt", "0.0"); // Input From 4e9e230e34912d08ec0f0fc01d14ef80654c7cac Mon Sep 17 00:00:00 2001 From: rubenwardy Date: Sat, 21 May 2022 16:23:30 +0100 Subject: [PATCH 04/13] Deprecate game.conf name, use title instead (#12030) --- builtin/mainmenu/dlg_contentstore.lua | 16 ++++------ builtin/mainmenu/pkgmgr.lua | 8 +++-- builtin/mainmenu/tab_local.lua | 2 +- doc/lua_api.txt | 3 +- doc/menu_lua_api.txt | 6 ++-- games/devtest/game.conf | 2 +- src/content/content.cpp | 7 +++- src/content/content.h | 7 ++++ src/content/subgames.cpp | 46 ++++++++++++++++++++++----- src/content/subgames.h | 10 ++++-- src/script/lua_api/l_mainmenu.cpp | 11 ++++++- src/server.cpp | 3 +- 12 files changed, 90 insertions(+), 31 deletions(-) diff --git a/builtin/mainmenu/dlg_contentstore.lua b/builtin/mainmenu/dlg_contentstore.lua index 276a7b096..16ab1c3a7 100644 --- a/builtin/mainmenu/dlg_contentstore.lua +++ b/builtin/mainmenu/dlg_contentstore.lua @@ -151,11 +151,9 @@ local function start_install(package, reason) if conf_path then local conf = Settings(conf_path) - if name_is_title then - conf:set("name", package.title) - else - conf:set("title", package.title) - conf:set("name", package.name) + conf:set("title", package.title) + if not name_is_title then + conf:set("name", package.name) end if not conf:get("description") then conf:set("description", package.short_description) @@ -360,7 +358,7 @@ function install_dialog.get_formspec() selected_game_idx = i end - games[i] = core.formspec_escape(games[i].name) + games[i] = core.formspec_escape(games[i].title) end local selected_game = pkgmgr.games[selected_game_idx] @@ -410,7 +408,7 @@ function install_dialog.get_formspec() "container[0.375,0.70]", "label[0,0.25;", fgettext("Base Game:"), "]", - "dropdown[2,0;4.25,0.5;gameid;", table.concat(games, ","), ";", selected_game_idx, "]", + "dropdown[2,0;4.25,0.5;selected_game;", table.concat(games, ","), ";", selected_game_idx, "]", "label[0,0.8;", fgettext("Dependencies:"), "]", @@ -461,9 +459,9 @@ function install_dialog.handle_submit(this, fields) return true end - if fields.gameid then + if fields.selected_game then for _, game in pairs(pkgmgr.games) do - if game.name == fields.gameid then + if game.title == fields.selected_game then core.settings:set("menu_last_game", game.id) break end diff --git a/builtin/mainmenu/pkgmgr.lua b/builtin/mainmenu/pkgmgr.lua index 334fcf5f8..b2f3243c4 100644 --- a/builtin/mainmenu/pkgmgr.lua +++ b/builtin/mainmenu/pkgmgr.lua @@ -646,6 +646,8 @@ function pkgmgr.install_dir(type, path, basename, targetpath) else targetpath = core.get_gamepath() .. DIR_DELIM .. basename end + else + error("basefolder didn't return a recognised type, this shouldn't happen") end -- Copy it @@ -692,7 +694,7 @@ function pkgmgr.preparemodlist(data) retval[#retval + 1] = { type = "game", is_game_content = true, - name = fgettext("$1 mods", gamespec.name), + name = fgettext("$1 mods", gamespec.title), path = gamespec.path } end @@ -873,10 +875,10 @@ end function pkgmgr.gamelist() local retval = "" if #pkgmgr.games > 0 then - retval = retval .. core.formspec_escape(pkgmgr.games[1].name) + retval = retval .. core.formspec_escape(pkgmgr.games[1].title) for i=2,#pkgmgr.games,1 do - retval = retval .. "," .. core.formspec_escape(pkgmgr.games[i].name) + retval = retval .. "," .. core.formspec_escape(pkgmgr.games[i].title) end end return retval diff --git a/builtin/mainmenu/tab_local.lua b/builtin/mainmenu/tab_local.lua index e77c6f04d..049d16507 100644 --- a/builtin/mainmenu/tab_local.lua +++ b/builtin/mainmenu/tab_local.lua @@ -88,7 +88,7 @@ if enable_gamebar then local image = nil local text = nil - local tooltip = core.formspec_escape(game.name) + local tooltip = core.formspec_escape(game.title) if (game.menuicon_path or "") ~= "" then image = core.formspec_escape(game.menuicon_path) diff --git a/doc/lua_api.txt b/doc/lua_api.txt index abfaf08aa..6046a5902 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -62,7 +62,8 @@ Where `` is unique to each game. The game directory can contain the following files: * `game.conf`, with the following keys: - * `name`: Required, a human readable title to address the game, e.g. `name = Minetest`. + * `title`: Required, a human-readable title to address the game, e.g. `title = Minetest Game`. + * `name`: (Deprecated) same as title. * `description`: Short description to be shown in the content tab * `allowed_mapgens = ` e.g. `allowed_mapgens = v5,v6,flat` diff --git a/doc/menu_lua_api.txt b/doc/menu_lua_api.txt index c2931af31..68e7b4b9d 100644 --- a/doc/menu_lua_api.txt +++ b/doc/menu_lua_api.txt @@ -246,13 +246,14 @@ Package - content which is downloadable from the content db, may or may not be i * core.get_texturepath() (possible in async calls) * returns path to default textures * core.get_game(index) + * `name` in return value is deprecated, use `title` instead. * returns: { id = , path = , gamemods_path = , - name = , + title = , menuicon_path = <full path to menuicon>, author = "author", DEPRECATED: @@ -264,8 +265,9 @@ Package - content which is downloadable from the content db, may or may not be i * returns { - name = "name of content", + name = "technical_id", type = "mod" or "modpack" or "game" or "txp", + title = "Human readable title", description = "description", author = "author", path = "path/to/content", diff --git a/games/devtest/game.conf b/games/devtest/game.conf index d6e382ad7..0f5656c99 100644 --- a/games/devtest/game.conf +++ b/games/devtest/game.conf @@ -1,2 +1,2 @@ -name = Development Test +title = Development Test description = Testing environment to help with testing the engine features of Minetest. It can also be helpful in mod development. diff --git a/src/content/content.cpp b/src/content/content.cpp index 66ef83d42..e576943ff 100644 --- a/src/content/content.cpp +++ b/src/content/content.cpp @@ -96,7 +96,12 @@ void parseContentInfo(ContentSpec &spec) Settings conf; if (!conf_path.empty() && conf.readConfigFile(conf_path.c_str())) { - if (conf.exists("name")) + if (conf.exists("title")) + spec.title = conf.get("title"); + else if (spec.type == "game" && conf.exists("name")) + spec.title = conf.get("name"); + + if (spec.type != "game" && conf.exists("name")) spec.name = conf.get("name"); if (conf.exists("description")) diff --git a/src/content/content.h b/src/content/content.h index e246ed411..ce09a2eb9 100644 --- a/src/content/content.h +++ b/src/content/content.h @@ -27,7 +27,14 @@ struct ContentSpec std::string type; std::string author; u32 release = 0; + + /// Technical name / Id std::string name; + + /// Human-readable title + std::string title; + + /// Short description std::string desc; std::string path; }; diff --git a/src/content/subgames.cpp b/src/content/subgames.cpp index 23355990e..d0de926ef 100644 --- a/src/content/subgames.cpp +++ b/src/content/subgames.cpp @@ -17,6 +17,7 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include <common/c_internal.h> #include "content/subgames.h" #include "porting.h" #include "filesys.h" @@ -45,6 +46,25 @@ bool getGameMinetestConfig(const std::string &game_path, Settings &conf) } + +void SubgameSpec::checkAndLog() const +{ + // Log deprecation messages + auto handling_mode = get_deprecated_handling_mode(); + if (!deprecation_msgs.empty() && handling_mode != DeprecatedHandlingMode::Ignore) { + std::ostringstream os; + os << "Game " << title << " at " << path << ":" << std::endl; + for (auto msg : deprecation_msgs) + os << "\t" << msg << std::endl; + + if (handling_mode == DeprecatedHandlingMode::Error) + throw ModError(os.str()); + else + warningstream << os.str(); + } +} + + struct GameFindPath { std::string path; @@ -121,11 +141,13 @@ SubgameSpec findSubgame(const std::string &id) Settings conf; conf.readConfigFile(conf_path.c_str()); - std::string game_name; - if (conf.exists("name")) - game_name = conf.get("name"); + std::string game_title; + if (conf.exists("title")) + game_title = conf.get("title"); + else if (conf.exists("name")) + game_title = conf.get("name"); else - game_name = id; + game_title = id; std::string game_author; if (conf.exists("author")) @@ -140,8 +162,14 @@ SubgameSpec findSubgame(const std::string &id) menuicon_path = getImagePath( game_path + DIR_DELIM + "menu" + DIR_DELIM + "icon.png"); #endif - return SubgameSpec(id, game_path, gamemod_path, mods_paths, game_name, + + SubgameSpec spec(id, game_path, gamemod_path, mods_paths, game_title, menuicon_path, game_author, game_release); + + if (conf.exists("name") && !conf.exists("title")) + spec.deprecation_msgs.push_back("\"name\" setting in game.conf is deprecated, please use \"title\" instead"); + + return spec; } SubgameSpec findWorldSubgame(const std::string &world_path) @@ -159,10 +187,12 @@ SubgameSpec findWorldSubgame(const std::string &world_path) std::string conf_path = world_gamepath + DIR_DELIM + "game.conf"; conf.readConfigFile(conf_path.c_str()); - if (conf.exists("name")) - gamespec.name = conf.get("name"); + if (conf.exists("title")) + gamespec.title = conf.get("title"); + else if (conf.exists("name")) + gamespec.title = conf.get("name"); else - gamespec.name = world_gameid; + gamespec.title = world_gameid; return gamespec; } diff --git a/src/content/subgames.h b/src/content/subgames.h index d36b4952f..d5d168243 100644 --- a/src/content/subgames.h +++ b/src/content/subgames.h @@ -29,7 +29,7 @@ class Settings; struct SubgameSpec { std::string id; - std::string name; + std::string title; std::string author; int release; std::string path; @@ -41,20 +41,24 @@ struct SubgameSpec std::unordered_map<std::string, std::string> addon_mods_paths; std::string menuicon_path; + // For logging purposes + std::vector<const char *> deprecation_msgs; + SubgameSpec(const std::string &id = "", const std::string &path = "", const std::string &gamemods_path = "", const std::unordered_map<std::string, std::string> &addon_mods_paths = {}, - const std::string &name = "", + const std::string &title = "", const std::string &menuicon_path = "", const std::string &author = "", int release = 0) : id(id), - name(name), author(author), release(release), path(path), + title(title), author(author), release(release), path(path), gamemods_path(gamemods_path), addon_mods_paths(addon_mods_paths), menuicon_path(menuicon_path) { } bool isValid() const { return (!id.empty() && !path.empty()); } + void checkAndLog() const; }; SubgameSpec findSubgame(const std::string &id); diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp index db031dde5..4d9fa5b14 100644 --- a/src/script/lua_api/l_mainmenu.cpp +++ b/src/script/lua_api/l_mainmenu.cpp @@ -304,7 +304,11 @@ int ModApiMainMenu::l_get_games(lua_State *L) lua_settable(L, top_lvl2); lua_pushstring(L, "name"); - lua_pushstring(L, game.name.c_str()); + lua_pushstring(L, game.title.c_str()); + lua_settable(L, top_lvl2); + + lua_pushstring(L, "title"); + lua_pushstring(L, game.title.c_str()); lua_settable(L, top_lvl2); lua_pushstring(L, "author"); @@ -356,6 +360,11 @@ int ModApiMainMenu::l_get_content_info(lua_State *L) lua_pushstring(L, spec.author.c_str()); lua_setfield(L, -2, "author"); + if (!spec.title.empty()) { + lua_pushstring(L, spec.title.c_str()); + lua_setfield(L, -2, "title"); + } + lua_pushinteger(L, spec.release); lua_setfield(L, -2, "release"); diff --git a/src/server.cpp b/src/server.cpp index d93f300d2..b6330c96a 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -440,6 +440,7 @@ void Server::init() m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME); + m_gamespec.checkAndLog(); m_modmgr->loadMods(m_script); // Read Textures and calculate sha1 sums @@ -3109,7 +3110,7 @@ std::string Server::getStatusString() // Version os << "version: " << g_version_string; // Game - os << " | game: " << (m_gamespec.name.empty() ? m_gamespec.id : m_gamespec.name); + os << " | game: " << (m_gamespec.title.empty() ? m_gamespec.id : m_gamespec.title); // Uptime os << " | uptime: " << duration_to_string((int) m_uptime_counter->get()); // Max lag estimate From 70dc23f996683a59dd85db74e8f15e49c4f7b9fd Mon Sep 17 00:00:00 2001 From: sfan5 <sfan5@live.de> Date: Sun, 1 May 2022 13:43:29 +0200 Subject: [PATCH 05/13] Improve testSerializeJsonString unit tests this also removes the requirement that / is escaped, there is no reason for doing so. --- src/unittest/test.h | 2 +- src/unittest/test_serialization.cpp | 76 +++++++++++++++++++++++------ src/util/serialize.cpp | 3 -- 3 files changed, 61 insertions(+), 20 deletions(-) diff --git a/src/unittest/test.h b/src/unittest/test.h index 1102f6d33..79ea09471 100644 --- a/src/unittest/test.h +++ b/src/unittest/test.h @@ -80,7 +80,7 @@ class TestFailedException : public std::exception { << #expected << std::endl \ << " at " << fs::GetFilenameFromPath(__FILE__) << ":" \ << __LINE__ << std::endl \ - << " actual: " << a << std::endl << " expected: " \ + << " actual : " << a << std::endl << " expected: " \ << e << std::endl; \ throw TestFailedException(); \ } \ diff --git a/src/unittest/test_serialization.cpp b/src/unittest/test_serialization.cpp index 660d77d02..ff6b57507 100644 --- a/src/unittest/test_serialization.cpp +++ b/src/unittest/test_serialization.cpp @@ -169,23 +169,50 @@ void TestSerialization::testDeSerializeLongString() void TestSerialization::testSerializeJsonString() { + std::istringstream is(std::ios::binary); + const auto reset_is = [&] (const std::string &s) { + is.clear(); + is.str(s); + }; + const auto assert_at_eof = [] (std::istream &is) { + is.get(); + UASSERT(is.eof()); + }; + // Test blank string - UASSERT(serializeJsonString("") == "\"\""); + UASSERTEQ(std::string, serializeJsonString(""), "\"\""); + reset_is("\"\""); + UASSERTEQ(std::string, deSerializeJsonString(is), ""); + assert_at_eof(is); // Test basic string - UASSERT(serializeJsonString("Hello world!") == "\"Hello world!\""); + UASSERTEQ(std::string, serializeJsonString("Hello world!"), "\"Hello world!\""); + reset_is("\"Hello world!\""); + UASSERTEQ(std::string, deSerializeJsonString(is), "Hello world!"); + assert_at_eof(is); - // MSVC fails when directly using "\\\\" - std::string backslash = "\\"; - UASSERT(serializeJsonString(teststring2) == - mkstr("\"") + + // Test optional serialization + const std::pair<const char*, const char*> test_pairs[] = { + { "abc", "abc" }, + { "x y z", "\"x y z\"" }, + { "\"", "\"\\\"\"" }, + }; + for (auto it : test_pairs) { + UASSERTEQ(std::string, serializeJsonStringIfNeeded(it.first), it.second); + reset_is(it.second); + UASSERTEQ(std::string, deSerializeJsonStringIfNeeded(is), it.first); + assert_at_eof(is); + } + + // Test all byte values + const std::string bs = "\\"; // MSVC fails when directly using "\\\\" + const std::string expected = mkstr("\"") + "\\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007" + "\\b\\t\\n\\u000b\\f\\r\\u000e\\u000f" + "\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017" + "\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f" + - " !\\\"" + teststring2.substr(0x23, 0x2f-0x23) + - "\\/" + teststring2.substr(0x30, 0x5c-0x30) + - backslash + backslash + teststring2.substr(0x5d, 0x7f-0x5d) + "\\u007f" + + " !\\\"" + teststring2.substr(0x23, 0x5c-0x23) + + bs + bs + teststring2.substr(0x5d, 0x7f-0x5d) + "\\u007f" + "\\u0080\\u0081\\u0082\\u0083\\u0084\\u0085\\u0086\\u0087" + "\\u0088\\u0089\\u008a\\u008b\\u008c\\u008d\\u008e\\u008f" + "\\u0090\\u0091\\u0092\\u0093\\u0094\\u0095\\u0096\\u0097" + @@ -202,14 +229,31 @@ void TestSerialization::testSerializeJsonString() "\\u00e8\\u00e9\\u00ea\\u00eb\\u00ec\\u00ed\\u00ee\\u00ef" + "\\u00f0\\u00f1\\u00f2\\u00f3\\u00f4\\u00f5\\u00f6\\u00f7" + "\\u00f8\\u00f9\\u00fa\\u00fb\\u00fc\\u00fd\\u00fe\\u00ff" + - "\""); + "\""; + std::string serialized = serializeJsonString(teststring2); + UASSERTEQ(std::string, serialized, expected); - // Test deserialize - std::istringstream is(serializeJsonString(teststring2), std::ios::binary); - UASSERT(deSerializeJsonString(is) == teststring2); - UASSERT(!is.eof()); - is.get(); - UASSERT(is.eof()); + reset_is(serialized); + UASSERTEQ(std::string, deSerializeJsonString(is), teststring2); + UASSERT(!is.eof()); // should have stopped at " so eof must not be set yet + assert_at_eof(is); + + // Test that deserialization leaves rest of stream alone + std::string tmp; + reset_is("\"foo\"bar"); + UASSERTEQ(std::string, deSerializeJsonString(is), "foo"); + std::getline(is, tmp, '\0'); + UASSERTEQ(std::string, tmp, "bar"); + + reset_is("\"x y z\"bar"); + UASSERTEQ(std::string, deSerializeJsonStringIfNeeded(is), "x y z"); + std::getline(is, tmp, '\0'); + UASSERTEQ(std::string, tmp, "bar"); + + reset_is("foo bar"); + UASSERTEQ(std::string, deSerializeJsonStringIfNeeded(is), "foo"); + std::getline(is, tmp, '\0'); + UASSERTEQ(std::string, tmp, " bar"); } diff --git a/src/util/serialize.cpp b/src/util/serialize.cpp index 281061229..32e0a8936 100644 --- a/src/util/serialize.cpp +++ b/src/util/serialize.cpp @@ -136,9 +136,6 @@ std::string serializeJsonString(const std::string &plain) case '\\': os << "\\\\"; break; - case '/': - os << "\\/"; - break; case '\b': os << "\\b"; break; From 9ee3dc71f1bb094c04afe98832f69f2a95995340 Mon Sep 17 00:00:00 2001 From: sfan5 <sfan5@live.de> Date: Sun, 1 May 2022 13:44:42 +0200 Subject: [PATCH 06/13] Optimize JSON string (de)serialization routines stringstreams were shown to be slow when reading/writing single characters and there is lots of potential by having functions perform on existing buffers whenever possible. --- src/util/serialize.cpp | 215 +++++++++++++++++++++-------------------- 1 file changed, 112 insertions(+), 103 deletions(-) diff --git a/src/util/serialize.cpp b/src/util/serialize.cpp index 32e0a8936..ee46fd941 100644 --- a/src/util/serialize.cpp +++ b/src/util/serialize.cpp @@ -18,15 +18,14 @@ with this program; if not, write to the Free Software Foundation, Inc., */ #include "serialize.h" -#include "pointer.h" #include "porting.h" #include "util/string.h" +#include "util/hex.h" #include "exceptions.h" #include "irrlichttypes.h" -#include <sstream> -#include <iomanip> -#include <vector> +#include <iostream> +#include <cassert> FloatType g_serialize_f32_type = FLOATTYPE_UNKNOWN; @@ -120,118 +119,148 @@ std::string deSerializeString32(std::istream &is) } //// -//// JSON +//// JSON-like strings //// std::string serializeJsonString(const std::string &plain) { - std::ostringstream os(std::ios::binary); - os << "\""; + std::string tmp; + + tmp.reserve(plain.size() + 2); + tmp.push_back('"'); for (char c : plain) { switch (c) { case '"': - os << "\\\""; + tmp.append("\\\""); break; case '\\': - os << "\\\\"; + tmp.append("\\\\"); break; case '\b': - os << "\\b"; + tmp.append("\\b"); break; case '\f': - os << "\\f"; + tmp.append("\\f"); break; case '\n': - os << "\\n"; + tmp.append("\\n"); break; case '\r': - os << "\\r"; + tmp.append("\\r"); break; case '\t': - os << "\\t"; + tmp.append("\\t"); break; default: { if (c >= 32 && c <= 126) { - os << c; + tmp.push_back(c); } else { - u32 cnum = (u8)c; - os << "\\u" << std::hex << std::setw(4) - << std::setfill('0') << cnum; + // We pretend that Unicode codepoints map to bytes (they don't) + u8 cnum = static_cast<u8>(c); + tmp.append("\\u00"); + tmp.push_back(hex_chars[cnum >> 4]); + tmp.push_back(hex_chars[cnum & 0xf]); } break; } } } - os << "\""; - return os.str(); + tmp.push_back('"'); + return tmp; +} + +static void deSerializeJsonString(std::string &s) +{ + assert(s.size() >= 2); + assert(s.front() == '"' && s.back() == '"'); + + size_t w = 0; // write index + size_t i = 1; // read index + const size_t len = s.size() - 1; // string length with trailing quote removed + + while (i < len) { + char c = s[i++]; + assert(c != '"'); + + if (c != '\\') { + s[w++] = c; + continue; + } + + if (i >= len) + throw SerializationError("JSON string ended prematurely"); + char c2 = s[i++]; + switch (c2) { + case 'b': + s[w++] = '\b'; + break; + case 'f': + s[w++] = '\f'; + break; + case 'n': + s[w++] = '\n'; + break; + case 'r': + s[w++] = '\r'; + break; + case 't': + s[w++] = '\t'; + break; + case 'u': { + if (i + 3 >= len) + throw SerializationError("JSON string ended prematurely"); + unsigned char v[4] = {}; + for (int j = 0; j < 4; j++) + hex_digit_decode(s[i+j], v[j]); + i += 4; + u32 hexnumber = (v[0] << 12) | (v[1] << 8) | (v[2] << 4) | v[3]; + // Note that this does not work for anything other than ASCII + // but these functions do not actually interact with real JSON input. + s[w++] = (int) hexnumber; + break; + } + default: + s[w++] = c2; + break; + } + } + + assert(w <= i && i <= len); + // Truncate string to current write index + s.resize(w); } std::string deSerializeJsonString(std::istream &is) { - std::ostringstream os(std::ios::binary); - char c, c2; + std::string tmp; + char c; + bool was_backslash = false; // Parse initial doublequote - is >> c; + c = is.get(); if (c != '"') throw SerializationError("JSON string must start with doublequote"); + tmp.push_back(c); - // Parse characters + // Grab the entire json string for (;;) { c = is.get(); if (is.eof()) throw SerializationError("JSON string ended prematurely"); - if (c == '"') { - return os.str(); - } - - if (c == '\\') { - c2 = is.get(); - if (is.eof()) - throw SerializationError("JSON string ended prematurely"); - switch (c2) { - case 'b': - os << '\b'; - break; - case 'f': - os << '\f'; - break; - case 'n': - os << '\n'; - break; - case 'r': - os << '\r'; - break; - case 't': - os << '\t'; - break; - case 'u': { - int hexnumber; - char hexdigits[4 + 1]; - - is.read(hexdigits, 4); - if (is.eof()) - throw SerializationError("JSON string ended prematurely"); - hexdigits[4] = 0; - - std::istringstream tmp_is(hexdigits, std::ios::binary); - tmp_is >> std::hex >> hexnumber; - os << (char)hexnumber; - break; - } - default: - os << c2; - break; - } - } else { - os << c; - } + tmp.push_back(c); + if (was_backslash) + was_backslash = false; + else if (c == '\\') + was_backslash = true; + else if (c == '"') + break; // found end of string } - return os.str(); + deSerializeJsonString(tmp); + return tmp; } std::string serializeJsonStringIfNeeded(const std::string &s) @@ -245,41 +274,21 @@ std::string serializeJsonStringIfNeeded(const std::string &s) std::string deSerializeJsonStringIfNeeded(std::istream &is) { - std::stringstream tmp_os(std::ios_base::binary | std::ios_base::in | std::ios_base::out); - bool expect_initial_quote = true; - bool is_json = false; - bool was_backslash = false; - for (;;) { - char c = is.get(); - if (is.eof()) - break; + // Check for initial quote + char c = is.peek(); + if (is.eof()) + return ""; - if (expect_initial_quote && c == '"') { - tmp_os << c; - is_json = true; - } else if(is_json) { - tmp_os << c; - if (was_backslash) - was_backslash = false; - else if (c == '\\') - was_backslash = true; - else if (c == '"') - break; // Found end of string - } else { - if (c == ' ') { - // Found end of word - is.unget(); - break; - } - - tmp_os << c; - } - expect_initial_quote = false; - } - if (is_json) { - return deSerializeJsonString(tmp_os); + if (c == '"') { + // json string: defer to the right implementation + return deSerializeJsonString(is); } - return tmp_os.str(); + // not a json string: + std::string tmp; + std::getline(is, tmp, ' '); + if (!is.eof()) + is.unget(); // we hit a space, put it back + return tmp; } From e1f707d7e1ac0412eedbfcc200a1b90339d3ab0d Mon Sep 17 00:00:00 2001 From: paradust7 <102263465+paradust7@users.noreply.github.com> Date: Sat, 21 May 2022 08:46:50 -0700 Subject: [PATCH 07/13] Patch built-in Lua to fix miscompile on Android (#12347) --- lib/lua/src/lgc.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/lua/src/lgc.c b/lib/lua/src/lgc.c index e909c79a9..9141a1c60 100644 --- a/lib/lua/src/lgc.c +++ b/lib/lua/src/lgc.c @@ -164,8 +164,13 @@ static int traversetable (global_State *g, Table *h) { markobject(g, h->metatable); mode = gfasttm(g, h->metatable, TM_MODE); if (mode && ttisstring(mode)) { /* is there a weak mode? */ - weakkey = (strchr(svalue(mode), 'k') != NULL); - weakvalue = (strchr(svalue(mode), 'v') != NULL); + // Android's 'FORTIFY libc' calls __builtin_object_size on the argument of strchr. + // This produces an incorrect size for the expression `svalue(mode)`, causing + // an assertion. By placing it in a temporary, __builtin_object_size returns + // -1 (for unknown size) which functions correctly. + const char *tmp = svalue(mode); + weakkey = (strchr(tmp, 'k') != NULL); + weakvalue = (strchr(tmp, 'v') != NULL); if (weakkey || weakvalue) { /* is really weak? */ h->marked &= ~(KEYWEAK | VALUEWEAK); /* clear bits */ h->marked |= cast_byte((weakkey << KEYWEAKBIT) | From 8edc0fae5f0789e45a0dd1393a37c9993c694c82 Mon Sep 17 00:00:00 2001 From: Zughy <63455151+Zughy@users.noreply.github.com> Date: Sat, 21 May 2022 17:48:28 +0200 Subject: [PATCH 08/13] Make no_screenshot image more clear (#12346) --- LICENSE.txt | 3 +++ textures/base/pack/no_screenshot.png | Bin 586 -> 2043 bytes 2 files changed, 3 insertions(+) diff --git a/LICENSE.txt b/LICENSE.txt index ab44488a7..6eae833d5 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -63,6 +63,9 @@ Zughy: appgurueu: textures/base/pack/server_incompatible.png + +erlehmann, Warr1024, rollerozxa: + textures/base/pack/no_screenshot.png License of Minetest source code ------------------------------- diff --git a/textures/base/pack/no_screenshot.png b/textures/base/pack/no_screenshot.png index 8c7089897218a4aa453493ad6d25e360501dfc5a..14df091a24ef9c3ed15e28688c9b08296a324d7f 100644 GIT binary patch literal 2043 zcmb`I`B&138ixU;T+(d0kTqtLPGgGN;$W$vl#U~ssR@16FoeW~aLFCRl&+RbF1g=K znarI8ZX#l4;#z8X%5crC3^Ei$bHT0KoH_SDm~)=<zR&r*KfFJFl3kqbHPrU2fj}S) zhd*rHKp-&UhrdwyF+fpuw~|4i?X3>BX!q!mxv|mf9~yUWn_P0*FfQp^MYIgz*ef@4 z=xE{&@Y(9fg#4N2A_vjc=6j#&-vw?eC0BgZ{aFhk-2FF@{|n+D3uzMT+J}a2j3syF z#DPXN2Tq*EQ-9uoC%;S&$Y{ejyL(c`^z#U3?o_^AT+Ogboo_kJemCgas1KO8j@7UE znH3rX)^8K*-tbE`q0&GAyB1W(h|uQ3Sl_K-9*iYK-bI~y45wJ=7SMOCvCQ|1WBWt@ zz6yW3ke2r8OV)EzB|_Mk;S2XOB#TizWhoNot8=9bwVUMy+<!1t;!|e?m~&{&+9V(K zfhR!I9+n?>Ep7Vv4NVF{r^Wj$qcIv$if3T%-)Q~sLewh)yEA1g$yZaA*-EQ7`#j)z z>Dw;AFz9={r~)>LqfSB04&2veK!+66+WL@MPSOZumg)tK&t0}GL20T_!_8UMnal+b z=fDw=OF(}+Ol!U{hBcPa1~I5)-^Q|RrsUUr(|09ol#h)ZvcI|6!72N3V}-vK1yNgq z{o1}17`607Op!kJT0bt`*$ye1yNYd4t~p44A`*gGO^=nJyfd#Q+^dT*K)uF7HCyKx zBX<WpScpsbV1Z>$hA84TtPq%|CVG{XDA8#rqf*JsvF&>&d4n}tB}sN$<Hzpb0~ytU zbIb>PoqUzPwS7sm(@pq9AFk^cpATD<DhjIDIa9DaY?8FgO%YO@e~`#M{qOi(4L)~` z%Nx8~_Am&QY~4vj^3;L3=sl@1(GkWk9k~$dswvP*|1&-$>OiU@^DTxu+kLrg`*YHR z6EXkV$>$EudV35mSs+HXUX&HL5XC8+qw|F08D&p9v+Tw<j^2Rv)S<u~c!YS|LnrV4 zFtfojY-UCgpz9K`i{Mr8J8lPM)J(N%n3&GDK=g$lB~UBAPiNlLc+7fEiRj&HAZ<N~ zqbSuXtxEhny^Pw4PgYbT&p5}p+Z>uF$XxH1K^JzGuaJ@F%0bd5t>gM?ly>4lBe=@) zgjIQRx7-9PRr01Lb#G&KCrdLQjR``gbE^g@+=6vubVq-658iMbs$8?*=_5Gu8d#PS zlhzNsLkR-{9s|AjN6eHdpL#;Nst~i*55Ms4^AY#>2|SA1l|zu+@;DAVK&Lg!yfg&Q z&`lB(Ec0`CD|3fR&QI((gVV>@`=u1IW~1fhaxPl-I!yqz$Y<~q&vO>!>$iV89PAgp z1WcS3%E@$Bm4;8Jkg_G8G$fB3I+`^+d${HFD@B(vF1@2%9bB<`To{$b=#Cv%DCgpJ zJ1a>L#X8EBd69+`o8HiAR!<!^Gnt$-ZCEQ}es~?OirySD?e~;+{~B-O)75Jg2<M1s z+@u-1p?sJDs<-?ETqUx+4{^v~epW6qv8nj2mhR-@KxM-z^G>SSGbHE|4;EPG81f~Q zg~-gdHb}lRwU2!8WW-1<{%9WR#JuX1Al&_S{Kbsk^?jUFVI7K4F?Wl2;6VvzcV-FY znJ4Q-Rc~=fR+~A}z<-Z=j?OETe&wS#JM|Jt1?L%GuQuX-yjIPhpq(RwnIXaH+GwbV zRBiF7|B_$@ug&*nE$SA9t)7Fhe>*n?@|G7=I~X6bDB8`N>ms}gi$0lF9-*>aPrp{C z*YYNb5}Wt_CIm*d(<Q^f%fZ>X0~R*Nj;*LUBL#8WU|L1j-=c8L%7HaiR$5_33OQh? zf)Mj7YyWh<=XYq$76DN~@5Zb%ux<2|YE2a{G528vNwBexvSNwN_GC7E#H*Z=M4@@j zV>;bQ_Q03HM`(%Wq<?>f+TIJeIrXPoO(FIp0ZFld<$<p~w=ZK=hDNgl|4~Em2B`Ax z(mU+O4?|^y(EMHRZp{}RskfO)C=`q|WCv=qcqwAB6Vl0}suj<w=b&Ym%4~V^BSLso zTy)f}_Q_ZtxlTsJf{~Ii@dOa;pZaY%=$@e!sx$C#1b6##BK8#9REW2co)3J^33{eA z`hJ^&=3UE^kBhpgs&tGxS^Q>OqID-O)D^RES7bXsv&7klkU<!jk)EhSXuMAIWFYBT zjdAC7&X5^cY-CC$EB)C#?(x2P9*$SeD~u@qnQz5+YNA031s6nqB-i1-K7|`V!P_ev zJ*(wuOZmuhkKgqI*~QCME4v6C$@Gr~YEpB)%jG`?gD~XLHBIoe+2HyneM2^&=@<}t zaKo~u$?%%d^Ek*AFD=D{kSNO-Y^z>EaY!%10Bg0Z4|W^(9EA%CACbN?1=VKX6^qTD zBd&FrN;K7TC#(XvMMolg8o#z}#sF*XW`_ZDzuHac;1ELEnUskCrSzVM`OC4lv|>}) z_=B1Dm=Y72ECK56HjUI<bTR(=I_H=1&$hxiiLo4`F4)3wlpX&<|L^q=nsle!dJ&h- U?f{>3`K#3(?3`_D&k`8_11q}ZMF0Q* literal 586 zcmeAS@N?(olHy`uVBq!ia0y~yVAKJ!PjIjR$sgB5?g1&r;vjb?hIQv;UIIBxN#5=* z46WwzA#;H|&H|6fVg?3oVGw3ym^DWND9B#o>Fdh=fL&6=&|34x1X-X7=R92;Ln>~) zz3a$#NI}HG(O}Mu=7Q8aTV_W!&f3OVmX_=je)PF}FQ?%F|5u+R%GdAH5eOF$JLD9> z!QIljK|qXyJMm-0@BPQyXX)}bcXhU|6-YeTe&r`en9jwUx9ZJjzOXBLZRewt(+X7B z2vmQFDN#|Ug%!mBMIEq-3OYa&9e@TCr7*!`6HAX}nb8`son#q7v|U&f`si-e57%z# z1ckwzf0Ei!iasPcAB&NQ5LMKP`05vNc3Ow8@Z9HWV%wZrSRcL?Tvb|pGxOW_{VZx? tGXKJU+<&hHv=S1MiIGgeu&dZ+esB^$*Y|&yHv%J@!PC{xWt~$(69CRl!ZrW^ From 371f21fb350a29ad1ade4ffaf38c07ca1742cd63 Mon Sep 17 00:00:00 2001 From: paradust7 <102263465+paradust7@users.noreply.github.com> Date: Sat, 21 May 2022 08:48:40 -0700 Subject: [PATCH 09/13] Fixes to Android build + option to turn LuaJIT on/off for testing purposes (#12334) --- .../net/minetest/minetest/GameActivity.java | 4 ++ android/native/jni/Android.mk | 60 ++++++++++++++++++- 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/android/app/src/main/java/net/minetest/minetest/GameActivity.java b/android/app/src/main/java/net/minetest/minetest/GameActivity.java index 46fc9b1de..eeb90ea7f 100644 --- a/android/app/src/main/java/net/minetest/minetest/GameActivity.java +++ b/android/app/src/main/java/net/minetest/minetest/GameActivity.java @@ -34,10 +34,14 @@ import android.widget.Button; import android.widget.EditText; import android.widget.LinearLayout; +import androidx.annotation.Keep; import androidx.appcompat.app.AlertDialog; import java.util.Objects; +// Native code finds these methods by name (see porting_android.cpp). +// This annotation prevents the minifier/Proguard from mangling them. +@Keep public class GameActivity extends NativeActivity { static { System.loadLibrary("c++_shared"); diff --git a/android/native/jni/Android.mk b/android/native/jni/Android.mk index f8ca74d3c..b522042de 100644 --- a/android/native/jni/Android.mk +++ b/android/native/jni/Android.mk @@ -1,6 +1,7 @@ LOCAL_PATH := $(call my-dir)/.. #LOCAL_ADDRESS_SANITIZER:=true +#USE_BUILTIN_LUA:=true include $(CLEAR_VARS) LOCAL_MODULE := Curl @@ -42,11 +43,15 @@ LOCAL_MODULE := Irrlicht LOCAL_SRC_FILES := deps/$(APP_ABI)/Irrlicht/libIrrlichtMt.a include $(PREBUILT_STATIC_LIBRARY) +ifndef USE_BUILTIN_LUA + include $(CLEAR_VARS) LOCAL_MODULE := LuaJIT LOCAL_SRC_FILES := deps/$(APP_ABI)/LuaJIT/libluajit.a include $(PREBUILT_STATIC_LIBRARY) +endif + include $(CLEAR_VARS) LOCAL_MODULE := OpenAL LOCAL_SRC_FILES := deps/$(APP_ABI)/OpenAL-Soft/libopenal.a @@ -92,7 +97,6 @@ LOCAL_CFLAGS += \ -DUSE_CURL=1 \ -DUSE_SOUND=1 \ -DUSE_LEVELDB=0 \ - -DUSE_LUAJIT=1 \ -DUSE_GETTEXT=1 \ -DVERSION_MAJOR=${versionMajor} \ -DVERSION_MINOR=${versionMinor} \ @@ -100,6 +104,12 @@ LOCAL_CFLAGS += \ -DVERSION_EXTRA=${versionExtra} \ $(GPROF_DEF) +ifdef USE_BUILTIN_LUA + LOCAL_CFLAGS += -DUSE_LUAJIT=0 +else + LOCAL_CFLAGS += -DUSE_LUAJIT=1 +endif + ifdef NDEBUG LOCAL_CFLAGS += -DNDEBUG=1 endif @@ -120,12 +130,19 @@ LOCAL_C_INCLUDES := \ deps/$(APP_ABI)/Irrlicht/include \ deps/$(APP_ABI)/Gettext/include \ deps/$(APP_ABI)/Iconv/include \ - deps/$(APP_ABI)/LuaJIT/include \ deps/$(APP_ABI)/OpenAL-Soft/include \ deps/$(APP_ABI)/SQLite/include \ deps/$(APP_ABI)/Vorbis/include \ deps/$(APP_ABI)/Zstd/include +ifdef USE_BUILTIN_LUA + LOCAL_C_INCLUDES += \ + ../../lib/lua/src \ + ../../lib/bitop +else + LOCAL_C_INCLUDES += deps/$(APP_ABI)/LuaJIT/include +endif + LOCAL_SRC_FILES := \ $(wildcard ../../src/client/*.cpp) \ $(wildcard ../../src/client/*/*.cpp) \ @@ -207,6 +224,41 @@ LOCAL_SRC_FILES := \ ../../src/voxel.cpp \ ../../src/voxelalgorithms.cpp +# Built-in Lua +ifdef USE_BUILTIN_LUA + LOCAL_SRC_FILES += \ + ../../lib/lua/src/lapi.c \ + ../../lib/lua/src/lauxlib.c \ + ../../lib/lua/src/lbaselib.c \ + ../../lib/lua/src/lcode.c \ + ../../lib/lua/src/ldblib.c \ + ../../lib/lua/src/ldebug.c \ + ../../lib/lua/src/ldo.c \ + ../../lib/lua/src/ldump.c \ + ../../lib/lua/src/lfunc.c \ + ../../lib/lua/src/lgc.c \ + ../../lib/lua/src/linit.c \ + ../../lib/lua/src/liolib.c \ + ../../lib/lua/src/llex.c \ + ../../lib/lua/src/lmathlib.c \ + ../../lib/lua/src/lmem.c \ + ../../lib/lua/src/loadlib.c \ + ../../lib/lua/src/lobject.c \ + ../../lib/lua/src/lopcodes.c \ + ../../lib/lua/src/loslib.c \ + ../../lib/lua/src/lparser.c \ + ../../lib/lua/src/lstate.c \ + ../../lib/lua/src/lstring.c \ + ../../lib/lua/src/lstrlib.c \ + ../../lib/lua/src/ltable.c \ + ../../lib/lua/src/ltablib.c \ + ../../lib/lua/src/ltm.c \ + ../../lib/lua/src/lundump.c \ + ../../lib/lua/src/lvm.c \ + ../../lib/lua/src/lzio.c \ + ../../lib/bitop/bit.c +endif + # GMP LOCAL_SRC_FILES += ../../lib/gmp/mini-gmp.c @@ -218,12 +270,14 @@ LOCAL_STATIC_LIBRARIES += \ Freetype \ Iconv libcharset \ Irrlicht \ - LuaJIT \ OpenAL \ Gettext \ SQLite3 \ Vorbis libvorbisfile libogg \ Zstd +ifndef USE_BUILTIN_LUA + LOCAL_STATIC_LIBRARIES += LuaJIT +endif LOCAL_STATIC_LIBRARIES += android_native_app_glue $(PROFILER_LIBS) LOCAL_LDLIBS := -lEGL -lGLESv1_CM -lGLESv2 -landroid -lOpenSLES From 2f32044273d107e82fb1c35d4a0f616fa480cdf0 Mon Sep 17 00:00:00 2001 From: sfan5 <sfan5@live.de> Date: Fri, 6 May 2022 20:13:45 +0200 Subject: [PATCH 10/13] Don't ignore server disconnects in client code If the server stops talking to us without saying bye we should actually end the in-game session with an error message. --- src/client/client.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/client/client.cpp b/src/client/client.cpp index cb556c1ce..8ab96b7d1 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -786,16 +786,18 @@ void Client::peerAdded(con::Peer *peer) infostream << "Client::peerAdded(): peer->id=" << peer->id << std::endl; } + void Client::deletingPeer(con::Peer *peer, bool timeout) { infostream << "Client::deletingPeer(): " "Server Peer is getting deleted " << "(timeout=" << timeout << ")" << std::endl; - if (timeout) { - m_access_denied = true; + m_access_denied = true; + if (timeout) m_access_denied_reason = gettext("Connection timed out."); - } + else + m_access_denied_reason = gettext("Connection aborted (protocol error?)."); } /* From bc59fcf5c5cc44ea18e93f64aca9c20be71c1b07 Mon Sep 17 00:00:00 2001 From: sfan5 <sfan5@live.de> Date: Sun, 22 May 2022 00:11:22 +0200 Subject: [PATCH 11/13] Bump IrrlichtMt version in CI --- .github/workflows/build.yml | 2 +- .github/workflows/macos.yml | 2 +- .gitlab-ci.yml | 2 +- util/buildbot/buildwin32.sh | 2 +- util/buildbot/buildwin64.sh | 2 +- util/ci/common.sh | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2cc83923b..70340d82d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -230,7 +230,7 @@ jobs: with: repository: minetest/irrlicht path: lib/irrlichtmt/ - ref: "1.9.0mt5" + ref: "1.9.0mt6" - name: Restore from cache and run vcpkg uses: lukka/run-vcpkg@v7 diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index c0278a38c..346e4f300 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -22,7 +22,7 @@ on: - '.github/workflows/macos.yml' env: - IRRLICHT_TAG: 1.9.0mt5 + IRRLICHT_TAG: 1.9.0mt6 MINETEST_GAME_REPO: https://github.com/minetest/minetest_game.git MINETEST_GAME_BRANCH: master MINETEST_GAME_NAME: minetest_game diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c225bfcd4..8e8186570 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -9,7 +9,7 @@ stages: - deploy variables: - IRRLICHT_TAG: "1.9.0mt5" + IRRLICHT_TAG: "1.9.0mt6" MINETEST_GAME_REPO: "https://github.com/minetest/minetest_game.git" CONTAINER_IMAGE: registry.gitlab.com/$CI_PROJECT_PATH diff --git a/util/buildbot/buildwin32.sh b/util/buildbot/buildwin32.sh index e0c431711..89d97c54e 100755 --- a/util/buildbot/buildwin32.sh +++ b/util/buildbot/buildwin32.sh @@ -45,7 +45,7 @@ done echo "The compiler runtime DLLs could not be found, they might be missing in the final package." # Get stuff -irrlicht_version=1.9.0mt5 +irrlicht_version=1.9.0mt6 ogg_version=1.3.5 openal_version=1.21.1 vorbis_version=1.3.7 diff --git a/util/buildbot/buildwin64.sh b/util/buildbot/buildwin64.sh index e79397be4..5648962ed 100755 --- a/util/buildbot/buildwin64.sh +++ b/util/buildbot/buildwin64.sh @@ -45,7 +45,7 @@ done echo "The compiler runtime DLLs could not be found, they might be missing in the final package." # Get stuff -irrlicht_version=1.9.0mt5 +irrlicht_version=1.9.0mt6 ogg_version=1.3.5 openal_version=1.21.1 vorbis_version=1.3.7 diff --git a/util/ci/common.sh b/util/ci/common.sh index 82529c712..16327ec30 100644 --- a/util/ci/common.sh +++ b/util/ci/common.sh @@ -13,7 +13,7 @@ install_linux_deps() { shift pkgs+=(libirrlicht-dev) else - wget "https://github.com/minetest/irrlicht/releases/download/1.9.0mt5/ubuntu-bionic.tar.gz" + wget "https://github.com/minetest/irrlicht/releases/download/1.9.0mt6/ubuntu-bionic.tar.gz" sudo tar -xaf ubuntu-bionic.tar.gz -C /usr/local fi From 2742fef458c3626476193c9e2d1b9231e042e420 Mon Sep 17 00:00:00 2001 From: paradust7 <102263465+paradust7@users.noreply.github.com> Date: Sat, 21 May 2022 15:11:49 -0700 Subject: [PATCH 12/13] Fixes needed to use irrArray backed by std::vector (#12263) --- src/client/clientmap.cpp | 39 ++++++++++++++--------------- src/client/clientmap.h | 3 +++ src/client/mapblock_mesh.cpp | 21 ++++++++-------- src/client/mapblock_mesh.h | 17 ++++++++++--- src/irrlicht_changes/CGUITTFont.cpp | 14 ++++------- src/irrlicht_changes/CGUITTFont.h | 38 ++++++++++++++++++---------- 6 files changed, 77 insertions(+), 55 deletions(-) diff --git a/src/client/clientmap.cpp b/src/client/clientmap.cpp index 46cb115aa..98e3f40d3 100644 --- a/src/client/clientmap.cpp +++ b/src/client/clientmap.cpp @@ -449,15 +449,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) drawcall_count += draw_order.size(); for (auto &descriptor : draw_order) { - scene::IMeshBuffer *buf; - - if (descriptor.m_use_partial_buffer) { - descriptor.m_partial_buffer->beforeDraw(); - buf = descriptor.m_partial_buffer->getBuffer(); - } - else { - buf = descriptor.m_buffer; - } + scene::IMeshBuffer *buf = descriptor.getBuffer(); // Check and abort if the machine is swapping a lot if (draw.getTimerTime() > 2000) { @@ -501,7 +493,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) m.setTranslation(block_wpos - offset); driver->setTransform(video::ETS_WORLD, m); - driver->drawMeshBuffer(buf); + descriptor.draw(driver); vertex_count += buf->getIndexCount(); } @@ -812,15 +804,7 @@ void ClientMap::renderMapShadows(video::IVideoDriver *driver, drawcall_count += draw_order.size(); for (auto &descriptor : draw_order) { - scene::IMeshBuffer *buf; - - if (descriptor.m_use_partial_buffer) { - descriptor.m_partial_buffer->beforeDraw(); - buf = descriptor.m_partial_buffer->getBuffer(); - } - else { - buf = descriptor.m_buffer; - } + scene::IMeshBuffer *buf = descriptor.getBuffer(); // Check and abort if the machine is swapping a lot if (draw.getTimerTime() > 1000) { @@ -845,7 +829,7 @@ void ClientMap::renderMapShadows(video::IVideoDriver *driver, m.setTranslation(block_wpos - offset); driver->setTransform(video::ETS_WORLD, m); - driver->drawMeshBuffer(buf); + descriptor.draw(driver); vertex_count += buf->getIndexCount(); } @@ -966,3 +950,18 @@ void ClientMap::updateTransparentMeshBuffers() m_needs_update_transparent_meshes = false; } +scene::IMeshBuffer* ClientMap::DrawDescriptor::getBuffer() +{ + return m_use_partial_buffer ? m_partial_buffer->getBuffer() : m_buffer; +} + +void ClientMap::DrawDescriptor::draw(video::IVideoDriver* driver) +{ + if (m_use_partial_buffer) { + m_partial_buffer->beforeDraw(); + driver->drawMeshBuffer(m_partial_buffer->getBuffer()); + m_partial_buffer->afterDraw(); + } else { + driver->drawMeshBuffer(m_buffer); + } +} diff --git a/src/client/clientmap.h b/src/client/clientmap.h index 6d57f1911..823870c68 100644 --- a/src/client/clientmap.h +++ b/src/client/clientmap.h @@ -174,6 +174,9 @@ private: DrawDescriptor(v3s16 pos, const PartialMeshBuffer *buffer) : m_pos(pos), m_partial_buffer(buffer), m_reuse_material(false), m_use_partial_buffer(true) {} + + scene::IMeshBuffer* getBuffer(); + void draw(video::IVideoDriver* driver); }; Client *m_client; diff --git a/src/client/mapblock_mesh.cpp b/src/client/mapblock_mesh.cpp index 868573bf0..965dd5e29 100644 --- a/src/client/mapblock_mesh.cpp +++ b/src/client/mapblock_mesh.cpp @@ -1162,15 +1162,16 @@ void MapBlockBspTree::traverse(s32 node, v3f viewpoint, std::vector<s32> &output void PartialMeshBuffer::beforeDraw() const { // Patch the indexes in the mesh buffer before draw - - m_buffer->Indices.clear(); - if (!m_vertex_indexes.empty()) { - for (auto index : m_vertex_indexes) - m_buffer->Indices.push_back(index); - } + m_buffer->Indices = std::move(m_vertex_indexes); m_buffer->setDirty(scene::EBT_INDEX); } +void PartialMeshBuffer::afterDraw() const +{ + // Take the data back + m_vertex_indexes = std::move(m_buffer->Indices.steal()); +} + /* MapBlockMesh */ @@ -1514,7 +1515,7 @@ void MapBlockMesh::updateTransparentBuffers(v3f camera_pos, v3s16 block_pos) const auto &t = m_transparent_triangles[i]; if (current_buffer != t.buffer) { if (current_buffer) { - m_transparent_buffers.emplace_back(current_buffer, current_strain); + m_transparent_buffers.emplace_back(current_buffer, std::move(current_strain)); current_strain.clear(); } current_buffer = t.buffer; @@ -1525,7 +1526,7 @@ void MapBlockMesh::updateTransparentBuffers(v3f camera_pos, v3s16 block_pos) } if (!current_strain.empty()) - m_transparent_buffers.emplace_back(current_buffer, current_strain); + m_transparent_buffers.emplace_back(current_buffer, std::move(current_strain)); } void MapBlockMesh::consolidateTransparentBuffers() @@ -1539,7 +1540,7 @@ void MapBlockMesh::consolidateTransparentBuffers() for (const auto &t : m_transparent_triangles) { if (current_buffer != t.buffer) { if (current_buffer != nullptr) { - this->m_transparent_buffers.emplace_back(current_buffer, current_strain); + this->m_transparent_buffers.emplace_back(current_buffer, std::move(current_strain)); current_strain.clear(); } current_buffer = t.buffer; @@ -1550,7 +1551,7 @@ void MapBlockMesh::consolidateTransparentBuffers() } if (!current_strain.empty()) { - this->m_transparent_buffers.emplace_back(current_buffer, current_strain); + this->m_transparent_buffers.emplace_back(current_buffer, std::move(current_strain)); } } diff --git a/src/client/mapblock_mesh.h b/src/client/mapblock_mesh.h index 72d128038..169b3a8c1 100644 --- a/src/client/mapblock_mesh.h +++ b/src/client/mapblock_mesh.h @@ -140,20 +140,31 @@ private: s32 root = -1; // index of the root node }; +/* + * PartialMeshBuffer + * + * Attach alternate `Indices` to an existing mesh buffer, to make it possible to use different + * indices with the same vertex buffer. + * + * Irrlicht does not currently support this: `CMeshBuffer` ties together a single vertex buffer + * and a single index buffer. There's no way to share these between mesh buffers. + * + */ class PartialMeshBuffer { public: - PartialMeshBuffer(scene::SMeshBuffer *buffer, const std::vector<u16> &vertex_indexes) : - m_buffer(buffer), m_vertex_indexes(vertex_indexes) + PartialMeshBuffer(scene::SMeshBuffer *buffer, std::vector<u16> &&vertex_indexes) : + m_buffer(buffer), m_vertex_indexes(std::move(vertex_indexes)) {} scene::IMeshBuffer *getBuffer() const { return m_buffer; } const std::vector<u16> &getVertexIndexes() const { return m_vertex_indexes; } void beforeDraw() const; + void afterDraw() const; private: scene::SMeshBuffer *m_buffer; - std::vector<u16> m_vertex_indexes; + mutable std::vector<u16> m_vertex_indexes; }; /* diff --git a/src/irrlicht_changes/CGUITTFont.cpp b/src/irrlicht_changes/CGUITTFont.cpp index fe86adae6..0f2572ee0 100644 --- a/src/irrlicht_changes/CGUITTFont.cpp +++ b/src/irrlicht_changes/CGUITTFont.cpp @@ -292,9 +292,6 @@ shadow_offset(0), shadow_alpha(0), fallback(0) Driver->grab(); setInvisibleCharacters(L" "); - - // Glyphs aren't reference counted, so don't try to delete them when we free the array. - Glyphs.set_free_when_destroyed(false); } bool CGUITTFont::load(const io::path& filename, const u32 size, const bool antialias, const bool transparency) @@ -411,8 +408,7 @@ CGUITTFont::~CGUITTFont() { // Delete the glyphs and glyph pages. reset_images(); - CGUITTAssistDelete::Delete(Glyphs); - //Glyphs.clear(); + Glyphs.clear(); // We aren't using this face anymore. auto n = c_faces.find(filename); @@ -675,6 +671,8 @@ void CGUITTFont::draw(const EnrichedString &text, const core::rect<s32>& positio update_glyph_pages(); auto it = Render_Map.begin(); auto ie = Render_Map.end(); + core::array<core::vector2di> tmp_positions; + core::array<core::recti> tmp_source_rects; while (it != ie) { CGUITTGlyphPage* page = it->second; @@ -696,10 +694,8 @@ void CGUITTFont::draw(const EnrichedString &text, const core::rect<s32>& positio do ++i; while (i < page->render_positions.size() && page->render_colors[i] == colprev); - core::array<core::vector2di> tmp_positions; - core::array<core::recti> tmp_source_rects; - tmp_positions.set_pointer(&page->render_positions[ibegin], i - ibegin, false, false); // no copy - tmp_source_rects.set_pointer(&page->render_source_rects[ibegin], i - ibegin, false, false); + tmp_positions.set_data(&page->render_positions[ibegin], i - ibegin); + tmp_source_rects.set_data(&page->render_source_rects[ibegin], i - ibegin); --i; if (!use_transparency) diff --git a/src/irrlicht_changes/CGUITTFont.h b/src/irrlicht_changes/CGUITTFont.h index 9457e5b18..210222ed4 100644 --- a/src/irrlicht_changes/CGUITTFont.h +++ b/src/irrlicht_changes/CGUITTFont.h @@ -37,6 +37,7 @@ #include <map> #include <irrUString.h> #include "util/enriched_string.h" +#include "util/basic_macros.h" #include FT_FREETYPE_H namespace irr @@ -46,23 +47,34 @@ namespace gui struct SGUITTFace; class CGUITTFont; - //! Class to assist in deleting glyphs. - class CGUITTAssistDelete - { - public: - template <class T, typename TAlloc> - static void Delete(core::array<T, TAlloc>& a) - { - TAlloc allocator; - allocator.deallocate(a.pointer()); - } - }; - //! Structure representing a single TrueType glyph. struct SGUITTGlyph { //! Constructor. - SGUITTGlyph() : isLoaded(false), glyph_page(0), surface(0), parent(0) {} + SGUITTGlyph() : + isLoaded(false), + glyph_page(0), + source_rect(), + offset(), + advance(), + surface(0), + parent(0) + {} + + DISABLE_CLASS_COPY(SGUITTGlyph); + + //! This class would be trivially copyable except for the reference count on `surface`. + SGUITTGlyph(SGUITTGlyph &&other) : + isLoaded(other.isLoaded), + glyph_page(other.glyph_page), + source_rect(other.source_rect), + offset(other.offset), + advance(other.advance), + surface(other.surface), + parent(other.parent) + { + other.surface = 0; + } //! Destructor. ~SGUITTGlyph() { unload(); } From 9f338f5a56e5adee3d11d59827f7e2b8a714e6c2 Mon Sep 17 00:00:00 2001 From: paradust7 <102263465+paradust7@users.noreply.github.com> Date: Sat, 21 May 2022 15:11:59 -0700 Subject: [PATCH 13/13] Replace all uses of core::list with std::list (#12313) --- src/gui/guiConfirmRegistration.cpp | 17 +-------- src/gui/guiConfirmRegistration.h | 3 -- src/gui/guiFormSpecMenu.cpp | 59 ++++++++++-------------------- src/gui/guiFormSpecMenu.h | 4 +- src/gui/guiKeyChangeMenu.cpp | 20 ++-------- src/gui/guiKeyChangeMenu.h | 1 - src/gui/guiPasswordChange.cpp | 19 +--------- src/gui/guiPasswordChange.h | 2 - src/gui/guiPathSelectMenu.cpp | 3 +- src/gui/guiScrollContainer.cpp | 9 ++--- src/gui/guiVolumeChange.cpp | 22 +---------- src/gui/guiVolumeChange.h | 3 -- src/gui/mainmenumanager.h | 4 -- src/gui/modalMenu.cpp | 13 ------- src/gui/modalMenu.h | 1 - src/unittest/test.cpp | 4 +- 16 files changed, 36 insertions(+), 148 deletions(-) diff --git a/src/gui/guiConfirmRegistration.cpp b/src/gui/guiConfirmRegistration.cpp index b8887a4af..c5aa9c85e 100644 --- a/src/gui/guiConfirmRegistration.cpp +++ b/src/gui/guiConfirmRegistration.cpp @@ -54,25 +54,10 @@ GUIConfirmRegistration::GUIConfirmRegistration(gui::IGUIEnvironment *env, #endif } -GUIConfirmRegistration::~GUIConfirmRegistration() -{ - removeChildren(); -} - -void GUIConfirmRegistration::removeChildren() -{ - const core::list<gui::IGUIElement *> &children = getChildren(); - core::list<gui::IGUIElement *> children_copy; - for (gui::IGUIElement *i : children) - children_copy.push_back(i); - for (gui::IGUIElement *i : children_copy) - i->remove(); -} - void GUIConfirmRegistration::regenerateGui(v2u32 screensize) { acceptInput(); - removeChildren(); + removeAllChildren(); /* Calculate new sizes and positions diff --git a/src/gui/guiConfirmRegistration.h b/src/gui/guiConfirmRegistration.h index d8387201d..fb2157756 100644 --- a/src/gui/guiConfirmRegistration.h +++ b/src/gui/guiConfirmRegistration.h @@ -34,9 +34,6 @@ public: s32 id, IMenuManager *menumgr, Client *client, const std::string &playername, const std::string &password, bool *aborted, ISimpleTextureSource *tsrc); - ~GUIConfirmRegistration(); - - void removeChildren(); /* Remove and re-add (or reposition) stuff */ diff --git a/src/gui/guiFormSpecMenu.cpp b/src/gui/guiFormSpecMenu.cpp index f3570ccaf..422d6da16 100644 --- a/src/gui/guiFormSpecMenu.cpp +++ b/src/gui/guiFormSpecMenu.cpp @@ -127,7 +127,8 @@ GUIFormSpecMenu::GUIFormSpecMenu(JoystickController *joystick, GUIFormSpecMenu::~GUIFormSpecMenu() { - removeChildren(); + removeAllChildren(); + removeTooltip(); for (auto &table_it : m_tables) table_it.second->drop(); @@ -174,14 +175,8 @@ void GUIFormSpecMenu::create(GUIFormSpecMenu *&cur_formspec, Client *client, } } -void GUIFormSpecMenu::removeChildren() +void GUIFormSpecMenu::removeTooltip() { - const core::list<gui::IGUIElement*> &children = getChildren(); - - while (!children.empty()) { - (*children.getLast())->remove(); - } - if (m_tooltip_element) { m_tooltip_element->remove(); m_tooltip_element->drop(); @@ -199,16 +194,7 @@ void GUIFormSpecMenu::setInitialFocus() // 5. first focusable (not statictext, not tabheader) // 6. first child element - core::list<gui::IGUIElement*> children = getChildren(); - - // in case "children" contains any NULL elements, remove them - for (core::list<gui::IGUIElement*>::Iterator it = children.begin(); - it != children.end();) { - if (*it) - ++it; - else - it = children.erase(it); - } + const auto& children = getChildren(); // 1. first empty editbox for (gui::IGUIElement *it : children) { @@ -236,8 +222,7 @@ void GUIFormSpecMenu::setInitialFocus() } // 4. last button - for (core::list<gui::IGUIElement*>::Iterator it = children.getLast(); - it != children.end(); --it) { + for (auto it = children.rbegin(); it != children.rend(); ++it) { if ((*it)->getType() == gui::EGUIET_BUTTON) { Environment->setFocus(*it); return; @@ -257,7 +242,7 @@ void GUIFormSpecMenu::setInitialFocus() if (children.empty()) Environment->setFocus(this); else - Environment->setFocus(*(children.begin())); + Environment->setFocus(children.front()); } GUITable* GUIFormSpecMenu::getTable(const std::string &tablename) @@ -3045,7 +3030,8 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize) } // Remove children - removeChildren(); + removeAllChildren(); + removeTooltip(); for (auto &table_it : m_tables) table_it.second->drop(); @@ -3341,7 +3327,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize) pos_offset = v2f32(); // used for formspec versions < 3 - core::list<IGUIElement *>::Iterator legacy_sort_start = Children.getLast(); + std::list<IGUIElement *>::iterator legacy_sort_start = std::prev(Children.end()); // last element if (enable_prepends) { // Backup the coordinates so that prepends can use the coordinates of choice. @@ -3356,7 +3342,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize) // legacy sorting for formspec versions < 3 if (m_formspec_version >= 3) // prepends do not need to be reordered - legacy_sort_start = Children.getLast(); + legacy_sort_start = std::prev(Children.end()); // last element else if (version_backup >= 3) // only prepends elements have to be reordered legacySortElements(legacy_sort_start); @@ -3437,7 +3423,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize) } } -void GUIFormSpecMenu::legacySortElements(core::list<IGUIElement *>::Iterator from) +void GUIFormSpecMenu::legacySortElements(std::list<IGUIElement *>::iterator from) { /* Draw order for formspec_version <= 2: @@ -3454,17 +3440,16 @@ void GUIFormSpecMenu::legacySortElements(core::list<IGUIElement *>::Iterator fro if (from == Children.end()) from = Children.begin(); else - from++; + ++from; - core::list<IGUIElement *>::Iterator to = Children.end(); + std::list<IGUIElement *>::iterator to = Children.end(); // 1: Copy into a sortable container - std::vector<IGUIElement *> elements; - for (auto it = from; it != to; ++it) - elements.emplace_back(*it); + std::vector<IGUIElement *> elements(from, to); // 2: Sort the container std::stable_sort(elements.begin(), elements.end(), [this] (const IGUIElement *a, const IGUIElement *b) -> bool { + // TODO: getSpecByID is a linear search. It should made O(1), or cached here. const FieldSpec *spec_a = getSpecByID(a->getID()); const FieldSpec *spec_b = getSpecByID(b->getID()); return spec_a && spec_b && @@ -3472,10 +3457,7 @@ void GUIFormSpecMenu::legacySortElements(core::list<IGUIElement *>::Iterator fro }); // 3: Re-assign the pointers - for (auto e : elements) { - *from = e; - from++; - } + reorderChildren(from, to, elements); } #ifdef __ANDROID__ @@ -3600,12 +3582,11 @@ void GUIFormSpecMenu::drawMenu() /* This is where all the drawing happens. */ - core::list<IGUIElement*>::Iterator it = Children.begin(); - for (; it != Children.end(); ++it) - if ((*it)->isNotClipped() || + for (auto child : Children) + if (child->isNotClipped() || AbsoluteClippingRect.isRectCollided( - (*it)->getAbsolutePosition())) - (*it)->draw(); + child->getAbsolutePosition())) + child->draw(); for (gui::IGUIElement *e : m_clickthrough_elements) e->setVisible(false); diff --git a/src/gui/guiFormSpecMenu.h b/src/gui/guiFormSpecMenu.h index 3fedb3b78..a584456db 100644 --- a/src/gui/guiFormSpecMenu.h +++ b/src/gui/guiFormSpecMenu.h @@ -212,7 +212,7 @@ public: m_lockscreensize = basescreensize; } - void removeChildren(); + void removeTooltip(); void setInitialFocus(); void setFocus(const std::string &elementname) @@ -467,7 +467,7 @@ private: * types were drawn before others. * This function sorts the elements in the old order for backwards compatibility. */ - void legacySortElements(core::list<IGUIElement *>::Iterator from); + void legacySortElements(std::list<IGUIElement *>::iterator from); int m_btn_height; gui::IGUIFont *m_font = nullptr; diff --git a/src/gui/guiKeyChangeMenu.cpp b/src/gui/guiKeyChangeMenu.cpp index ada6280f6..021f5f0a9 100644 --- a/src/gui/guiKeyChangeMenu.cpp +++ b/src/gui/guiKeyChangeMenu.cpp @@ -93,7 +93,8 @@ GUIKeyChangeMenu::GUIKeyChangeMenu(gui::IGUIEnvironment* env, GUIKeyChangeMenu::~GUIKeyChangeMenu() { - removeChildren(); + removeAllChildren(); + key_used_text = nullptr; for (key_setting *ks : key_settings) { delete[] ks->button_name; @@ -102,23 +103,10 @@ GUIKeyChangeMenu::~GUIKeyChangeMenu() key_settings.clear(); } -void GUIKeyChangeMenu::removeChildren() -{ - const core::list<gui::IGUIElement*> &children = getChildren(); - core::list<gui::IGUIElement*> children_copy; - for (gui::IGUIElement*i : children) { - children_copy.push_back(i); - } - - for (gui::IGUIElement *i : children_copy) { - i->remove(); - } - key_used_text = nullptr; -} - void GUIKeyChangeMenu::regenerateGui(v2u32 screensize) { - removeChildren(); + removeAllChildren(); + key_used_text = nullptr; const float s = m_gui_scale; DesiredRect = core::rect<s32>( diff --git a/src/gui/guiKeyChangeMenu.h b/src/gui/guiKeyChangeMenu.h index 1c0f40247..84a898774 100644 --- a/src/gui/guiKeyChangeMenu.h +++ b/src/gui/guiKeyChangeMenu.h @@ -46,7 +46,6 @@ public: IMenuManager *menumgr, ISimpleTextureSource *tsrc); ~GUIKeyChangeMenu(); - void removeChildren(); /* Remove and re-add (or reposition) stuff */ diff --git a/src/gui/guiPasswordChange.cpp b/src/gui/guiPasswordChange.cpp index c983260f6..c39df176b 100644 --- a/src/gui/guiPasswordChange.cpp +++ b/src/gui/guiPasswordChange.cpp @@ -51,23 +51,6 @@ GUIPasswordChange::GUIPasswordChange(gui::IGUIEnvironment* env, { } -GUIPasswordChange::~GUIPasswordChange() -{ - removeChildren(); -} - -void GUIPasswordChange::removeChildren() -{ - const core::list<gui::IGUIElement *> &children = getChildren(); - core::list<gui::IGUIElement *> children_copy; - for (gui::IGUIElement *i : children) { - children_copy.push_back(i); - } - - for (gui::IGUIElement *i : children_copy) { - i->remove(); - } -} void GUIPasswordChange::regenerateGui(v2u32 screensize) { /* @@ -78,7 +61,7 @@ void GUIPasswordChange::regenerateGui(v2u32 screensize) /* Remove stuff */ - removeChildren(); + removeAllChildren(); /* Calculate new sizes and positions diff --git a/src/gui/guiPasswordChange.h b/src/gui/guiPasswordChange.h index 7141100c0..452702add 100644 --- a/src/gui/guiPasswordChange.h +++ b/src/gui/guiPasswordChange.h @@ -31,9 +31,7 @@ public: GUIPasswordChange(gui::IGUIEnvironment *env, gui::IGUIElement *parent, s32 id, IMenuManager *menumgr, Client *client, ISimpleTextureSource *tsrc); - ~GUIPasswordChange(); - void removeChildren(); /* Remove and re-add (or reposition) stuff */ diff --git a/src/gui/guiPathSelectMenu.cpp b/src/gui/guiPathSelectMenu.cpp index 489927a11..9c63e06b5 100644 --- a/src/gui/guiPathSelectMenu.cpp +++ b/src/gui/guiPathSelectMenu.cpp @@ -32,13 +32,12 @@ GUIFileSelectMenu::GUIFileSelectMenu(gui::IGUIEnvironment* env, GUIFileSelectMenu::~GUIFileSelectMenu() { - removeChildren(); setlocale(LC_NUMERIC, "C"); } void GUIFileSelectMenu::regenerateGui(v2u32 screensize) { - removeChildren(); + removeAllChildren(); m_fileOpenDialog = 0; core::dimension2du size(600 * m_gui_scale, 400 * m_gui_scale); diff --git a/src/gui/guiScrollContainer.cpp b/src/gui/guiScrollContainer.cpp index 0fe4c41bd..2d71f3453 100644 --- a/src/gui/guiScrollContainer.cpp +++ b/src/gui/guiScrollContainer.cpp @@ -59,12 +59,11 @@ bool GUIScrollContainer::OnEvent(const SEvent &event) void GUIScrollContainer::draw() { if (isVisible()) { - core::list<IGUIElement *>::Iterator it = Children.begin(); - for (; it != Children.end(); ++it) - if ((*it)->isNotClipped() || + for (auto child : Children) + if (child->isNotClipped() || AbsoluteClippingRect.isRectCollided( - (*it)->getAbsolutePosition())) - (*it)->draw(); + child->getAbsolutePosition())) + child->draw(); } } diff --git a/src/gui/guiVolumeChange.cpp b/src/gui/guiVolumeChange.cpp index 61ab758a1..0f6f43fe9 100644 --- a/src/gui/guiVolumeChange.cpp +++ b/src/gui/guiVolumeChange.cpp @@ -45,32 +45,12 @@ GUIVolumeChange::GUIVolumeChange(gui::IGUIEnvironment* env, { } -GUIVolumeChange::~GUIVolumeChange() -{ - removeChildren(); -} - -void GUIVolumeChange::removeChildren() -{ - if (gui::IGUIElement *e = getElementFromId(ID_soundText)) - e->remove(); - - if (gui::IGUIElement *e = getElementFromId(ID_soundExitButton)) - e->remove(); - - if (gui::IGUIElement *e = getElementFromId(ID_soundSlider)) - e->remove(); - - if (gui::IGUIElement *e = getElementFromId(ID_soundMuteButton)) - e->remove(); -} - void GUIVolumeChange::regenerateGui(v2u32 screensize) { /* Remove stuff */ - removeChildren(); + removeAllChildren(); /* Calculate new sizes and positions */ diff --git a/src/gui/guiVolumeChange.h b/src/gui/guiVolumeChange.h index 466e17f9d..ccdaca00b 100644 --- a/src/gui/guiVolumeChange.h +++ b/src/gui/guiVolumeChange.h @@ -31,9 +31,6 @@ public: GUIVolumeChange(gui::IGUIEnvironment* env, gui::IGUIElement* parent, s32 id, IMenuManager *menumgr, ISimpleTextureSource *tsrc); - ~GUIVolumeChange(); - - void removeChildren(); /* Remove and re-add (or reposition) stuff */ diff --git a/src/gui/mainmenumanager.h b/src/gui/mainmenumanager.h index 102492255..76d357340 100644 --- a/src/gui/mainmenumanager.h +++ b/src/gui/mainmenumanager.h @@ -64,10 +64,6 @@ public: // Remove all entries if there are duplicates m_stack.remove(menu); - /*core::list<GUIModalMenu*>::Iterator i = m_stack.getLast(); - assert(*i == menu); - m_stack.erase(i);*/ - if(!m_stack.empty()) m_stack.back()->setVisible(true); } diff --git a/src/gui/modalMenu.cpp b/src/gui/modalMenu.cpp index 56a5d2cb9..d27f63d94 100644 --- a/src/gui/modalMenu.cpp +++ b/src/gui/modalMenu.cpp @@ -108,19 +108,6 @@ void GUIModalMenu::quitMenu() #endif } -void GUIModalMenu::removeChildren() -{ - const core::list<gui::IGUIElement *> &children = getChildren(); - core::list<gui::IGUIElement *> children_copy; - for (gui::IGUIElement *i : children) { - children_copy.push_back(i); - } - - for (gui::IGUIElement *i : children_copy) { - i->remove(); - } -} - // clang-format off bool GUIModalMenu::DoubleClickDetection(const SEvent &event) { diff --git a/src/gui/modalMenu.h b/src/gui/modalMenu.h index 06e78f06b..e37c41533 100644 --- a/src/gui/modalMenu.h +++ b/src/gui/modalMenu.h @@ -47,7 +47,6 @@ public: bool canTakeFocus(gui::IGUIElement *e); void draw(); void quitMenu(); - void removeChildren(); virtual void regenerateGui(v2u32 screensize) = 0; virtual void drawMenu() = 0; diff --git a/src/unittest/test.cpp b/src/unittest/test.cpp index 676fe8e13..af30c209d 100644 --- a/src/unittest/test.cpp +++ b/src/unittest/test.cpp @@ -360,7 +360,7 @@ struct TestMapBlock: public TestBase MapNode node; bool position_valid; - core::list<v3s16> validity_exceptions; + std::list<v3s16> validity_exceptions; TC() { @@ -371,7 +371,7 @@ struct TestMapBlock: public TestBase { //return position_valid ^ (p==position_valid_exception); bool exception = false; - for(core::list<v3s16>::Iterator i=validity_exceptions.begin(); + for(std::list<v3s16>::iterator i=validity_exceptions.begin(); i != validity_exceptions.end(); i++) { if(p == *i)