Compare commits

...

82 commits

Author SHA1 Message Date
sfan5
7892541383 Various random code cleanups 2025-03-04 19:53:01 +01:00
sfan5
358658fa34 Fix cloud-related bugs
First, this reverts 56123b2fbe,
which un-fixes #15031 but fixes #15798 and #15854.

Then we disable culling for the cloud scene node which fixes #15031 again.
2025-03-04 19:53:01 +01:00
sfan5
68602b2eaf Fix shadow flicker on camera offset update (take 2)
The previous fix never did what it was supposed to, so let's do this.
2025-03-04 19:53:01 +01:00
sfan5
e84ac56e35 Don't try to update uninitialized shadow frustum 2025-03-04 19:53:01 +01:00
sfan5
47c000a293 Add unittest that lints builtin JSON files 2025-03-04 19:53:01 +01:00
sfan5
304ce4cd54 Fix syntax error in credits.json
reported at <https://forum.luanti.org/viewtopic.php?p=442729>

As it happens this didn't affect most users as jsoncpp allows trailing commas
by default since 2019.
2025-03-04 19:53:01 +01:00
sfan5
d54646d342 Improve error handling of map database creation 2025-03-04 19:53:01 +01:00
sfan5
7abaa8d4cd Make Irrlicht identity material const 2025-03-04 19:53:01 +01:00
sfan5
2796283550 Remove broken fall bobbing 2025-03-04 19:53:01 +01:00
sfan5
7602308835 Revert "Restrict relative mouse mode to Wayland users (#15697)"
see #15761
SDL is the only device that supports relative mode and
mouse input is actually somewhat broken if it's *not* enabled.

This reverts commit 45c5ef8798
and 88b007907a.
2025-03-04 19:53:01 +01:00
sfan5
bc43019467 Fix TerminalChatConsole crash
this setting was removed in #15633
2025-03-04 19:53:01 +01:00
sfan5
8449f5f6db Make devtest grass use overlay tiles 2025-03-04 19:53:01 +01:00
Medley
0eb047ca33
Disable debug-breaking locale workaround when debugging (#15859) 2025-03-03 20:33:42 +01:00
wrrrzr
98048cb06d
Fix missing includes in skyparams.h 2025-03-03 20:33:19 +01:00
Erich Schubert
6e995972bb check y limits early 2025-03-03 20:33:05 +01:00
Erich Schubert
08fad862aa Code cleanups. Function does not return deco count. 2025-03-03 20:33:05 +01:00
sfan5
c3477a4d08 Adjust Android default view range and mapblock limit 2025-03-01 22:40:10 +01:00
sfan5
062207e696 Enforce minimum client_mapblock_limit depending on view range 2025-03-01 22:40:10 +01:00
SmallJoker
24c1230c7b Client: fix disappearing node inventories on older servers
ee9258ce introduced a logic error, which caused clients to lose
node metadata when they should not and vice-versa.
See also: server.cpp / Server::sendAddNode
2025-03-01 21:05:17 +01:00
sfan5
eb79a76742
Android: update SDL support code (#15853) 2025-03-01 18:27:46 +01:00
millennIumAMbiguity
c0328e5363
Centered title in README.md and added icon 2025-03-01 12:27:43 +01:00
Joshua Gerrish
8d822d8231
Fix compile error with MSVC: string is not a member of std 2025-03-01 12:26:33 +01:00
y5nw
a11b25f3f5 Use fallback font correctly for fonts provided by the server 2025-03-01 12:25:24 +01:00
Lars Mueller
90121dc66f Fix & improve glTF loader matrix decomposition 2025-02-27 12:31:04 +01:00
Lars Mueller
d74af2f1a7 Use matrix4::getRotationRadians 2025-02-27 12:31:04 +01:00
Lars Mueller
b6c71b2379 Improve matrix4::getRotationDegrees a bit, radians 2025-02-27 12:31:04 +01:00
Lars Mueller
c261c26456 Add Irrlicht rotation consistency unit tests 2025-02-27 12:31:04 +01:00
Lars Mueller
5abf220979 Fix random usage in matrix4 tests 2025-02-27 12:31:04 +01:00
Lars Mueller
1ceeea34f4 Extend quaternion tests 2025-02-27 12:31:04 +01:00
Lars Mueller
3ae1fd459a Add quaternion conversion unit tests 2025-02-27 12:31:04 +01:00
Lars Mueller
0e86366324 Add test for matrix4::getRotationDegrees 2025-02-27 12:31:04 +01:00
Erich Schubert
58ad604a4b
Note that core.hash_node_position is not a hash function 2025-02-27 12:30:55 +01:00
guinea7pig
415e96184d
Update copyright date in README 2025-02-26 12:22:19 +01:00
sfan5
8654e16725 Disable shadow force updates with performance_tradeoffs 2025-02-26 12:22:06 +01:00
sfan5
eb8b449817 Fix shadow performance regression due to force update
broken by: b861f0c5c5
2025-02-26 12:22:06 +01:00
sfan5
22c81e5292 Print if sdl2-compat is in use 2025-02-26 12:21:57 +01:00
sfan5
42a35cec83 Allow looking straight up or down 2025-02-26 12:21:57 +01:00
sfan5
fc8c6742c4 Update Wireshark dissector 2025-02-26 12:21:57 +01:00
sfan5
ee9258cefd Clean up some packet-related code 2025-02-26 12:21:57 +01:00
grorp
5e89371ecd
TouchControls: touch_use_crosshair, dig/place simulation refactoring (#15800)
-   get rid of simulated mouse events for digging/placing, use keyboard events
    instead
    -   consistent with other simulated events, less code, no need for a
        pointer position
    -   more correct: touch controls no longer break if you have custom
        dig/place keybindings set
-   move reading of "touch_use_crosshair" setting from Game to TouchControls
2025-02-25 13:19:44 -05:00
Andrii Nemchenko
abcd2e0b81
Re-save active entities more often if they move a certain distance (#15605) 2025-02-22 16:19:19 +01:00
sfan5
d12ce68e64 Show unknown object visuals using unknown_object.png sprite 2025-02-22 16:19:04 +01:00
sfan5
83fd837d75 Clean up TileLayer::applyMaterialOptions 2025-02-22 16:19:04 +01:00
sfan5
7d3f0628c4 Use visual = "node" for builtin falling node entity
This greatly simplifies the code at the expense of some
falling nodes not showing up on older clients.
2025-02-22 16:19:04 +01:00
sfan5
27bbe3a873 CAO 'node' visual (#15683) 2025-02-22 16:19:04 +01:00
sfan5
5a8720a484 Change material sharing for CMeshSceneNode 2025-02-22 16:19:04 +01:00
Andrii Nemchenko
e51221d247
Implement metadata-aware version of InvRef:remove_item() (#15771) 2025-02-22 16:18:48 +01:00
DS
0890125962
SDL Irr device: Ignore +-0.0f y mouse wheel events (#15815)
our code often assumes that it's non-zero, e.g.: `event.MouseInput.Wheel < 0 ? -1 : 1`
2025-02-22 16:17:07 +01:00
DS
0667cbf5a2
Clang-Tidy config: Ignore performance-avoid-endl and performance-inefficient-string-concatenation 2025-02-22 16:16:41 +01:00
sfan5
ba62808fe8
Basic camera control API (#15796) 2025-02-19 18:45:45 +01:00
James Morey
50819ace8f
Move clickable_chat_weblinks to Advanced > Miscellaneous (#15799) 2025-02-19 18:45:31 +01:00
et
ef0219c2ed
Prevent accidental wallmounted_to_dir poisoning (#15810)
Prior to this commit, if you used a function like `core.wallmounted_to_dir`, and modified its output, it would modify all of the output in the future.
2025-02-18 21:51:33 +01:00
sfan5
f4bdf72aa4 Simplify SQLite3 schema types
see: <https://www.sqlite.org/datatype3.html>
2025-02-18 19:29:06 +01:00
sfan5
cc352f3b66 Add unit tests for MapDatabase implementations 2025-02-18 19:29:06 +01:00
sfan5
215b000793 Split blockpos into three columns in sqlite3 map database 2025-02-18 19:29:06 +01:00
sfan5
e8728acc5c Some cleanups in Database_SQLite3 2025-02-18 19:29:06 +01:00
Desour
166e02955e Decrease fps_max_unfocused from 20 to 10
This used to be the default for android.
There's not much issues now with using a lower value, so a lower default on all platforms
is reasonable.
The only downside I know of is that if you re-focus the window, it can up till the
next client step until it goes back to normal fps, but 10 Hz feels fast enough.
2025-02-15 18:21:01 +01:00
Desour
138111a542 Don't use fps_max_unfocused for server step time on non-singleplayer main-menu-hosted servers
It's unreasonable to change server step time when the hosting user unfocuses their window.
(m_is_paused is already not set if it's not singleplayer.)
2025-02-15 18:21:01 +01:00
Desour
191cb117f9 Don't use fps_max_unfocused for the pause menu
Nowadays, we have things like buttons that change appearance on hover, or scoll bars
in the pause menu. These do not work fine with low fps.
2025-02-15 18:21:01 +01:00
Miguel P.L
a57677120a
Correct keycode URL in settingtypes.txt/minetest.conf.example (#15784) 2025-02-15 18:20:45 +01:00
sfan5
75dcd94b90
Optimize add_area_node_boxes in collision code (#15719) 2025-02-15 12:19:17 +01:00
sfan5
d027fc9a88 Enable ipv6_server by default 2025-02-15 12:18:07 +01:00
sfan5
a11d526110 Rework socket IPV6_V6ONLY handling 2025-02-15 12:18:07 +01:00
siliconsniffer
eb797c502a
Tweak main menu server list behavior (#15736)
Co-authored-by: Lars Mueller <appgurulars@gmx.de>
2025-02-15 12:17:56 +01:00
Erich Schubert
567b9a997a
Collision: more accurate computation with acceleration and long dtime (#15408)
Co-authored-by: SmallJoker <mk939@ymail.com>
2025-02-15 12:17:44 +01:00
Lars Müller
319e270664
Clean up Irrlicht matrices a bit more (#15733) 2025-02-15 12:17:30 +01:00
sfan5
d015944f6c Revert "Disable SDL2 for 5.11.0"
This reverts commit 29cfb6efff.
2025-02-15 12:14:12 +01:00
Lars Müller
b7f01b0cc7
Don't save load_mod_* = false lines in world.mt (#15758) 2025-02-14 22:25:39 +01:00
sfan5
54bf5d62f2
Fix fgettext call in dlg_settings.lua
(#15614)
2025-02-14 22:17:10 +01:00
sfan5
849a583f66 Continue with 5.12.0-dev 2025-02-14 19:38:30 +01:00
sfan5
0cb7735125 Bump version to 5.11.0 2025-02-14 19:38:27 +01:00
sfan5
028949beca Delete empty languages 2025-02-14 19:13:14 +01:00
ninjum
6bdeb10c16 Translated using Weblate (Galician)
Currently translated at 99.9% (1391 of 1392 strings)
2025-02-14 19:11:16 +01:00
BlackImpostor
44cbae8fad Translated using Weblate (Russian)
Currently translated at 100.0% (1392 of 1392 strings)
2025-02-14 19:11:16 +01:00
waxtatect
f7b2d4760f Translated using Weblate (French)
Currently translated at 100.0% (1392 of 1392 strings)
2025-02-14 19:11:16 +01:00
109247019824
1ec19c2ad2 Translated using Weblate (Bulgarian)
Currently translated at 51.7% (721 of 1392 strings)
2025-02-14 19:11:12 +01:00
Linerly
9bfd39f036 Translated using Weblate (Indonesian)
Currently translated at 99.6% (1387 of 1392 strings)
2025-02-14 19:11:12 +01:00
Miguel
cfff6c4fd7 Translated using Weblate (Spanish)
Currently translated at 97.9% (1363 of 1392 strings)
2025-02-14 19:11:12 +01:00
Wuzzy
147dd3d372 Translated using Weblate (German)
Currently translated at 100.0% (1392 of 1392 strings)
2025-02-14 19:11:12 +01:00
sfan5
cda3dc08ca
Translated using Weblate (German)
Currently translated at 100.0% (1392 of 1392 strings)
2025-02-14 19:10:19 +01:00
mineplayer
78b4f929ce
Translated using Weblate (German)
Currently translated at 100.0% (1392 of 1392 strings)
2025-02-14 19:10:19 +01:00
Desour
2c50066c16 Keep the game paused in pause menu settings
The button_exit[]s were replaced by regular button[]s, to avoid a very short unpause when you
click the btn_settings (probably because it uses ClientEvent stuff).
2025-02-14 16:31:57 +01:00
202 changed files with 3119 additions and 15521 deletions

View file

@ -1,4 +1,4 @@
Checks: '-*,modernize-use-emplace,modernize-avoid-bind,misc-throw-by-value-catch-by-reference,misc-unconventional-assign-operator,performance-*'
Checks: '-*,modernize-use-emplace,modernize-avoid-bind,misc-throw-by-value-catch-by-reference,misc-unconventional-assign-operator,performance-*,-performance-avoid-endl,performance-inefficient-string-concatenation'
WarningsAsErrors: '-*,modernize-use-emplace,performance-type-promotion-in-math-fn,performance-faster-string-find,performance-implicit-cast-in-loop'
CheckOptions:
- key: performance-unnecessary-value-param.AllowedTypes

View file

@ -73,7 +73,7 @@ jobs:
env:
VCPKG_VERSION: 01f602195983451bc83e72f4214af2cbc495aa94
# 2024.05.24
vcpkg_packages: zlib zstd curl[winssl] openal-soft libvorbis libogg libjpeg-turbo sqlite3 freetype luajit gmp jsoncpp opengl-registry
vcpkg_packages: zlib zstd curl[winssl] openal-soft libvorbis libogg libjpeg-turbo sqlite3 freetype luajit gmp jsoncpp sdl2
strategy:
fail-fast: false
matrix:

View file

@ -11,7 +11,7 @@ set(CLANG_MINIMUM_VERSION "7.0.1")
# You should not need to edit these manually, use util/bump_version.sh
set(VERSION_MAJOR 5)
set(VERSION_MINOR 11)
set(VERSION_MINOR 12)
set(VERSION_PATCH 0)
set(VERSION_EXTRA "" CACHE STRING "Stuff to append to version string")

View file

@ -1,13 +1,15 @@
Luanti (formerly Minetest)
==========================
![Build Status](https://github.com/luanti-org/luanti/workflows/build/badge.svg)
[![Translation status](https://hosted.weblate.org/widgets/minetest/-/svg-badge.svg)](https://hosted.weblate.org/engage/minetest/?utm_source=widget)
[![License](https://img.shields.io/badge/license-LGPLv2.1%2B-blue.svg)](https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html)
<div align="center">
<img src="textures/base/pack/logo.png" width="32%">
<h1>Luanti (formerly Minetest)</h1>
<img src="https://github.com/luanti-org/luanti/workflows/build/badge.svg" alt="Build Status">
<a href="https://hosted.weblate.org/engage/minetest/?utm_source=widget"><img src="https://hosted.weblate.org/widgets/minetest/-/svg-badge.svg" alt="Translation status"></a>
<a href="https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html"><img src="https://img.shields.io/badge/license-LGPLv2.1%2B-blue.svg" alt="License"></a>
</div>
<br><br>
Luanti is a free open-source voxel game engine with easy modding and game creation.
Copyright (C) 2010-2024 Perttu Ahola <celeron55@gmail.com>
Copyright (C) 2010-2025 Perttu Ahola <celeron55@gmail.com>
and contributors (see source file comments and the version control log)
Table of Contents

View file

@ -1,5 +1,4 @@
diff --git a/android/app/src/main/java/org/libsdl/app/SDLActivity.java b/android/app/src/main/java/org/libsdl/app/SDLActivity.java
index fd5a056e3..83e3cf657 100644
--- a/android/app/src/main/java/org/libsdl/app/SDLActivity.java
+++ b/android/app/src/main/java/org/libsdl/app/SDLActivity.java
@@ -1345,7 +1345,12 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
@ -9,7 +8,7 @@ index fd5a056e3..83e3cf657 100644
- if ((source & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) {
+ if ((source & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE ||
+ /*
+ * CUSTOM ADDITION FOR MINETEST
+ * CUSTOM ADDITION FOR LUANTI
+ * should be upstreamed
+ */
+ (source & InputDevice.SOURCE_MOUSE_RELATIVE) == InputDevice.SOURCE_MOUSE_RELATIVE) {

View file

@ -60,8 +60,8 @@ import java.util.Locale;
public class SDLActivity extends Activity implements View.OnSystemUiVisibilityChangeListener {
private static final String TAG = "SDL";
private static final int SDL_MAJOR_VERSION = 2;
private static final int SDL_MINOR_VERSION = 30;
private static final int SDL_MICRO_VERSION = 8;
private static final int SDL_MINOR_VERSION = 32;
private static final int SDL_MICRO_VERSION = 0;
/*
// Display InputType.SOURCE/CLASS of events and devices
//
@ -790,6 +790,9 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
SDLActivity.mFullscreenModeActive = false;
}
if (Build.VERSION.SDK_INT >= 28 /* Android 9 (Pie) */) {
window.getAttributes().layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
}
}
} else {
Log.e(TAG, "error handling message, getContext() returned no Activity");
@ -1347,7 +1350,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
if ((source & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE ||
/*
* CUSTOM ADDITION FOR MINETEST
* CUSTOM ADDITION FOR LUANTI
* should be upstreamed
*/
(source & InputDevice.SOURCE_MOUSE_RELATIVE) == InputDevice.SOURCE_MOUSE_RELATIVE) {

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="label">Luanti</string>
<string name="loading">Chargement…</string>
<string name="notification_channel_name">Notification générale</string>
<string name="notification_channel_description">Notifications de Luanti</string>
<string name="unzip_notification_title">Chargement de Luanti</string>
<string name="unzip_notification_description">Moins d\'une minute…</string>
<string name="ime_dialog_done">Terminé</string>
<string name="no_web_browser">Aucun navigateur web trouvé</string>
</resources>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="label">Luanti</string>
<string name="loading">Cargando…</string>
<string name="notification_channel_name">Notificación xeral</string>
<string name="notification_channel_description">Notificacións de Luanti</string>
<string name="unzip_notification_title">Cargando Luanti</string>
<string name="unzip_notification_description">Menos de 1 minuto…</string>
<string name="ime_dialog_done">Feito</string>
<string name="no_web_browser">Non se atopou ningún navegador web</string>
</resources>

View file

@ -1,7 +1,7 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
project.ext.set("versionMajor", 5) // Version Major
project.ext.set("versionMinor", 11) // Version Minor
project.ext.set("versionMinor", 12) // Version Minor
project.ext.set("versionPatch", 0) // Version Patch
// ^ keep in sync with cmake

View file

@ -90,7 +90,7 @@ local facedir_to_dir_map = {
1, 4, 3, 2,
}
function core.facedir_to_dir(facedir)
return facedir_to_dir[facedir_to_dir_map[facedir % 32]]
return vector.copy(facedir_to_dir[facedir_to_dir_map[facedir % 32]])
end
function core.dir_to_fourdir(dir)
@ -110,7 +110,7 @@ function core.dir_to_fourdir(dir)
end
function core.fourdir_to_dir(fourdir)
return facedir_to_dir[facedir_to_dir_map[fourdir % 4]]
return vector.copy(facedir_to_dir[facedir_to_dir_map[fourdir % 4]])
end
function core.dir_to_wallmounted(dir)
@ -147,7 +147,7 @@ local wallmounted_to_dir = {
vector.new( 0, -1, 0),
}
function core.wallmounted_to_dir(wallmounted)
return wallmounted_to_dir[wallmounted % 8]
return vector.copy(wallmounted_to_dir[wallmounted % 8])
end
function core.dir_to_yaw(dir)

View file

@ -159,7 +159,6 @@ local function load()
{ heading = fgettext_ne("Movement") },
"arm_inertia",
"view_bobbing_amount",
"fall_bobbing_amount",
},
})
@ -517,7 +516,7 @@ local function get_formspec(dialogdata)
("button[0,%f;%f,0.8;back;%s]"):format(
tabsize.height + 0.2, back_w,
fgettext(INIT == "pause_menu" and "Exit" or "Back")),
INIT == "pause_menu" and fgettext("Exit") or fgettext("Back")),
("box[%f,%f;%f,0.8;#0000008C]"):format(
back_w + 0.2, tabsize.height + 0.2, checkbox_w),

View file

@ -61,7 +61,7 @@ local function create_minetest_conf_example(settings)
end
end
if entry.type == "key" then
local line = "See https://github.com/minetest/irrlicht/blob/master/include/Keycodes.h"
local line = "See https://github.com/luanti-org/luanti/blob/master/irr/include/Keycodes.h"
insert(result, "# " .. line .. "\n")
end
insert(result, "# type: " .. entry.type)

View file

@ -1,5 +1,4 @@
local builtin_shared = ...
local SCALE = 0.667
local facedir_to_euler = {
{y = 0, x = 0, z = 0},
@ -36,9 +35,7 @@ local gravity = tonumber(core.settings:get("movement_gravity")) or 9.81
core.register_entity(":__builtin:falling_node", {
initial_properties = {
visual = "item",
visual_size = vector.new(SCALE, SCALE, SCALE),
textures = {},
visual = "node",
physical = true,
is_visible = false,
collide_with_objects = true,
@ -80,41 +77,15 @@ core.register_entity(":__builtin:falling_node", {
-- Save liquidtype for falling water
self.liquidtype = def.liquidtype
-- Set entity visuals
if def.drawtype == "torchlike" or def.drawtype == "signlike" then
local textures
if def.tiles and def.tiles[1] then
local tile = def.tiles[1]
if type(tile) == "table" then
tile = tile.name
end
if def.drawtype == "torchlike" then
textures = { "("..tile..")^[transformFX", tile }
else
textures = { tile, "("..tile..")^[transformFX" }
end
end
local vsize
if def.visual_scale then
local s = def.visual_scale
vsize = vector.new(s, s, s)
end
self.object:set_properties({
is_visible = true,
visual = "upright_sprite",
visual_size = vsize,
textures = textures,
glow = def.light_source,
})
elseif def.drawtype ~= "airlike" then
local itemstring = node.name
if core.is_colored_paramtype(def.paramtype2) then
itemstring = core.itemstring_with_palette(itemstring, node.param2)
end
-- FIXME: solution needed for paramtype2 == "leveled"
-- Set up entity visuals
-- For compatibility with older clients we continue to use "item" visual
-- for simple situations.
local drawtypes = {normal=true, glasslike=true, allfaces=true, nodebox=true}
local p2types = {none=true, facedir=true, ["4dir"]=true}
if drawtypes[def.drawtype] and p2types[def.paramtype2] and def.use_texture_alpha ~= "blend" then
-- Calculate size of falling node
local s = {}
s.x = (def.visual_scale or 1) * SCALE
local s = vector.zero()
s.x = (def.visual_scale or 1) * 0.667
s.y = s.x
s.z = s.x
-- Compensate for wield_scale
@ -125,10 +96,31 @@ core.register_entity(":__builtin:falling_node", {
end
self.object:set_properties({
is_visible = true,
wield_item = itemstring,
visual = "item",
wield_item = node.name,
visual_size = s,
glow = def.light_source,
})
-- Rotate as needed
if def.paramtype2 == "facedir" then
local fdir = node.param2 % 32 % 24
local euler = facedir_to_euler[fdir + 1]
if euler then
self.object:set_rotation(euler)
end
elseif def.paramtype2 == "4dir" then
local fdir = node.param2 % 4
local euler = facedir_to_euler[fdir + 1]
if euler then
self.object:set_rotation(euler)
end
end
elseif def.drawtype ~= "airlike" then
self.object:set_properties({
is_visible = true,
node = node,
glow = def.light_source,
})
end
-- Set collision box (certain nodeboxes only for now)
@ -148,111 +140,6 @@ core.register_entity(":__builtin:falling_node", {
})
end
end
-- Rotate entity
if def.drawtype == "torchlike" then
if (def.paramtype2 == "wallmounted" or def.paramtype2 == "colorwallmounted")
and node.param2 % 8 == 7 then
self.object:set_yaw(-math.pi*0.25)
else
self.object:set_yaw(math.pi*0.25)
end
elseif ((node.param2 ~= 0 or def.drawtype == "nodebox" or def.drawtype == "mesh")
and (def.wield_image == "" or def.wield_image == nil))
or def.drawtype == "signlike"
or def.drawtype == "mesh"
or def.drawtype == "normal"
or def.drawtype == "nodebox" then
if (def.paramtype2 == "facedir" or def.paramtype2 == "colorfacedir") then
local fdir = node.param2 % 32 % 24
-- Get rotation from a precalculated lookup table
local euler = facedir_to_euler[fdir + 1]
if euler then
self.object:set_rotation(euler)
end
elseif (def.paramtype2 == "4dir" or def.paramtype2 == "color4dir") then
local fdir = node.param2 % 4
-- Get rotation from a precalculated lookup table
local euler = facedir_to_euler[fdir + 1]
if euler then
self.object:set_rotation(euler)
end
elseif (def.drawtype ~= "plantlike" and def.drawtype ~= "plantlike_rooted" and
(def.paramtype2 == "wallmounted" or def.paramtype2 == "colorwallmounted" or def.drawtype == "signlike")) then
local rot = node.param2 % 8
if (def.drawtype == "signlike" and def.paramtype2 ~= "wallmounted" and def.paramtype2 ~= "colorwallmounted") then
-- Change rotation to "floor" by default for non-wallmounted paramtype2
rot = 1
end
local pitch, yaw, roll = 0, 0, 0
if def.drawtype == "nodebox" or def.drawtype == "mesh" then
if rot == 0 then
pitch, yaw = math.pi/2, 0
elseif rot == 1 then
pitch, yaw = -math.pi/2, math.pi
elseif rot == 2 then
pitch, yaw = 0, math.pi/2
elseif rot == 3 then
pitch, yaw = 0, -math.pi/2
elseif rot == 4 then
pitch, yaw = 0, math.pi
elseif rot == 6 then
pitch, yaw = math.pi/2, 0
elseif rot == 7 then
pitch, yaw = -math.pi/2, math.pi
end
else
if rot == 1 then
pitch, yaw = math.pi, math.pi
elseif rot == 2 then
pitch, yaw = math.pi/2, math.pi/2
elseif rot == 3 then
pitch, yaw = math.pi/2, -math.pi/2
elseif rot == 4 then
pitch, yaw = math.pi/2, math.pi
elseif rot == 5 then
pitch, yaw = math.pi/2, 0
elseif rot == 6 then
pitch, yaw = math.pi, -math.pi/2
elseif rot == 7 then
pitch, yaw = 0, -math.pi/2
end
end
if def.drawtype == "signlike" then
pitch = pitch - math.pi/2
if rot == 0 then
yaw = yaw + math.pi/2
elseif rot == 1 then
yaw = yaw - math.pi/2
elseif rot == 6 then
yaw = yaw - math.pi/2
pitch = pitch + math.pi
elseif rot == 7 then
yaw = yaw + math.pi/2
pitch = pitch + math.pi
end
elseif def.drawtype == "mesh" or def.drawtype == "normal" or def.drawtype == "nodebox" then
if rot == 0 or rot == 1 then
roll = roll + math.pi
elseif rot == 6 or rot == 7 then
if def.drawtype ~= "normal" then
roll = roll - math.pi/2
end
else
yaw = yaw + math.pi
end
end
self.object:set_rotation({x=pitch, y=yaw, z=roll})
elseif (def.drawtype == "mesh" and def.paramtype2 == "degrotate") then
local p2 = (node.param2 - (def.place_param2 or 0)) % 240
local yaw = (p2 / 240) * (math.pi * 2)
self.object:set_yaw(yaw)
elseif (def.drawtype == "mesh" and def.paramtype2 == "colordegrotate") then
local p2 = (node.param2 % 32 - (def.place_param2 or 0) % 32) % 24
local yaw = (p2 / 24) * (math.pi * 2)
self.object:set_yaw(yaw)
end
end
end,
get_staticdata = function(self)

View file

@ -45,6 +45,7 @@ core.features = {
abm_without_neighbors = true,
biome_weights = true,
particle_blend_clip = true,
remove_item_match_meta = true,
}
function core.has_feature(arg)

View file

@ -57,7 +57,7 @@
"AFCMS",
"siliconsniffer",
"Wuzzy",
"Zemtzov7",
"Zemtzov7"
],
"previous_contributors": [
"Ælla Chiana Moskopp (erle) <erle@dieweltistgarnichtso.net> [Logo]",

View file

@ -21,7 +21,7 @@ local function clients_list_formspec(dialogdata)
"size[6,9.5]",
TOUCH_GUI and "padding[0.01,0.01]" or "",
"hypertext[0,0;6,1.5;;<global margin=5 halign=center valign=middle>",
fgettext("This is the list of clients connected to\n$1",
fgettext("Players connected to\n$1",
"<b>" .. core.hypertext_escape(servername) .. "</b>") .. "]",
"textlist[0.5,1.5;5,6.8;;" .. fmt_formspec_list(clients_list) .. "]",
"button[1.5,8.5;3,0.8;quit;OK]"

View file

@ -299,7 +299,7 @@ local function handle_buttons(this, fields)
worldfile:set("load_mod_" .. mod.name, mod.virtual_path)
was_set[mod.name] = true
elseif not was_set[mod.name] then
worldfile:set("load_mod_" .. mod.name, "false")
worldfile:remove("load_mod_" .. mod.name)
end
elseif mod.enabled then
gamedata.errormessage = fgettext_ne("Failed to enable mo" ..

View file

@ -190,10 +190,10 @@ local function get_formspec(tabview, name, tabdata)
local max_clients = 5
if #clients_list > max_clients then
retval = retval .. "tooltip[btn_view_clients;" ..
fgettext("Clients:\n$1", table.concat(clients_list, "\n", 1, max_clients)) .. "\n..." .. "]"
fgettext("Players:\n$1", table.concat(clients_list, "\n", 1, max_clients)) .. "\n..." .. "]"
else
retval = retval .. "tooltip[btn_view_clients;" ..
fgettext("Clients:\n$1", table.concat(clients_list, "\n")) .. "]"
fgettext("Players:\n$1", table.concat(clients_list, "\n")) .. "]"
end
retval = retval .. "style[btn_view_clients;padding=6]"
retval = retval .. "image_button[4.5,1.3;0.5,0.5;" .. core.formspec_escape(defaulttexturedir ..
@ -391,12 +391,15 @@ local function matches_query(server, query)
return name_matches and 50 or description_matches and 0
end
local function search_server_list(input)
local function search_server_list(input, tabdata)
menudata.search_result = nil
if #serverlistmgr.servers < 2 then
return
end
tabdata.pre_search_selection = tabdata.pre_search_selection or find_selected_server()
-- setup the search query
local query = parse_search_input(input)
if not query then
@ -419,11 +422,23 @@ local function search_server_list(input)
return
end
local current_server = find_selected_server()
table.sort(search_result, function(a, b)
return a.points > b.points
end)
menudata.search_result = search_result
-- Keep current selection if it's in search results
if current_server then
for _, server in ipairs(search_result) do
if server.address == current_server.address and
server.port == current_server.port then
return
end
end
end
-- Find first compatible server (favorite or public)
for _, server in ipairs(search_result) do
if is_server_protocol_compat(server.proto_min, server.proto_max) then
@ -434,6 +449,7 @@ local function search_server_list(input)
-- If no compatible server found, clear selection
set_selected_server(nil)
end
local function main_button_handler(tabview, fields, name, tabdata)
if fields.te_name then
gamedata.playername = fields.te_name
@ -471,6 +487,7 @@ local function main_button_handler(tabview, fields, name, tabdata)
end
if event.type == "CHG" then
set_selected_server(server)
tabdata.pre_search_selection = nil
return true
end
end
@ -484,11 +501,9 @@ local function main_button_handler(tabview, fields, name, tabdata)
if fields.btn_delete_favorite then
local idx = core.get_table_index("servers")
if not idx then return end
local server = tabdata.lookup[idx]
if not server then return end
serverlistmgr.delete_favorite(server)
set_selected_server(server)
serverlistmgr.delete_favorite(tabdata.lookup[idx])
set_selected_server(tabdata.lookup[idx+1])
return true
end
@ -516,13 +531,16 @@ local function main_button_handler(tabview, fields, name, tabdata)
if fields.btn_mp_clear then
tabdata.search_for = ""
menudata.search_result = nil
set_selected_server(nil)
if tabdata.pre_search_selection then
set_selected_server(tabdata.pre_search_selection)
tabdata.pre_search_selection = nil
end
return true
end
if fields.btn_mp_search or fields.key_enter_field == "te_search" then
tabdata.search_for = fields.te_search
search_server_list(fields.te_search)
search_server_list(fields.te_search, tabdata)
return true
end

View file

@ -256,8 +256,8 @@ fps_max (Maximum FPS) int 60 1 4294967295
# Vertical screen synchronization. Your system may still force VSync on even if this is disabled.
vsync (VSync) bool false
# Maximum FPS when the window is not focused, or when the game is paused.
fps_max_unfocused (FPS when unfocused or paused) int 20 1 4294967295
# Maximum FPS when the window is not focused.
fps_max_unfocused (FPS when unfocused) int 10 1 4294967295
# View distance in nodes.
viewing_range (Viewing range) int 190 20 4000
@ -295,10 +295,6 @@ arm_inertia (Arm inertia) bool true
# For example: 0 for no view bobbing; 1.0 for normal; 2.0 for double.
view_bobbing_amount (View bobbing factor) float 1.0 0.0 7.9
# Multiplier for fall bobbing.
# For example: 0 for no view bobbing; 1.0 for normal; 2.0 for double.
fall_bobbing_amount (Fall bobbing factor) float 0.03 0.0 100.0
[**Camera]
# Field of view in degrees.
@ -717,9 +713,6 @@ console_color (Console color) string (0,0,0)
# In-game chat console background alpha (opaqueness, between 0 and 255).
console_alpha (Console alpha) int 200 0 255
# Clickable weblinks (middle-click or Ctrl+left-click) enabled in chat console output.
clickable_chat_weblinks (Chat weblinks) bool true
# Optional override for chat weblink color.
chat_weblink_color (Weblink color) string #8888FF
@ -835,11 +828,12 @@ protocol_version_min (Protocol version minimum) int 1 1 65535
# Files that are not present will be fetched the usual way.
remote_media (Remote media) string
# Enable/disable running an IPv6 server.
# Enable IPv6 support for server.
# Note that clients will be able to connect with both IPv4 and IPv6.
# Ignored if bind_address is set.
#
# Requires: enable_ipv6
ipv6_server (IPv6 server) bool false
ipv6_server (IPv6 server) bool true
[*Server Security]
@ -1797,14 +1791,6 @@ profiler_print_interval (Engine profiling data print interval) int 0 0
[*Advanced]
# Enable IPv6 support (for both client and server).
# Required for IPv6 connections to work at all.
enable_ipv6 (IPv6) bool true
# If enabled, invalid world data won't cause the server to shut down.
# Only enable this if you know what you are doing.
ignore_world_load_errors (Ignore world errors) bool false
[**Graphics]
# Enables debug and error-checking in the OpenGL driver.
@ -1990,6 +1976,10 @@ lighting_boost_spread (Light curve boost spread) float 0.2 0.0 0.4
[**Networking]
# Enable IPv6 support (for both client and server).
# Required for IPv6 connections to work at all.
enable_ipv6 (IPv6) bool true
# Prometheus listener address.
# If Luanti is compiled with ENABLE_PROMETHEUS option enabled,
# enable metrics listener for Prometheus on that address.
@ -2004,7 +1994,9 @@ max_out_chat_queue_size (Maximum size of the outgoing chat queue) int 20 -1 3276
client_unload_unused_data_timeout (Mapblock unload timeout) float 600.0 0.0
# Maximum number of mapblocks for client to be kept in memory.
# Set to -1 for unlimited amount.
# Note that there is an internal dynamic minimum number of blocks that
# won't be deleted, depending on the current view range.
# Set to -1 for no limit.
client_mapblock_limit (Mapblock limit) int 7500 -1 2147483647
# Maximum number of blocks that are simultaneously sent per client.
@ -2192,6 +2184,13 @@ curl_file_download_timeout (cURL file download timeout) int 300000 5000 21474836
[**Miscellaneous]
# Clickable weblinks (middle-click or Ctrl+left-click) enabled in chat console output.
clickable_chat_weblinks (Chat weblinks) bool true
# If enabled, invalid world data won't cause the server to shut down.
# Only enable this if you know what you are doing.
ignore_world_load_errors (Ignore world errors) bool false
# Adjust the detected display density, used for scaling UI elements.
display_density_factor (Display Density Scaling Factor) float 1 0.5 5.0

View file

@ -1,4 +1,4 @@
Luanti Lua Client Modding API Reference 5.11.0
Luanti Lua Client Modding API Reference 5.12.0
==============================================
**WARNING**: if you're looking for the `minetest` namespace (e.g. `minetest.something`),

View file

@ -22,27 +22,27 @@
For Debian/Ubuntu users:
sudo apt install g++ make libc6-dev cmake libpng-dev libjpeg-dev libxi-dev libgl1-mesa-dev libsqlite3-dev libogg-dev libvorbis-dev libopenal-dev libcurl4-gnutls-dev libfreetype6-dev zlib1g-dev libgmp-dev libjsoncpp-dev libzstd-dev libluajit-5.1-dev gettext
sudo apt install g++ make libc6-dev cmake libpng-dev libjpeg-dev libgl1-mesa-dev libsqlite3-dev libogg-dev libvorbis-dev libopenal-dev libcurl4-gnutls-dev libfreetype6-dev zlib1g-dev libgmp-dev libjsoncpp-dev libzstd-dev libluajit-5.1-dev gettext libsdl2-dev
For Fedora users:
sudo dnf install make automake gcc gcc-c++ kernel-devel cmake libcurl-devel openal-soft-devel libpng-devel libjpeg-devel libvorbis-devel libXi-devel libogg-devel freetype-devel mesa-libGL-devel zlib-devel jsoncpp-devel gmp-devel sqlite-devel luajit-devel leveldb-devel ncurses-devel spatialindex-devel libzstd-devel gettext
sudo dnf install make automake gcc gcc-c++ kernel-devel cmake libcurl-devel openal-soft-devel libpng-devel libjpeg-devel libvorbis-devel libogg-devel freetype-devel mesa-libGL-devel zlib-devel jsoncpp-devel gmp-devel sqlite-devel luajit-devel leveldb-devel ncurses-devel spatialindex-devel libzstd-devel gettext SDL2-devel
For openSUSE users:
sudo zypper install gcc gcc-c++ cmake libjpeg8-devel libpng16-devel openal-soft-devel libcurl-devel sqlite3-devel luajit-devel libzstd-devel Mesa-libGL-devel libXi-devel libvorbis-devel freetype2-devel
sudo zypper install gcc gcc-c++ cmake libjpeg8-devel libpng16-devel openal-soft-devel libcurl-devel sqlite3-devel luajit-devel libzstd-devel Mesa-libGL-devel libvorbis-devel freetype2-devel SDL2-devel
For Arch users:
sudo pacman -S --needed base-devel libcurl-gnutls cmake libxi libpng libjpeg-turbo sqlite libogg libvorbis openal freetype2 jsoncpp gmp luajit leveldb ncurses zstd gettext
sudo pacman -S --needed base-devel libcurl-gnutls cmake libpng libjpeg-turbo sqlite libogg libvorbis openal freetype2 jsoncpp gmp luajit leveldb ncurses zstd gettext sdl2
For Alpine users:
sudo apk add build-base cmake libpng-dev jpeg-dev libxi-dev mesa-dev sqlite-dev libogg-dev libvorbis-dev openal-soft-dev curl-dev freetype-dev zlib-dev gmp-dev jsoncpp-dev luajit-dev zstd-dev gettext
sudo apk add build-base cmake libpng-dev jpeg-dev mesa-dev sqlite-dev libogg-dev libvorbis-dev openal-soft-dev curl-dev freetype-dev zlib-dev gmp-dev jsoncpp-dev luajit-dev zstd-dev gettext sdl2-dev
For Void users:
sudo xbps-install cmake libpng-devel jpeg-devel libXi-devel mesa sqlite-devel libogg-devel libvorbis-devel libopenal-devel libcurl-devel freetype-devel zlib-devel gmp-devel jsoncpp-devel LuaJIT-devel zstd libzstd-devel gettext
sudo xbps-install cmake libpng-devel jpeg-devel mesa sqlite-devel libogg-devel libvorbis-devel libopenal-devel libcurl-devel freetype-devel zlib-devel gmp-devel jsoncpp-devel LuaJIT-devel zstd libzstd-devel gettext SDL2-devel
## Download

View file

@ -13,9 +13,8 @@
It is highly recommended to use vcpkg as package manager.
After you successfully built vcpkg you can easily install the required libraries:
```powershell
vcpkg install zlib zstd curl[winssl] openal-soft libvorbis libogg libjpeg-turbo sqlite3 freetype luajit gmp jsoncpp gettext[tools] opengl-registry --triplet x64-windows
vcpkg install zlib zstd curl[winssl] openal-soft libvorbis libogg libjpeg-turbo sqlite3 freetype luajit gmp jsoncpp gettext[tools] sdl2 --triplet x64-windows
```
- `curl` is optional, but required to read the serverlist, `curl[winssl]` is required to use the content store.

View file

@ -1522,7 +1522,7 @@ There are a bunch of different looking node types.
* `allfaces`
* Often used for partially-transparent nodes.
* External sides of textures, and unlike other drawtypes, the external sides
of other blocks, are visible from the inside.
of other nodes, are visible from the inside.
* `allfaces_optional`
* Often used for leaves nodes.
* This switches between `normal`, `glasslike` and `allfaces` according to
@ -5689,6 +5689,8 @@ Utilities
biome_weights = true,
-- Particles can specify a "clip" blend mode (5.11.0)
particle_blend_clip = true,
-- The `match_meta` optional parameter is available for `InvRef:remove_item()` (5.12.0)
remove_item_match_meta = true,
}
```
@ -7454,7 +7456,8 @@ Misc.
* This function can be overridden by mods to change the leave message.
* `core.hash_node_position(pos)`: returns a 48-bit integer
* `pos`: table {x=number, y=number, z=number},
* Gives a unique hash number for a node position (16+16+16=48bit)
* Gives a unique numeric encoding for a node position (16+16+16=48bit)
* Despite the name, this is not a hash function (so it doesn't mix or produce collisions).
* `core.get_position_from_hash(hash)`: returns a position
* Inverse transform of `core.hash_node_position`
* `core.get_item_group(name, group)`: returns a rating
@ -7872,13 +7875,15 @@ An `InvRef` is a reference to an inventory.
can be fully added to the list
* `contains_item(listname, stack, [match_meta])`: returns `true` if
the stack of items can be fully taken from the list.
If `match_meta` is false, only the items' names are compared
(default: `false`).
* `remove_item(listname, stack)`: take as many items as specified from the
list, returns the items that were actually removed (as an `ItemStack`)
-- note that any item metadata is ignored, so attempting to remove a specific
unique item this way will likely remove the wrong one -- to do that use
`set_stack` with an empty `ItemStack`.
* If `match_meta` is `true`, item metadata is also considered when comparing
items. Otherwise, only the items names are compared. Default: `false`
* The method ignores wear.
* `remove_item(listname, stack, [match_meta])`: take as many items as specified from the
list, returns the items that were actually removed (as an `ItemStack`).
* If `match_meta` is `true` (available since feature `remove_item_match_meta`),
item metadata is also considered when comparing items. Otherwise, only the
items names are compared. Default: `false`
* The method ignores wear.
* `get_location()`: returns a location compatible to
`core.get_inventory(location)`.
* returns `{type="undefined"}` in case location is not known
@ -8827,6 +8832,14 @@ child will follow movement and rotation of that bone.
Same limits as for `thirdperson_back` apply.
Defaults to `thirdperson_back` if unspecified.
* `get_eye_offset()`: Returns camera offset vectors as set via `set_eye_offset`.
* `set_camera(params)`: Sets camera parameters.
* `mode`: Defines the camera mode used
- `any`: free choice between all modes (default)
- `first`: first-person camera
- `third`: third-person camera
- `third_front`: third-person camera, looking opposite of movement direction
* Supported by client since 5.12.0.
* `get_camera()`: Returns the camera parameters as a table as above.
* `send_mapblock(blockpos)`:
* Sends an already loaded mapblock to the player.
* Returns `false` if nothing was sent (note that this can also mean that
@ -9221,7 +9234,7 @@ Player properties need to be saved manually.
-- Clients older than 5.9.0 interpret `pointable = "blocking"` as `pointable = true`.
-- Can be overridden by the `pointabilities` of the held item.
visual = "cube" / "sprite" / "upright_sprite" / "mesh" / "wielditem" / "item",
visual = "",
-- "cube" is a node-sized cube.
-- "sprite" is a flat texture always facing the player.
-- "upright_sprite" is a vertical flat texture.
@ -9243,6 +9256,8 @@ Player properties need to be saved manually.
-- Wielditems are scaled a bit. If you want a wielditem to appear
-- to be as large as a node, use `0.667` in `visual_size`
-- "item" is similar to "wielditem" but ignores the 'wield_image' parameter.
-- "node" looks exactly like a node in-world (supported since 5.12.0)
-- Note that visual effects like waving or liquid reflections will not work.
visual_size = {x = 1, y = 1, z = 1},
-- Multipliers for the visual size. If `z` is not specified, `x` will be used
@ -9252,7 +9267,7 @@ Player properties need to be saved manually.
-- File name of mesh when using "mesh" visual
textures = {},
-- Number of required textures depends on visual.
-- Number of required textures depends on visual:
-- "cube" uses 6 textures just like a node, but all 6 must be defined.
-- "sprite" uses 1 texture.
-- "upright_sprite" uses 2 textures: {front, back}.
@ -9262,11 +9277,14 @@ Player properties need to be saved manually.
colors = {},
-- Currently unused.
node = {name = "ignore", param1=0, param2=0},
-- Node to show when using the "node" visual
use_texture_alpha = false,
-- Use texture's alpha channel.
-- Excludes "upright_sprite" and "wielditem".
-- Use texture's alpha channel for transparency blending.
-- Note: currently causes visual issues when viewed through other
-- semi-transparent materials such as water.
-- Note: ignored for "item", "wielditem" and "node" visual.
spritediv = {x = 1, y = 1},
-- Used with spritesheet textures for animation and/or frame selection
@ -9283,7 +9301,7 @@ Player properties need to be saved manually.
-- If false, object is invisible and can't be pointed.
makes_footstep_sound = false,
-- If true, is able to make footstep sounds of nodes
-- If true, object is able to make footstep sounds of nodes
-- (see node sound definition for details).
automatic_rotate = 0,
@ -9306,6 +9324,7 @@ Player properties need to be saved manually.
backface_culling = true,
-- Set to false to disable backface_culling for model
-- Note: only used by "mesh" and "cube" visual
glow = 0,
-- Add this much extra lighting when calculating texture color.
@ -9341,6 +9360,7 @@ Player properties need to be saved manually.
shaded = true,
-- Setting this to 'false' disables diffuse lighting of entity
-- Note: ignored for "item", "wielditem" and "node" visual
show_on_minimap = false,
-- Defaults to true for players, false for other entities.

View file

@ -1,4 +1,4 @@
Luanti Lua Mainmenu API Reference 5.11.0
Luanti Lua Mainmenu API Reference 5.12.0
========================================
Introduction

View file

@ -281,15 +281,27 @@ storing coordinates separately), but the format has been kept unchanged for
that part.
## `map.sqlite`
`map.sqlite` is a `SQLite3` database, containing a single table, called
`map.sqlite` is an `SQLite3` database, containing a single table, called
`blocks`. It looks like this:
```sql
CREATE TABLE `blocks` (
`x` INTEGER, `y` INTEGER, `z` INTEGER,
`data` BLOB NOT NULL,
PRIMARY KEY (`x`, `z`, `y`)
);
```
Before 5.12.0 it looked like this:
```sql
CREATE TABLE `blocks` (`pos` INT NOT NULL PRIMARY KEY, `data` BLOB);
```
## Position Hashing
Applies to the pre-5.12.0 schema:
`pos` (a node position hash) is created from the three coordinates of a
`MapBlock` using this algorithm, defined here in Python:
@ -335,8 +347,8 @@ See below for description.
> * NOTE: Byte order is MSB first (big-endian).
> * NOTE: Zlib data is in such a format that Python's `zlib` at least can
> directly decompress.
> * NOTE: Since version 29 zstd is used instead of zlib. In addition, the entire
> block is first serialized and then compressed (except the version byte).
> * NOTE: Since version 29 zstd is used instead of zlib. In addition, the
> **entire block** is first serialized and then compressed (except version byte).
`u8` version
* map format version number, see serialization.h for the latest number

View file

@ -22,11 +22,15 @@ core.register_node("basenodes:desert_stone", {
core.register_node("basenodes:dirt_with_grass", {
description = "Dirt with Grass",
tiles ={"default_grass.png",
-- Using overlays here has no real merit here but we do it anyway so
-- overlay-related bugs become more apparent in devtest.
tiles = {"default_dirt.png"},
overlay_tiles = {
"default_grass.png",
-- a little dot on the bottom to distinguish it from dirt
"default_dirt.png^basenodes_dirt_with_grass_bottom.png",
{name = "default_dirt.png^default_grass_side.png",
tileable_vertical = false}},
"basenodes_dirt_with_grass_bottom.png",
{name = "default_grass_side.png", tileable_vertical = false},
},
groups = {crumbly=3, soil=1},
})

View file

@ -66,6 +66,15 @@ core.register_entity("testentities:mesh_unshaded", {
},
})
core.register_entity("testentities:node", {
initial_properties = {
visual = "node",
node = { name = "stairs:stair_stone" },
},
})
-- More complex meshes
core.register_entity("testentities:sam", {
initial_properties = {
visual = "mesh",

View file

@ -1,10 +1,11 @@
local item_with_meta = ItemStack({name = "air", meta = {test = "abc"}})
local function get_stack_with_meta(count)
return ItemStack({name = "air", count = count, meta = {test = "abc"}})
end
local test_list = {
ItemStack("air"),
ItemStack(""),
ItemStack(item_with_meta),
ItemStack(get_stack_with_meta(1)),
}
local function compare_lists(a, b)
@ -34,12 +35,12 @@ local function test_inventory()
assert(not inv:set_width("test", -1))
inv:set_stack("test", 1, "air")
inv:set_stack("test", 3, item_with_meta)
inv:set_stack("test", 3, get_stack_with_meta(1))
assert(not inv:is_empty("test"))
assert(compare_lists(inv:get_list("test"), test_list))
assert(inv:add_item("test", "air") == ItemStack())
assert(inv:add_item("test", item_with_meta) == ItemStack())
assert(inv:add_item("test", get_stack_with_meta(1)) == ItemStack())
assert(inv:get_stack("test", 1) == ItemStack("air 2"))
assert(inv:room_for_item("test", "air 99"))
@ -48,16 +49,28 @@ local function test_inventory()
inv:set_stack("test", 2, "")
assert(inv:contains_item("test", "air"))
assert(inv:contains_item("test", "air 4"))
assert(not inv:contains_item("test", "air 5"))
assert(not inv:contains_item("test", "air 99"))
assert(inv:contains_item("test", item_with_meta, true))
assert(inv:contains_item("test", "air 2", true))
assert(not inv:contains_item("test", "air 3", true))
assert(inv:contains_item("test", get_stack_with_meta(2), true))
assert(not inv:contains_item("test", get_stack_with_meta(3), true))
-- Items should be removed in reverse and combine with first stack removed
assert(inv:remove_item("test", "air") == item_with_meta)
item_with_meta:set_count(2)
assert(inv:remove_item("test", "air 2") == item_with_meta)
assert(inv:remove_item("test", "air") == get_stack_with_meta(1))
assert(inv:remove_item("test", "air 2") == get_stack_with_meta(2))
assert(inv:remove_item("test", "air") == ItemStack("air"))
assert(inv:is_empty("test"))
inv:set_stack("test", 1, "air 3")
inv:set_stack("test", 3, get_stack_with_meta(2))
assert(inv:remove_item("test", "air 4", true) == ItemStack("air 3"))
inv:set_stack("test", 1, "air 3")
assert(inv:remove_item("test", get_stack_with_meta(3), true) == get_stack_with_meta(2))
assert(inv:remove_item("test", "air 3", true) == ItemStack("air 3"))
assert(inv:is_empty("test"))
-- Failure of set_list(s) should not change inventory
local before = inv:get_list("test")
pcall(inv.set_lists, inv, {test = true})

View file

@ -189,6 +189,29 @@ local function test_write_json()
end
unittests.register("test_write_json", test_write_json)
local function lint_json_files()
-- Check that files we ship with Luanti are valid JSON
local stack = {core.get_builtin_path()}
local checked = 0
while #stack > 0 do
local path = table.remove(stack)
for _, name in ipairs(core.get_dir_list(path, true)) do
stack[#stack+1] = path .. "/" .. name
end
for _, name in ipairs(core.get_dir_list(path, false)) do
if name:match("%.json$") then
local f = io.open(path .. "/" .. name, "rb")
print(path .. "/" .. name)
assert(core.parse_json(f:read("*all"), -1) ~= nil)
f:close()
checked = checked + 1
end
end
end
assert(checked > 0, "no files found?!")
end
unittests.register("lint_json_files", lint_json_files)
local function test_game_info()
local info = core.get_game_info()
local game_conf = Settings(info.path .. "/game.conf")

View file

@ -21,7 +21,7 @@ Aside from standard search options (`ZLIB_INCLUDE_DIR`, `ZLIB_LIBRARY`, ...) the
* `ENABLE_OPENGL` - Enable OpenGL driver
* `ENABLE_OPENGL3` (default: `OFF`) - Enable OpenGL 3+ driver
* `ENABLE_GLES2` - Enable OpenGL ES 2+ driver
* `USE_SDL2` (default: ON for Android, OFF for other platforms) - Use SDL2 instead of older native device code
* `USE_SDL2` (default: platform-dependent, usually `ON`) - Use SDL2 instead of older native device code
However, IrrlichtMt cannot be built or installed separately.

View file

@ -34,16 +34,16 @@ public:
/** \return Pointer to mesh which is displayed by this node. */
virtual IMesh *getMesh(void) = 0;
//! Sets if the scene node should not copy the materials of the mesh but use them in a read only style.
//! Sets if the scene node should not copy the materials of the mesh but use them directly.
/** In this way it is possible to change the materials of a mesh
causing all mesh scene nodes referencing this mesh to change, too.
\param readonly Flag if the materials shall be read-only. */
virtual void setReadOnlyMaterials(bool readonly) = 0;
\param shared Flag if the materials shall be shared. */
virtual void setSharedMaterials(bool shared) = 0;
//! Check if the scene node should not copy the materials of the mesh but use them in a read only style
/** This flag can be set by setReadOnlyMaterials().
\return Whether the materials are read-only. */
virtual bool isReadOnlyMaterials() const = 0;
//! Check if the scene node does not copy the materials of the mesh but uses them directly.
/** This flag can be set by setSharedMaterials().
\return Whether the materials are shared. */
virtual bool isSharedMaterials() const = 0;
};
} // end namespace scene

View file

@ -310,7 +310,11 @@ public:
\return The material at that index. */
virtual video::SMaterial &getMaterial(u32 num)
{
return video::IdentityMaterial;
// We return a default material since a reference can't be null,
// but note that writing to this is a mistake either by a child class
// or the caller, because getMaterialCount() is zero.
// Doing so will helpfully cause a segfault.
return const_cast<video::SMaterial&>(video::IdentityMaterial);
}
//! Get amount of materials used by this scene node.

View file

@ -198,9 +198,6 @@ public:
or similar. */
virtual bool supportsTouchEvents() const { return false; }
//! Checks whether windowing uses the Wayland protocol.
virtual bool isUsingWayland() const { return false; }
//! Get the current color format of the window
/** \return Color format of the window. */
virtual video::ECOLOR_FORMAT getColorFormat() const = 0;

View file

@ -472,7 +472,7 @@ public:
};
//! global const identity Material
IRRLICHT_API extern SMaterial IdentityMaterial;
IRRLICHT_API extern const SMaterial IdentityMaterial;
} // end namespace video
} // end namespace irr

View file

@ -18,47 +18,38 @@ namespace core
//! Rounding error constant often used when comparing f32 values.
const f32 ROUNDING_ERROR_f32 = 0.000001f;
const f64 ROUNDING_ERROR_f64 = 0.00000001;
constexpr f32 ROUNDING_ERROR_f32 = 0.000001f;
constexpr f64 ROUNDING_ERROR_f64 = 0.00000001;
#ifdef PI // make sure we don't collide with a define
#undef PI
#endif
//! Constant for PI.
const f32 PI = 3.14159265359f;
//! Constant for reciprocal of PI.
const f32 RECIPROCAL_PI = 1.0f / PI;
//! Constant for half of PI.
const f32 HALF_PI = PI / 2.0f;
constexpr f32 PI = M_PI;
#ifdef PI64 // make sure we don't collide with a define
#undef PI64
#endif
//! Constant for 64bit PI.
const f64 PI64 = 3.1415926535897932384626433832795028841971693993751;
//! Constant for 64bit reciprocal of PI.
const f64 RECIPROCAL_PI64 = 1.0 / PI64;
constexpr f64 PI64 = M_PI;
//! 32bit Constant for converting from degrees to radians
const f32 DEGTORAD = PI / 180.0f;
constexpr f32 DEGTORAD = PI / 180.0f;
//! 32bit constant for converting from radians to degrees (formally known as GRAD_PI)
const f32 RADTODEG = 180.0f / PI;
constexpr f32 RADTODEG = 180.0f / PI;
//! 64bit constant for converting from degrees to radians (formally known as GRAD_PI2)
const f64 DEGTORAD64 = PI64 / 180.0;
constexpr f64 DEGTORAD64 = PI64 / 180.0;
//! 64bit constant for converting from radians to degrees
const f64 RADTODEG64 = 180.0 / PI64;
constexpr f64 RADTODEG64 = 180.0 / PI64;
//! Utility function to convert a radian value to degrees
/** Provided as it can be clearer to write radToDeg(X) than RADTODEG * X
\param radians The radians value to convert to degrees.
*/
inline f32 radToDeg(f32 radians)
inline constexpr f32 radToDeg(f32 radians)
{
return RADTODEG * radians;
}
@ -67,7 +58,7 @@ inline f32 radToDeg(f32 radians)
/** Provided as it can be clearer to write radToDeg(X) than RADTODEG * X
\param radians The radians value to convert to degrees.
*/
inline f64 radToDeg(f64 radians)
inline constexpr f64 radToDeg(f64 radians)
{
return RADTODEG64 * radians;
}
@ -76,7 +67,7 @@ inline f64 radToDeg(f64 radians)
/** Provided as it can be clearer to write degToRad(X) than DEGTORAD * X
\param degrees The degrees value to convert to radians.
*/
inline f32 degToRad(f32 degrees)
inline constexpr f32 degToRad(f32 degrees)
{
return DEGTORAD * degrees;
}
@ -85,44 +76,44 @@ inline f32 degToRad(f32 degrees)
/** Provided as it can be clearer to write degToRad(X) than DEGTORAD * X
\param degrees The degrees value to convert to radians.
*/
inline f64 degToRad(f64 degrees)
inline constexpr f64 degToRad(f64 degrees)
{
return DEGTORAD64 * degrees;
}
//! returns minimum of two values. Own implementation to get rid of the STL (VS6 problems)
//! returns minimum of two values.
template <class T>
inline const T &min_(const T &a, const T &b)
{
return a < b ? a : b;
}
//! returns minimum of three values. Own implementation to get rid of the STL (VS6 problems)
//! returns minimum of three values.
template <class T>
inline const T &min_(const T &a, const T &b, const T &c)
{
return a < b ? min_(a, c) : min_(b, c);
}
//! returns maximum of two values. Own implementation to get rid of the STL (VS6 problems)
//! returns maximum of two values.
template <class T>
inline const T &max_(const T &a, const T &b)
{
return a < b ? b : a;
}
//! returns maximum of three values. Own implementation to get rid of the STL (VS6 problems)
//! returns maximum of three values.
template <class T>
inline const T &max_(const T &a, const T &b, const T &c)
{
return a < b ? max_(b, c) : max_(a, c);
}
//! returns abs of two values. Own implementation to get rid of STL (VS6 problems)
//! returns abs of two values.
template <class T>
inline T abs_(const T &a)
{
return a < (T)0 ? -a : a;
return std::abs(a);
}
//! returns linear interpolation of a and b with ratio t
@ -140,19 +131,6 @@ inline const T clamp(const T &value, const T &low, const T &high)
return min_(max_(value, low), high);
}
//! swaps the content of the passed parameters
// Note: We use the same trick as boost and use two template arguments to
// avoid ambiguity when swapping objects of an Irrlicht type that has not
// it's own swap overload. Otherwise we get conflicts with some compilers
// in combination with stl.
template <class T1, class T2>
inline void swap(T1 &a, T2 &b)
{
T1 c(a);
a = b;
b = c;
}
template <class T>
inline T roundingError();

View file

@ -162,21 +162,12 @@ public:
//! Returns true if the matrix is the identity matrix
inline bool isIdentity() const;
//! Returns true if the matrix is orthogonal
inline bool isOrthogonal() const;
//! Returns true if the matrix is the identity matrix
bool isIdentity_integer_base() const;
//! Set the translation of the current matrix. Will erase any previous values.
CMatrix4<T> &setTranslation(const vector3d<T> &translation);
//! Gets the current translation
vector3d<T> getTranslation() const;
//! Set the inverse translation of the current matrix. Will erase any previous values.
CMatrix4<T> &setInverseTranslation(const vector3d<T> &translation);
//! Make a rotation matrix from Euler angles. The 4th row and column are unmodified.
//! NOTE: Rotation order is ZYX. This means that vectors are
//! first rotated around the X, then the Y, and finally the Z axis.
@ -188,9 +179,7 @@ public:
CMatrix4<T> &setRotationDegrees(const vector3d<T> &rotation);
//! Get the rotation, as set by setRotation() when you already know the scale used to create the matrix
/** NOTE: The scale needs to be the correct one used to create this matrix.
You can _not_ use the result of getScale(), but have to save your scale
variable in another place (like ISceneNode does).
/**
NOTE: No scale value can be 0 or the result is undefined.
NOTE: It does not necessarily return the *same* Euler angles as those set by setRotationDegrees(),
but the rotation will be equivalent, i.e. will have the same result when used to rotate a vector or node.
@ -198,24 +187,18 @@ public:
WARNING: There have been troubles with this function over the years and we may still have missed some corner cases.
It's generally safer to keep the rotation and scale you used to create the matrix around and work with those.
*/
core::vector3d<T> getRotationDegrees(const vector3d<T> &scale) const;
vector3d<T> getRotationRadians(const vector3d<T> &scale) const;
//! Returns the rotation, as set by setRotation().
/** NOTE: You will have the same end-rotation as used in setRotation, but it might not use the same axis values.
NOTE: This only works correct if no other matrix operations have been done on the inner 3x3 matrix besides
setting rotation (so no scale/shear). Thought it (probably) works as long as scale doesn't flip handedness.
NOTE: This only works correctly for TRS matrix products where S is a positive, component-wise scaling (see setScale).
NOTE: It does not necessarily return the *same* Euler angles as those set by setRotationDegrees(),
but the rotation will be equivalent, i.e. will have the same result when used to rotate a vector or node.
but the rotation will be equivalent, i.e. will have the same result when used to rotate a vector or node.
*/
core::vector3d<T> getRotationDegrees() const;
vector3d<T> getRotationRadians() const;
//! Make an inverted rotation matrix from Euler angles.
/** The 4th row and column are unmodified. */
inline CMatrix4<T> &setInverseRotationRadians(const vector3d<T> &rotation);
//! Make an inverted rotation matrix from Euler angles.
/** The 4th row and column are unmodified. */
inline CMatrix4<T> &setInverseRotationDegrees(const vector3d<T> &rotation);
//! Same as getRotationRadians, but returns degrees.
vector3d<T> getRotationDegrees() const;
//! Make a rotation matrix from angle and axis, assuming left handed rotation.
/** The 4th row and column are unmodified. */
@ -225,10 +208,10 @@ public:
CMatrix4<T> &setScale(const vector3d<T> &scale);
//! Set Scale
CMatrix4<T> &setScale(const T scale) { return setScale(core::vector3d<T>(scale, scale, scale)); }
CMatrix4<T> &setScale(const T scale) { return setScale(vector3d<T>(scale, scale, scale)); }
//! Get Scale
core::vector3d<T> getScale() const;
vector3d<T> getScale() const;
//! Translate a vector by the inverse of the translation part of this matrix.
void inverseTranslateVect(vector3df &vect) const;
@ -259,7 +242,7 @@ public:
//! An alternate transform vector method, writing into an array of 4 floats
/** This operation is performed as if the vector was 4d with the 4th component =1.
NOTE: out[3] will be written to (4th vector component)*/
void transformVect(T *out, const core::vector3df &in) const;
void transformVect(T *out, const vector3df &in) const;
//! An alternate transform vector method, reading from and writing to an array of 3 floats
/** This operation is performed as if the vector was 4d with the 4th component =1
@ -274,13 +257,13 @@ public:
void translateVect(vector3df &vect) const;
//! Transforms a plane by this matrix
void transformPlane(core::plane3d<f32> &plane) const;
void transformPlane(plane3d<f32> &plane) const;
//! Transforms a plane by this matrix
void transformPlane(const core::plane3d<f32> &in, core::plane3d<f32> &out) const;
void transformPlane(const plane3d<f32> &in, plane3d<f32> &out) const;
//! Transforms a axis aligned bounding box
void transformBoxEx(core::aabbox3d<f32> &box) const;
void transformBoxEx(aabbox3d<f32> &box) const;
//! Multiplies this matrix by a 1x4 matrix
void multiplyWith1x4Matrix(T *matrix) const;
@ -338,16 +321,16 @@ public:
\param plane: plane into which the geometry if flattened into
\param point: value between 0 and 1, describing the light source.
If this is 1, it is a point light, if it is 0, it is a directional light. */
CMatrix4<T> &buildShadowMatrix(const core::vector3df &light, core::plane3df plane, f32 point = 1.0f);
CMatrix4<T> &buildShadowMatrix(const vector3df &light, plane3df plane, f32 point = 1.0f);
//! Builds a matrix which transforms a normalized Device Coordinate to Device Coordinates.
/** Used to scale <-1,-1><1,1> to viewport, for example from <-1,-1> <1,1> to the viewport <0,0><0,640> */
CMatrix4<T> &buildNDCToDCMatrix(const core::rect<s32> &area, f32 zScale);
CMatrix4<T> &buildNDCToDCMatrix(const rect<s32> &area, f32 zScale);
//! Creates a new matrix as interpolated matrix from two other ones.
/** \param b: other matrix to interpolate with
\param time: Must be a value between 0 and 1. */
CMatrix4<T> interpolate(const core::CMatrix4<T> &b, f32 time) const;
CMatrix4<T> interpolate(const CMatrix4<T> &b, f32 time) const;
//! Gets transposed matrix
CMatrix4<T> getTransposed() const;
@ -359,13 +342,13 @@ public:
/** \param from: vector to rotate from
\param to: vector to rotate to
*/
CMatrix4<T> &buildRotateFromTo(const core::vector3df &from, const core::vector3df &to);
CMatrix4<T> &buildRotateFromTo(const vector3df &from, const vector3df &to);
//! Builds a combined matrix which translates to a center before rotation and translates from origin afterwards
/** \param center Position to rotate around
\param translate Translation applied after the rotation
*/
void setRotationCenter(const core::vector3df &center, const core::vector3df &translate);
void setRotationCenter(const vector3df &center, const vector3df &translate);
//! Builds a matrix which rotates a source vector to a look vector over an arbitrary axis
/** \param camPos: viewer position in world coo
@ -374,11 +357,11 @@ public:
\param axis: axis to rotate about
\param from: source vector to rotate from
*/
void buildAxisAlignedBillboard(const core::vector3df &camPos,
const core::vector3df &center,
const core::vector3df &translation,
const core::vector3df &axis,
const core::vector3df &from);
void buildAxisAlignedBillboard(const vector3df &camPos,
const vector3df &center,
const vector3df &translation,
const vector3df &axis,
const vector3df &from);
/*
construct 2D Texture transformations
@ -386,9 +369,9 @@ public:
*/
//! Set to a texture transformation matrix with the given parameters.
CMatrix4<T> &buildTextureTransform(f32 rotateRad,
const core::vector2df &rotatecenter,
const core::vector2df &translate,
const core::vector2df &scale);
const vector2df &rotatecenter,
const vector2df &translate,
const vector2df &scale);
//! Set texture transformation rotation
/** Rotate about z axis, recenter at (0.5,0.5).
@ -439,9 +422,12 @@ public:
CMatrix4<T> &setM(const T *data);
//! Compare two matrices using the equal method
bool equals(const core::CMatrix4<T> &other, const T tolerance = (T)ROUNDING_ERROR_f64) const;
bool equals(const CMatrix4<T> &other, const T tolerance = (T)ROUNDING_ERROR_f64) const;
private:
template <bool degrees>
vector3d<T> getRotation(const vector3d<T> &scale) const;
//! Matrix data, stored in row-major order
T M[16];
};
@ -645,21 +631,8 @@ inline CMatrix4<T> &CMatrix4<T>::operator*=(const T &scalar)
template <class T>
inline CMatrix4<T> &CMatrix4<T>::operator*=(const CMatrix4<T> &other)
{
#if defined(USE_MATRIX_TEST)
// do checks on your own in order to avoid copy creation
if (!other.isIdentity()) {
if (this->isIdentity()) {
return (*this = other);
} else {
CMatrix4<T> temp(*this);
return setbyproduct_nocheck(temp, other);
}
}
return *this;
#else
CMatrix4<T> temp(*this);
return setbyproduct_nocheck(temp, other);
#endif
}
//! multiply by another matrix
@ -699,30 +672,13 @@ inline CMatrix4<T> &CMatrix4<T>::setbyproduct_nocheck(const CMatrix4<T> &other_a
template <class T>
inline CMatrix4<T> &CMatrix4<T>::setbyproduct(const CMatrix4<T> &other_a, const CMatrix4<T> &other_b)
{
#if defined(USE_MATRIX_TEST)
if (other_a.isIdentity())
return (*this = other_b);
else if (other_b.isIdentity())
return (*this = other_a);
else
return setbyproduct_nocheck(other_a, other_b);
#else
return setbyproduct_nocheck(other_a, other_b);
#endif
}
//! multiply by another matrix
template <class T>
inline CMatrix4<T> CMatrix4<T>::operator*(const CMatrix4<T> &m2) const
{
#if defined(USE_MATRIX_TEST)
// Testing purpose..
if (this->isIdentity())
return m2;
if (m2.isIdentity())
return *this;
#endif
CMatrix4<T> m3(EM4CONST_NOTHING);
const T *m1 = M;
@ -764,15 +720,6 @@ inline CMatrix4<T> &CMatrix4<T>::setTranslation(const vector3d<T> &translation)
return *this;
}
template <class T>
inline CMatrix4<T> &CMatrix4<T>::setInverseTranslation(const vector3d<T> &translation)
{
M[12] = -translation.X;
M[13] = -translation.Y;
M[14] = -translation.Z;
return *this;
}
template <class T>
inline CMatrix4<T> &CMatrix4<T>::setScale(const vector3d<T> &scale)
{
@ -805,13 +752,7 @@ inline vector3d<T> CMatrix4<T>::getScale() const
template <class T>
inline CMatrix4<T> &CMatrix4<T>::setRotationDegrees(const vector3d<T> &rotation)
{
return setRotationRadians(rotation * core::DEGTORAD);
}
template <class T>
inline CMatrix4<T> &CMatrix4<T>::setInverseRotationDegrees(const vector3d<T> &rotation)
{
return setInverseRotationRadians(rotation * core::DEGTORAD);
return setRotationRadians(rotation * DEGTORAD);
}
template <class T>
@ -841,91 +782,60 @@ inline CMatrix4<T> &CMatrix4<T>::setRotationRadians(const vector3d<T> &rotation)
return *this;
}
//! Returns a rotation which (mostly) works in combination with the given scale
/**
This code was originally written by by Chev (assuming no scaling back then,
we can be blamed for all problems added by regarding scale)
*/
template <class T>
inline core::vector3d<T> CMatrix4<T>::getRotationDegrees(const vector3d<T> &scale_) const
template <bool degrees>
inline vector3d<T> CMatrix4<T>::getRotation(const vector3d<T> &scale_) const
{
// Based on code by Chev
const CMatrix4<T> &mat = *this;
const core::vector3d<f64> scale(core::iszero(scale_.X) ? FLT_MAX : scale_.X, core::iszero(scale_.Y) ? FLT_MAX : scale_.Y, core::iszero(scale_.Z) ? FLT_MAX : scale_.Z);
const core::vector3d<f64> invScale(core::reciprocal(scale.X), core::reciprocal(scale.Y), core::reciprocal(scale.Z));
const vector3d<f64> scale(iszero(scale_.X) ? FLT_MAX : scale_.X, iszero(scale_.Y) ? FLT_MAX : scale_.Y, iszero(scale_.Z) ? FLT_MAX : scale_.Z);
const vector3d<f64> invScale(reciprocal(scale.X), reciprocal(scale.Y), reciprocal(scale.Z));
f64 Y = -asin(core::clamp(mat[2] * invScale.X, -1.0, 1.0));
const f64 C = cos(Y);
Y *= RADTODEG64;
f64 a = clamp(mat[2] * invScale.X, -1.0, 1.0);
f64 Y = -asin(a);
f64 rotx, roty, X, Z;
if (!core::iszero((T)C)) {
const f64 invC = core::reciprocal(C);
rotx = mat[10] * invC * invScale.Z;
roty = mat[6] * invC * invScale.Y;
X = atan2(roty, rotx) * RADTODEG64;
rotx = mat[0] * invC * invScale.X;
roty = mat[1] * invC * invScale.X;
Z = atan2(roty, rotx) * RADTODEG64;
if (!core::equals(std::abs(a), 1.0)) {
// abs(a) = abs(sin(Y)) = 1 <=> cos(Y) = 0
rotx = mat[10] * invScale.Z;
roty = mat[6] * invScale.Y;
X = atan2(roty, rotx);
rotx = mat[0] * invScale.X;
roty = mat[1] * invScale.X;
Z = atan2(roty, rotx);
} else {
X = 0.0;
rotx = mat[5] * invScale.Y;
roty = -mat[4] * invScale.Y;
Z = atan2(roty, rotx) * RADTODEG64;
rotx = mat[5];
roty = -mat[4];
Z = atan2(roty, rotx);
}
// fix values that get below zero
if (X < 0.0)
X += 360.0;
if (Y < 0.0)
Y += 360.0;
if (Z < 0.0)
Z += 360.0;
if (degrees) {
X *= core::RADTODEG64;
Y *= core::RADTODEG64;
Z *= core::RADTODEG64;
}
return vector3d<T>((T)X, (T)Y, (T)Z);
}
//! Returns a rotation that is equivalent to that set by setRotationDegrees().
template <class T>
inline vector3d<T> CMatrix4<T>::getRotationRadians(const vector3d<T> &scale) const
{
return getRotation<false>(scale);
}
template <class T>
inline vector3d<T> CMatrix4<T>::getRotationRadians() const
{
return getRotationRadians(getScale());
}
template <class T>
inline vector3d<T> CMatrix4<T>::getRotationDegrees() const
{
// Note: Using getScale() here make it look like it could do matrix decomposition.
// It can't! It works (or should work) as long as rotation doesn't flip the handedness
// aka scale swapping 1 or 3 axes. (I think we could catch that as well by comparing
// crossproduct of first 2 axes to direction of third axis, but TODO)
// And maybe it should also offer the solution for the simple calculation
// without regarding scaling as Irrlicht did before 1.7
vector3d<T> scale(getScale());
return getRotationDegrees(scale);
}
//! Sets matrix to rotation matrix of inverse angles given as parameters
template <class T>
inline CMatrix4<T> &CMatrix4<T>::setInverseRotationRadians(const vector3d<T> &rotation)
{
f64 cPitch = cos(rotation.X);
f64 sPitch = sin(rotation.X);
f64 cYaw = cos(rotation.Y);
f64 sYaw = sin(rotation.Y);
f64 cRoll = cos(rotation.Z);
f64 sRoll = sin(rotation.Z);
M[0] = (T)(cYaw * cRoll);
M[4] = (T)(cYaw * sRoll);
M[8] = (T)(-sYaw);
f64 sPitch_sYaw = sPitch * sYaw;
f64 cPitch_sYaw = cPitch * sYaw;
M[1] = (T)(sPitch_sYaw * cRoll - cPitch * sRoll);
M[5] = (T)(sPitch_sYaw * sRoll + cPitch * cRoll);
M[9] = (T)(sPitch * cYaw);
M[2] = (T)(cPitch_sYaw * cRoll + sPitch * sRoll);
M[6] = (T)(cPitch_sYaw * sRoll - sPitch * cRoll);
M[10] = (T)(cPitch * cYaw);
return *this;
return getRotation<true>(getScale());
}
//! Sets matrix to rotation matrix defined by axis and angle, assuming LH rotation
@ -959,8 +869,6 @@ inline CMatrix4<T> &CMatrix4<T>::setRotationAxisRadians(const T &angle, const ve
return *this;
}
/*!
*/
template <class T>
inline CMatrix4<T> &CMatrix4<T>::makeIdentity()
{
@ -1002,77 +910,6 @@ inline bool CMatrix4<T>::isIdentity() const
return true;
}
/* Check orthogonality of matrix. */
template <class T>
inline bool CMatrix4<T>::isOrthogonal() const
{
T dp = M[0] * M[4] + M[1] * M[5] + M[2] * M[6] + M[3] * M[7];
if (!iszero(dp))
return false;
dp = M[0] * M[8] + M[1] * M[9] + M[2] * M[10] + M[3] * M[11];
if (!iszero(dp))
return false;
dp = M[0] * M[12] + M[1] * M[13] + M[2] * M[14] + M[3] * M[15];
if (!iszero(dp))
return false;
dp = M[4] * M[8] + M[5] * M[9] + M[6] * M[10] + M[7] * M[11];
if (!iszero(dp))
return false;
dp = M[4] * M[12] + M[5] * M[13] + M[6] * M[14] + M[7] * M[15];
if (!iszero(dp))
return false;
dp = M[8] * M[12] + M[9] * M[13] + M[10] * M[14] + M[11] * M[15];
return (iszero(dp));
}
/*
doesn't solve floating range problems..
but takes care on +/- 0 on translation because we are changing it..
reducing floating point branches
but it needs the floats in memory..
*/
template <class T>
inline bool CMatrix4<T>::isIdentity_integer_base() const
{
if (IR(M[0]) != F32_VALUE_1)
return false;
if (IR(M[1]) != 0)
return false;
if (IR(M[2]) != 0)
return false;
if (IR(M[3]) != 0)
return false;
if (IR(M[4]) != 0)
return false;
if (IR(M[5]) != F32_VALUE_1)
return false;
if (IR(M[6]) != 0)
return false;
if (IR(M[7]) != 0)
return false;
if (IR(M[8]) != 0)
return false;
if (IR(M[9]) != 0)
return false;
if (IR(M[10]) != F32_VALUE_1)
return false;
if (IR(M[11]) != 0)
return false;
if (IR(M[12]) != 0)
return false;
if (IR(M[13]) != 0)
return false;
if (IR(M[13]) != 0)
return false;
if (IR(M[15]) != F32_VALUE_1)
return false;
return true;
}
template <class T>
inline vector3d<T> CMatrix4<T>::rotateAndScaleVect(const vector3d<T> &v) const
{
@ -1104,7 +941,7 @@ inline vector3d<T> CMatrix4<T>::transformVect(const vector3d<T> &v) const
}
template <class T>
inline void CMatrix4<T>::transformVect(T *out, const core::vector3df &in) const
inline void CMatrix4<T>::transformVect(T *out, const vector3df &in) const
{
out[0] = in.X * M[0] + in.Y * M[4] + in.Z * M[8] + M[12];
out[1] = in.X * M[1] + in.Y * M[5] + in.Z * M[9] + M[13];
@ -1131,7 +968,7 @@ inline void CMatrix4<T>::transformVec4(T *out, const T *in) const
//! Transforms a plane by this matrix
template <class T>
inline void CMatrix4<T>::transformPlane(core::plane3d<f32> &plane) const
inline void CMatrix4<T>::transformPlane(plane3d<f32> &plane) const
{
vector3df member;
// Transform the plane member point, i.e. rotate, translate and scale it.
@ -1145,7 +982,7 @@ inline void CMatrix4<T>::transformPlane(core::plane3d<f32> &plane) const
//! Transforms a plane by this matrix
template <class T>
inline void CMatrix4<T>::transformPlane(const core::plane3d<f32> &in, core::plane3d<f32> &out) const
inline void CMatrix4<T>::transformPlane(const plane3d<f32> &in, plane3d<f32> &out) const
{
out = in;
transformPlane(out);
@ -1153,13 +990,8 @@ inline void CMatrix4<T>::transformPlane(const core::plane3d<f32> &in, core::plan
//! Transforms a axis aligned bounding box more accurately than transformBox()
template <class T>
inline void CMatrix4<T>::transformBoxEx(core::aabbox3d<f32> &box) const
inline void CMatrix4<T>::transformBoxEx(aabbox3d<f32> &box) const
{
#if defined(USE_MATRIX_TEST)
if (isIdentity())
return;
#endif
const f32 Amin[3] = {box.MinEdge.X, box.MinEdge.Y, box.MinEdge.Z};
const f32 Amax[3] = {box.MaxEdge.X, box.MaxEdge.Y, box.MaxEdge.Z};
@ -1242,12 +1074,6 @@ inline bool CMatrix4<T>::getInverse(CMatrix4<T> &out) const
/// The inverse is calculated using Cramers rule.
/// If no inverse exists then 'false' is returned.
#if defined(USE_MATRIX_TEST)
if (this->isIdentity()) {
out = *this;
return true;
}
#endif
const CMatrix4<T> &m = *this;
f32 d = (m[0] * m[5] - m[1] * m[4]) * (m[10] * m[15] - m[11] * m[14]) -
@ -1257,10 +1083,10 @@ inline bool CMatrix4<T>::getInverse(CMatrix4<T> &out) const
(m[1] * m[7] - m[3] * m[5]) * (m[8] * m[14] - m[10] * m[12]) +
(m[2] * m[7] - m[3] * m[6]) * (m[8] * m[13] - m[9] * m[12]);
if (core::iszero(d, FLT_MIN))
if (iszero(d, FLT_MIN))
return false;
d = core::reciprocal(d);
d = reciprocal(d);
out[0] = d * (m[5] * (m[10] * m[15] - m[11] * m[14]) +
m[6] * (m[11] * m[13] - m[9] * m[15]) +
@ -1642,7 +1468,7 @@ inline CMatrix4<T> &CMatrix4<T>::buildProjectionMatrixPerspectiveLH(
// Builds a matrix that flattens geometry into a plane.
template <class T>
inline CMatrix4<T> &CMatrix4<T>::buildShadowMatrix(const core::vector3df &light, core::plane3df plane, f32 point)
inline CMatrix4<T> &CMatrix4<T>::buildShadowMatrix(const vector3df &light, plane3df plane, f32 point)
{
plane.Normal.normalize();
const f32 d = plane.Normal.dotProduct(light);
@ -1748,7 +1574,7 @@ inline CMatrix4<T> &CMatrix4<T>::buildCameraLookAtMatrixRH(
// creates a new matrix as interpolated matrix from this and the passed one.
template <class T>
inline CMatrix4<T> CMatrix4<T>::interpolate(const core::CMatrix4<T> &b, f32 time) const
inline CMatrix4<T> CMatrix4<T>::interpolate(const CMatrix4<T> &b, f32 time) const
{
CMatrix4<T> mat(EM4CONST_NOTHING);
@ -1797,7 +1623,7 @@ inline void CMatrix4<T>::getTransposed(CMatrix4<T> &o) const
// used to scale <-1,-1><1,1> to viewport
template <class T>
inline CMatrix4<T> &CMatrix4<T>::buildNDCToDCMatrix(const core::rect<s32> &viewport, f32 zScale)
inline CMatrix4<T> &CMatrix4<T>::buildNDCToDCMatrix(const rect<s32> &viewport, f32 zScale)
{
const f32 scaleX = (viewport.getWidth() - 0.75f) * 0.5f;
const f32 scaleY = -(viewport.getHeight() - 0.75f) * 0.5f;
@ -1808,7 +1634,7 @@ inline CMatrix4<T> &CMatrix4<T>::buildNDCToDCMatrix(const core::rect<s32> &viewp
makeIdentity();
M[12] = (T)dx;
M[13] = (T)dy;
return setScale(core::vector3d<T>((T)scaleX, (T)scaleY, (T)zScale));
return setScale(vector3d<T>((T)scaleX, (T)scaleY, (T)zScale));
}
//! Builds a matrix that rotates from one vector to another
@ -1818,25 +1644,25 @@ inline CMatrix4<T> &CMatrix4<T>::buildNDCToDCMatrix(const core::rect<s32> &viewp
http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToMatrix/index.htm
*/
template <class T>
inline CMatrix4<T> &CMatrix4<T>::buildRotateFromTo(const core::vector3df &from, const core::vector3df &to)
inline CMatrix4<T> &CMatrix4<T>::buildRotateFromTo(const vector3df &from, const vector3df &to)
{
// unit vectors
core::vector3df f(from);
core::vector3df t(to);
vector3df f(from);
vector3df t(to);
f.normalize();
t.normalize();
// axis multiplication by sin
core::vector3df vs(t.crossProduct(f));
vector3df vs(t.crossProduct(f));
// axis of rotation
core::vector3df v(vs);
vector3df v(vs);
v.normalize();
// cosine angle
T ca = f.dotProduct(t);
core::vector3df vt(v * (1 - ca));
vector3df vt(v * (1 - ca));
M[0] = vt.X * v.X + ca;
M[5] = vt.Y * v.Y + ca;
@ -1875,29 +1701,29 @@ inline CMatrix4<T> &CMatrix4<T>::buildRotateFromTo(const core::vector3df &from,
*/
template <class T>
inline void CMatrix4<T>::buildAxisAlignedBillboard(
const core::vector3df &camPos,
const core::vector3df &center,
const core::vector3df &translation,
const core::vector3df &axis,
const core::vector3df &from)
const vector3df &camPos,
const vector3df &center,
const vector3df &translation,
const vector3df &axis,
const vector3df &from)
{
// axis of rotation
core::vector3df up = axis;
vector3df up = axis;
up.normalize();
const core::vector3df forward = (camPos - center).normalize();
const core::vector3df right = up.crossProduct(forward).normalize();
const vector3df forward = (camPos - center).normalize();
const vector3df right = up.crossProduct(forward).normalize();
// correct look vector
const core::vector3df look = right.crossProduct(up);
const vector3df look = right.crossProduct(up);
// rotate from to
// axis multiplication by sin
const core::vector3df vs = look.crossProduct(from);
const vector3df vs = look.crossProduct(from);
// cosine angle
const f32 ca = from.dotProduct(look);
core::vector3df vt(up * (1.f - ca));
vector3df vt(up * (1.f - ca));
M[0] = static_cast<T>(vt.X * up.X + ca);
M[5] = static_cast<T>(vt.Y * up.Y + ca);
@ -1924,7 +1750,7 @@ inline void CMatrix4<T>::buildAxisAlignedBillboard(
//! Builds a combined matrix which translate to a center before rotation and translate afterward
template <class T>
inline void CMatrix4<T>::setRotationCenter(const core::vector3df &center, const core::vector3df &translation)
inline void CMatrix4<T>::setRotationCenter(const vector3df &center, const vector3df &translation)
{
M[12] = -M[0] * center.X - M[4] * center.Y - M[8] * center.Z + (center.X - translation.X);
M[13] = -M[1] * center.X - M[5] * center.Y - M[9] * center.Z + (center.Y - translation.Y);
@ -1945,9 +1771,9 @@ inline void CMatrix4<T>::setRotationCenter(const core::vector3df &center, const
template <class T>
inline CMatrix4<T> &CMatrix4<T>::buildTextureTransform(f32 rotateRad,
const core::vector2df &rotatecenter,
const core::vector2df &translate,
const core::vector2df &scale)
const vector2df &rotatecenter,
const vector2df &translate,
const vector2df &scale)
{
const f32 c = cosf(rotateRad);
const f32 s = sinf(rotateRad);
@ -2052,7 +1878,7 @@ inline CMatrix4<T> &CMatrix4<T>::setM(const T *data)
//! Compare two matrices using the equal method
template <class T>
inline bool CMatrix4<T>::equals(const core::CMatrix4<T> &other, const T tolerance) const
inline bool CMatrix4<T>::equals(const CMatrix4<T> &other, const T tolerance) const
{
for (s32 i = 0; i < 16; ++i)
if (!core::equals(M[i], other.M[i], tolerance))

View file

@ -33,6 +33,12 @@ public:
explicit constexpr vector3d(T n) :
X(n), Y(n), Z(n) {}
template <class U>
constexpr static vector3d<T> from(const vector3d<U> &other)
{
return {static_cast<T>(other.X), static_cast<T>(other.Y), static_cast<T>(other.Z)};
}
// operators
vector3d<T> operator-() const { return vector3d<T>(-X, -Y, -Z); }

View file

@ -619,7 +619,7 @@ void CAnimatedMeshSceneNode::animateJoints(bool CalculateAbsolutePositions)
// Code is slow, needs to be fixed up
const core::quaternion RotationStart(PretransitingSave[n].getRotationDegrees() * core::DEGTORAD);
const core::quaternion RotationStart(PretransitingSave[n].getRotationRadians());
const core::quaternion RotationEnd(JointChildSceneNodes[n]->getRotation() * core::DEGTORAD);
core::quaternion QRotation;

View file

@ -546,16 +546,6 @@ void SelfType::MeshExtractor::deferAddMesh(
});
}
// Base transformation between left & right handed coordinate systems.
// This just inverts the Z axis.
static const core::matrix4 leftToRight = core::matrix4(
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, -1, 0,
0, 0, 0, 1
);
static const core::matrix4 rightToLeft = leftToRight;
static core::matrix4 loadTransform(const tiniergltf::Node::Matrix &m, SkinnedMesh::SJoint *joint)
{
// Note: Under the hood, this casts these doubles to floats.
@ -570,14 +560,7 @@ static core::matrix4 loadTransform(const tiniergltf::Node::Matrix &m, SkinnedMes
auto scale = mat.getScale();
joint->Animatedscale = scale;
core::matrix4 inverseScale;
inverseScale.setScale(core::vector3df(
scale.X == 0 ? 0 : 1 / scale.X,
scale.Y == 0 ? 0 : 1 / scale.Y,
scale.Z == 0 ? 0 : 1 / scale.Z));
core::matrix4 axisNormalizedMat = inverseScale * mat;
joint->Animatedrotation = axisNormalizedMat.getRotationDegrees();
joint->Animatedrotation = mat.getRotationRadians(scale);
// Invert the rotation because it is applied using `getMatrix_transposed`,
// which again inverts.
joint->Animatedrotation.makeInverse();

View file

@ -308,8 +308,6 @@ CIrrDeviceSDL::CIrrDeviceSDL(const SIrrlichtCreationParameters &param) :
if (SDL_Init(flags) < 0) {
os::Printer::log("Unable to initialize SDL", SDL_GetError(), ELL_ERROR);
Close = true;
} else {
os::Printer::log("SDL initialized", ELL_INFORMATION);
}
}
@ -324,21 +322,27 @@ CIrrDeviceSDL::CIrrDeviceSDL(const SIrrlichtCreationParameters &param) :
}
}
SDL_VERSION(&Info.version);
core::stringc sdlver = "SDL ";
{
SDL_version v{};
SDL_GetVersion(&v);
sdlver += v.major;
sdlver += ".";
sdlver += v.minor;
sdlver += ".";
sdlver += v.patch;
// the SDL team seems to intentionally number sdl2-compat this way:
// <https://github.com/libsdl-org/sdl2-compat/tags>
if (v.patch >= 50)
sdlver += " (compat)";
#ifndef _IRR_EMSCRIPTEN_PLATFORM_
SDL_GetWindowWMInfo(Window, &Info);
#endif //_IRR_EMSCRIPTEN_PLATFORM_
core::stringc sdlversion = "SDL Version ";
sdlversion += Info.version.major;
sdlversion += ".";
sdlversion += Info.version.minor;
sdlversion += ".";
sdlversion += Info.version.patch;
sdlver += " on ";
sdlver += SDL_GetPlatform();
}
Operator = new COSOperator(sdlversion);
Operator = new COSOperator(sdlver);
if (SDLDeviceInstances == 1) {
os::Printer::log(sdlversion.c_str(), ELL_INFORMATION);
os::Printer::log(sdlver.c_str(), ELL_INFORMATION);
}
// create cursor control
@ -706,6 +710,10 @@ bool CIrrDeviceSDL::run()
irrevent.MouseInput.X = MouseX;
irrevent.MouseInput.Y = MouseY;
// wheel y can be 0 if scrolling sideways
if (irrevent.MouseInput.Wheel == 0.0f)
break;
postEventFromUser(irrevent);
break;
}
@ -1248,15 +1256,6 @@ bool CIrrDeviceSDL::supportsTouchEvents() const
return true;
}
//! Checks whether windowing uses the Wayland protocol.
bool CIrrDeviceSDL::isUsingWayland() const
{
if (!Window)
return false;
auto *name = SDL_GetCurrentVideoDriver();
return name && !strcmp(name, "wayland");
}
//! returns if window is active. if not, nothing need to be drawn
bool CIrrDeviceSDL::isWindowActive() const
{

View file

@ -96,9 +96,6 @@ public:
//! Checks if the Irrlicht device supports touch events.
bool supportsTouchEvents() const override;
//! Checks whether windowing uses the Wayland protocol.
bool isUsingWayland() const override;
//! Get the position of this window on screen
core::position2di getWindowPosition() override;
@ -340,7 +337,6 @@ private:
};
core::array<SKeyMap> KeyMap;
SDL_SysWMinfo Info;
s32 CurrentTouchCount;
bool IsInBackground;

View file

@ -1,6 +1,6 @@
# When enabling SDL2 by default on macOS, don't forget to change
# "NSHighResolutionCapable" to true in "Info.plist".
if(ANDROID)
if(NOT APPLE)
set(DEFAULT_SDL2 ON)
endif()
@ -33,6 +33,15 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "^(GNU|Clang|AppleClang)$")
elseif(MSVC)
string(APPEND CMAKE_CXX_STANDARD_LIBRARIES " msvcrt.lib") # ???? fuck off
add_compile_definitions(
# Suppress some useless warnings
_CRT_SECURE_NO_DEPRECATE
# Get M_PI to work
_USE_MATH_DEFINES
# Don't define min/max macros in minwindef.h
NOMINMAX
)
add_compile_options(/Zl)
# Enable SSE for floating point math on 32-bit x86 by default

View file

@ -21,7 +21,7 @@ CMeshSceneNode::CMeshSceneNode(IMesh *mesh, ISceneNode *parent, ISceneManager *m
const core::vector3df &scale) :
IMeshSceneNode(parent, mgr, id, position, rotation, scale),
Mesh(0),
PassCount(0), ReadOnlyMaterials(false)
PassCount(0), SharedMaterials(false)
{
setMesh(mesh);
}
@ -49,9 +49,9 @@ void CMeshSceneNode::OnRegisterSceneNode()
int solidCount = 0;
// count transparent and solid materials in this scene node
const u32 numMaterials = ReadOnlyMaterials ? Mesh->getMeshBufferCount() : Materials.size();
const u32 numMaterials = SharedMaterials ? Mesh->getMeshBufferCount() : Materials.size();
for (u32 i = 0; i < numMaterials; ++i) {
const video::SMaterial &material = ReadOnlyMaterials ? Mesh->getMeshBuffer(i)->getMaterial() : Materials[i];
const auto &material = SharedMaterials ? Mesh->getMeshBuffer(i)->getMaterial() : Materials[i];
if (driver->needsTransparentRenderPass(material))
++transparentCount;
@ -93,7 +93,7 @@ void CMeshSceneNode::render()
for (u32 i = 0; i < Mesh->getMeshBufferCount(); ++i) {
scene::IMeshBuffer *mb = Mesh->getMeshBuffer(i);
if (mb) {
const video::SMaterial &material = ReadOnlyMaterials ? mb->getMaterial() : Materials[i];
const auto &material = SharedMaterials ? mb->getMaterial() : Materials[i];
const bool transparent = driver->needsTransparentRenderPass(material);
@ -164,14 +164,10 @@ const core::aabbox3d<f32> &CMeshSceneNode::getBoundingBox() const
//! returns the material based on the zero based index i. To get the amount
//! of materials used by this scene node, use getMaterialCount().
//! This function is needed for inserting the node into the scene hierarchy on a
//! optimal position for minimizing renderstate changes, but can also be used
//! to directly modify the material of a scene node.
video::SMaterial &CMeshSceneNode::getMaterial(u32 i)
{
if (Mesh && ReadOnlyMaterials && i < Mesh->getMeshBufferCount()) {
ReadOnlyMaterial = Mesh->getMeshBuffer(i)->getMaterial();
return ReadOnlyMaterial;
if (Mesh && SharedMaterials && i < Mesh->getMeshBufferCount()) {
return Mesh->getMeshBuffer(i)->getMaterial();
}
if (i >= Materials.size())
@ -183,7 +179,7 @@ video::SMaterial &CMeshSceneNode::getMaterial(u32 i)
//! returns amount of materials used by this scene node.
u32 CMeshSceneNode::getMaterialCount() const
{
if (Mesh && ReadOnlyMaterials)
if (Mesh && SharedMaterials)
return Mesh->getMeshBufferCount();
return Materials.size();
@ -206,9 +202,10 @@ void CMeshSceneNode::copyMaterials()
{
Materials.clear();
if (Mesh) {
if (Mesh && !SharedMaterials) {
video::SMaterial mat;
Materials.reserve(Mesh->getMeshBufferCount());
for (u32 i = 0; i < Mesh->getMeshBufferCount(); ++i) {
IMeshBuffer *mb = Mesh->getMeshBuffer(i);
if (mb)
@ -222,15 +219,18 @@ void CMeshSceneNode::copyMaterials()
//! Sets if the scene node should not copy the materials of the mesh but use them in a read only style.
/* In this way it is possible to change the materials a mesh causing all mesh scene nodes
referencing this mesh to change too. */
void CMeshSceneNode::setReadOnlyMaterials(bool readonly)
void CMeshSceneNode::setSharedMaterials(bool shared)
{
ReadOnlyMaterials = readonly;
if (SharedMaterials != shared) {
SharedMaterials = shared;
copyMaterials();
}
}
//! Returns if the scene node should not copy the materials of the mesh but use them in a read only style
bool CMeshSceneNode::isReadOnlyMaterials() const
bool CMeshSceneNode::isSharedMaterials() const
{
return ReadOnlyMaterials;
return SharedMaterials;
}
//! Creates a clone of this scene node and its children.
@ -245,7 +245,7 @@ ISceneNode *CMeshSceneNode::clone(ISceneNode *newParent, ISceneManager *newManag
newManager, ID, RelativeTranslation, RelativeRotation, RelativeScale);
nb->cloneMembers(this, newManager);
nb->ReadOnlyMaterials = ReadOnlyMaterials;
nb->SharedMaterials = SharedMaterials;
nb->Materials = Materials;
if (newParent)

View file

@ -52,13 +52,16 @@ public:
//! Returns the current mesh
IMesh *getMesh(void) override { return Mesh; }
//! Sets if the scene node should not copy the materials of the mesh but use them in a read only style.
/* In this way it is possible to change the materials a mesh causing all mesh scene nodes
referencing this mesh to change too. */
void setReadOnlyMaterials(bool readonly) override;
//! Sets if the scene node should not copy the materials of the mesh but use them directly.
/** In this way it is possible to change the materials of a mesh
causing all mesh scene nodes referencing this mesh to change, too.
\param shared Flag if the materials shall be shared. */
void setSharedMaterials(bool shared) override;
//! Returns if the scene node should not copy the materials of the mesh but use them in a read only style
bool isReadOnlyMaterials() const override;
//! Check if the scene node does not copy the materials of the mesh but uses them directly.
/** This flag can be set by setSharedMaterials().
\return Whether the materials are shared. */
bool isSharedMaterials() const override;
//! Creates a clone of this scene node and its children.
ISceneNode *clone(ISceneNode *newParent = 0, ISceneManager *newManager = 0) override;
@ -71,14 +74,13 @@ public:
protected:
void copyMaterials();
core::array<video::SMaterial> Materials;
std::vector<video::SMaterial> Materials;
core::aabbox3d<f32> Box{{0, 0, 0}};
video::SMaterial ReadOnlyMaterial;
IMesh *Mesh;
s32 PassCount;
bool ReadOnlyMaterials;
bool SharedMaterials;
};
} // end namespace scene

View file

@ -1455,9 +1455,9 @@ void CNullDriver::setMaterialRendererName(u32 idx, const char *name)
void CNullDriver::swapMaterialRenderers(u32 idx1, u32 idx2, bool swapNames)
{
if (idx1 < MaterialRenderers.size() && idx2 < MaterialRenderers.size()) {
irr::core::swap(MaterialRenderers[idx1].Renderer, MaterialRenderers[idx2].Renderer);
std::swap(MaterialRenderers[idx1].Renderer, MaterialRenderers[idx2].Renderer);
if (swapNames)
irr::core::swap(MaterialRenderers[idx1].Name, MaterialRenderers[idx2].Name);
std::swap(MaterialRenderers[idx1].Name, MaterialRenderers[idx2].Name);
}
}

View file

@ -1526,8 +1526,6 @@ bool CXMeshFileLoader::parseDataObjectAnimationKey(SkinnedMesh::SJoint *joint)
os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING);
}
// core::vector3df rotation = mat.getRotationDegrees();
AnimatedMesh->addRotationKey(joint, time, core::quaternion(mat.getTransposed()));
AnimatedMesh->addPositionKey(joint, time, mat.getTranslation());

View file

@ -88,7 +88,7 @@ const matrix4 IdentityMatrix(matrix4::EM4CONST_IDENTITY);
namespace video
{
SMaterial IdentityMaterial;
const SMaterial IdentityMaterial;
extern "C" IRRLICHT_API bool IRRCALLCONV isDriverSupported(E_DRIVER_TYPE driver)
{

View file

@ -149,6 +149,6 @@
<update_contact>celeron55@gmail.com</update_contact>
<releases>
<release date="2024-11-10" version="5.10.0"/>
<release date="2025-02-14" version="5.11.0"/>
</releases>
</component>

View file

@ -3,9 +3,9 @@ msgstr ""
"Project-Id-Version: minetest\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-02-09 13:23+0100\n"
"PO-Revision-Date: 2025-01-27 06:02+0000\n"
"Last-Translator: 109247019824 "
"<109247019824@users.noreply.hosted.weblate.org>\n"
"PO-Revision-Date: 2025-02-11 02:02+0000\n"
"Last-Translator: 109247019824 <109247019824@users.noreply.hosted.weblate.org>"
"\n"
"Language-Team: Bulgarian <https://hosted.weblate.org/projects/minetest/"
"minetest/bg/>\n"
"Language: bg\n"
@ -264,13 +264,12 @@ msgid "Show technical names"
msgstr "Технически наименования"
#: builtin/common/settings/dlg_settings.lua
#, fuzzy
msgid "Touchscreen layout"
msgstr "Сензорен екран"
msgstr "Подредба на сензорния екран"
#: builtin/common/settings/dlg_settings.lua
msgid "pause_menu"
msgstr ""
msgstr "pause_menu"
#: builtin/common/settings/settingtypes.lua
msgid "Client Mods"
@ -612,6 +611,8 @@ msgid ""
"This is the list of clients connected to\n"
"$1"
msgstr ""
"Това е списък на клиентите свързани с\n"
"$1"
#: builtin/mainmenu/dlg_config_world.lua
msgid "(Enabled, has error)"

View file

@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: German (Minetest)\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-02-09 13:23+0100\n"
"PO-Revision-Date: 2025-02-05 11:03+0000\n"
"PO-Revision-Date: 2025-02-11 02:02+0000\n"
"Last-Translator: Wuzzy <Wuzzy@disroot.org>\n"
"Language-Team: German <https://hosted.weblate.org/projects/minetest/minetest/"
"de/>\n"
@ -263,14 +263,12 @@ msgid "Show technical names"
msgstr "Technische Namen zeigen"
#: builtin/common/settings/dlg_settings.lua
#, fuzzy
msgid "Touchscreen layout"
msgstr "Touchscreen"
msgstr "Touchscreen-Layout"
#: builtin/common/settings/dlg_settings.lua
#, fuzzy
msgid "pause_menu"
msgstr "Bildwiederholrate im Pausenmenü"
msgstr "pause_menu"
#: builtin/common/settings/settingtypes.lua
msgid "Client Mods"
@ -436,7 +434,7 @@ msgstr "Mods"
#: builtin/mainmenu/content/dlg_contentdb.lua
#: builtin/mainmenu/content/dlg_package.lua
msgid "No packages could be retrieved"
msgstr "Es konnten keine Pakete abgerufen werden"
msgstr "Es konnten keine Pakete empfangen werden"
#: builtin/mainmenu/content/dlg_contentdb.lua
msgid "No updates"
@ -610,6 +608,8 @@ msgid ""
"This is the list of clients connected to\n"
"$1"
msgstr ""
"Dies ist die Liste der Clients, die zu\n"
"$1 verbunden sind"
#: builtin/mainmenu/dlg_config_world.lua
msgid "(Enabled, has error)"
@ -975,25 +975,24 @@ msgstr ""
"der jede Umbennenung hier überschreiben wird."
#: builtin/mainmenu/dlg_server_list_mods.lua
#, fuzzy
msgid "Expand all"
msgstr "Alle aktivieren"
msgstr "Alle ausklappen"
#: builtin/mainmenu/dlg_server_list_mods.lua
msgid "Group by prefix"
msgstr ""
msgstr "Nach Präfix gruppieren"
#: builtin/mainmenu/dlg_server_list_mods.lua
msgid "The $1 server uses a game called $2 and the following mods:"
msgstr ""
msgstr "Der Server $1 nutzt ein Spiel namens $2 und die folgenden Mods:"
#: builtin/mainmenu/dlg_server_list_mods.lua
msgid "The $1 server uses the following mods:"
msgstr ""
msgstr "Der Server $1 nutzt folgende Mods:"
#: builtin/mainmenu/dlg_version_info.lua
msgid "A new $1 version is available"
msgstr "Eine neue $1-Version ist verfügbar"
msgstr "Eine neue Version von $1 ist verfügbar"
#: builtin/mainmenu/dlg_version_info.lua
msgid ""
@ -1203,20 +1202,20 @@ msgstr ""
"Sie müssen ein Spiel installieren, bevor Sie eine Welt erstellen können."
#: builtin/mainmenu/tab_online.lua
#, fuzzy
msgid "Add favorite"
msgstr "Favorit entfernen"
msgstr "Favorit hinzufügen"
#: builtin/mainmenu/tab_online.lua
msgid "Address"
msgstr "Adresse"
#: builtin/mainmenu/tab_online.lua
#, fuzzy
msgid ""
"Clients:\n"
"$1"
msgstr "Client"
msgstr ""
"Clients:\n"
"$1"
#: builtin/mainmenu/tab_online.lua
msgid "Creative mode"
@ -1232,9 +1231,8 @@ msgid "Favorites"
msgstr "Favoriten"
#: builtin/mainmenu/tab_online.lua
#, fuzzy
msgid "Game: $1"
msgstr "Spiel"
msgstr "Spiel: $1"
#: builtin/mainmenu/tab_online.lua
msgid "Incompatible Servers"
@ -1249,14 +1247,12 @@ msgid "Login"
msgstr "Einloggen"
#: builtin/mainmenu/tab_online.lua
#, fuzzy
msgid "Number of mods: $1"
msgstr "Anzahl der Erzeugerthreads"
msgstr "Anzahl der Mods: $1"
#: builtin/mainmenu/tab_online.lua
#, fuzzy
msgid "Open server website"
msgstr "Taktung dedizierter Server"
msgstr "Server-Webseite besuchen"
#: builtin/mainmenu/tab_online.lua
msgid "Ping"
@ -1269,6 +1265,10 @@ msgid ""
"mod:<name>\n"
"player:<name>"
msgstr ""
"Mögliche Filter\n"
"game:<Name>\n"
"mod:<Name>\n"
"player:<Name>"
#: builtin/mainmenu/tab_online.lua
msgid "Public Servers"
@ -1364,9 +1364,8 @@ msgid "Access denied. Reason: %s"
msgstr "Zugriff verweigert. Grund: %s"
#: src/client/game.cpp
#, fuzzy
msgid "All debug info hidden"
msgstr "Debug-Infos angezeigt"
msgstr "Alle Debug-Infos verborgen"
#: src/client/game.cpp
msgid "Automatic forward disabled"
@ -1390,7 +1389,7 @@ msgstr "Blockgrenzen für Blöcke in Nähe angezeigt"
#: src/client/game.cpp
msgid "Bounding boxes shown"
msgstr ""
msgstr "Grenzboxen angezeigt"
#: src/client/game.cpp
msgid "Camera update disabled"
@ -1632,9 +1631,8 @@ msgid "Volume changed to %d%%"
msgstr "Lautstärke auf %d%% gesetzt"
#: src/client/game.cpp
#, fuzzy
msgid "Wireframe not supported by video driver"
msgstr "Shader sind aktiviert, aber GLSL wird vom Treiber nicht unterstützt."
msgstr "Drahtmodell vom Treiber nicht unterstützt"
#: src/client/game.cpp
msgid "Wireframe shown"
@ -2067,9 +2065,8 @@ msgid "Failed to compile the \"%s\" shader."
msgstr "Fehler beim Kompilieren des „%s“-Shaders."
#: src/client/shader.cpp
#, fuzzy
msgid "GLSL is not supported by the driver"
msgstr "Shader sind aktiviert, aber GLSL wird vom Treiber nicht unterstützt."
msgstr "GLSL wird vom Treiber nicht unterstützt"
#. ~ Error when a mod is missing dependencies. Ex: "Mod Title is missing: mod1, mod2, mod3"
#: src/content/mod_configuration.cpp
@ -2306,35 +2303,32 @@ msgid "Sound Volume: %d%%"
msgstr "Tonlautstärke: %d%%"
#: src/gui/touchscreeneditor.cpp
#, fuzzy
msgid "Add button"
msgstr "Mittlere Taste"
msgstr "Button hinzufügen"
#: src/gui/touchscreeneditor.cpp
#, fuzzy
msgid "Done"
msgstr "Fertig!"
msgstr "Fertig"
#: src/gui/touchscreeneditor.cpp
#, fuzzy
msgid "Remove"
msgstr "Entfernter Server"
msgstr "Entfernen"
#: src/gui/touchscreeneditor.cpp
msgid "Reset"
msgstr ""
msgstr "Zurücksetzen"
#: src/gui/touchscreeneditor.cpp
msgid "Start dragging a button to add. Tap outside to cancel."
msgstr ""
msgstr "Button ziehen zum Hinzufügen. Außerhalb antippen zum Abbrechen."
#: src/gui/touchscreeneditor.cpp
msgid "Tap a button to select it. Drag a button to move it."
msgstr ""
msgstr "Button antippen zum Auswählen. Button ziehen zum Verschieben."
#: src/gui/touchscreeneditor.cpp
msgid "Tap outside to deselect."
msgstr ""
msgstr "Außerhalb antippen zum Abwählen."
#: src/gui/touchscreenlayout.cpp
msgid "Joystick"
@ -2576,7 +2570,6 @@ msgid "3D noise that determines number of dungeons per mapchunk."
msgstr "3-D-Rauschen, welches die Anzahl der Verliese je Mapchunk festlegt."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"3D support.\n"
"Currently supported:\n"
@ -2595,9 +2588,7 @@ msgstr ""
"zeilenbasierte Polarisation.\n"
"- topbottom: Bildschirm horizontal teilen.\n"
"- sidebyside: Bildschirm vertikal teilen.\n"
"- crossview: Schieläugiges 3-D\n"
"Beachten Sie, dass der „interlaced“-Modus erfordert, dass Shader aktiviert "
"sind."
"- crossview: Schieläugiges 3-D"
#: src/settings_translation_file.cpp
msgid ""
@ -2692,11 +2683,13 @@ msgid ""
"All mesh buffers with less than this number of vertices will be merged\n"
"during map rendering. This improves rendering performance."
msgstr ""
"Alle Mesh-Puffer, die weniger als diese Anzahl Punkte haben, werden während\n"
"des Renderns der Karte zusammengeführt. Dies verbessert die Performanz\n"
"des Renderns."
#: src/settings_translation_file.cpp
#, fuzzy
msgid "Allow clouds to look 3D instead of flat."
msgstr "Wolken blockförmig statt flach aussehen lassen."
msgstr "Erlaubt, dass Wolken ein 3-D-Aussehen statt ein flaches Aussehen haben."
#: src/settings_translation_file.cpp
msgid "Allows liquids to be translucent."
@ -3107,7 +3100,7 @@ msgstr "Wolken im Menü"
#: src/settings_translation_file.cpp
msgid "Color depth for post-processing texture"
msgstr ""
msgstr "Farbtiefe für Nachbearbeitungstextur"
#: src/settings_translation_file.cpp
msgid "Colored fog"
@ -3127,7 +3120,6 @@ msgstr ""
"für Details."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Comma-separated list of flags to hide in the content repository.\n"
"\"nonfree\" can be used to hide packages which do not qualify as 'free "
@ -3145,7 +3137,7 @@ msgstr ""
"Sie können auch Inhaltseinstufungen festlegen.\n"
"Diese Flags sind von Luanti-Versionen unabhängig,\n"
"für eine vollständige Liste gehen Sie auf:\n"
"https://content.minetest.net/help/content_flags/"
"https://content.luanti.org/help/content_flags/"
#: src/settings_translation_file.cpp
msgid ""
@ -3316,6 +3308,11 @@ msgid ""
"Reducing this can improve performance, but some effects (e.g. debanding)\n"
"require more than 8 bits to work."
msgstr ""
"Die Farbtiefe der Textur, die für die Nachbearbeitungs-Pipeline benutzt "
"wird, festlegen.\n"
"Wird der Wert verringert, kann dies die Performanz verbessern, aber einige "
"Effekte (z.B. Debanding)\n"
"brauchen mehr als 8 Bit, um zu funktionieren."
#: src/settings_translation_file.cpp
msgid "Dedicated server step"
@ -3544,6 +3541,10 @@ msgid ""
"situations\n"
"where transparency sorting would be very slow otherwise."
msgstr ""
"Transparenzsortierte Dreiecke nach ihren Meshpuffern gruppiert zeichnen.\n"
"Dies macht die Transparenzsortierung zwischen Meshpuffern kaputt, aber "
"vermeidet\n"
"Situationen, wo die Transparenzsortierung sonst sehr langsam wäre."
#: src/settings_translation_file.cpp
msgid "Dump the mapgen debug information."
@ -3628,14 +3629,12 @@ msgstr ""
"Verhalten des menschlichen Auges simuliert."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Enable colored shadows for transculent nodes.\n"
"This is expensive."
msgstr ""
"Aktiviert gefärbte Schatten. \n"
"Falls aktiv, werden transluzente Blöcke gefärbte Schatten werfen. Dies ist "
"rechenintensiv."
"Aktiviert gefärbte Schatten für transluzente Blöcke.\n"
"Dies ist rechenintensiv."
#: src/settings_translation_file.cpp
msgid "Enable console window"
@ -3721,14 +3720,12 @@ msgstr ""
"1.0 für den Standardwert, 2.0 für doppelte Geschwindigkeit."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Enable/disable running an IPv6 server.\n"
"Ignored if bind_address is set."
msgstr ""
"Server als IPv6 laufen lassen (oder nicht).\n"
"Wird ignoriert, falls bind_address gesetzt ist.\n"
"Dafür muss außerdem enable_ipv6 aktiviert sein."
"Wird ignoriert, falls bind_address gesetzt ist."
#: src/settings_translation_file.cpp
msgid ""
@ -4399,15 +4396,15 @@ msgstr ""
"ihr Passwort zu ein leeres Passwort ändern."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"If enabled, server account registration is separate from login in the UI.\n"
"If disabled, connecting to a server will automatically register a new "
"account."
msgstr ""
"Falls aktiviert, wird die Kontoregistrierung vom Einloggen in der "
"Benutzeroberfläche getrennt behandelt.\n"
"Falls deaktiviert, werden neue Konten beim Einloggen automatisch registriert."
"Falls aktiviert, wird die Serverkontoregistrierung in der Benutzeroberfläche "
"getrennt vom Einloggen behandelt.\n"
"Falls deaktiviert, werden neue Konten beim Verbindungsaufbau zu einem Server "
"automatisch registriert."
#: src/settings_translation_file.cpp
msgid ""
@ -5313,7 +5310,7 @@ msgstr "Untergrenze der zufälligen Anzahl kleiner Höhlen je Mapchunk."
#: src/settings_translation_file.cpp
msgid "Minimum vertex count for mesh buffers"
msgstr ""
msgstr "Minimale Punktanzahl für Meshpuffer"
#: src/settings_translation_file.cpp
msgid "Mipmapping"
@ -5409,16 +5406,15 @@ msgstr ""
"- Die optionalen Schwebeländer von v7 (standardmäßig deaktiviert)."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Name of the player.\n"
"When running a server, a client connecting with this name is admin.\n"
"When starting from the main menu, this is overridden."
msgstr ""
"Name des Spielers.\n"
"Wenn ein Server gestartet wird, werden Clients mit diesem Namen zu "
"Administratoren.\n"
"Wird vom Hauptmenü aus gestartet, wird diese Einstellung überschrieben."
"Wenn ein Server gestartet wird, wird ein Client mit diesem Namen zum "
"Administrator.\n"
"Wenn vom Hauptmenü aus gestartet, wird diese Einstellung überschrieben."
#: src/settings_translation_file.cpp
msgid ""
@ -5938,7 +5934,6 @@ msgid "See https://www.sqlite.org/pragma.html#pragma_synchronous"
msgstr "Siehe https://www.sqlite.org/pragma.html#pragma_synchronous"
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Select the antialiasing method to apply.\n"
"\n"
@ -5965,20 +5960,22 @@ msgstr ""
"\n"
"* None Keine Kantenglättung (Standard)\n"
"\n"
"* FSAA Von der Hardware bereitgestellte Vollbildkantenglättung (nicht\n"
"kompatibel mit Nachbearbeitung und Unterabtastung), auch bekannt\n"
"als Multi-Sample Antialiasing (MSAA). Glättet Blockkanten aus, "
"beeinträchtigt\n"
"aber nicht die Innenseiten der Texturen.\n"
"Um diese Option zu ändern, ist ein Neustart erforderlich.\n"
"* FSAA Von der Hardware bereitgestellte Vollbildkantenglättung\n"
"Auch bekannt als „Multi-Sample Antialiasing“ (MSAA)\n"
"Glättet Blockkanten, aber hat keine Auswirkung auf das Innere von Texturen.\n"
"\n"
"* FXAA Schnelle annähende Kantenglättung (benötigt Shader).\n"
"Wenn die Nachbearbeitung deaktiviert ist, benötigt das Ändern von FSAA\n"
"einen Neustart. Außerdem wird, wenn die Nachbearbeitung deaktiviert ist,\n"
"FSAA nicht zusammen mit einer Unterabtastung oder einer\n"
"Nicht-Standard-„3d_mode“-Einstellung funktionieren.\n"
"\n"
"* FXAA Schnelle annähende Kantenglättung\n"
"Wendet einen Nachbearbeitungsfilter an, um kontrastreiche Kanten zu "
"erkennen\n"
"und zu glätten. Bietet eine Balance zwischen Geschwindigkeit und "
"Bildqualität.\n"
"\n"
"* SSAA Super-Sampling-Kantenglättung (benötigt Shader).\n"
"* SSAA Super-Sampling-Kantenglättung\n"
"Rendert ein hochauflösendes Bild der Szene, dann skaliert es herunter, um\n"
"die Aliasing-Effekte zu reduzieren. Dies ist die langsamste und genaueste "
"Methode."
@ -6419,7 +6416,6 @@ msgstr ""
"(oder alle) Gegenstände setzen kann."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Spread a complete update of the shadow map over a given number of frames.\n"
"Higher values might make shadows laggy, lower values\n"
@ -6427,8 +6423,7 @@ msgid ""
msgstr ""
"Eine vollständige Aktualisierung der Schattenkarte über die angegebene\n"
"Anzahl Frames verteilen. Höhere Werte können dazu führen, dass\n"
"Schatten langsamer reagieren, niedrigere Werte sind rechenintensiver.\n"
"Minimalwert: 1; Maximalwert: 16"
"Schatten langsamer reagieren, niedrigere Werte sind rechenintensiver."
#: src/settings_translation_file.cpp
msgid ""
@ -6876,9 +6871,8 @@ msgid "Transparency Sorting Distance"
msgstr "Transparenzsortierungsdistanz"
#: src/settings_translation_file.cpp
#, fuzzy
msgid "Transparency Sorting Group by Buffers"
msgstr "Transparenzsortierungsdistanz"
msgstr "Transparenzsortierung nach Puffer gruppieren"
#: src/settings_translation_file.cpp
msgid "Trees noise"
@ -6942,7 +6936,6 @@ msgid "Undersampling"
msgstr "Unterabtastung"
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Undersampling is similar to using a lower screen resolution, but it applies\n"
"to the game world only, keeping the GUI intact.\n"
@ -6954,11 +6947,14 @@ msgid ""
"to a non-default value."
msgstr ""
"Unterabtastung ist ähnlich der Verwendung einer niedrigeren "
"Bildschirmauflösung, aber sie wird nur auf die Spielwelt angewandt, während "
"die GUI intakt bleibt.\n"
"Bildschirmauflösung,\n"
"aber sie wird nur auf die Spielwelt angewandt, während die GUI intakt bleibt."
"\n"
"Dies sollte einen beträchtlichen Performanzschub auf Kosten einer weniger "
"detaillierten Grafik geben.\n"
"Hohe Werte führen zu einer weniger detaillierten Grafik."
"Hohe Werte führen zu einer weniger detaillierten Grafik.\n"
"Anmerkung: Unterabtastung wird im Moment nicht unterstützt, falls die\n"
"„3d_mode“-Einstellung auf einen Nicht-Standardwert gesetzt ist."
#: src/settings_translation_file.cpp
msgid "Unlimited player transfer distance"
@ -6985,13 +6981,14 @@ msgid "Use a cloud animation for the main menu background."
msgstr "Eine Wolkenanimation für den Hintergrund im Hauptmenü benutzen."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Use anisotropic filtering when looking at textures from an angle.\n"
"This provides a significant improvement when used together with mipmapping."
msgstr ""
"Anisotrope Filterung verwenden, wenn auf Texturen aus einem gewissen Winkel "
"heraus geschaut wird."
"heraus geschaut wird.\n"
"Dies bietet eine signifikante Verbesserung, wenn es gemeinsam mit Mipmapping "
"verwendet wird."
#: src/settings_translation_file.cpp
msgid "Use bilinear filtering when scaling textures."
@ -7268,7 +7265,6 @@ msgstr ""
"die Inventarbilder von Blöcken)."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"When using bilinear/trilinear filtering, low-resolution textures\n"
"can be blurred, so this option automatically upscales them to preserve\n"
@ -7279,14 +7275,14 @@ msgid ""
"This is also used as the base node texture size for world-aligned\n"
"texture autoscaling."
msgstr ""
"Wenn bilineare, trilineare oder anisotrope Filter benutzt werden, können\n"
"Wenn bilineare/trilineare Filter benutzt werden, können\n"
"niedrigauflösende Texturen verschwommen sein, also werden sie automatisch\n"
"mit Pixelwiederholung vergrößert, um scharfe Pixel zu behalten. Dies setzt "
"die\n"
"minimale Texturengröße für die vergrößerten Texturen; höhere Werte führen\n"
"zu einem schärferen Aussehen, aber erfordern mehr Speicher. Zweierpotenzen\n"
"werden empfohlen. Diese Einstellung trifft NUR dann in Kraft, falls\n"
"der bilineare/trilineare/anisotrope Filter aktiviert ist.\n"
"zu einem schärferen Aussehen, aber erfordern mehr Speicher.\n"
"Diese Einstellung trifft NUR dann in Kraft, falls\n"
"einer der genannten Filter aktiviert ist.\n"
"Dies wird außerdem verwendet als die Basisblocktexturengröße für\n"
"welt-ausgerichtete automatische Texturenskalierung."
@ -7326,17 +7322,15 @@ msgid "Whether to fog out the end of the visible area."
msgstr "Ob das Ende des sichtbaren Gebietes im Nebel verschwinden soll."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Whether to mute sounds. You can unmute sounds at any time.\n"
"In-game, you can toggle the mute state with the mute key or by using the\n"
"pause menu."
msgstr ""
"Ob die Töne stummgeschaltet werden. Man kann die Töne jederzeit "
"stummschalten,\n"
"außer, wenn das Tonsystem ausgeschaltet wurde (enable_sound=false).\n"
"stummschalten.\n"
"Im Spiel können die Töne mit der Stummtaste oder mit Hilfe des\n"
"Pausemenüs stummgeschaltet werden."
"Pausenmenüs stummgeschaltet werden."
#: src/settings_translation_file.cpp
msgid ""

View file

@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: Spanish (Minetest)\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-02-09 13:23+0100\n"
"PO-Revision-Date: 2025-01-23 21:01+0000\n"
"PO-Revision-Date: 2025-02-14 12:19+0000\n"
"Last-Translator: Miguel <mp0187595@tutamail.com>\n"
"Language-Team: Spanish <https://hosted.weblate.org/projects/minetest/"
"minetest/es/>\n"
@ -12,7 +12,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.10-dev\n"
"X-Generator: Weblate 5.10\n"
#: builtin/client/chatcommands.lua
msgid "Clear the out chat queue"
@ -263,14 +263,12 @@ msgid "Show technical names"
msgstr "Mostrar los nombres técnicos"
#: builtin/common/settings/dlg_settings.lua
#, fuzzy
msgid "Touchscreen layout"
msgstr "Pantalla táctil"
msgstr "Diseño de pantalla táctil"
#: builtin/common/settings/dlg_settings.lua
#, fuzzy
msgid "pause_menu"
msgstr "FPS (cuadros/s) en el menú de pausa"
msgstr "pause_menu"
#: builtin/common/settings/settingtypes.lua
msgid "Client Mods"
@ -610,6 +608,8 @@ msgid ""
"This is the list of clients connected to\n"
"$1"
msgstr ""
"Esta es la lista de clientes conectados a\n"
"$1"
#: builtin/mainmenu/dlg_config_world.lua
msgid "(Enabled, has error)"
@ -974,21 +974,20 @@ msgstr ""
"cual sobreescribirá cualquier renombrado desde aquí."
#: builtin/mainmenu/dlg_server_list_mods.lua
#, fuzzy
msgid "Expand all"
msgstr "Activar todos"
msgstr "Expandir todo"
#: builtin/mainmenu/dlg_server_list_mods.lua
msgid "Group by prefix"
msgstr ""
msgstr "Grupo por prefijo"
#: builtin/mainmenu/dlg_server_list_mods.lua
msgid "The $1 server uses a game called $2 and the following mods:"
msgstr ""
msgstr "El servidor $1 utiliza un juego llamado $2 y los siguientes mods:"
#: builtin/mainmenu/dlg_server_list_mods.lua
msgid "The $1 server uses the following mods:"
msgstr ""
msgstr "El servidor $1 usa los siguientes mods:"
#: builtin/mainmenu/dlg_version_info.lua
msgid "A new $1 version is available"
@ -1201,20 +1200,20 @@ msgid "You need to install a game before you can create a world."
msgstr "Necesitas instalar un juego antes de poder crear un mundo."
#: builtin/mainmenu/tab_online.lua
#, fuzzy
msgid "Add favorite"
msgstr "Eliminar el favorito"
msgstr "Añadir a favorito"
#: builtin/mainmenu/tab_online.lua
msgid "Address"
msgstr "Dirección"
#: builtin/mainmenu/tab_online.lua
#, fuzzy
msgid ""
"Clients:\n"
"$1"
msgstr "Cliente"
msgstr ""
"Clientes:\n"
"$1"
#: builtin/mainmenu/tab_online.lua
msgid "Creative mode"
@ -1230,9 +1229,8 @@ msgid "Favorites"
msgstr "Favoritos"
#: builtin/mainmenu/tab_online.lua
#, fuzzy
msgid "Game: $1"
msgstr "Juego"
msgstr "Juego: $1"
#: builtin/mainmenu/tab_online.lua
msgid "Incompatible Servers"
@ -1247,26 +1245,29 @@ msgid "Login"
msgstr "Iniciar sesión"
#: builtin/mainmenu/tab_online.lua
#, fuzzy
msgid "Number of mods: $1"
msgstr "Número de hilos emergentes"
msgstr "Número de mods: $1"
#: builtin/mainmenu/tab_online.lua
#, fuzzy
msgid "Open server website"
msgstr "Intervalo de servidor dedicado"
msgstr "Abrir sitio web del servidor"
#: builtin/mainmenu/tab_online.lua
msgid "Ping"
msgstr "Ping"
#: builtin/mainmenu/tab_online.lua
#, fuzzy
msgid ""
"Possible filters\n"
"game:<name>\n"
"mod:<name>\n"
"player:<name>"
msgstr ""
"Posibles filtros\n"
"game:<nombre>\n"
"mod:<nombre>\n"
"player:<nombre>"
#: builtin/mainmenu/tab_online.lua
msgid "Public Servers"
@ -1274,7 +1275,7 @@ msgstr "Servidores Públicos"
#: builtin/mainmenu/tab_online.lua
msgid "Refresh"
msgstr "Actualizar"
msgstr "Refrescar"
#: builtin/mainmenu/tab_online.lua
msgid "Remove favorite"
@ -1364,9 +1365,8 @@ msgid "Access denied. Reason: %s"
msgstr "Acceso denegado. Razón: %s"
#: src/client/game.cpp
#, fuzzy
msgid "All debug info hidden"
msgstr "Info de depuración mostrada"
msgstr "Toda la información de depuración oculta"
#: src/client/game.cpp
msgid "Automatic forward disabled"
@ -1390,7 +1390,7 @@ msgstr "Límites de bloque mostrados para bloques cercanos"
#: src/client/game.cpp
msgid "Bounding boxes shown"
msgstr ""
msgstr "Cajas delimitadoras mostradas"
#: src/client/game.cpp
msgid "Camera update disabled"
@ -1633,9 +1633,8 @@ msgid "Volume changed to %d%%"
msgstr "Volumen cambiado a %d%%"
#: src/client/game.cpp
#, fuzzy
msgid "Wireframe not supported by video driver"
msgstr "Los shaders están activados pero el driver no soporta GLSL."
msgstr "El controlador de vídeo no admite la estructura alámbrica"
#: src/client/game.cpp
msgid "Wireframe shown"
@ -2068,9 +2067,8 @@ msgid "Failed to compile the \"%s\" shader."
msgstr "Fallo al compilar el shader \"%s\"."
#: src/client/shader.cpp
#, fuzzy
msgid "GLSL is not supported by the driver"
msgstr "Los shaders están activados pero el driver no soporta GLSL."
msgstr "El controlador no admite GLSL"
#. ~ Error when a mod is missing dependencies. Ex: "Mod Title is missing: mod1, mod2, mod3"
#: src/content/mod_configuration.cpp
@ -2235,11 +2233,11 @@ msgstr "Alternar el registro del chat"
#: src/gui/guiKeyChangeMenu.cpp src/gui/touchscreenlayout.cpp
msgid "Toggle fast"
msgstr "Activar rápido"
msgstr "Alternar rápido"
#: src/gui/guiKeyChangeMenu.cpp src/gui/touchscreenlayout.cpp
msgid "Toggle fly"
msgstr "Activar volar"
msgstr "Alternar volar"
#: src/gui/guiKeyChangeMenu.cpp
msgid "Toggle fog"
@ -2307,35 +2305,33 @@ msgid "Sound Volume: %d%%"
msgstr "Volumen del sonido: %d%%"
#: src/gui/touchscreeneditor.cpp
#, fuzzy
msgid "Add button"
msgstr "Botón central"
msgstr "Agregar botón"
#: src/gui/touchscreeneditor.cpp
#, fuzzy
msgid "Done"
msgstr "¡Completado!"
msgstr "Hecho"
#: src/gui/touchscreeneditor.cpp
#, fuzzy
msgid "Remove"
msgstr "Servidor remoto"
msgstr "Eliminar"
#: src/gui/touchscreeneditor.cpp
msgid "Reset"
msgstr ""
msgstr "Reiniciar"
#: src/gui/touchscreeneditor.cpp
msgid "Start dragging a button to add. Tap outside to cancel."
msgstr ""
"Comienza arrastrando un botón para agregarlo. Toca afuera para cancelar."
#: src/gui/touchscreeneditor.cpp
msgid "Tap a button to select it. Drag a button to move it."
msgstr ""
msgstr "Toca un botón para seleccionarlo. Arrastra un botón para moverlo."
#: src/gui/touchscreeneditor.cpp
msgid "Tap outside to deselect."
msgstr ""
msgstr "Toca afuera para anular la selección."
#: src/gui/touchscreenlayout.cpp
msgid "Joystick"
@ -2575,7 +2571,6 @@ msgid "3D noise that determines number of dungeons per mapchunk."
msgstr "Ruido 3D que determina la cantidad de mazmorras por chunk."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"3D support.\n"
"Currently supported:\n"
@ -2588,14 +2583,13 @@ msgid ""
msgstr ""
"Soporte 3D.\n"
"Soportado actualmente:\n"
"- Ninguno (none): sin salida 3D.\n"
"- Anaglifo (anaglyph): 3D en colores cían y magenta.\n"
"- Entrelazado (interlaced): soporte para pantallas con polarización "
"basada en filas impar/par.\n"
"- Arriba-abajo (topbottom): dividir pantalla arriba y abajo.\n"
"- Lado a lado (sidebyside): dividir pantalla lado a lado.\n"
"- Vista cruzada (crossview): visión 3D cruzada.\n"
"Nota: el modo entrelazado requiere que los sombreadores estén activados."
"- Ninguno: sin salida 3D.\n"
"- Anaglifo: 3D en colores cían y magenta.\n"
"- Entrelazado: soporte para pantallas con polarización basada en filas "
"impar/par.\n"
"- Arriba-abajo: dividir pantalla arriba y abajo.\n"
"- Lado a lado: dividir pantalla lado a lado.\n"
"- Vista cruzada: visión 3D cruzada"
#: src/settings_translation_file.cpp
msgid ""
@ -2687,11 +2681,14 @@ msgid ""
"All mesh buffers with less than this number of vertices will be merged\n"
"during map rendering. This improves rendering performance."
msgstr ""
"Se fusionarán todos los buffers de malla con menos de este número de "
"vértices\n"
"Durante la representación del mapa. Esto mejora el rendimiento de "
"renderizado."
#: src/settings_translation_file.cpp
#, fuzzy
msgid "Allow clouds to look 3D instead of flat."
msgstr "Usar nubes 3D en lugar de planas."
msgstr "Permitir que las nubes se vean en 3D en lugar de planas."
#: src/settings_translation_file.cpp
msgid "Allows liquids to be translucent."
@ -3105,7 +3102,7 @@ msgstr "Nubes en el menú"
#: src/settings_translation_file.cpp
msgid "Color depth for post-processing texture"
msgstr ""
msgstr "Profundidad de color para la textura post-procesamiento"
#: src/settings_translation_file.cpp
msgid "Colored fog"
@ -3125,7 +3122,6 @@ msgstr ""
"Útil para pruebas. Ver al_extensions.[h,cpp] para más detalles."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Comma-separated list of flags to hide in the content repository.\n"
"\"nonfree\" can be used to hide packages which do not qualify as 'free "
@ -3142,7 +3138,7 @@ msgstr ""
"según lo definido por la Free Software Foundation.\n"
"También puedes especificar clasificaciones de contenido.\n"
"Estas banderas son independientes de las versiones de Luanti,\n"
"así que consulta una lista completa en https://content.minetest.net/help/"
"así que consulta una lista completa en https://content.luanti.org/help/"
"content_flags/"
#: src/settings_translation_file.cpp
@ -3313,6 +3309,11 @@ msgid ""
"Reducing this can improve performance, but some effects (e.g. debanding)\n"
"require more than 8 bits to work."
msgstr ""
"Decide la profundidad de color de la textura utilizada para la canalización "
"post-procesamiento.\n"
"Reducir esto puede mejorar el rendimiento, pero algunos efectos (por "
"ejemplo, tramado)\n"
"requieren más de 8 bits para trabajar."
#: src/settings_translation_file.cpp
msgid "Dedicated server step"
@ -3537,6 +3538,11 @@ msgid ""
"situations\n"
"where transparency sorting would be very slow otherwise."
msgstr ""
"Dibuja los triángulos clasificados por transparencia agrupados por sus "
"buffers de malla.\n"
"Esto rompe la clasificación de transparencia entre los buffers de malla, "
"pero evita situaciones\n"
"donde la clasificación de transparencia sería muy lenta de lo contrario."
#: src/settings_translation_file.cpp
msgid "Dump the mapgen debug information."
@ -3621,14 +3627,12 @@ msgstr ""
"el comportamiento del ojo humano."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Enable colored shadows for transculent nodes.\n"
"This is expensive."
msgstr ""
"Habilitar las sombras coloreadas.\n"
"Si el valor es verdadero los nodos traslúcidos proyectarán sombras "
"coloreadas. Esta opción usa muchos recursos."
"Habilita las sombras de colores para nodos translúcidos.\n"
"Esto es costoso."
#: src/settings_translation_file.cpp
msgid "Enable console window"
@ -3712,14 +3716,12 @@ msgstr ""
"Por ejemplo: 0 para balanceo sin vista; 1.0 para normal; 2.0 para doble."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Enable/disable running an IPv6 server.\n"
"Ignored if bind_address is set."
msgstr ""
"Habilita/deshabilita la ejecución de un servidor IPv6.\n"
"Ignorado si se establece bind_address.\n"
"Necesita habilitar enable_ipv6 para ser activado."
"Activa/desactiva la ejecución de un servidor IPv6.\n"
"Se ignora si bind_address está establecido."
#: src/settings_translation_file.cpp
msgid ""
@ -3749,7 +3751,7 @@ msgstr "Activar el desplazamiento suave."
#: src/settings_translation_file.cpp
msgid "Enables the post processing pipeline."
msgstr "Habilita la canalización para el posprocesamiento."
msgstr "Habilita la canalización posterior al procesamiento."
#: src/settings_translation_file.cpp
msgid ""
@ -4384,7 +4386,6 @@ msgstr ""
"la suya por una contraseña vacía."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"If enabled, server account registration is separate from login in the UI.\n"
"If disabled, connecting to a server will automatically register a new "
@ -4392,8 +4393,8 @@ msgid ""
msgstr ""
"Si está activado, el registro de la cuenta es independiente del inicio de "
"sesión en la interfaz de usuario.\n"
"Si está deshabilitado, las cuentas nuevas se registrarán automáticamente al "
"iniciar sesión."
"Si está desactivado, la conexión a un servidor registrará automáticamente "
"una nueva cuenta."
#: src/settings_translation_file.cpp
msgid ""
@ -5298,7 +5299,7 @@ msgstr ""
#: src/settings_translation_file.cpp
msgid "Minimum vertex count for mesh buffers"
msgstr ""
msgstr "Recuento mínimo de vértices para buffers de malla"
#: src/settings_translation_file.cpp
msgid "Mipmapping"
@ -5393,15 +5394,14 @@ msgstr ""
"- Las islas flotantes opcionales de v7 (desactivadas por defecto)."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Name of the player.\n"
"When running a server, a client connecting with this name is admin.\n"
"When starting from the main menu, this is overridden."
msgstr ""
"Nombre del jugador.\n"
"Cuando se ejecuta un servidor, los clientes que se conecten con este nombre "
"son administradores.\n"
"Al ejecutar un servidor, el cliente que se conecta con este nombre es "
"administrador.\n"
"Al comenzar desde el menú principal, esto se anula."
#: src/settings_translation_file.cpp
@ -5927,7 +5927,6 @@ msgid "See https://www.sqlite.org/pragma.html#pragma_synchronous"
msgstr "Ver https://www.sqlite.org/pragma.html#pragma_synchronous"
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Select the antialiasing method to apply.\n"
"\n"
@ -5950,26 +5949,28 @@ msgid ""
"Renders higher-resolution image of the scene, then scales down to reduce\n"
"the aliasing effects. This is the slowest and the most accurate method."
msgstr ""
"Seleccione el método de antialiasing a aplicar.\n"
"Seleccione el método de suavizado a aplicar.\n"
"\n"
"* Ninguno - Sin antialiasing (por defecto)\n"
"* Ninguno - Sin suavizado (por defecto)\n"
"\n"
"* FSAA - Antialiasing de pantalla completa por hardware\n"
"(incompatible con Postprocesado y Submuestreo)\n"
"También conocido como antialiasing multimuestra (MSAA)\n"
"Suaviza los bordes de los bloques pero no afecta al interior de las "
"texturas.\n"
"Es necesario reiniciar para cambiar esta opción.\n"
"* FSAA - Suavizado de pantalla completa por hardware\n"
"También conocido como suavizado multimuestra (MSAA)\n"
"Suaviza los bordes de los bloques pero no afecta al interior de las texturas."
"\n"
"* FXAA - Antialiasing rápido aproximado (requiere shaders)\n"
"Aplica un filtro de postprocesado para detectar y suavizar los bordes de "
"\n"
"Si el posprocesamiento está desactivado, cambiar FSAA requiere reiniciar.\n"
"Además, si se desactiva el posprocesamiento, FSAA no funcionará con\n"
"submuestreo o una configuración no predeterminada de \"3d_mode\".\n"
"\n"
"* FXAA - Suavizado aproximado rápido\n"
"Aplica un filtro de pos-procesamiento para detectar y suavizar los bordes de "
"alto contraste.\n"
"Proporciona un equilibrio entre velocidad y calidad de imagen.\n"
"\n"
"* SSAA - Antialiasing de supermuestreo (requiere shaders)\n"
"* SSAA - Suavizado de supermuestreo\n"
"Renderiza una imagen de mayor resolución de la escena y, a continuación, "
"reduce la escala para reducir los efectos de aliasing.\n"
"los efectos del aliasing. Es el método más lento y preciso."
"reduce la escala para reducir\n"
"los efectos de distorsión. Es el método más lento y preciso."
#: src/settings_translation_file.cpp
msgid "Selection box border color (R,G,B)."
@ -6410,7 +6411,6 @@ msgstr ""
"pila para ciertos ítems (o para todos)."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Spread a complete update of the shadow map over a given number of frames.\n"
"Higher values might make shadows laggy, lower values\n"
@ -6420,8 +6420,7 @@ msgstr ""
"determinado de fotogramas.\n"
"Los valores más altos pueden hacer que las sombras se retrasen, los valores "
"más bajos\n"
"consumirán más recursos.\n"
"Valor mínimo: 1; valor máximo: 16"
"consumirán más recursos."
#: src/settings_translation_file.cpp
msgid ""
@ -6872,9 +6871,8 @@ msgid "Transparency Sorting Distance"
msgstr "Distancia de Clasificación de Transparencia"
#: src/settings_translation_file.cpp
#, fuzzy
msgid "Transparency Sorting Group by Buffers"
msgstr "Distancia de Clasificación de Transparencia"
msgstr "Grupo de Clasificación de Transparencia por búferes"
#: src/settings_translation_file.cpp
msgid "Trees noise"
@ -6978,11 +6976,13 @@ msgid "Use a cloud animation for the main menu background."
msgstr "Usar nubes con animaciones para el fondo del menú principal."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Use anisotropic filtering when looking at textures from an angle.\n"
"This provides a significant improvement when used together with mipmapping."
msgstr "Usar filtrado anisotrópico al mirar texturas desde un ángulo."
msgstr ""
"Usar filtrado anisotrópico al mirar texturas desde un ángulo.\n"
"Esto proporciona una mejora significativa cuando se utiliza junto con el "
"mapeo MIP."
#: src/settings_translation_file.cpp
msgid "Use bilinear filtering when scaling textures."
@ -7319,18 +7319,16 @@ msgid "Whether to fog out the end of the visible area."
msgstr "Si se debe nublar el final del área visible."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Whether to mute sounds. You can unmute sounds at any time.\n"
"In-game, you can toggle the mute state with the mute key or by using the\n"
"pause menu."
msgstr ""
"Si deseas silenciar los sonidos. Puedes activar el sonido en cualquier "
"momento,\n"
"a menos que el sistema de sonido esté desactivado (enable_sound=false).\n"
"En el juego, puedes alternar el estado de silencio con la tecla de silencio "
"o\n"
"usando el menú de pausa."
"momento.\n"
"En el juego, puedes alternar el estado de silencio con la tecla de silenciar "
"o usando el\n"
"menú de pausa."
#: src/settings_translation_file.cpp
msgid ""

View file

@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: French (Minetest)\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-02-09 13:23+0100\n"
"PO-Revision-Date: 2024-11-06 18:04+0000\n"
"PO-Revision-Date: 2025-02-12 12:18+0000\n"
"Last-Translator: waxtatect <piero@live.ie>\n"
"Language-Team: French <https://hosted.weblate.org/projects/minetest/minetest/"
"fr/>\n"
@ -12,7 +12,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
"X-Generator: Weblate 5.8.2\n"
"X-Generator: Weblate 5.10-dev\n"
#: builtin/client/chatcommands.lua
msgid "Clear the out chat queue"
@ -263,14 +263,12 @@ msgid "Show technical names"
msgstr "Montrer les noms techniques"
#: builtin/common/settings/dlg_settings.lua
#, fuzzy
msgid "Touchscreen layout"
msgstr "Écran tactile"
msgstr "Disposition de l'écran tactile"
#: builtin/common/settings/dlg_settings.lua
#, fuzzy
msgid "pause_menu"
msgstr "FPS maximum sur le menu pause"
msgstr "pause_menu"
#: builtin/common/settings/settingtypes.lua
msgid "Client Mods"
@ -319,7 +317,7 @@ msgstr "Très basses"
#: builtin/fstk/ui.lua
msgid "<none available>"
msgstr "< aucun disponible >"
msgstr "<non disponible>"
#: builtin/fstk/ui.lua
msgid "An error occurred in a Lua script:"
@ -610,6 +608,8 @@ msgid ""
"This is the list of clients connected to\n"
"$1"
msgstr ""
"Voici la liste des clients connectés à\n"
"$1"
#: builtin/mainmenu/dlg_config_world.lua
msgid "(Enabled, has error)"
@ -977,21 +977,20 @@ msgstr ""
"remplace tout renommage effectué ici."
#: builtin/mainmenu/dlg_server_list_mods.lua
#, fuzzy
msgid "Expand all"
msgstr "Tout activer"
msgstr "Tout développer"
#: builtin/mainmenu/dlg_server_list_mods.lua
msgid "Group by prefix"
msgstr ""
msgstr "Grouper par préfixe"
#: builtin/mainmenu/dlg_server_list_mods.lua
msgid "The $1 server uses a game called $2 and the following mods:"
msgstr ""
msgstr "Le serveur $1 utilise un jeu appelé $2 et les mods suivants :"
#: builtin/mainmenu/dlg_server_list_mods.lua
msgid "The $1 server uses the following mods:"
msgstr ""
msgstr "Le serveur $1 utilise les mods suivants :"
#: builtin/mainmenu/dlg_version_info.lua
msgid "A new $1 version is available"
@ -1205,20 +1204,20 @@ msgid "You need to install a game before you can create a world."
msgstr "Vous devez en installer un pour créer un nouveau monde."
#: builtin/mainmenu/tab_online.lua
#, fuzzy
msgid "Add favorite"
msgstr "Supprimer le favori"
msgstr "Ajouter aux favoris"
#: builtin/mainmenu/tab_online.lua
msgid "Address"
msgstr "Adresse"
#: builtin/mainmenu/tab_online.lua
#, fuzzy
msgid ""
"Clients:\n"
"$1"
msgstr "Client"
msgstr ""
"Clients : \n"
"$1"
#: builtin/mainmenu/tab_online.lua
msgid "Creative mode"
@ -1234,9 +1233,8 @@ msgid "Favorites"
msgstr "Favoris"
#: builtin/mainmenu/tab_online.lua
#, fuzzy
msgid "Game: $1"
msgstr "Jeu"
msgstr "Jeu : $1"
#: builtin/mainmenu/tab_online.lua
msgid "Incompatible Servers"
@ -1251,14 +1249,12 @@ msgid "Login"
msgstr "Connexion"
#: builtin/mainmenu/tab_online.lua
#, fuzzy
msgid "Number of mods: $1"
msgstr "Nombre de fils émergents"
msgstr "Nombre de mods : $1"
#: builtin/mainmenu/tab_online.lua
#, fuzzy
msgid "Open server website"
msgstr "Intervalle de mise à jour des objets sur le serveur"
msgstr "Visiter le site web du serveur"
#: builtin/mainmenu/tab_online.lua
msgid "Ping"
@ -1271,6 +1267,10 @@ msgid ""
"mod:<name>\n"
"player:<name>"
msgstr ""
"Filtres possibles :\n"
"game:<nom>\n"
"mod:<nom>\n"
"player:<nom>"
#: builtin/mainmenu/tab_online.lua
msgid "Public Servers"
@ -1366,9 +1366,8 @@ msgid "Access denied. Reason: %s"
msgstr "Accès refusé. Raison : %s"
#: src/client/game.cpp
#, fuzzy
msgid "All debug info hidden"
msgstr "Informations de débogage affichées"
msgstr "Informations de débogage cachées"
#: src/client/game.cpp
msgid "Automatic forward disabled"
@ -1392,7 +1391,7 @@ msgstr "Limites des blocs affichées pour les blocs voisins"
#: src/client/game.cpp
msgid "Bounding boxes shown"
msgstr ""
msgstr "Limites des boîtes affichées"
#: src/client/game.cpp
msgid "Camera update disabled"
@ -1635,10 +1634,8 @@ msgid "Volume changed to %d%%"
msgstr "Volume réglé sur %d %%"
#: src/client/game.cpp
#, fuzzy
msgid "Wireframe not supported by video driver"
msgstr ""
"Les nuanceurs sont activés mais GLSL n'est pas pris en charge par le pilote."
msgstr "Fils de fer non pris en charge par le pilote vidéo"
#: src/client/game.cpp
msgid "Wireframe shown"
@ -2068,10 +2065,8 @@ msgid "Failed to compile the \"%s\" shader."
msgstr "Échec de la compilation du nuanceur « %s »."
#: src/client/shader.cpp
#, fuzzy
msgid "GLSL is not supported by the driver"
msgstr ""
"Les nuanceurs sont activés mais GLSL n'est pas pris en charge par le pilote."
msgstr "GLSL n'est pas pris en charge par le pilote vidéo"
#. ~ Error when a mod is missing dependencies. Ex: "Mod Title is missing: mod1, mod2, mod3"
#: src/content/mod_configuration.cpp
@ -2091,7 +2086,7 @@ msgid ""
"Note: this may be caused by a dependency cycle, in which case try updating "
"the mods."
msgstr ""
"Note : ceci peut être dû à un cycle de dépendances, dans ce cas essayer de "
"Note : cela peut être dû à un cycle de dépendances, dans ce cas essayer de "
"mettre à jour les mods."
#: src/content/mod_configuration.cpp
@ -2308,35 +2303,35 @@ msgid "Sound Volume: %d%%"
msgstr "Volume du son : %d %%"
#: src/gui/touchscreeneditor.cpp
#, fuzzy
msgid "Add button"
msgstr "Clic central"
msgstr "Ajouter un bouton"
#: src/gui/touchscreeneditor.cpp
#, fuzzy
msgid "Done"
msgstr "Terminé !"
msgstr "Terminé"
#: src/gui/touchscreeneditor.cpp
#, fuzzy
msgid "Remove"
msgstr "Serveur distant"
msgstr "Supprimer"
#: src/gui/touchscreeneditor.cpp
msgid "Reset"
msgstr ""
msgstr "Réinitialiser"
#: src/gui/touchscreeneditor.cpp
msgid "Start dragging a button to add. Tap outside to cancel."
msgstr ""
"Faire glisser un bouton pour ajouter. Appuyer à l'extérieur pour annuler."
#: src/gui/touchscreeneditor.cpp
msgid "Tap a button to select it. Drag a button to move it."
msgstr ""
"Appuyer sur un bouton pour le sélectionner. Faire glisser un bouton pour le "
"déplacer."
#: src/gui/touchscreeneditor.cpp
msgid "Tap outside to deselect."
msgstr ""
msgstr "Appuyer à l'extérieur pour désélectionner."
#: src/gui/touchscreenlayout.cpp
msgid "Joystick"
@ -2524,7 +2519,7 @@ msgstr "Nuages 3D"
#: src/settings_translation_file.cpp
msgid "3D mode"
msgstr "Mode écran 3D"
msgstr "Mode 3D"
#: src/settings_translation_file.cpp
msgid "3D mode parallax strength"
@ -2573,7 +2568,6 @@ msgid "3D noise that determines number of dungeons per mapchunk."
msgstr "Bruit 3D qui détermine le nombre de donjons par tranche de carte."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"3D support.\n"
"Currently supported:\n"
@ -2592,8 +2586,7 @@ msgstr ""
"lignes paires/impaires.\n"
" haut-bas : partage haut et bas de l'écran.\n"
" côte-à-côte : partage côte à côte de l'écran.\n"
" vision croisée : vision croisée 3D.\n"
"Noter que le mode entrelacé nécessite que les nuanceurs soient activés."
" vision croisée : vision croisée 3D."
#: src/settings_translation_file.cpp
msgid ""
@ -2683,11 +2676,13 @@ msgid ""
"All mesh buffers with less than this number of vertices will be merged\n"
"during map rendering. This improves rendering performance."
msgstr ""
"Tous les tampons de maillage ayant moins de ce nombre de sommets sont "
"fusionnés lors du rendu de la carte.\n"
"Cela améliore les performances de rendu."
#: src/settings_translation_file.cpp
#, fuzzy
msgid "Allow clouds to look 3D instead of flat."
msgstr "Activer les nuages 3D au lieu des nuages 2D (plats)."
msgstr "Permet aux nuages de paraître en 3D au lieu de plats."
#: src/settings_translation_file.cpp
msgid "Allows liquids to be translucent."
@ -2705,7 +2700,7 @@ msgstr ""
"Des valeurs plus élevées rendent les niveaux de lumière moyens et inférieurs "
"plus lumineux.\n"
"La valeur « 1,0 » laisse la courbe de lumière intacte.\n"
"Ceci a un effet significatif seulement sur la lumière du jour et la lumière "
"Cela a un effet significatif seulement sur la lumière du jour et la lumière "
"artificielle, et a très peu d'effet sur la lumière naturelle nocturne."
#: src/settings_translation_file.cpp
@ -2777,7 +2772,7 @@ msgstr ""
"effectue un tramage supplémentaire ou si les canaux de couleur ne sont pas "
"quantifiés à 8 bits.\n"
"Avec OpenGL ES, le tramage fonctionne seulement si les nuanceurs prennent en "
"charge une précision élevée en virgule flottante et ceci peut avoir un "
"charge une précision élevée en virgule flottante et cela peut avoir un "
"impact plus important sur les performances."
#: src/settings_translation_file.cpp
@ -2836,8 +2831,8 @@ msgstr ""
"Des valeurs plus faibles peuvent augmenter la performance du serveur, mais "
"peut provoquer l'apparition de problèmes de rendu (certains blocs ne sont "
"pas visibles).\n"
"Ceci est particulièrement utile pour les très grandes distances de vue (plus "
"de 500).\n"
"C'est particulièrement utile pour les très grandes distances de vue (plus de "
"500).\n"
"Établie en blocs de carte (16 nœuds)."
#: src/settings_translation_file.cpp
@ -3099,7 +3094,7 @@ msgstr "Nuages dans le menu"
#: src/settings_translation_file.cpp
msgid "Color depth for post-processing texture"
msgstr ""
msgstr "Profondeur de couleur pour la texture de post-traitement"
#: src/settings_translation_file.cpp
msgid "Colored fog"
@ -3119,7 +3114,6 @@ msgstr ""
"Utile pour les tests. Voir « al_extensions.[h, cpp] » pour plus de détails."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Comma-separated list of flags to hide in the content repository.\n"
"\"nonfree\" can be used to hide packages which do not qualify as 'free "
@ -3272,7 +3266,7 @@ msgid ""
"This also applies to the object crosshair."
msgstr ""
"Opacité du réticule (entre 0 et 255).\n"
"Ceci s'applique également au réticule de l'objet."
"Cela s'applique également au réticule de l'objet."
#: src/settings_translation_file.cpp
msgid "Crosshair color"
@ -3284,7 +3278,7 @@ msgid ""
"Also controls the object crosshair color"
msgstr ""
"Couleur du réticule (R,V,B).\n"
"Ceci s'applique également à la couleur du réticule de l'objet."
"Cela s'applique également à la couleur du réticule de l'objet."
#: src/settings_translation_file.cpp
msgid "Debug log file size threshold"
@ -3305,6 +3299,10 @@ msgid ""
"Reducing this can improve performance, but some effects (e.g. debanding)\n"
"require more than 8 bits to work."
msgstr ""
"Détermine la profondeur de couleur de la texture utilisée pour les "
"opérations de post-traitement.\n"
"Réduire cette valeur peut améliorer les performances, mais certains effets ("
"ex. : le tramage) nécessitent plus de 8 bits pour fonctionner."
#: src/settings_translation_file.cpp
msgid "Dedicated server step"
@ -3345,8 +3343,8 @@ msgid ""
"but also uses more resources."
msgstr ""
"Définir la qualité du filtrage des ombres.\n"
"Ceci simule l'effet d'ombres douces en appliquant un disque PCF ou Poisson "
"mais utilise également plus de ressources."
"Cela simule l'effet d'ombres douces en appliquant le PCF ou le disque de "
"Poisson mais utilise également plus de ressources."
#: src/settings_translation_file.cpp
msgid ""
@ -3364,10 +3362,10 @@ msgstr ""
"Les anciens clients sont compatibles dans le sens où ils ne plantent pas "
"lors de la connexion aux serveurs récents,\n"
"mais ils peuvent ne pas prendre en charge certaines fonctionnalités.\n"
"Ceci permet un contrôle plus précis que "
"« strict_protocol_version_checking ».\n"
"Luanti applique toujours son propre minimum interne, activer "
"« strict_protocol_version_checking » le remplace."
"Cela permet un contrôle plus précis que « strict_protocol_version_checking »."
"\n"
"Luanti applique toujours son propre minimum interne, activer « "
"strict_protocol_version_checking » le remplace."
#: src/settings_translation_file.cpp
msgid "Defines areas where trees have apples."
@ -3441,7 +3439,7 @@ msgid ""
"down the rate of mesh updates, thus reducing jitter on slower clients."
msgstr ""
"Délai entre les mises à jour du maillage du client en ms.\n"
"Augmenter ceci ralentit le taux de mise à jour et réduit donc les "
"Augmenter cela ralentit le taux de mise à jour et réduit donc les "
"tremblements sur les clients lents."
#: src/settings_translation_file.cpp
@ -3528,6 +3526,10 @@ msgid ""
"situations\n"
"where transparency sorting would be very slow otherwise."
msgstr ""
"Dessine les triangles triés par transparence regroupés par leurs tampons de "
"maillage.\n"
"Cela empêche le tri par transparence entre les tampons de maillage, mais "
"évite les situations où le tri par transparence serait très lent autrement."
#: src/settings_translation_file.cpp
msgid "Dump the mapgen debug information."
@ -3589,7 +3591,7 @@ msgid ""
msgstr ""
"Activer le filtrage par disque de Poisson.\n"
"Si activé, utilise le disque de Poisson pour créer des « ombres douces ». "
"Sinon, utilise le filtrage PCF."
"Sinon, utilise le PCF."
#: src/settings_translation_file.cpp
msgid "Enable Post Processing"
@ -3597,7 +3599,7 @@ msgstr "Activer le post-traitement"
#: src/settings_translation_file.cpp
msgid "Enable Raytraced Culling"
msgstr "Activer l'élimination des blocs invisibles par Ray Tracing"
msgstr "Activer l'élimination des blocs invisibles par lancer de rayons"
#: src/settings_translation_file.cpp
msgid ""
@ -3613,14 +3615,12 @@ msgstr ""
"simulant le comportement de lœil humain."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Enable colored shadows for transculent nodes.\n"
"This is expensive."
msgstr ""
"Activer les ombres colorées.\n"
"Sur les nœuds vraiment transparents, projette des ombres colorées. Ceci est "
"coûteux."
"Activer les ombres colorées pour les nœuds translucides.\n"
"Cela utilise beaucoup de ressources."
#: src/settings_translation_file.cpp
msgid "Enable console window"
@ -3707,14 +3707,12 @@ msgstr ""
"double."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Enable/disable running an IPv6 server.\n"
"Ignored if bind_address is set."
msgstr ""
"Activer/désactiver l'usage d'un serveur IPv6.\n"
"Ignoré si « bind_address » est activé.\n"
"A besoin de « enable_ipv6 » pour être activé."
"Ignoré si « bind_address » est activé."
#: src/settings_translation_file.cpp
msgid ""
@ -3978,7 +3976,7 @@ msgid ""
"be\n"
"sized 16, 32, 48, etc., so a mod requesting a size of 25 will get 32."
msgstr ""
"Pour les polices de style pixel qui ne s'adaptent pas bien, ceci garantit "
"Pour les polices de style pixel qui ne s'adaptent pas bien, cela garantit "
"que les tailles de police utilisées avec cette police sont toujours "
"divisibles par cette valeur, en pixels.\n"
"Par exemple une police de style pixel de 16 pixels de haut doit avoir cette "
@ -4057,7 +4055,7 @@ msgstr ""
"Distance maximale à laquelle les clients ont connaissance des objets, "
"établie en blocs de carte (16 nœuds).\n"
"\n"
"Définir ceci plus grand que « active_block_range », ainsi le serveur "
"Définir cela plus grand que « active_block_range », ainsi le serveur "
"maintient les objets actifs jusquà cette distance dans la direction où un "
"joueur regarde (cela peut éviter que des mobs disparaissent soudainement de "
"la vue)."
@ -4288,7 +4286,7 @@ msgid ""
"Decrease this to increase liquid resistance to movement."
msgstr ""
"Ralentissement lors du déplacement dans un liquide.\n"
"Réduire ceci pour augmenter la résistance au mouvement."
"Réduire cette valeur pour augmenter la résistance au mouvement."
#: src/settings_translation_file.cpp
msgid "How wide to make rivers."
@ -4376,16 +4374,15 @@ msgstr ""
"de le remplacer par un mot de passe vide."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"If enabled, server account registration is separate from login in the UI.\n"
"If disabled, connecting to a server will automatically register a new "
"account."
msgstr ""
"Si activé, l'enregistrement du compte est séparé de la connexion dans "
"l'interface utilisateur.\n"
"Si désactivé, les nouveaux comptes sont enregistrés automatiquement lors de "
"la connexion."
"Si activé, l'enregistrement du compte sur le serveur est séparé de la "
"connexion dans l'interface utilisateur.\n"
"Si désactivé, la connexion à un serveur entraîne automatiquement "
"l'enregistrement d'un nouveau compte."
#: src/settings_translation_file.cpp
msgid ""
@ -4396,7 +4393,7 @@ msgid ""
msgstr ""
"Si activé, le serveur effectue la détermination des blocs de carte "
"invisibles selon la position des yeux du joueur.\n"
"Ceci peut réduire le nombre de blocs envoyés au client de 50 à 80 %.\n"
"Cela peut réduire le nombre de blocs envoyés au client de 50 à 80 %.\n"
"Les clients ne reçoivent plus la plupart des blocs invisibles, de sorte que "
"l'utilité du mode sans collisions est réduite."
@ -4473,7 +4470,7 @@ msgid ""
"This is usually only needed by core/builtin contributors"
msgstr ""
"Instrumenter « Intégré » (« builtin »).\n"
"Ceci est habituellement nécessaire seulement pour les développeurs "
"Cela est habituellement nécessaire seulement pour les développeurs "
"principaux."
#: src/settings_translation_file.cpp
@ -4752,7 +4749,7 @@ msgid ""
"- trace"
msgstr ""
"Niveau de journalisation à écrire dans « debug.txt » :\n"
" < rien > (pas de journalisation)\n"
" <vide> (pas de journalisation)\n"
" aucun (messages sans niveau)\n"
" erreur\n"
" avertissement\n"
@ -5282,7 +5279,7 @@ msgstr ""
#: src/settings_translation_file.cpp
msgid "Minimum vertex count for mesh buffers"
msgstr ""
msgstr "Nombre minimal de sommets pour les tampons de maillage"
#: src/settings_translation_file.cpp
msgid "Mipmapping"
@ -5378,15 +5375,14 @@ msgstr ""
" les terrains flottants optionnels du générateur v7 (désactivé par défaut)."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Name of the player.\n"
"When running a server, a client connecting with this name is admin.\n"
"When starting from the main menu, this is overridden."
msgstr ""
"Nom du joueur.\n"
"Lorsqu'un serveur est lancé, les clients se connectant avec ce nom sont "
"administrateurs.\n"
"Lorsqu'un serveur est lancé, le client se connectant avec ce nom est "
"administrateur.\n"
"Lors du démarrage à partir du menu principal, celui-ci est remplacé."
#: src/settings_translation_file.cpp
@ -5614,7 +5610,7 @@ msgstr ""
"des boutons de la souris.\n"
"Activer cette option lorsque vous creusez ou placez trop souvent par "
"accident.\n"
"Sur écrans tactiles, ceci a un effet seulement pour creuser."
"Sur écrans tactiles, cela a un effet seulement pour le minage."
#: src/settings_translation_file.cpp
msgid "Prevent mods from doing insecure things like running shell commands."
@ -5847,9 +5843,9 @@ msgid ""
"edge pixels when images are scaled by non-integer sizes."
msgstr ""
"Met à l'échelle l'interface graphique par une valeur spécifiée par "
"l'utilisateur, à l'aide d'un filtre au plus proche voisin avec "
"anticrénelage.\n"
"Ceci lisse certains bords grossiers, et mélange les pixels en réduisant "
"l'utilisateur, à l'aide d'un filtre au plus proche voisin avec anticrénelage."
"\n"
"Cela lisse certains bords grossiers, et mélange les pixels en réduisant "
"l'échelle.\n"
"Au détriment d'un effet de flou sur des pixels en bordure quand les images "
"sont mises à l'échelle par des valeurs fractionnelles."
@ -5911,7 +5907,6 @@ msgid "See https://www.sqlite.org/pragma.html#pragma_synchronous"
msgstr "Voir http://www.sqlite.org/pragma.html#pragma_synchronous"
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Select the antialiasing method to apply.\n"
"\n"
@ -5938,17 +5933,22 @@ msgstr ""
"\n"
"* Aucun Pas d'anticrénelage (par défaut)\n"
"\n"
"* FSAA Anticrénelage de la scène complète (incompatible avec « Post-"
"traitement » et « Sous-échantillonnage »)\n"
"* FSAA Anticrénelage matériel de la scène complète\n"
"Alias anticrénelage multi-échantillon (MSAA), lisse les bords des blocs mais "
"n'affecte pas l'intérieur des textures.\n"
"Un redémarrage est nécessaire pour modifier cette option.\n"
"\n"
"* FXAA Anticrénelage approximatif rapide (nécessite des nuanceurs)\n"
"Si le post-traitement est désactivé, la modification de FSAA nécessite un "
"redémarrage.\n"
"De même, si le post-traitement est désactivé, le FSAA ne fonctionne pas avec "
"le sous-échantillonnage,\n"
"pour un paramètre « Mode 3D » défini sur une autre valeur que celle par "
"défaut.\n"
"\n"
"* FXAA Anticrénelage approximatif rapide\n"
"Applique un filtre de post-traitement pour détecter et lisser les bords à "
"contraste élevé, fournit un équilibre entre vitesse et qualité d'image.\n"
"\n"
"* SSAA Anticrénelage par super-échantillonnage (nécessite des nuanceurs)\n"
"* SSAA Anticrénelage par super-échantillonnage\n"
"Rendu d'une image haute résolution de la scène, puis réduit l'échelle pour "
"diminuer le crénelage. C'est la méthode la plus lente et la plus précise."
@ -6187,7 +6187,7 @@ msgid ""
msgstr ""
"Définit la qualité de la texture de l'ombre sur 32 bits.\n"
"Si désactivé, une texture de 16 bits est utilisée.\n"
"Ceci peut causer beaucoup plus d'artefacts sur l'ombre."
"Cela peut causer beaucoup plus d'artefacts sur l'ombre."
#: src/settings_translation_file.cpp
msgid "Shader path"
@ -6389,7 +6389,6 @@ msgstr ""
"certains (ou tous) objets."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Spread a complete update of the shadow map over a given number of frames.\n"
"Higher values might make shadows laggy, lower values\n"
@ -6398,8 +6397,7 @@ msgstr ""
"Répartit une mise à jour complète de la carte des ombres sur un nombre donné "
"d'images.\n"
"Des valeurs plus élevées peuvent rendre les ombres plus lentes, des valeurs "
"plus faibles consomment plus de ressources.\n"
"Valeur minimale : 1 ; valeur maximale : 16"
"plus faibles consomment plus de ressources."
#: src/settings_translation_file.cpp
msgid ""
@ -6666,11 +6664,11 @@ msgid ""
msgstr ""
"Le rayon du volume de blocs autour de chaque joueur soumis au bloc actif, "
"établi en blocs de carte (16 nœuds).\n"
"Dans les blocs actifs, les objets sont chargés et les « ABMs » sont "
"exécutés.\n"
"Dans les blocs actifs, les objets sont chargés et les « ABMs » sont exécutés."
"\n"
"C'est également la distance minimale dans laquelle les objets actifs (mobs) "
"sont conservés.\n"
"Ceci doit être configuré avec « active_object_send_range_blocks »."
"Cela doit être configuré avec « active_object_send_range_blocks »."
#: src/settings_translation_file.cpp
msgid ""
@ -6701,7 +6699,7 @@ msgstr ""
"Intensité (obscurité) de l'ombrage des blocs avec l'occlusion ambiante.\n"
"Les valeurs plus faibles sont plus sombres, les valeurs plus hautes sont "
"plus claires.\n"
"Une plage valide de valeurs pour ceci se situe entre 0,25 et 4,0.\n"
"Une plage valide de valeurs pour cela se situe entre 0,25 et 4,0.\n"
"Si la valeur est en dehors de cette plage alors elle est définie à la plus "
"proche des valeurs valides."
@ -6798,7 +6796,7 @@ msgid ""
msgstr ""
"Pour réduire le décalage, le transfert des blocs est ralenti quand un joueur "
"construit quelque chose.\n"
"Ceci détermine la durée du ralentissement après placement ou destruction "
"Cela détermine la durée du ralentissement après placement ou destruction "
"d'un nœud."
#: src/settings_translation_file.cpp
@ -6843,12 +6841,11 @@ msgstr "Liquides translucides"
#: src/settings_translation_file.cpp
msgid "Transparency Sorting Distance"
msgstr "Distance de tri de la transparence"
msgstr "Tri de la transparence par distance"
#: src/settings_translation_file.cpp
#, fuzzy
msgid "Transparency Sorting Group by Buffers"
msgstr "Distance de tri de la transparence"
msgstr "Tri de la transparence regroupés par tampons"
#: src/settings_translation_file.cpp
msgid "Trees noise"
@ -6912,7 +6909,6 @@ msgid "Undersampling"
msgstr "Sous-échantillonnage"
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Undersampling is similar to using a lower screen resolution, but it applies\n"
"to the game world only, keeping the GUI intact.\n"
@ -6926,9 +6922,12 @@ msgstr ""
"Le sous-échantillonnage ressemble à l'utilisation d'une résolution d'écran "
"inférieure.\n"
"Il ne s'applique qu'au rendu 3D, gardant l'interface graphique intacte.\n"
"Ceci doit donner un bonus de performance conséquent, au détriment de la "
"Cela doit donner un bonus de performance conséquent, au détriment de la "
"qualité d'image.\n"
"Les valeurs plus élevées réduisent la qualité du détail des images."
"Les valeurs plus élevées réduisent la qualité du détail des images.\n"
"Note : le sous-échantillonnage n'est actuellement pas pris en charge,\n"
"si le paramètre « Mode 3D » est définie sur une autre valeur que celle par "
"défaut."
#: src/settings_translation_file.cpp
msgid "Unlimited player transfer distance"
@ -6955,13 +6954,14 @@ msgid "Use a cloud animation for the main menu background."
msgstr "Utiliser l'animation des nuages pour l'arrière-plan du menu principal."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Use anisotropic filtering when looking at textures from an angle.\n"
"This provides a significant improvement when used together with mipmapping."
msgstr ""
"Utiliser le filtrage anisotrope lorsque l'on regarde les textures sous un "
"certain angle."
"certain angle.\n"
"Cela apporte une amélioration significative lorsqu'il est utilisé avec le "
"mip-mapping."
#: src/settings_translation_file.cpp
msgid "Use bilinear filtering when scaling textures."
@ -6998,10 +6998,10 @@ msgid ""
"This flag enables use of raytraced occlusion culling test for\n"
"client mesh sizes smaller than 4x4x4 map blocks."
msgstr ""
"Utiliser l'élimination des blocs invisibles par Ray Tracing avec le nouvel "
"algorithme.\n"
"Utiliser l'élimination des blocs invisibles par lancer de rayons avec le "
"nouvel algorithme.\n"
"Cette option active l'utilisation du test d'élimination des blocs invisibles "
"par Ray Tracing,\n"
"par lancer de rayons,\n"
"pour les maillages clients de taille inférieure à 4 × 4 × 4 blocs de carte."
#: src/settings_translation_file.cpp
@ -7237,7 +7237,6 @@ msgstr ""
"directement par le matériel (ex. : textures des blocs dans l'inventaire)."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"When using bilinear/trilinear filtering, low-resolution textures\n"
"can be blurred, so this option automatically upscales them to preserve\n"
@ -7248,16 +7247,16 @@ msgid ""
"This is also used as the base node texture size for world-aligned\n"
"texture autoscaling."
msgstr ""
"En utilisant le filtrage bilinéaire/trilinéaire/anisotrope, les textures de "
"basse résolution peuvent être floues.\n"
"Elles sont donc agrandies avec l'interpolation au plus proche voisin pour "
"préserver des pixels nets.\n"
"Ceci détermine la taille minimale pour les textures agrandies;\n"
"En utilisant le filtrage bilinéaire/trilinéaire, les textures de basse "
"résolution peuvent être floues.\n"
"Cette option les agrandies automatiquement afin de préserver des pixels nets."
"\n"
"Cela définit la taille minimale pour les textures agrandies;\n"
"les valeurs plus élevées ont un rendu plus net, mais nécessitent plus de "
"mémoire. Les puissances de 2 sont recommandées.\n"
"Ce paramètre est appliqué seulement si le filtrage bilinéaire/trilinéaire/"
"anisotrope est activé.\n"
"Ceci est également utilisé comme taille de texture de nœud de base pour "
"mémoire.\n"
"Ce paramètre est appliqué UNIQUEMENT si l'un des filtres mentionnés est "
"activé.\n"
"Cela est également utilisé comme taille de texture de nœud de base pour "
"l'agrandissement automatique des textures alignées sur le monde."
#: src/settings_translation_file.cpp
@ -7293,14 +7292,12 @@ msgid "Whether to fog out the end of the visible area."
msgstr "Détermine la visibilité du brouillard au bout de l'aire visible."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Whether to mute sounds. You can unmute sounds at any time.\n"
"In-game, you can toggle the mute state with the mute key or by using the\n"
"pause menu."
msgstr ""
"S'il faut couper le son. Vous pouvez réactiver le son à tout moment, sauf si "
"le système audio est désactivé (« enable_sound=false »).\n"
"S'il faut couper le son. Vous pouvez réactiver le son à tout moment.\n"
"Dans le jeu, vous pouvez basculer l'état du son avec la touche « Muet » ou "
"en utilisant le menu pause."
@ -7399,7 +7396,7 @@ msgstr ""
"Distance Y sur laquelle les terrains flottants passent d'une densité "
"maximale à une densité nulle.\n"
"L'effilage commence à cette distance, depuis la limite en Y.\n"
"Pour une couche solide de terrain flottant, ceci contrôle la hauteur des "
"Pour une couche solide de terrain flottant, cela contrôle la hauteur des "
"collines et des montagnes.\n"
"Doit être inférieure ou égale à la moitié de la distance entre les limites Y."

View file

@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: minetest\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-02-09 13:23+0100\n"
"PO-Revision-Date: 2024-11-24 10:00+0000\n"
"PO-Revision-Date: 2025-02-13 12:44+0000\n"
"Last-Translator: ninjum <ninhum@gmx.com>\n"
"Language-Team: Galician <https://hosted.weblate.org/projects/minetest/"
"minetest/gl/>\n"
@ -12,7 +12,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.9-dev\n"
"X-Generator: Weblate 5.10-dev\n"
#: builtin/client/chatcommands.lua
msgid "Clear the out chat queue"
@ -263,13 +263,12 @@ msgid "Show technical names"
msgstr "Mostrar nomes técnicos"
#: builtin/common/settings/dlg_settings.lua
#, fuzzy
msgid "Touchscreen layout"
msgstr "Pantalla táctil"
msgstr "Disposición da pantalla táctil"
#: builtin/common/settings/dlg_settings.lua
msgid "pause_menu"
msgstr ""
msgstr "_menú de pausa"
#: builtin/common/settings/settingtypes.lua
msgid "Client Mods"
@ -609,6 +608,8 @@ msgid ""
"This is the list of clients connected to\n"
"$1"
msgstr ""
"Esta é a lista de clientes conectados a\n"
"$1"
#: builtin/mainmenu/dlg_config_world.lua
msgid "(Enabled, has error)"
@ -882,7 +883,7 @@ msgstr "Desexa eliminar \"$1\"?"
#: builtin/mainmenu/dlg_delete_content.lua
#: builtin/mainmenu/dlg_delete_world.lua builtin/mainmenu/tab_local.lua
msgid "Delete"
msgstr "Eliminar"
msgstr "Borrar"
#: builtin/mainmenu/dlg_delete_content.lua
msgid "pkgmgr: failed to delete \"$1\""
@ -971,21 +972,20 @@ msgstr ""
"non permitirá cambios de nome aquí."
#: builtin/mainmenu/dlg_server_list_mods.lua
#, fuzzy
msgid "Expand all"
msgstr "Activar todo"
msgstr "Expandir todo"
#: builtin/mainmenu/dlg_server_list_mods.lua
msgid "Group by prefix"
msgstr ""
msgstr "Agrupar por prefixo"
#: builtin/mainmenu/dlg_server_list_mods.lua
msgid "The $1 server uses a game called $2 and the following mods:"
msgstr ""
msgstr "O servidor $1 usa un xogo chamado $2 e as seguintes modificacións:"
#: builtin/mainmenu/dlg_server_list_mods.lua
msgid "The $1 server uses the following mods:"
msgstr ""
msgstr "O servidor $1 usa as seguintes modificacións:"
#: builtin/mainmenu/dlg_version_info.lua
msgid "A new $1 version is available"
@ -1199,20 +1199,20 @@ msgid "You need to install a game before you can create a world."
msgstr "Tes que instalar un xogo antes de poder crear un mundo."
#: builtin/mainmenu/tab_online.lua
#, fuzzy
msgid "Add favorite"
msgstr "Favorito remoto"
msgstr "Engadir aos favoritos"
#: builtin/mainmenu/tab_online.lua
msgid "Address"
msgstr "Enderezo"
#: builtin/mainmenu/tab_online.lua
#, fuzzy
msgid ""
"Clients:\n"
"$1"
msgstr "Cliente"
msgstr ""
"Clientes:\n"
"$1"
#: builtin/mainmenu/tab_online.lua
msgid "Creative mode"
@ -1228,9 +1228,8 @@ msgid "Favorites"
msgstr "Favoritos"
#: builtin/mainmenu/tab_online.lua
#, fuzzy
msgid "Game: $1"
msgstr "Xogo"
msgstr "Xogo: $1"
#: builtin/mainmenu/tab_online.lua
msgid "Incompatible Servers"
@ -1245,14 +1244,12 @@ msgid "Login"
msgstr "Identificarse"
#: builtin/mainmenu/tab_online.lua
#, fuzzy
msgid "Number of mods: $1"
msgstr "Número de fíos emerxentes"
msgstr "Número de modificacións: $1"
#: builtin/mainmenu/tab_online.lua
#, fuzzy
msgid "Open server website"
msgstr "Intervalo de servidor dedicado"
msgstr "Abrir o sitio web do servidor"
#: builtin/mainmenu/tab_online.lua
msgid "Ping"
@ -1265,6 +1262,10 @@ msgid ""
"mod:<name>\n"
"player:<name>"
msgstr ""
"Filtros posibles\n"
"xogo:<nome>\n"
"mod:<nome>\"\n"
"xogador:<nome"
#: builtin/mainmenu/tab_online.lua
msgid "Public Servers"
@ -1360,9 +1361,8 @@ msgid "Access denied. Reason: %s"
msgstr "Acceso negado. Motivo: %s"
#: src/client/game.cpp
#, fuzzy
msgid "All debug info hidden"
msgstr "Info de depuración mostrada"
msgstr "Toda a información de depuración oculta"
#: src/client/game.cpp
msgid "Automatic forward disabled"
@ -1386,7 +1386,7 @@ msgstr "Límites de bloques mostrados para bloques pretos"
#: src/client/game.cpp
msgid "Bounding boxes shown"
msgstr ""
msgstr "Caixas delimitadoras amosadas"
#: src/client/game.cpp
msgid "Camera update disabled"
@ -1627,9 +1627,8 @@ msgid "Volume changed to %d%%"
msgstr "Volume cambiado a %d%%"
#: src/client/game.cpp
#, fuzzy
msgid "Wireframe not supported by video driver"
msgstr "Os sombreadores están habilitados pero o controlador non admite GLSL."
msgstr "O wireframe non é compatible co controlador de vídeo"
#: src/client/game.cpp
msgid "Wireframe shown"
@ -2062,9 +2061,8 @@ msgid "Failed to compile the \"%s\" shader."
msgstr "Produciuse un erro ao compilar o sombreador \"%s\"."
#: src/client/shader.cpp
#, fuzzy
msgid "GLSL is not supported by the driver"
msgstr "Os sombreadores están habilitados pero o controlador non admite GLSL."
msgstr "GLSL non é compatible co controlador"
#. ~ Error when a mod is missing dependencies. Ex: "Mod Title is missing: mod1, mod2, mod3"
#: src/content/mod_configuration.cpp
@ -2301,35 +2299,32 @@ msgid "Sound Volume: %d%%"
msgstr "Son: %d%%"
#: src/gui/touchscreeneditor.cpp
#, fuzzy
msgid "Add button"
msgstr "Botón central"
msgstr "Engadir botón"
#: src/gui/touchscreeneditor.cpp
#, fuzzy
msgid "Done"
msgstr "Feito!"
msgstr "Feito"
#: src/gui/touchscreeneditor.cpp
#, fuzzy
msgid "Remove"
msgstr "Servidor remoto"
msgstr "Eliminar"
#: src/gui/touchscreeneditor.cpp
msgid "Reset"
msgstr ""
msgstr "Restablecer"
#: src/gui/touchscreeneditor.cpp
msgid "Start dragging a button to add. Tap outside to cancel."
msgstr ""
msgstr "Comeza a arrastrar un botón para engadir. Toca fóra para cancelar."
#: src/gui/touchscreeneditor.cpp
msgid "Tap a button to select it. Drag a button to move it."
msgstr ""
msgstr "Toca un botón para seccionalo. Arrastra un botón para movelo."
#: src/gui/touchscreeneditor.cpp
msgid "Tap outside to deselect."
msgstr ""
msgstr "Toca fóra para deseleccionar."
#: src/gui/touchscreenlayout.cpp
msgid "Joystick"
@ -2565,7 +2560,6 @@ msgid "3D noise that determines number of dungeons per mapchunk."
msgstr "Ruído 3D que determina a cantidade de calabozos por chunk."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"3D support.\n"
"Currently supported:\n"
@ -2578,14 +2572,13 @@ msgid ""
msgstr ""
"Soporte 3D.\n"
"Soportado actualmente:\n"
"- none: sen saída 3D.\n"
"- anaglyph: 3D en cor ciano/maxenta.\n"
"- interlaced: soporte de pantalla polarizada baseada en liñas par/ímpar.\n"
"- topbottom: pantalla dividida superior/inferior.\n"
"- sidebyside: pantalla dividida lado a lado.\n"
" - crossview: 3D para ver cruzado\n"
"Teña en conta que o modo entrelazado require cos sombreadores estean "
"activados."
"- ningún: sen saída 3D.\n"
"- anáglifo: 3D en cor ciano/maxenta.\n"
"- entrelazado: soporte de pantalla polarizada baseada en liñas par/ímpar."
"\n"
"- arriba-abaixo: pantalla dividida superior/inferior.\n"
"- lado a lado: pantalla dividida lado a lado.\n"
"- vista cruzada: 3D para ver cruzado"
#: src/settings_translation_file.cpp
msgid ""
@ -2674,11 +2667,13 @@ msgid ""
"All mesh buffers with less than this number of vertices will be merged\n"
"during map rendering. This improves rendering performance."
msgstr ""
"Todos os buffers de malla con menos de este número de vértices serán "
"fusionados\n"
"durante o renderizado do mapa. Isto mellora o rendemento do renderizado."
#: src/settings_translation_file.cpp
#, fuzzy
msgid "Allow clouds to look 3D instead of flat."
msgstr "Activa as nubes 3D en lugar de nubes 2D (planas)."
msgstr "Permitir que as nubes se vexan en 3D en vez de planas."
#: src/settings_translation_file.cpp
msgid "Allows liquids to be translucent."
@ -3089,7 +3084,7 @@ msgstr "Nubes no menú"
#: src/settings_translation_file.cpp
msgid "Color depth for post-processing texture"
msgstr ""
msgstr "Profundidade de cor para a textura de post-procesamento"
#: src/settings_translation_file.cpp
msgid "Colored fog"
@ -3108,7 +3103,6 @@ msgstr ""
"Útil para probas. Vexa al_extensions.[h,cpp] para máis detalles."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Comma-separated list of flags to hide in the content repository.\n"
"\"nonfree\" can be used to hide packages which do not qualify as 'free "
@ -3294,6 +3288,11 @@ msgid ""
"Reducing this can improve performance, but some effects (e.g. debanding)\n"
"require more than 8 bits to work."
msgstr ""
"Decide a profundidade de cor da textura utilizada para o proceso de post-"
"procesamento.\n"
"Reducir isto pode mellorar o rendemento, pero algúns efectos (por exemplo, "
"tramado)\n"
"require máis de 8 bits para funcionar."
#: src/settings_translation_file.cpp
msgid "Dedicated server step"
@ -3518,6 +3517,11 @@ msgid ""
"situations\n"
"where transparency sorting would be very slow otherwise."
msgstr ""
"Debuxar triángulos ordenados por transparencia agrupados polos seus buffers "
"de malla.\n"
"Isto rompe a orde de transparencia entre os buffers de malla, pero evita "
"situacións\n"
"onde a orde de transparencia sería moi lenta noutro caso."
#: src/settings_translation_file.cpp
msgid "Dump the mapgen debug information."
@ -3602,14 +3606,12 @@ msgstr ""
"simulando o comportamento do ollo humano."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Enable colored shadows for transculent nodes.\n"
"This is expensive."
msgstr ""
"Activar sombras coloridas.\n"
"Se o valor é verdadeiro, os bloques traslúcidos proxectarán sombras "
"coloridas. Esta opción precisa de moitos recursos."
"Activar sombras coloreadas para nós translúcidos.\n"
"Isto é custoso."
#: src/settings_translation_file.cpp
msgid "Enable console window"
@ -3695,14 +3697,12 @@ msgstr ""
"Por exemplo: 0 para nada de balanceo; 1.0 para o normal; 2.0 para o dobre."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Enable/disable running an IPv6 server.\n"
"Ignored if bind_address is set."
msgstr ""
"Activa/desactiva a execución dun servidor IPv6.\n"
"Ignorado se establécese bind_address.\n"
"É preciso enable_ipv6 para activalo."
"Activar/desactivar a execución dun servidor IPv6.\n"
"Ignorado se está configurada a bind_address."
#: src/settings_translation_file.cpp
msgid ""
@ -4364,14 +4364,15 @@ msgstr ""
"cambiar o seu contrasinal a un contrasinal baleiro."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"If enabled, server account registration is separate from login in the UI.\n"
"If disabled, connecting to a server will automatically register a new "
"account."
msgstr ""
"Activar confirmación de rexistro ao se conectar ao servidor\n"
"Se está desactivado, rexistrarase unha nova conta automáticamente."
"Se está activado, o rexistro da conta do servidor é separado do inicio de "
"sesión na interface de usuario.\n"
"Se está desactivado, conectar a un servidor rexistrará automaticamente unha "
"nova conta."
#: src/settings_translation_file.cpp
msgid ""
@ -5262,7 +5263,7 @@ msgstr "Límite mínimo do número aleatorio de covas pequenas por chunk."
#: src/settings_translation_file.cpp
msgid "Minimum vertex count for mesh buffers"
msgstr ""
msgstr "Contaxe mínima de vértices para os buffers de malla"
#: src/settings_translation_file.cpp
msgid "Mipmapping"
@ -5357,16 +5358,15 @@ msgstr ""
"- Os terreos flotantes opcionais de v7 (desactivados por defecto)."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Name of the player.\n"
"When running a server, a client connecting with this name is admin.\n"
"When starting from the main menu, this is overridden."
msgstr ""
"Nome do xogador.\n"
"Cando se executa un servidor, os clientes que se conectan con este nome son "
"administradores.\n"
"Ao comezar desde o menú principal, isto substitúese."
"Cando se executa un servidor, un cliente que se conecte con este nome será "
"administrador.\n"
"Cando se inicie desde o menú principal, isto será substituído."
#: src/settings_translation_file.cpp
msgid ""
@ -6356,18 +6356,16 @@ msgstr ""
"cantidade na que agrupar algúns (ou todos) os obxectos."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Spread a complete update of the shadow map over a given number of frames.\n"
"Higher values might make shadows laggy, lower values\n"
"will consume more resources."
msgstr ""
"Distribuír unha actualización completa do mapa de sombras sobre unha "
"determinada cantidade de fotogramas.\n"
"Os valores máis altos poden facer cas sombras sexan lentas e os valores máis "
"baixos\n"
"consumirán máis recursos.\n"
"Valor mínimo: 1; Valor máximo 16"
"Espallar unha actualización completa do mapa de sombras ao longo dun número "
"determinado de fotogramas.\n"
"Valores máis altos poden facer que as sombras vaian con retardo, mentres que "
"valores máis baixos\n"
"consumirán máis recursos."
#: src/settings_translation_file.cpp
msgid ""
@ -6650,7 +6648,7 @@ msgid ""
msgstr ""
"O backend de renderizado.\n"
"Nota: É necesario reiniciar despois de cambiar isto!\n"
"OpenGL é o predeterminado para escritorio, e OGLES2 para Android"
"OpenGL é o predeterminado para escritorio, e OGLES2 para Android."
#: src/settings_translation_file.cpp
msgid ""
@ -6814,9 +6812,8 @@ msgid "Transparency Sorting Distance"
msgstr "Distancia de ordenación de transparencias"
#: src/settings_translation_file.cpp
#, fuzzy
msgid "Transparency Sorting Group by Buffers"
msgstr "Distancia de ordenación de transparencias"
msgstr "Grupo de orde de transparencia por buffers"
#: src/settings_translation_file.cpp
msgid "Trees noise"
@ -6876,7 +6873,6 @@ msgid "Undersampling"
msgstr "Submostraxe"
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Undersampling is similar to using a lower screen resolution, but it applies\n"
"to the game world only, keeping the GUI intact.\n"
@ -6892,7 +6888,10 @@ msgstr ""
"só para o mundo, mantendo a GUI intacta.\n"
"Debería dar un aumento máis significativo do rendemento a costa dunha imaxe "
"menos detallada.\n"
"Os valores máis altos dan como resultado unha imaxe menos detallada."
"Os valores máis altos dan como resultado unha imaxe menos detallada.\n"
"Nota: A submostraxe actualmente non está soportada se a configuración "
"'3d_mode' está establecida\n"
"cun valor non predeterminado."
#: src/settings_translation_file.cpp
msgid "Unlimited player transfer distance"
@ -6919,11 +6918,13 @@ msgid "Use a cloud animation for the main menu background."
msgstr "Usa unha animación de nube para o fondo do menú principal."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Use anisotropic filtering when looking at textures from an angle.\n"
"This provides a significant improvement when used together with mipmapping."
msgstr "Usar filtrado anisotrópico ao observar texturas desde un ángulo."
msgstr ""
"Usar filtrado anisotrópico ao observar texturas desde un ángulo.\n"
"Isto proporciona unha mellora significativa cando se usa xunto con "
"mipmapping."
#: src/settings_translation_file.cpp
msgid "Use bilinear filtering when scaling textures."
@ -7195,7 +7196,6 @@ msgstr ""
"ao hardware (por exemplo, renderizado en textura para nós do inventario)."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"When using bilinear/trilinear filtering, low-resolution textures\n"
"can be blurred, so this option automatically upscales them to preserve\n"
@ -7206,17 +7206,16 @@ msgid ""
"This is also used as the base node texture size for world-aligned\n"
"texture autoscaling."
msgstr ""
"Cando se usan filtros bilineais/trilineais/anisótropos, texturas de baixa "
"resolución\n"
"poden ser borrosas, polo que amplíaos automaticamente co veciño máis "
"próximo\n"
"interpolación para preservar píxeles nítidos. Isto establece o tamaño mínimo "
"de textura\n"
"para as texturas mejoradas; valores máis altos parecen máis nítidos, pero "
"requiren máis\n"
"memoria. Recoméndase potencias de 2. Esta configuración só se aplica se\n"
"O filtrado bilineal/trilineal/anisótropo está activado.\n"
"Tamén se usa como tamaño de textura do nodo base para aliñados ao mundo\n"
"Cando se usa filtrado bilineal/trilineal, as texturas de baixa resolución\n"
"poden quedar borrosas, polo que esta opción amplía automaticamente as "
"texturas para preservar\n"
"píxeles nítidos. Isto define o tamaño mínimo da textura para as texturas "
"ampliadas;\n"
"valores máis altos son máis nítidos, pero requiren máis memoria.\n"
"Esta configuración APLÍCASE SÓ se algún dos filtros mencionados está "
"habilitado.\n"
"Este tamén se usa como tamaño de textura do nodo base para aliñados ao "
"mundo\n"
"autoescalado de texturas."
#: src/settings_translation_file.cpp
@ -7253,17 +7252,16 @@ msgid "Whether to fog out the end of the visible area."
msgstr "Indica se hai que poñar néboa ao final da zona visible."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Whether to mute sounds. You can unmute sounds at any time.\n"
"In-game, you can toggle the mute state with the mute key or by using the\n"
"pause menu."
msgstr ""
"Indica se hai que silenciar os sons. Podes activar o son en calquera "
"momento, a non ser que\n"
"esté desactivado (enable_sound=false).\n"
"No xogo podes cambiar o estado de silencio coa tecla de silencio ou no\n"
"menú de pausa."
"Se activar ou desactivar os sons. Pódese reactivar o son en calquera momento."
"\n"
"No xogo, podes alternar o estado de silencio coa tecla de silencio ou "
"utilizando\n"
"o menú de pausa."
#: src/settings_translation_file.cpp
msgid ""

File diff suppressed because it is too large Load diff

View file

@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: Indonesian (Minetest)\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-02-09 13:23+0100\n"
"PO-Revision-Date: 2024-12-22 16:00+0000\n"
"PO-Revision-Date: 2025-02-11 02:02+0000\n"
"Last-Translator: Linerly <linerly@proton.me>\n"
"Language-Team: Indonesian <https://hosted.weblate.org/projects/minetest/"
"minetest/id/>\n"
@ -263,14 +263,12 @@ msgid "Show technical names"
msgstr "Tampilkan nama teknis"
#: builtin/common/settings/dlg_settings.lua
#, fuzzy
msgid "Touchscreen layout"
msgstr "Layar Sentuh"
msgstr "Tata letak layar sentuh"
#: builtin/common/settings/dlg_settings.lua
#, fuzzy
msgid "pause_menu"
msgstr "FPS (bingkai per detik) pada menu jeda"
msgstr "pause_menu"
#: builtin/common/settings/settingtypes.lua
msgid "Client Mods"
@ -608,6 +606,8 @@ msgid ""
"This is the list of clients connected to\n"
"$1"
msgstr ""
"Ini daftar klien yang terhubung ke\n"
"$1"
#: builtin/mainmenu/dlg_config_world.lua
msgid "(Enabled, has error)"
@ -967,21 +967,20 @@ msgstr ""
"akan menimpa penggantian nama yang ada."
#: builtin/mainmenu/dlg_server_list_mods.lua
#, fuzzy
msgid "Expand all"
msgstr "Nyalakan semua"
msgstr "Buka semua"
#: builtin/mainmenu/dlg_server_list_mods.lua
msgid "Group by prefix"
msgstr ""
msgstr "Kelompokkan berdasarkan awalan"
#: builtin/mainmenu/dlg_server_list_mods.lua
msgid "The $1 server uses a game called $2 and the following mods:"
msgstr ""
msgstr "Server $1 menggunakan permainan bernama $2 dan mod berikut:"
#: builtin/mainmenu/dlg_server_list_mods.lua
msgid "The $1 server uses the following mods:"
msgstr ""
msgstr "Server $1 menggunakan mod berikut:"
#: builtin/mainmenu/dlg_version_info.lua
msgid "A new $1 version is available"
@ -1193,20 +1192,20 @@ msgid "You need to install a game before you can create a world."
msgstr "Anda perlu pasang sebuah permainan sebelum bisa membuat dunia."
#: builtin/mainmenu/tab_online.lua
#, fuzzy
msgid "Add favorite"
msgstr "Hapus favorit"
msgstr "Tambahkan favorit"
#: builtin/mainmenu/tab_online.lua
msgid "Address"
msgstr "Alamat"
#: builtin/mainmenu/tab_online.lua
#, fuzzy
msgid ""
"Clients:\n"
"$1"
msgstr "Klien"
msgstr ""
"Klien:\n"
"$1"
#: builtin/mainmenu/tab_online.lua
msgid "Creative mode"
@ -1222,9 +1221,8 @@ msgid "Favorites"
msgstr "Favorit"
#: builtin/mainmenu/tab_online.lua
#, fuzzy
msgid "Game: $1"
msgstr "Permainan"
msgstr "Permainan: $1"
#: builtin/mainmenu/tab_online.lua
msgid "Incompatible Servers"
@ -1239,14 +1237,12 @@ msgid "Login"
msgstr "Masuk"
#: builtin/mainmenu/tab_online.lua
#, fuzzy
msgid "Number of mods: $1"
msgstr "Jumlah utas kemunculan"
msgstr "Jumlah mod: $1"
#: builtin/mainmenu/tab_online.lua
#, fuzzy
msgid "Open server website"
msgstr "Langkah server khusus"
msgstr "Buka situs web server"
#: builtin/mainmenu/tab_online.lua
msgid "Ping"
@ -1259,6 +1255,10 @@ msgid ""
"mod:<name>\n"
"player:<name>"
msgstr ""
"Filter yang memungkinkan\n"
"game:<nama>\n"
"mod:<nama>\n"
"player:<name>"
#: builtin/mainmenu/tab_online.lua
msgid "Public Servers"
@ -1354,9 +1354,8 @@ msgid "Access denied. Reason: %s"
msgstr "Akses ditolak. Alasan: %s"
#: src/client/game.cpp
#, fuzzy
msgid "All debug info hidden"
msgstr "Info awakutu ditampilkan"
msgstr "Semua info awakutu disembunyikan"
#: src/client/game.cpp
msgid "Automatic forward disabled"
@ -1380,7 +1379,7 @@ msgstr "Batasan blok ditampilkan untuk blok sekitar"
#: src/client/game.cpp
msgid "Bounding boxes shown"
msgstr ""
msgstr "Kotak ikatan ditampilkan"
#: src/client/game.cpp
msgid "Camera update disabled"
@ -1623,9 +1622,8 @@ msgid "Volume changed to %d%%"
msgstr "Volume diubah ke %d%%"
#: src/client/game.cpp
#, fuzzy
msgid "Wireframe not supported by video driver"
msgstr "Shader dinyalakan, tetapi GLSL tidak didukung oleh pengandar."
msgstr "Kerangka tidak didukung oleh pengandar video"
#: src/client/game.cpp
msgid "Wireframe shown"
@ -2058,9 +2056,8 @@ msgid "Failed to compile the \"%s\" shader."
msgstr "Gagal mengompilasi shader \"%s\"."
#: src/client/shader.cpp
#, fuzzy
msgid "GLSL is not supported by the driver"
msgstr "Shader dinyalakan, tetapi GLSL tidak didukung oleh pengandar."
msgstr "GLSL tidak didukung oleh pengandar"
#. ~ Error when a mod is missing dependencies. Ex: "Mod Title is missing: mod1, mod2, mod3"
#: src/content/mod_configuration.cpp
@ -2297,35 +2294,33 @@ msgid "Sound Volume: %d%%"
msgstr "Volume Suara: %d%%"
#: src/gui/touchscreeneditor.cpp
#, fuzzy
msgid "Add button"
msgstr "Klik Tengah"
msgstr "Tambahkan tombol"
#: src/gui/touchscreeneditor.cpp
#, fuzzy
msgid "Done"
msgstr "Selesai!"
msgstr "Selesai"
#: src/gui/touchscreeneditor.cpp
#, fuzzy
msgid "Remove"
msgstr "Server jarak jauh"
msgstr "Hapus"
#: src/gui/touchscreeneditor.cpp
msgid "Reset"
msgstr ""
msgstr "Atur ulang"
#: src/gui/touchscreeneditor.cpp
msgid "Start dragging a button to add. Tap outside to cancel."
msgstr ""
"Mulai menarik tombol untuk menambahkan. Ketuk di luar untuk membatalkan."
#: src/gui/touchscreeneditor.cpp
msgid "Tap a button to select it. Drag a button to move it."
msgstr ""
msgstr "Ketuk tombol untuk memilih. Tarik tombol untuk memindahkan."
#: src/gui/touchscreeneditor.cpp
msgid "Tap outside to deselect."
msgstr ""
msgstr "Ketuk di luar untuk membatalkan pilihan."
#: src/gui/touchscreenlayout.cpp
msgid "Joystick"
@ -2553,7 +2548,6 @@ msgid "3D noise that determines number of dungeons per mapchunk."
msgstr "Noise 3D yang mengatur jumlah dungeon per potongan peta."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"3D support.\n"
"Currently supported:\n"
@ -2571,8 +2565,7 @@ msgstr ""
"- interlaced: garis ganjil/genap berdasarkan polarisasi layar.\n"
"- topbottom: pisahkan layar atas/bawah.\n"
"- sidebyside: pisahkan layar kiri/kanan.\n"
"- crossview: 3d dengan pandang silang\n"
"Catat bahwa mode interlaced memerlukan penggunaan shader."
"- crossview: 3d dengan pandang silang"
#: src/settings_translation_file.cpp
msgid ""
@ -2661,11 +2654,12 @@ msgid ""
"All mesh buffers with less than this number of vertices will be merged\n"
"during map rendering. This improves rendering performance."
msgstr ""
"Semua penyangga jaring kurang dari jumlah verteks ini akan digabungkan\n"
"saat perenderan peta. Ini meningkatkan performa perenderan."
#: src/settings_translation_file.cpp
#, fuzzy
msgid "Allow clouds to look 3D instead of flat."
msgstr "Gunakan tampilan awan 3D alih-alih datar."
msgstr "Perbolehkan awan terlihat 3D daripada datar."
#: src/settings_translation_file.cpp
msgid "Allows liquids to be translucent."
@ -3075,7 +3069,7 @@ msgstr "Awan dalam menu"
#: src/settings_translation_file.cpp
msgid "Color depth for post-processing texture"
msgstr ""
msgstr "Kedalaman warna untuk tekstur pasca-pemrosesan"
#: src/settings_translation_file.cpp
msgid "Colored fog"
@ -3095,7 +3089,6 @@ msgstr ""
"Berguna untuk pengujian. Lihat al_extensions.[h,cpp] untuk detailnya."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Comma-separated list of flags to hide in the content repository.\n"
"\"nonfree\" can be used to hide packages which do not qualify as 'free "
@ -3281,6 +3274,11 @@ msgid ""
"Reducing this can improve performance, but some effects (e.g. debanding)\n"
"require more than 8 bits to work."
msgstr ""
"Tentukan kedalaman warna tekstur yang digunakan untuk alur pasca-pemrosesan."
"\n"
"Mengurangi ini dapat meningkatkan performa, tetapi beberapa efek (mis. "
"debanding)\n"
"memerlukan lebih dari 8 bit supaya bekerja."
#: src/settings_translation_file.cpp
msgid "Dedicated server step"
@ -3500,6 +3498,11 @@ msgid ""
"situations\n"
"where transparency sorting would be very slow otherwise."
msgstr ""
"Gambar segitiga diurutkan berdasarkan transparansi berdasarkan penyangga "
"jaringnya.\n"
"Ini merusak pengurutan transparansi antara penyangga jaring, tetapi "
"menghindari situasi\n"
"di mana pengurutan transparansi akan menjadi lebih lambat."
#: src/settings_translation_file.cpp
msgid "Dump the mapgen debug information."
@ -3584,14 +3587,12 @@ msgstr ""
"menyimulasikan perilaku mata manusia."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Enable colored shadows for transculent nodes.\n"
"This is expensive."
msgstr ""
"Menyalakan bayangan berwarna.\n"
"Nilai true berarti nodus agak tembus pandang memiliki bayangan berwarna. Ini "
"memerlukan sumber daya besar."
"Aktif kan bayangan berwarna untuk nodus translusen.\n"
"Ini komputasi mahal."
#: src/settings_translation_file.cpp
msgid "Enable console window"
@ -3670,14 +3671,12 @@ msgstr ""
"Contoh: 0 untuk tanpa view bobbing; 1.0 untuk normal; 2.0 untuk 2x lipat."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Enable/disable running an IPv6 server.\n"
"Ignored if bind_address is set."
msgstr ""
"Nyalakan/matikan server IPv6.\n"
"Diabaikan jika bind_address telah diatur.\n"
"Perlu menyalakan enable_ipv6."
"Aktif kan/nonaktifkan menjalankan server IPv6.\n"
"Diabaikan jika bind_address telah diatur."
#: src/settings_translation_file.cpp
msgid ""
@ -4323,14 +4322,14 @@ msgstr ""
"menggantinya dengan kata sandi kosong."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"If enabled, server account registration is separate from login in the UI.\n"
"If disabled, connecting to a server will automatically register a new "
"account."
msgstr ""
"Jika dinyalakan, tampilan pendaftaran akun dan masuk akan dipisah.\n"
"Jika dimatikan, akun baru akan didaftarkan secara otomatis saat masuk."
"Jika diaktifkan, pendaftaran akun server terpisah dari log masuk dalam UI.\n"
"Jika dinonaktifkan, menghubungkan ke server akan mendaftarkan akun secara "
"otomatis."
#: src/settings_translation_file.cpp
msgid ""
@ -5204,7 +5203,7 @@ msgstr "Batas minimal nilai acak untuk gua kecil per potongan peta."
#: src/settings_translation_file.cpp
msgid "Minimum vertex count for mesh buffers"
msgstr ""
msgstr "Jumlah verteks minimum untuk penyangga jaring"
#: src/settings_translation_file.cpp
msgid "Mipmapping"
@ -5299,16 +5298,15 @@ msgstr ""
"- \"floatlands\" pada pembuat peta v7 (dimatikan secara bawaan)."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Name of the player.\n"
"When running a server, a client connecting with this name is admin.\n"
"When starting from the main menu, this is overridden."
msgstr ""
"Nama si pemain.\n"
"Saat menjalankan server, klien yang tersambung dengan nama ini adalah "
"pengurus.\n"
"Saat menjalankan dari menu utama, nilai ini ditimpa."
"Nama pemain.\n"
"Saat menjalankan server, klien yang tersambung dengan nama ini adalah admin."
"\n"
"Saat memulai dari menu utama, ini ditimpa."
#: src/settings_translation_file.cpp
msgid ""
@ -5814,7 +5812,6 @@ msgid "See https://www.sqlite.org/pragma.html#pragma_synchronous"
msgstr "Lihat https://www.sqlite.org/pragma.html#pragma_synchronous"
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Select the antialiasing method to apply.\n"
"\n"
@ -5837,26 +5834,46 @@ msgid ""
"Renders higher-resolution image of the scene, then scales down to reduce\n"
"the aliasing effects. This is the slowest and the most accurate method."
msgstr ""
"Pilih metode antialiasing yang akan diterapkan.\n"
"Pilih metode antialiasing untuk diterapkan.\n"
"\n"
"* Tidak ada - Tidak ada antialiasing (bawaan)\n"
"\n"
"* FSAA - Antialiasing layar penuh yang disediakan perangkat keras\n"
"(tidak kompatibel dengan Post Processing dan Undersampling)\n"
"Antialiasing multi-sampel (MSAA)\n"
"Menghaluskan tepi blok, tetapi tidak memengaruhi bagian dalam tekstur.\n"
"Diperlukan pengaktifan ulang untuk mengubah opsi ini.\n"
"\n"
"* FXAA - Antialiasing perkiraan cepat (memerlukan shader)\n"
"Menerapkan filter pasca-pemrosesan untuk mendeteksi dan memperhalus tepi "
"yang sangat kontras.\n"
"* Tidak ada - tidak ada antialiasing (default)\n"
"\n"
"\n"
"\n"
"* FSAA-Antialiasing layar penuh yang disediakan perangkat keras\n"
"\n"
"A.k.a antialiasing multi-sampel (MSAA)\n"
"\n"
"Menghancur tepi blok tetapi tidak mempengaruhi bagian dalam tekstur.\n"
"\n"
"\n"
"\n"
"Jika pemrosesan pos dinonaktifkan, mengubah FSAA memerlukan restart.\n"
"\n"
"Juga, jika pemrosesan pos dinonaktifkan, FSAA tidak akan bekerja sama "
"dengannya\n"
"\n"
"pengaturan undersampling atau non-default \"3D_MODE\".\n"
"\n"
"\n"
"\n"
"* Fxaa - perkiraan cepat antialiasing\n"
"\n"
"Menerapkan filter pasca pemrosesan untuk mendeteksi dan menghaluskan tepi "
"kontras tinggi.\n"
"\n"
"Memberikan keseimbangan antara kecepatan dan kualitas gambar.\n"
"\n"
"* SSAA - Antialiasing super-sampling (memerlukan shader)\n"
"Merender gambar pemandangan dengan resolusi lebih tinggi, kemudian "
"memperkecil skala untuk mengurangi\n"
"mengurangi efek aliasing. Ini adalah metode yang paling lambat dan paling "
"akurat."
"\n"
"\n"
"* SSAA - Antialiasing Super -Sampling\n"
"\n"
"Membuat gambar resolusi yang lebih tinggi dari pemandangan itu, lalu "
"berskala ke bawah untuk mengurangi\n"
"\n"
"Efek aliasing. Ini adalah metode paling lambat dan paling akurat."
#: src/settings_translation_file.cpp
msgid "Selection box border color (R,G,B)."
@ -6283,16 +6300,15 @@ msgstr ""
"semua) barang."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Spread a complete update of the shadow map over a given number of frames.\n"
"Higher values might make shadows laggy, lower values\n"
"will consume more resources."
msgstr ""
"Menyebarkan pembaruan peta bayangan dalam jumlah bingkai yang diberikan.\n"
"Nilai tinggi bisa membuat bayangan patah-patah, nilai rendah akan perlu\n"
"sumber daya lebih banyak.\n"
"Nilai minimum: 1; nilai maksimum: 16"
"Sebarkan pembaruan lengkap peta bayangan pada sejumlah bingkai tertentu.\n"
"Nilai yang lebih tinggi mungkin membuat bayangan lambat, nilai yang lebih "
"rendah\n"
"akan mengkonsumsi lebih banyak sumber daya."
#: src/settings_translation_file.cpp
msgid ""
@ -6721,9 +6737,8 @@ msgid "Transparency Sorting Distance"
msgstr "Jarak Pengurutan Transparansi"
#: src/settings_translation_file.cpp
#, fuzzy
msgid "Transparency Sorting Group by Buffers"
msgstr "Jarak Pengurutan Transparansi"
msgstr "Jarak Pengurutan Transparansi berdasarkan Penyangga"
#: src/settings_translation_file.cpp
msgid "Trees noise"
@ -6783,7 +6798,6 @@ msgid "Undersampling"
msgstr "Undersampling(Pengambilan sampel yang terlalu rendah)"
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Undersampling is similar to using a lower screen resolution, but it applies\n"
"to the game world only, keeping the GUI intact.\n"
@ -6794,10 +6808,13 @@ msgid ""
"set\n"
"to a non-default value."
msgstr ""
"Undersampling seperti menggunakan resolusi layar yang lebih rendah, tetapi\n"
"hanya berlaku untuk dunia permainan saja, antarmuka grafis tetap.\n"
"Seharusnya memberikan dorongan kinerja dengan gambar yang kurang detail.\n"
"Nilai yang lebih tinggi menghasilkan gambar yang kurang detail."
"Undersampling hampir mirip seperti menggunakan resolusi layer yang lebih "
"rendah, tetapi hanya diterapkan ke dunia permainan saja sambil menjaga GUI.\n"
"Ini seharusnya memberikan peningkatan performa dengan mengurangi detail "
"gambar.\n"
"Nilai yang lebih tinggi membuat detail gambar lebih sedikit.\n"
"Catatan: Undersampling saat ini tidak didukung jika pengaturan \"3d_mode\" "
"ditetapkan ke nilai non-bawaan."
#: src/settings_translation_file.cpp
msgid "Unlimited player transfer distance"
@ -6824,12 +6841,13 @@ msgid "Use a cloud animation for the main menu background."
msgstr "Gunakan animasi awan untuk latar belakang menu utama."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Use anisotropic filtering when looking at textures from an angle.\n"
"This provides a significant improvement when used together with mipmapping."
msgstr ""
"Gunakan pemfilteran anisotropik saat melihat tekstur pada sudut tertentu."
"Gunakan pemfilteran anisotropik saat melihat tekstur pada sudut tertentu.\n"
"Ini menyediakan peningkatan yang lebih baik ketika digunakan bersama dengan "
"mipmapping."
#: src/settings_translation_file.cpp
msgid "Use bilinear filtering when scaling textures."
@ -7102,7 +7120,6 @@ msgstr ""
"perangkat keras (misal gambar ke tekstur untuk nodus dalam inventaris)."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"When using bilinear/trilinear filtering, low-resolution textures\n"
"can be blurred, so this option automatically upscales them to preserve\n"
@ -7113,15 +7130,18 @@ msgid ""
"This is also used as the base node texture size for world-aligned\n"
"texture autoscaling."
msgstr ""
"Saat menggunakan filter bilinear/trilinear/anisotropik, tekstur resolusi\n"
"rendah dapat dikaburkan sehingga diperbesar otomatis dengan interpolasi\n"
"nearest-neighbor untuk menjaga ketajaman piksel. Ini mengatur ukuran\n"
"tekstur minimum untuk tekstur yang diperbesar; semakin tinggi semakin\n"
"tajam, tetapi butuh memori lebih. Perpangkatan dua disarankan. Pengaturan\n"
"ini HANYA diterapkan jika menggunakan filter bilinear/trilinear/"
"anisotropik.\n"
"Ini juga digunakan sebagai ukuran dasar tekstur nodus untuk penyekalaan\n"
"otomatis tekstur yang sejajar dengan dunia."
"Saat menggunakan pemfilteran bilinear/trilinear, tekstur resolusi rendah\n"
"bisa dikaburkan, jadi opsi ini secara otomatis meningkatkannya untuk "
"menjaga\n"
"piksel tajam. Ini mendefinisikan ukuran tekstur minimum untuk tekstur yang "
"ditingkatkan;\n"
"Nilai yang lebih tinggi terlihat lebih tajam, tetapi membutuhkan lebih "
"banyak memori.\n"
"Pengaturan ini hanya diterapkan jika salah satu filter yang disebutkan "
"diaktifkan.\n"
"Ini juga digunakan sebagai ukuran tekstur simpul dasar untuk dunia yang "
"selaras\n"
"Tekstur Autoscaling."
#: src/settings_translation_file.cpp
msgid ""
@ -7156,16 +7176,15 @@ msgid "Whether to fog out the end of the visible area."
msgstr "Apakah harus memberi kabut pada akhir daerah yang terlihat."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Whether to mute sounds. You can unmute sounds at any time.\n"
"In-game, you can toggle the mute state with the mute key or by using the\n"
"pause menu."
msgstr ""
"Apakah akan membisukan suara atau tidak. Anda dapat membunyikan\n"
"suara kapan pun, kecuali sistem suara dimatikan (enable_sound = false).\n"
"Dalam permainan, Anda dapat beralih mode bisu dengan tombol bisu\n"
"atau melalui menu jeda."
"Apakah suara dibisukan atau tidak. Kamu bisa membunyikan suara kapan pun.\n"
"Dalam permainan, kamu bisa sakelar keadaan bisu dengan tombol bisikan atau "
"menggunakan\n"
"menu jeda."
#: src/settings_translation_file.cpp
msgid ""

View file

@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: Russian (Minetest)\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-02-09 13:23+0100\n"
"PO-Revision-Date: 2025-01-27 06:02+0000\n"
"PO-Revision-Date: 2025-02-12 12:18+0000\n"
"Last-Translator: BlackImpostor <SkyBuilderOFFICAL@yandex.ru>\n"
"Language-Team: Russian <https://hosted.weblate.org/projects/minetest/"
"minetest/ru/>\n"
@ -264,14 +264,12 @@ msgid "Show technical names"
msgstr "Показывать технические названия"
#: builtin/common/settings/dlg_settings.lua
#, fuzzy
msgid "Touchscreen layout"
msgstr "Сенсорный экран"
msgstr "Pазложение сенсорного экрана"
#: builtin/common/settings/dlg_settings.lua
#, fuzzy
msgid "pause_menu"
msgstr "Кадровая частота во время паузы"
msgstr "меню_паузы"
#: builtin/common/settings/settingtypes.lua
msgid "Client Mods"
@ -609,6 +607,8 @@ msgid ""
"This is the list of clients connected to\n"
"$1"
msgstr ""
"Это список подключённых клиентов к\n"
"$1"
#: builtin/mainmenu/dlg_config_world.lua
msgid "(Enabled, has error)"
@ -972,21 +972,21 @@ msgstr ""
"перезапишет указанное здесь значение."
#: builtin/mainmenu/dlg_server_list_mods.lua
#, fuzzy
msgid "Expand all"
msgstr "Включить всё"
msgstr "Расширить всё"
#: builtin/mainmenu/dlg_server_list_mods.lua
msgid "Group by prefix"
msgstr ""
msgstr "Сгруппировать по префиксу"
#: builtin/mainmenu/dlg_server_list_mods.lua
msgid "The $1 server uses a game called $2 and the following mods:"
msgstr ""
"На сервере $1 используется игра под названием $2 со следующими дополнениями:"
#: builtin/mainmenu/dlg_server_list_mods.lua
msgid "The $1 server uses the following mods:"
msgstr ""
msgstr "Сервер $1 использует следующие дополнения:"
#: builtin/mainmenu/dlg_version_info.lua
msgid "A new $1 version is available"
@ -1198,20 +1198,20 @@ msgid "You need to install a game before you can create a world."
msgstr "Вам требуется установить игру, прежде чем вы сможете создать мир."
#: builtin/mainmenu/tab_online.lua
#, fuzzy
msgid "Add favorite"
msgstr "Удалить избранное"
msgstr "Добавить избранное"
#: builtin/mainmenu/tab_online.lua
msgid "Address"
msgstr "Адрес"
#: builtin/mainmenu/tab_online.lua
#, fuzzy
msgid ""
"Clients:\n"
"$1"
msgstr "Клиент"
msgstr ""
"Клиенты:\n"
"$1"
#: builtin/mainmenu/tab_online.lua
msgid "Creative mode"
@ -1227,9 +1227,8 @@ msgid "Favorites"
msgstr "Избранное"
#: builtin/mainmenu/tab_online.lua
#, fuzzy
msgid "Game: $1"
msgstr "Игра"
msgstr "Игра: $1"
#: builtin/mainmenu/tab_online.lua
msgid "Incompatible Servers"
@ -1244,14 +1243,12 @@ msgid "Login"
msgstr "Войти"
#: builtin/mainmenu/tab_online.lua
#, fuzzy
msgid "Number of mods: $1"
msgstr "Количество потоков подгрузки"
msgstr "Количество модов: $1"
#: builtin/mainmenu/tab_online.lua
#, fuzzy
msgid "Open server website"
msgstr "Шаг выделенного сервера"
msgstr "Открыть веб-сайт сервера"
#: builtin/mainmenu/tab_online.lua
msgid "Ping"
@ -1264,6 +1261,10 @@ msgid ""
"mod:<name>\n"
"player:<name>"
msgstr ""
"Возможные фильтры\n"
"игра:<имя>\n"
"дополнение:<имя>\n"
"игрок:<имя>"
#: builtin/mainmenu/tab_online.lua
msgid "Public Servers"
@ -1359,9 +1360,8 @@ msgid "Access denied. Reason: %s"
msgstr "Доступ запрещён. Причина: %s"
#: src/client/game.cpp
#, fuzzy
msgid "All debug info hidden"
msgstr "Отладочные сведения отображены"
msgstr "Все отладочные сведения скрыты"
#: src/client/game.cpp
msgid "Automatic forward disabled"
@ -1385,7 +1385,7 @@ msgstr "Границы показаны для ближайших мапблок
#: src/client/game.cpp
msgid "Bounding boxes shown"
msgstr ""
msgstr "Показаны ограничивающие рамки"
#: src/client/game.cpp
msgid "Camera update disabled"
@ -1623,9 +1623,8 @@ msgid "Volume changed to %d%%"
msgstr "Громкость установлена на %d%%"
#: src/client/game.cpp
#, fuzzy
msgid "Wireframe not supported by video driver"
msgstr "Шейдеры включены, но GLSL не поддерживается драйвером."
msgstr "Полигоны не доступны этим видео драйвером"
#: src/client/game.cpp
msgid "Wireframe shown"
@ -2058,9 +2057,8 @@ msgid "Failed to compile the \"%s\" shader."
msgstr "Не удалось скомпилировать шейдер «%s»."
#: src/client/shader.cpp
#, fuzzy
msgid "GLSL is not supported by the driver"
msgstr "Шейдеры включены, но GLSL не поддерживается драйвером."
msgstr "GLSL не поддерживается драйвером"
#. ~ Error when a mod is missing dependencies. Ex: "Mod Title is missing: mod1, mod2, mod3"
#: src/content/mod_configuration.cpp
@ -2296,35 +2294,35 @@ msgid "Sound Volume: %d%%"
msgstr "Громкость звука: %d%%"
#: src/gui/touchscreeneditor.cpp
#, fuzzy
msgid "Add button"
msgstr "Средняя кнопка"
msgstr "Добавить кнопку"
#: src/gui/touchscreeneditor.cpp
#, fuzzy
msgid "Done"
msgstr "Готово!"
msgstr "Готово"
#: src/gui/touchscreeneditor.cpp
#, fuzzy
msgid "Remove"
msgstr "Удалённый сервер"
msgstr "Убрать"
#: src/gui/touchscreeneditor.cpp
msgid "Reset"
msgstr ""
msgstr "Сбросить"
#: src/gui/touchscreeneditor.cpp
msgid "Start dragging a button to add. Tap outside to cancel."
msgstr ""
"Начните перетаскивать кнопку, чтобы добавить. Нажмите \"За пределами\", "
"чтобы отменить."
#: src/gui/touchscreeneditor.cpp
msgid "Tap a button to select it. Drag a button to move it."
msgstr ""
"Нажмите на кнопку, чтобы выбрать её. Перетащите кнопку, чтобы перемещать её."
#: src/gui/touchscreeneditor.cpp
msgid "Tap outside to deselect."
msgstr ""
msgstr "Нажмите \"Снаружи\", чтобы отменить выбор."
#: src/gui/touchscreenlayout.cpp
msgid "Joystick"
@ -2555,7 +2553,6 @@ msgid "3D noise that determines number of dungeons per mapchunk."
msgstr "3D-шум, определяющий количество подземелий на мапчанк карты."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"3D support.\n"
"Currently supported:\n"
@ -2566,15 +2563,14 @@ msgid ""
"- sidebyside: split screen side by side.\n"
"- crossview: Cross-eyed 3d"
msgstr ""
"3D-анаглиф.\n"
"Поддержка 3D.\n"
"Сейчас поддерживаются:\n"
"- none: без 3D.\n"
"- none: без 3d выхода.\n"
"- anaglyph: для красно/синих очков.\n"
"- interlaced: поляризация с чётными/нечётными линиями.\n"
"- topbottom: горизонтальное разделение экрана.\n"
"- sidebyside: вертикальное разделение экрана.\n"
"- crossview: перекрёстная стереопара.\n"
"Примечание: для режима «interlaced» должны быть включены шейдеры."
"- crossview: перекрёстная стереопара 3d"
#: src/settings_translation_file.cpp
msgid ""
@ -2663,11 +2659,12 @@ msgid ""
"All mesh buffers with less than this number of vertices will be merged\n"
"during map rendering. This improves rendering performance."
msgstr ""
"Все буферы мешей с меньшим количеством вершин будут объединены\n"
"во время рендера карты. Это повышает производительность рендеринга."
#: src/settings_translation_file.cpp
#, fuzzy
msgid "Allow clouds to look 3D instead of flat."
msgstr "Объёмные облака вместо плоских."
msgstr "Позволяет облакам выглядеть больше 3D, чем плоскими."
#: src/settings_translation_file.cpp
msgid "Allows liquids to be translucent."
@ -3080,7 +3077,7 @@ msgstr "Облака в меню"
#: src/settings_translation_file.cpp
msgid "Color depth for post-processing texture"
msgstr ""
msgstr "Глубина цвета для постобработки текстуры"
#: src/settings_translation_file.cpp
msgid "Colored fog"
@ -3101,7 +3098,6 @@ msgstr ""
"[h,cpp]."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Comma-separated list of flags to hide in the content repository.\n"
"\"nonfree\" can be used to hide packages which do not qualify as 'free "
@ -3112,12 +3108,12 @@ msgid ""
"so see a full list at https://content.luanti.org/help/content_flags/"
msgstr ""
"Список разделенных запятыми флажков для скрытия в хранилище контента.\n"
"\"nonfree\" может использоваться для скрытия пакетов,\n"
"которые не подпадают под категорию Free Software Foundation,\n"
"как это определено Фондом свободного программного обеспечения.\n"
"Вы также можете указать рейтинг контента. Эти флаги не зависят от версий "
"Luanti,\n"
"поэтому смотрите полный список по адресу https://content.minetest.net/help/"
"«несвободный» может использоваться для скрытия пакетов, которые не подпадают "
"под категорию «свободного программного обеспечения»,\n"
"как это определено Фондом Свободного Программного Обеспечения.\n"
"Вы также можете указать рейтинг контента.\n"
"Эти флаги не зависят от версий Luanti,\n"
"поэтому смотрите полный список по адресу https://content.luanti.org/help/"
"content_flags/"
#: src/settings_translation_file.cpp
@ -3287,6 +3283,11 @@ msgid ""
"Reducing this can improve performance, but some effects (e.g. debanding)\n"
"require more than 8 bits to work."
msgstr ""
"Определить глубину цвета текстуры, используемой для конвейера постобработки."
"\n"
"Уменьшение этого параметра может повысить производительность, но для работы "
"некоторых эффектов (например, для удаления пятен)\n"
"требуется более 8 бит."
#: src/settings_translation_file.cpp
msgid "Dedicated server step"
@ -3507,6 +3508,11 @@ msgid ""
"situations\n"
"where transparency sorting would be very slow otherwise."
msgstr ""
"Рисовать треугольники, отсортированные по прозрачности, сгруппированные по "
"их меш буферам.\n"
"Это нарушает сортировку по прозрачности между меш буферами, но позволяет "
"избежать ситуаций,\n"
"когда в противном случае сортировка по прозрачности была бы очень медленной."
#: src/settings_translation_file.cpp
msgid "Dump the mapgen debug information."
@ -3591,14 +3597,12 @@ msgstr ""
"имитируя поведение человеческого глаза."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Enable colored shadows for transculent nodes.\n"
"This is expensive."
msgstr ""
"Включить цветные тени.\n"
"Когда включено, прозрачные ноды отбрасывают цветные тени. Это "
"ресурсозатратно."
"Включите цветные тени для трансгенных блоков.\n"
"Это дорого."
#: src/settings_translation_file.cpp
msgid "Enable console window"
@ -3681,14 +3685,12 @@ msgstr ""
"Например: 0 отключает покачивание, 1.0 для обычного, 2.0 для двойного."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Enable/disable running an IPv6 server.\n"
"Ignored if bind_address is set."
msgstr ""
"Включить/отключить запуск IPv6-сервера.\n"
"Игнорируется, если задан «bind_address».\n"
"Для включения необходим «enable_ipv6»."
"Включить/отключить запуск сервера IPv6.\n"
"Игнорируется, если задан параметр bind_address."
#: src/settings_translation_file.cpp
msgid ""
@ -4333,16 +4335,15 @@ msgstr ""
"Если включено, то новые игроки не смогут подключаться с пустым паролем."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"If enabled, server account registration is separate from login in the UI.\n"
"If disabled, connecting to a server will automatically register a new "
"account."
msgstr ""
"Если включено, регистрация аккаунта выполняется в интерфейсе отдельно от "
"входа.\n"
"Если отключено, новые учётные записи будут регистрироваться автоматически "
"при входе."
"Если этот параметр включен, регистрация учетной записи сервера выполняется "
"отдельно от входа в пользовательский интерфейс.\n"
"Если он отключен, при подключении к серверу автоматически регистрируется "
"новая учетная запись."
#: src/settings_translation_file.cpp
msgid ""
@ -5212,7 +5213,7 @@ msgstr "Минимум малых пещер на мапчанк."
#: src/settings_translation_file.cpp
msgid "Minimum vertex count for mesh buffers"
msgstr ""
msgstr "Минимальное количество вершин для меш буферов"
#: src/settings_translation_file.cpp
msgid "Mipmapping"
@ -5307,15 +5308,15 @@ msgstr ""
"- Дополнительные парящие острова из v7 (выключено по умолчанию)."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Name of the player.\n"
"When running a server, a client connecting with this name is admin.\n"
"When starting from the main menu, this is overridden."
msgstr ""
"Имя игрока.\n"
"При запуске сервера клиенты с этим именем будут администраторами.\n"
"Будет переопределено при запуске из главного меню."
"При запуске сервера клиент, подключающийся под этим именем, является "
"администратором.\n"
"При запуске из главного меню это значение переопределяется."
#: src/settings_translation_file.cpp
msgid ""
@ -5824,7 +5825,6 @@ msgid "See https://www.sqlite.org/pragma.html#pragma_synchronous"
msgstr "См. http://www.sqlite.org/pragma.html#pragma_synchronous"
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Select the antialiasing method to apply.\n"
"\n"
@ -5849,25 +5849,27 @@ msgid ""
msgstr ""
"Выберите метод сглаживания, который необходимо применить.\n"
"\n"
"* * Нет - сглаживание отсутствует (по умолчанию).\n"
"* None - Нет сглаживания (по умолчанию)\n"
"\n"
"* FSAA - Аппаратное полноэкранное сглаживание\n"
"(несовместимое с постобработкой и недостаточной дискретизацией)\n"
", аналогичное сглаживанию с несколькими выборками (MSAA)\n"
"* FSAA - Аппаратное полноэкранное сглаживание,\n"
"аналогичное сглаживанию с несколькими выборками (MSAA).\n"
"Сглаживает края блоков, но не влияет на внутреннюю часть текстур.\n"
"Для изменения этого параметра требуется перезагрузка.\n"
"\n"
"* FXAA - Быстрое приблизительное сглаживание (требуется использование "
"шейдеров)\n"
"Применяется фильтр последующей обработки для обнаружения и сглаживания "
"Если постобработка отключена, для изменения FSAA требуется перезапуск.\n"
"Кроме того, если постобработка отключена, FSAA не будет работать в сочетании "
"с\n"
"недостаточной дискретизацией или настройкой \"3d_mode\", не используемой по "
"умолчанию.\n"
"\n"
"* FXAA - Быстрое приблизительное сглаживание\n"
"Применяет фильтр последующей обработки для обнаружения и сглаживания "
"высококонтрастных краев.\n"
"Обеспечивает баланс между скоростью и качеством изображения.\n"
"\n"
"* SSAA - сглаживание с использованием суперсэмплирования (требуются "
"шейдеры)\n"
"Визуализирует изображение сцены с более высоким разрешением, затем уменьшает "
"масштаб, чтобы уменьшить\n"
"эффекты наложения. Это самый медленный и точный метод."
"* SSAA - Сглаживание с использованием суперсэмплирования\n"
"Позволяет получить изображение сцены с более высоким разрешением, а затем "
"уменьшить масштаб, чтобы уменьшить\n"
"эффекты сглаживания. Это самый медленный и точный метод."
#: src/settings_translation_file.cpp
msgid "Selection box border color (R,G,B)."
@ -6300,17 +6302,14 @@ msgstr ""
"(или всех) предметов."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Spread a complete update of the shadow map over a given number of frames.\n"
"Higher values might make shadows laggy, lower values\n"
"will consume more resources."
msgstr ""
"Распространяет полное обновление карты теней на заданное количество кадров.\n"
"Более высокие значения могут сделать тени нестабильными, более низкие "
"значения\n"
"будут потреблять больше ресурсов.\n"
"Минимум: 1; максимум: 16"
"Распространить полное обновление карты теней на заданное количество кадров.\n"
"Более высокие значения могут привести к запаздыванию теней,\n"
"более низкие значения потребляют больше ресурсов."
#: src/settings_translation_file.cpp
msgid ""
@ -6753,9 +6752,8 @@ msgid "Transparency Sorting Distance"
msgstr "Дальность сортировки по прозрачности"
#: src/settings_translation_file.cpp
#, fuzzy
msgid "Transparency Sorting Group by Buffers"
msgstr "Дальность сортировки по прозрачности"
msgstr "Прозрачность Сортировки Групп по Буферам"
#: src/settings_translation_file.cpp
msgid "Trees noise"
@ -6816,7 +6814,6 @@ msgid "Undersampling"
msgstr "Субдискретизация"
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Undersampling is similar to using a lower screen resolution, but it applies\n"
"to the game world only, keeping the GUI intact.\n"
@ -6827,12 +6824,15 @@ msgid ""
"set\n"
"to a non-default value."
msgstr ""
"Субдискретизация аналогична использованию низкого разрешения экрана,\n"
"но она применяется только к игровому миру, графический интерфейс не "
"затрагивается.\n"
"Значительно увеличивает производительность за счёт вывода менее подробного "
"изображения.\n"
"Высокие значения приводят к менее проработанному изображению."
"Недостаточная дискретизация аналогична использованию более низкого "
"разрешения экрана, но применяется\n"
"только к игровому миру, сохраняя графический интерфейс без изменений.\n"
"Это должно значительно повысить производительность за счет снижения "
"детализации изображения.\n"
"Более высокие значения приводят к снижению детализации изображения.\n"
"Примечание: В настоящее время недостаточная дискретизация не поддерживается, "
"если для параметра \"3d_mode\" установлено\n"
"значение, отличное от значения по умолчанию."
#: src/settings_translation_file.cpp
msgid "Unlimited player transfer distance"
@ -6859,12 +6859,13 @@ msgid "Use a cloud animation for the main menu background."
msgstr "Анимированные облака в главном меню."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Use anisotropic filtering when looking at textures from an angle.\n"
"This provides a significant improvement when used together with mipmapping."
msgstr ""
"Использовать анизотропную фильтрацию при взгляде на текстуры под углом."
"Использовать анизотропную фильтрацию при просмотре текстур под углом.\n"
"Это обеспечивает значительное улучшение при использовании в сочетании с "
"мип-картированием."
#: src/settings_translation_file.cpp
msgid "Use bilinear filtering when scaling textures."
@ -7138,7 +7139,6 @@ msgstr ""
"аппаратно (прим. render-to-texture для нод в инвентаре)."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"When using bilinear/trilinear filtering, low-resolution textures\n"
"can be blurred, so this option automatically upscales them to preserve\n"
@ -7149,17 +7149,17 @@ msgid ""
"This is also used as the base node texture size for world-aligned\n"
"texture autoscaling."
msgstr ""
"Когда используются билинейный/трилинейный/анизотропный фильтры, то текстуры "
"низкого разрешения\n"
"могут быть размытыми, поэтому они автоматически увеличиваются ближайшей\n"
"интерполяцией для сохранения четкости пикселей. Это устанавливает "
"минимальный размер текстуры\n"
"для увеличенных текстур; большие значения выглядят чётче, но требуют больше\n"
"памяти. Рекомендуются степени числа 2. Эта настройки применяется ТОЛЬКО "
"если\n"
"билинейный/трилинейный/анизотропный фильтр включен.\n"
"Это также используется для автомасштабирования как основной размер для\n"
"повёрнутых по сторонам света текстур блока."
"При использовании билинейной/трилинейной фильтрации текстуры с низким "
"разрешением\n"
"могут быть размыты, поэтому этот параметр автоматически увеличивает их "
"масштаб, чтобы сохранить\n"
"четкие пиксели. Это определяет минимальный размер текстуры для текстур в "
"увеличенном масштабе;\n"
"более высокие значения выглядят четче, но требуют больше памяти.\n"
"Этот параметр применяется ТОЛЬКО в том случае, если включен любой из "
"упомянутых фильтров.\n"
"Он также используется в качестве базового размера текстуры узла для\n"
"автоматического масштабирования текстуры, выровненной по окружности."
#: src/settings_translation_file.cpp
msgid ""
@ -7194,16 +7194,15 @@ msgid "Whether to fog out the end of the visible area."
msgstr "Затуманивает конец видимой области."
#: src/settings_translation_file.cpp
#, fuzzy
msgid ""
"Whether to mute sounds. You can unmute sounds at any time.\n"
"In-game, you can toggle the mute state with the mute key or by using the\n"
"pause menu."
msgstr ""
"Заглушает звуки. Вы можете включить звуки в любое время, если\n"
"звуковая система не отключена (enable_sound=false).\n"
"Внутри игры, вы можете включить переключать звуки, нажав на клавишу\n"
"заглушения звука или используя меню паузы."
"Следует ли отключать звук. Вы можете включить звук в любое время.\n"
"В игре вы можете переключать режим отключения звука с помощью клавиши "
"отключения звука\n"
"или с помощью меню паузы."
#: src/settings_translation_file.cpp
msgid ""

File diff suppressed because it is too large Load diff

View file

@ -34,7 +34,7 @@ static constexpr f32 CAMERA_OFFSET_STEP = 200;
#define WIELDMESH_AMPLITUDE_Y 10.0f
static const char *setting_names[] = {
"fall_bobbing_amount", "view_bobbing_amount", "fov", "arm_inertia",
"view_bobbing_amount", "fov", "arm_inertia",
"show_nametag_backgrounds",
};
@ -78,7 +78,6 @@ void Camera::readSettings()
* (as opposed to the this local caching). This can be addressed in
* a later release.
*/
m_cache_fall_bobbing_amount = g_settings->getFloat("fall_bobbing_amount", 0.0f, 100.0f);
m_cache_view_bobbing_amount = g_settings->getFloat("view_bobbing_amount", 0.0f, 7.9f);
// 45 degrees is the lowest FOV that doesn't cause the server to treat this
// as a zoom FOV and load world beyond the set server limits.
@ -130,13 +129,6 @@ inline f32 my_modf(f32 x)
void Camera::step(f32 dtime)
{
if(m_view_bobbing_fall > 0)
{
m_view_bobbing_fall -= 3 * dtime;
if(m_view_bobbing_fall <= 0)
m_view_bobbing_fall = -1; // Mark the effect as finished
}
bool was_under_zero = m_wield_change_timer < 0;
m_wield_change_timer = MYMIN(m_wield_change_timer + dtime, 0.125);
@ -351,30 +343,13 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 tool_reload_ratio)
// Get camera tilt timer (hurt animation)
float cameratilt = fabs(fabs(player->hurt_tilt_timer-0.75)-0.75);
// Fall bobbing animation
float fall_bobbing = 0;
if(player->camera_impact >= 1 && m_camera_mode < CAMERA_MODE_THIRD)
{
if(m_view_bobbing_fall == -1) // Effect took place and has finished
player->camera_impact = m_view_bobbing_fall = 0;
else if(m_view_bobbing_fall == 0) // Initialize effect
m_view_bobbing_fall = 1;
// Convert 0 -> 1 to 0 -> 1 -> 0
fall_bobbing = m_view_bobbing_fall < 0.5 ? m_view_bobbing_fall * 2 : -(m_view_bobbing_fall - 0.5) * 2 + 1;
// Smoothen and invert the above
fall_bobbing = sin(fall_bobbing * 0.5 * M_PI) * -1;
// Amplify according to the intensity of the impact
if (player->camera_impact > 0.0f)
fall_bobbing *= (1 - rangelim(50 / player->camera_impact, 0, 1)) * 5;
fall_bobbing *= m_cache_fall_bobbing_amount;
}
// Calculate and translate the head SceneNode offsets
{
v3f eye_offset = player->getEyeOffset();
switch(m_camera_mode) {
case CAMERA_MODE_ANY:
assert(false);
break;
case CAMERA_MODE_FIRST:
eye_offset += player->eye_offset_first;
break;
@ -389,7 +364,7 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 tool_reload_ratio)
}
// Set head node transformation
eye_offset.Y += cameratilt * -player->hurt_tilt_strength + fall_bobbing;
eye_offset.Y += cameratilt * -player->hurt_tilt_strength;
m_headnode->setPosition(eye_offset);
m_headnode->setRotation(v3f(pitch, 0,
cameratilt * player->hurt_tilt_strength));

View file

@ -57,8 +57,6 @@ struct Nametag
}
};
enum CameraMode {CAMERA_MODE_FIRST, CAMERA_MODE_THIRD, CAMERA_MODE_THIRD_FRONT};
/*
Client camera class, manages the player and camera scene nodes, the viewing distance
and performs view bobbing etc. It also displays the wielded tool in front of the
@ -169,7 +167,8 @@ public:
void drawWieldedTool(irr::core::matrix4* translation=NULL);
// Toggle the current camera mode
void toggleCameraMode() {
void toggleCameraMode()
{
if (m_camera_mode == CAMERA_MODE_FIRST)
m_camera_mode = CAMERA_MODE_THIRD;
else if (m_camera_mode == CAMERA_MODE_THIRD)
@ -185,7 +184,7 @@ public:
}
//read the current camera mode
inline CameraMode getCameraMode()
inline CameraMode getCameraMode() const
{
return m_camera_mode;
}
@ -257,8 +256,6 @@ private:
s32 m_view_bobbing_state = 0;
// Speed of view bobbing animation
f32 m_view_bobbing_speed = 0.0f;
// Fall view bobbing
f32 m_view_bobbing_fall = 0.0f;
// Digging animation frame (0 <= m_digging_anim < 1)
f32 m_digging_anim = 0.0f;
@ -273,7 +270,6 @@ private:
CameraMode m_camera_mode = CAMERA_MODE_FIRST;
f32 m_cache_fall_bobbing_amount;
f32 m_cache_view_bobbing_amount;
bool m_arm_inertia;

View file

@ -398,11 +398,7 @@ void Client::step(float dtime)
if (dtime > DTIME_LIMIT)
dtime = DTIME_LIMIT;
m_animation_time += dtime;
if(m_animation_time > 60.0)
m_animation_time -= 60.0;
m_time_of_day_update_timer += dtime;
m_animation_time = fmodf(m_animation_time + dtime, 60.0f);
ReceiveAll();
@ -450,20 +446,43 @@ void Client::step(float dtime)
/*
Run Map's timers and unload unused data
*/
const float map_timer_and_unload_dtime = 5.25;
constexpr float map_timer_and_unload_dtime = 5.25f;
constexpr s32 mapblock_limit_enforce_distance = 200;
if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime)) {
std::vector<v3s16> deleted_blocks;
// Determine actual block limit to use
const s32 configured_limit = g_settings->getS32("client_mapblock_limit");
s32 mapblock_limit;
if (configured_limit < 0) {
mapblock_limit = -1;
} else {
s32 view_range = g_settings->getS16("viewing_range");
// Up to a certain limit we want to guarantee that the client can keep
// a full 360° view loaded in memory without blocks vanishing behind
// the players back.
// We use a sphere volume to approximate this. In practice far less
// blocks will be needed due to occlusion/culling.
float blocks_range = ceilf(std::min(mapblock_limit_enforce_distance, view_range)
/ (float) MAP_BLOCKSIZE);
mapblock_limit = (4.f/3.f) * M_PI * powf(blocks_range, 3);
assert(mapblock_limit > 0);
mapblock_limit = std::max(mapblock_limit, configured_limit);
if (mapblock_limit > std::max(configured_limit, m_mapblock_limit_logged)) {
infostream << "Client: using block limit of " << mapblock_limit
<< " rather than configured " << configured_limit
<< " due to view range." << std::endl;
m_mapblock_limit_logged = mapblock_limit;
}
}
m_env.getMap().timerUpdate(map_timer_and_unload_dtime,
std::max(g_settings->getFloat("client_unload_unused_data_timeout"), 0.0f),
g_settings->getS32("client_mapblock_limit"),
&deleted_blocks);
mapblock_limit, &deleted_blocks);
/*
Send info to server
NOTE: This loop is intentionally iterated the way it is.
*/
// Send info to server
std::vector<v3s16>::iterator i = deleted_blocks.begin();
auto i = deleted_blocks.begin();
std::vector<v3s16> sendlist;
for(;;) {
if(sendlist.size() == 255 || i == deleted_blocks.end()) {
@ -644,9 +663,11 @@ void Client::step(float dtime)
if (num_processed_meshes > 0)
g_profiler->graphAdd("num_processed_meshes", num_processed_meshes);
auto shadow_renderer = RenderingEngine::get_shadow_renderer();
if (shadow_renderer && force_update_shadows)
shadow_renderer->setForceUpdateShadowMap();
if (force_update_shadows && !g_settings->getFlag("performance_tradeoffs")) {
auto shadow = RenderingEngine::get_shadow_renderer();
if (shadow)
shadow->setForceUpdateShadowMap();
};
}
/*
@ -873,14 +894,6 @@ void Client::deletingPeer(con::IPeer *peer, bool timeout)
m_access_denied_reason = gettext("Connection aborted (protocol error?).");
}
/*
u16 command
u16 number of files requested
for each file {
u16 length of name
string name
}
*/
void Client::request_media(const std::vector<std::string> &file_requests)
{
std::ostringstream os(std::ios_base::binary);
@ -1031,8 +1044,8 @@ void Client::Send(NetworkPacket* pkt)
// Will fill up 12 + 12 + 4 + 4 + 4 + 1 + 1 + 1 + 4 + 4 bytes
void writePlayerPos(LocalPlayer *myplayer, ClientMap *clientMap, NetworkPacket *pkt, bool camera_inverted)
{
v3f pf = myplayer->getPosition() * 100;
v3f sf = myplayer->getSpeed() * 100;
v3s32 position = v3s32::from(myplayer->getPosition() * 100);
v3s32 speed = v3s32::from(myplayer->getSpeed() * 100);
s32 pitch = myplayer->getPitch() * 100;
s32 yaw = myplayer->getYaw() * 100;
u32 keyPressed = myplayer->control.getKeysPressed();
@ -1043,9 +1056,6 @@ void writePlayerPos(LocalPlayer *myplayer, ClientMap *clientMap, NetworkPacket *
f32 movement_speed = myplayer->control.movement_speed;
f32 movement_dir = myplayer->control.movement_direction;
v3s32 position(pf.X, pf.Y, pf.Z);
v3s32 speed(sf.X, sf.Y, sf.Z);
/*
Format:
[0] v3s32 position*100
@ -1742,12 +1752,7 @@ void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server, bool
void Client::addUpdateMeshTaskForNode(v3s16 nodepos, bool ack_to_server, bool urgent)
{
{
v3s16 p = nodepos;
infostream<<"Client::addUpdateMeshTaskForNode(): "
<<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
<<std::endl;
}
infostream << "Client::addUpdateMeshTaskForNode(): " << nodepos << std::endl;
v3s16 blockpos = getNodeBlockPos(nodepos);
v3s16 blockpos_relative = blockpos * MAP_BLOCKSIZE;

View file

@ -217,6 +217,7 @@ public:
void handleCommand_MediaPush(NetworkPacket *pkt);
void handleCommand_MinimapModes(NetworkPacket *pkt);
void handleCommand_SetLighting(NetworkPacket *pkt);
void handleCommand_Camera(NetworkPacket* pkt);
void ProcessData(NetworkPacket *pkt);
@ -485,23 +486,18 @@ private:
u8 m_server_ser_ver;
// Used version of the protocol with server
// Values smaller than 25 only mean they are smaller than 25,
// and aren't accurate. We simply just don't know, because
// the server didn't send the version back then.
// If 0, server init hasn't been received yet.
u16 m_proto_ver = 0;
bool m_update_wielded_item = false;
Inventory *m_inventory_from_server = nullptr;
float m_inventory_from_server_age = 0.0f;
s32 m_mapblock_limit_logged = 0;
PacketCounter m_packetcounter;
// Block mesh animation parameters
float m_animation_time = 0.0f;
int m_crack_level = -1;
v3s16 m_crack_pos;
// 0 <= m_daynight_i < DAYNIGHT_CACHE_COUNT
//s32 m_daynight_i;
//u32 m_daynight_ratio;
std::queue<std::wstring> m_out_chat_queue;
u32 m_last_chat_message_sent;
float m_chat_message_allowance = 5.0f;
@ -537,11 +533,6 @@ private:
// Pending downloads of dynamic media (key: token)
std::vector<std::pair<u32, std::shared_ptr<SingleMediaDownloader>>> m_pending_media_downloads;
// time_of_day speed approximation for old protocol
bool m_time_of_day_set = false;
float m_last_time_of_day_f = -1.0f;
float m_time_of_day_update_timer = 0.0f;
// An interval for generally sending object positions and stuff
float m_recommended_send_interval = 0.1f;

View file

@ -441,8 +441,8 @@ void ClientEnvironment::getSelectedActiveObjects(
GenericCAO* gcao = dynamic_cast<GenericCAO*>(obj);
if (gcao != nullptr && gcao->getProperties().rotate_selectionbox) {
gcao->getSceneNode()->updateAbsolutePosition();
const v3f deg = obj->getSceneNode()->getAbsoluteTransformation().getRotationDegrees();
collision = boxLineCollision(selection_box, deg,
const v3f rad = obj->getSceneNode()->getAbsoluteTransformation().getRotationRadians();
collision = boxLineCollision(selection_box, rad,
rel_pos, line_vector, &current_intersection, &current_normal, &current_raw_normal);
} else {
collision = boxLineCollision(selection_box, rel_pos, line_vector,

View file

@ -36,6 +36,7 @@ enum ClientEventType : u8
CE_SET_STARS,
CE_OVERRIDE_DAY_NIGHT_RATIO,
CE_CLOUD_PARAMS,
CE_UPDATE_CAMERA,
CLIENTEVENT_MAX,
};
@ -66,11 +67,14 @@ struct ClientEventHudChange
struct ClientEvent
{
// TODO: should get rid of this ctor
ClientEvent() : type(CE_NONE) {}
ClientEvent(ClientEventType type) : type(type) {}
ClientEventType type;
union
{
// struct{
//} none;
struct
{
u16 amount;
@ -86,8 +90,6 @@ struct ClientEvent
std::string *formspec;
std::string *formname;
} show_formspec;
// struct{
//} textures_updated;
ParticleParameters *spawn_particle;
struct
{

View file

@ -52,6 +52,13 @@ Clouds::Clouds(scene::ISceneManager* mgr, IShaderSource *ssrc,
updateBox();
// Neither EAC_BOX (the default) nor EAC_FRUSTUM_BOX will correctly cull
// the clouds.
// And yes, the bounding box is correct. You can check using the #if 0'd
// code in render() and see for yourself.
// So I give up and let's disable culling.
setAutomaticCulling(scene::EAC_OFF);
m_meshbuffer.reset(new scene::SMeshBuffer());
m_meshbuffer->setHardwareMappingHint(scene::EHM_DYNAMIC);
}
@ -366,6 +373,19 @@ void Clouds::render()
if (SceneManager->getSceneNodeRenderPass() != scene::ESNRP_TRANSPARENT)
return;
#if 0
{
video::SMaterial tmp;
tmp.Thickness = 1.f;
driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
driver->setMaterial(tmp);
aabb3f tmpbox = m_box;
tmpbox.MinEdge.X = tmpbox.MinEdge.Z = -1000 * BS;
tmpbox.MaxEdge.X = tmpbox.MaxEdge.Z = 1000 * BS;
driver->draw3DBox(tmpbox, video::SColor(255, 255, 0x4d, 0));
}
#endif
updateMesh();
// Update position
@ -425,14 +445,14 @@ void Clouds::update(const v3f &camera_p, const video::SColorf &color_diffuse)
// is the camera inside the cloud mesh?
m_camera_pos = camera_p;
m_camera_inside_cloud = false; // default
m_camera_inside_cloud = false;
if (is3D()) {
float camera_height = camera_p.Y - BS * m_camera_offset.Y;
if (camera_height >= m_box.MinEdge.Y &&
camera_height <= m_box.MaxEdge.Y) {
v2f camera_in_noise;
camera_in_noise.X = floor((camera_p.X - m_origin.X) / cloud_size + 0.5);
camera_in_noise.Y = floor((camera_p.Z - m_origin.Y) / cloud_size + 0.5);
camera_in_noise.X = floorf((camera_p.X - m_origin.X) / cloud_size + 0.5f);
camera_in_noise.Y = floorf((camera_p.Z - m_origin.Y) / cloud_size + 0.5f);
bool filled = gridFilled(camera_in_noise.X, camera_in_noise.Y);
m_camera_inside_cloud = filled;
}

View file

@ -134,8 +134,11 @@ private:
{
float height_bs = m_params.height * BS;
float thickness_bs = m_params.thickness * BS;
m_box = aabb3f(-BS * 1000000.0f, height_bs, -BS * 1000000.0f,
BS * 1000000.0f, height_bs + thickness_bs, BS * 1000000.0f);
float far_bs = 1000000.0f * BS;
m_box = aabb3f(-far_bs, height_bs, -far_bs,
far_bs, height_bs + thickness_bs, far_bs);
m_box.MinEdge -= v3f::from(m_camera_offset) * BS;
m_box.MaxEdge -= v3f::from(m_camera_offset) * BS;
}
void updateMesh();

View file

@ -12,6 +12,8 @@
#include "client/sound.h"
#include "client/texturesource.h"
#include "client/mapblock_mesh.h"
#include "client/content_mapblock.h"
#include "client/meshgen/collector.h"
#include "util/basic_macros.h"
#include "util/numeric.h"
#include "util/serialize.h"
@ -180,6 +182,55 @@ static void setColorParam(scene::ISceneNode *node, video::SColor color)
node->getMaterial(i).ColorParam = color;
}
static scene::SMesh *generateNodeMesh(Client *client, MapNode n,
std::vector<MeshAnimationInfo> &animation)
{
auto *ndef = client->ndef();
auto *shdsrc = client->getShaderSource();
MeshCollector collector(v3f(0), v3f());
{
MeshMakeData mmd(ndef, 1, MeshGrid{1});
n.setParam1(0xff);
mmd.fillSingleNode(n);
MapblockMeshGenerator(&mmd, &collector).generate();
}
auto mesh = make_irr<scene::SMesh>();
animation.clear();
for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
for (PreMeshBuffer &p : collector.prebuffers[layer]) {
// reset the pre-computed light data stored in the vertex color,
// since we do that ourselves via updateLight().
for (auto &v : p.vertices)
v.Color.set(0xFFFFFFFF);
// but still apply the tile color
p.applyTileColor();
if (p.layer.material_flags & MATERIAL_FLAG_ANIMATION) {
const FrameSpec &frame = (*p.layer.frames)[0];
p.layer.texture = frame.texture;
animation.emplace_back(MeshAnimationInfo{mesh->getMeshBufferCount(), 0, p.layer});
}
auto buf = make_irr<scene::SMeshBuffer>();
buf->append(&p.vertices[0], p.vertices.size(),
&p.indices[0], p.indices.size());
// Set up material
auto &mat = buf->Material;
u32 shader_id = shdsrc->getShader("object_shader", p.layer.material_type, NDT_NORMAL);
mat.MaterialType = shdsrc->getShaderInfo(shader_id).material;
p.layer.applyMaterialOptions(mat, layer);
mesh->addMeshBuffer(buf.get());
}
}
mesh->recalculateBoundingBox();
return mesh.release();
}
/*
TestCAO
*/
@ -572,6 +623,8 @@ void GenericCAO::removeFromScene(bool permanent)
m_spritenode = nullptr;
}
m_meshnode_animation.clear();
if (m_matrixnode) {
m_matrixnode->remove();
m_matrixnode->drop();
@ -602,8 +655,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
infostream << "GenericCAO::addToScene(): " << m_prop.visual << std::endl;
m_material_type_param = 0.5f; // May cut off alpha < 128 depending on m_material_type
if (m_prop.visual != "node" && m_prop.visual != "wielditem" && m_prop.visual != "item")
{
IShaderSource *shader_source = m_client->getShaderSource();
MaterialType material_type;
@ -617,15 +669,17 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
u32 shader_id = shader_source->getShader("object_shader", material_type, NDT_NORMAL);
m_material_type = shader_source->getShaderInfo(shader_id).material;
} else {
// Not used, so make sure it's not valid
m_material_type = EMT_INVALID;
}
auto grabMatrixNode = [this] {
m_matrixnode = m_smgr->addDummyTransformationSceneNode();
m_matrixnode->grab();
};
m_matrixnode = m_smgr->addDummyTransformationSceneNode();
m_matrixnode->grab();
auto setMaterial = [this] (video::SMaterial &mat) {
mat.MaterialType = m_material_type;
if (m_material_type != EMT_INVALID)
mat.MaterialType = m_material_type;
mat.FogEnable = true;
mat.forEachTexture([] (auto &tex) {
tex.MinFilter = video::ETMINF_NEAREST_MIPMAP_NEAREST;
@ -637,28 +691,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
node->forEachMaterial(setMaterial);
};
if (m_prop.visual == "sprite") {
grabMatrixNode();
m_spritenode = m_smgr->addBillboardSceneNode(
m_matrixnode, v2f(1, 1), v3f(0,0,0), -1);
m_spritenode->grab();
video::ITexture *tex = tsrc->getTextureForMesh("no_texture.png");
m_spritenode->forEachMaterial([tex] (auto &mat) {
mat.setTexture(0, tex);
});
setSceneNodeMaterials(m_spritenode);
m_spritenode->setSize(v2f(m_prop.visual_size.X,
m_prop.visual_size.Y) * BS);
{
const float txs = 1.0 / 1;
const float tys = 1.0 / 1;
setBillboardTextureMatrix(m_spritenode,
txs, tys, 0, 0);
}
} else if (m_prop.visual == "upright_sprite") {
grabMatrixNode();
if (m_prop.visual == "upright_sprite") {
auto mesh = make_irr<scene::SMesh>();
f32 dx = BS * m_prop.visual_size.X / 2;
f32 dy = BS * m_prop.visual_size.Y / 2;
@ -700,7 +733,6 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
m_meshnode = m_smgr->addMeshSceneNode(mesh.get(), m_matrixnode);
m_meshnode->grab();
} else if (m_prop.visual == "cube") {
grabMatrixNode();
scene::IMesh *mesh = createCubeMesh(v3f(BS,BS,BS));
m_meshnode = m_smgr->addMeshSceneNode(mesh, m_matrixnode);
m_meshnode->grab();
@ -714,7 +746,6 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
mat.BackfaceCulling = m_prop.backface_culling;
});
} else if (m_prop.visual == "mesh") {
grabMatrixNode();
scene::IAnimatedMesh *mesh = m_client->getMesh(m_prop.mesh, true);
if (mesh) {
if (!checkMeshNormals(mesh)) {
@ -741,7 +772,6 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
} else
errorstream<<"GenericCAO::addToScene(): Could not load mesh "<<m_prop.mesh<<std::endl;
} else if (m_prop.visual == "wielditem" || m_prop.visual == "item") {
grabMatrixNode();
ItemStack item;
if (m_prop.wield_item.empty()) {
// Old format, only textures are specified.
@ -761,9 +791,35 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
(m_prop.visual == "wielditem"));
m_wield_meshnode->setScale(m_prop.visual_size / 2.0f);
} else if (m_prop.visual == "node") {
auto *mesh = generateNodeMesh(m_client, m_prop.node, m_meshnode_animation);
assert(mesh);
m_meshnode = m_smgr->addMeshSceneNode(mesh, m_matrixnode);
m_meshnode->setSharedMaterials(true);
m_meshnode->grab();
mesh->drop();
m_meshnode->setScale(m_prop.visual_size);
setSceneNodeMaterials(m_meshnode);
} else {
infostream<<"GenericCAO::addToScene(): \""<<m_prop.visual
<<"\" not supported"<<std::endl;
m_spritenode = m_smgr->addBillboardSceneNode(m_matrixnode);
m_spritenode->grab();
setSceneNodeMaterials(m_spritenode);
m_spritenode->setSize(v2f(m_prop.visual_size.X,
m_prop.visual_size.Y) * BS);
setBillboardTextureMatrix(m_spritenode, 1, 1, 0, 0);
// This also serves as fallback for unknown visual types
if (m_prop.visual != "sprite") {
infostream << "GenericCAO::addToScene(): \"" << m_prop.visual
<< "\" not supported" << std::endl;
m_spritenode->getMaterial(0).setTexture(0,
tsrc->getTextureForMesh("unknown_object.png"));
}
}
/* Set VBO hint */
@ -789,8 +845,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
updateTextures(m_current_texture_modifier);
if (scene::ISceneNode *node = getSceneNode()) {
if (m_matrixnode)
node->setParent(m_matrixnode);
node->setParent(m_matrixnode);
if (auto shadow = RenderingEngine::get_shadow_renderer())
shadow->addNodeToShadowList(node);
@ -861,8 +916,7 @@ void GenericCAO::updateLight(u32 day_night_ratio)
if (!pos_ok)
light_at_pos = LIGHT_SUN;
// Initialize with full alpha, otherwise entity won't be visible
video::SColor light{0xFFFFFFFF};
video::SColor light;
// Encode light into color, adding a small boost
// based on the entity glow.
@ -965,6 +1019,7 @@ void GenericCAO::updateNodePos()
scene::ISceneNode *node = getSceneNode();
if (node) {
assert(m_matrixnode);
v3s16 camera_offset = m_env->getCameraOffset();
v3f pos = pos_translator.val_current -
intToFloat(camera_offset, BS);
@ -1153,7 +1208,7 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
m_anim_frame = 0;
}
updateTexturePos();
updateTextureAnim();
if(m_reset_textures_timer >= 0)
{
@ -1214,7 +1269,7 @@ static void setMeshBufferTextureCoords(scene::IMeshBuffer *buf, const v2f *uv, u
buf->setDirty(scene::EBT_VERTEX);
}
void GenericCAO::updateTexturePos()
void GenericCAO::updateTextureAnim()
{
if(m_spritenode)
{
@ -1279,6 +1334,23 @@ void GenericCAO::updateTexturePos()
auto mesh = m_meshnode->getMesh();
setMeshBufferTextureCoords(mesh->getMeshBuffer(0), t, 4);
setMeshBufferTextureCoords(mesh->getMeshBuffer(1), t, 4);
} else if (m_prop.visual == "node") {
// same calculation as MapBlockMesh::animate() with a global timer
const float time = m_client->getAnimationTime();
for (auto &it : m_meshnode_animation) {
const TileLayer &tile = it.tile;
int frameno = (int)(time * 1000 / tile.animation_frame_length_ms)
% tile.animation_frame_count;
if (frameno == it.frame)
continue;
it.frame = frameno;
auto *buf = m_meshnode->getMesh()->getMeshBuffer(it.i);
const FrameSpec &frame = (*tile.frames)[frameno];
buf->getMaterial().setTexture(0, frame.texture);
}
}
}
}
@ -1304,7 +1376,6 @@ void GenericCAO::updateTextures(std::string mod)
video::SMaterial &material = m_spritenode->getMaterial(0);
material.MaterialType = m_material_type;
material.MaterialTypeParam = m_material_type_param;
material.setTexture(0, tsrc->getTextureForMesh(texturestring));
material.forEachTexture([=] (auto &tex) {
@ -1333,7 +1404,6 @@ void GenericCAO::updateTextures(std::string mod)
// Set material flags and texture
video::SMaterial &material = m_animated_meshnode->getMaterial(i);
material.MaterialType = m_material_type;
material.MaterialTypeParam = m_material_type_param;
material.TextureLayers[0].Texture = texture;
material.BackfaceCulling = m_prop.backface_culling;
@ -1365,7 +1435,6 @@ void GenericCAO::updateTextures(std::string mod)
// Set material flags and texture
video::SMaterial &material = m_meshnode->getMaterial(i);
material.MaterialType = m_material_type;
material.MaterialTypeParam = m_material_type_param;
material.setTexture(0, tsrc->getTextureForMesh(texturestring));
material.getTextureMatrix(0).makeIdentity();
@ -1532,7 +1601,7 @@ bool GenericCAO::visualExpiryRequired(const ObjectProperties &new_) const
/* Visuals do not need to be expired for:
* - nametag props: handled by updateNametag()
* - textures: handled by updateTextures()
* - sprite props: handled by updateTexturePos()
* - sprite props: handled by updateTextureAnim()
* - glow: handled by updateLight()
* - any other properties that do not change appearance
*/
@ -1542,9 +1611,10 @@ bool GenericCAO::visualExpiryRequired(const ObjectProperties &new_) const
// Ordered to compare primitive types before std::vectors
return old.backface_culling != new_.backface_culling ||
old.is_visible != new_.is_visible ||
old.mesh != new_.mesh ||
old.shaded != new_.shaded ||
old.use_texture_alpha != new_.use_texture_alpha ||
old.node != new_.node ||
old.mesh != new_.mesh ||
old.visual != new_.visual ||
old.visual_size != new_.visual_size ||
old.wield_item != new_.wield_item ||
@ -1655,7 +1725,7 @@ void GenericCAO::processMessage(const std::string &data)
m_anim_framelength = framelength;
m_tx_select_horiz_by_yawpitch = select_horiz_by_yawpitch;
updateTexturePos();
updateTextureAnim();
} else if (cmd == AO_CMD_SET_PHYSICS_OVERRIDE) {
float override_speed = readF32(is);
float override_jump = readF32(is);

View file

@ -12,6 +12,7 @@
#include "clientobject.h"
#include "constants.h"
#include "itemgroup.h"
#include "client/tile.h"
#include <cassert>
#include <map>
#include <memory>
@ -27,7 +28,7 @@ struct Nametag;
struct MinimapMarker;
/*
SmoothTranslator
SmoothTranslator and other helpers
*/
template<typename T>
@ -60,9 +61,21 @@ struct SmoothTranslatorWrappedv3f : SmoothTranslator<v3f>
void translate(f32 dtime);
};
struct MeshAnimationInfo {
u32 i; /// index of mesh buffer
int frame; /// last animation frame
TileLayer tile;
};
/*
GenericCAO
*/
class GenericCAO : public ClientActiveObject
{
private:
static constexpr auto EMT_INVALID = video::EMT_FORCE_32BIT;
// Only set at initialization
std::string m_name = "";
bool m_is_player = false;
@ -73,6 +86,8 @@ private:
scene::ISceneManager *m_smgr = nullptr;
Client *m_client = nullptr;
aabb3f m_selection_box = aabb3f(-BS/3.,-BS/3.,-BS/3., BS/3.,BS/3.,BS/3.);
// Visuals
scene::IMeshSceneNode *m_meshnode = nullptr;
scene::IAnimatedMeshSceneNode *m_animated_meshnode = nullptr;
WieldMeshSceneNode *m_wield_meshnode = nullptr;
@ -80,6 +95,15 @@ private:
scene::IDummyTransformationSceneNode *m_matrixnode = nullptr;
Nametag *m_nametag = nullptr;
MinimapMarker *m_marker = nullptr;
bool m_visuals_expired = false;
video::SColor m_last_light = video::SColor(0xFFFFFFFF);
bool m_is_visible = false;
std::vector<MeshAnimationInfo> m_meshnode_animation;
// Material
video::E_MATERIAL_TYPE m_material_type = EMT_INVALID;
// Movement
v3f m_position = v3f(0.0f, 10.0f * BS, 0);
v3f m_velocity;
v3f m_acceleration;
@ -87,18 +111,25 @@ private:
u16 m_hp = 1;
SmoothTranslator<v3f> pos_translator;
SmoothTranslatorWrappedv3f rot_translator;
// Spritesheet/animation stuff
// Spritesheet stuff
v2f m_tx_size = v2f(1,1);
v2s16 m_tx_basepos;
bool m_initial_tx_basepos_set = false;
bool m_tx_select_horiz_by_yawpitch = false;
bool m_animation_loop = true;
v2f m_animation_range;
float m_animation_speed = 15.0f;
float m_animation_blend = 0.0f;
bool m_animation_loop = true;
int m_anim_frame = 0;
int m_anim_num_frames = 1;
float m_anim_framelength = 0.2f;
float m_anim_timer = 0.0f;
// stores position and rotation for each bone name
BoneOverrideMap m_bone_override;
// Attachments
object_t m_attachment_parent_id = 0;
std::unordered_set<object_t> m_attachment_child_ids;
std::string m_attachment_bone = "";
@ -107,23 +138,13 @@ private:
bool m_attached_to_local = false;
bool m_force_visible = false;
int m_anim_frame = 0;
int m_anim_num_frames = 1;
float m_anim_framelength = 0.2f;
float m_anim_timer = 0.0f;
ItemGroupList m_armor_groups;
float m_reset_textures_timer = -1.0f;
// stores texture modifier before punch update
std::string m_previous_texture_modifier = "";
// last applied texture modifier
std::string m_current_texture_modifier = "";
bool m_visuals_expired = false;
float m_step_distance_counter = 0.0f;
video::SColor m_last_light = video::SColor(0xFFFFFFFF);
bool m_is_visible = false;
// Material
video::E_MATERIAL_TYPE m_material_type;
f32 m_material_type_param;
bool visualExpiryRequired(const ObjectProperties &newprops) const;
@ -255,7 +276,7 @@ public:
void step(float dtime, ClientEnvironment *env) override;
void updateTexturePos();
void updateTextureAnim();
// ffs this HAS TO BE a string copy! See #5739 if you think otherwise
// Reason: updateTextures(m_previous_texture_modifier);

View file

@ -121,7 +121,7 @@ void MapblockMeshGenerator::drawQuad(const TileSpec &tile, v3f *coords, const v3
v2f(1.0, vertical_tiling), v2f(0.0, vertical_tiling)};
video::S3DVertex vertices[4];
bool shade_face = !cur_node.f->light_source && (normal != v3s16(0, 0, 0));
v3f normal2(normal.X, normal.Y, normal.Z);
v3f normal2 = v3f::from(normal);
for (int j = 0; j < 4; j++) {
vertices[j].Pos = coords[j] + cur_node.origin;
vertices[j].Normal = normal2;

View file

@ -33,7 +33,7 @@ public:
void put(MtEvent *e) override
{
std::map<MtEvent::Type, Dest>::iterator i = m_dest.find(e->getType());
auto i = m_dest.find(e->getType());
if (i != m_dest.end()) {
std::list<FuncSpec> &funcs = i->second.funcs;
for (FuncSpec &func : funcs) {
@ -44,7 +44,7 @@ public:
}
void reg(MtEvent::Type type, event_receive_func f, void *data) override
{
std::map<MtEvent::Type, Dest>::iterator i = m_dest.find(type);
auto i = m_dest.find(type);
if (i != m_dest.end()) {
i->second.funcs.emplace_back(f, data);
} else {

View file

@ -278,7 +278,7 @@ gui::IGUIFont *FontEngine::initFont(const FontSpec &spec)
};
auto it = m_media_faces.find(media_name);
if (it != m_media_faces.end()) {
if (spec.mode != _FM_Fallback && it != m_media_faces.end()) {
auto *face = it->second.get();
if (auto *font = createFont(face))
return font;

View file

@ -564,6 +564,7 @@ protected:
void updatePauseState();
void step(f32 dtime);
void processClientEvents(CameraOrientation *cam);
void updateCameraMode(); // call after changing it
void updateCameraOffset();
void updateCamera(f32 dtime);
void updateSound(f32 dtime);
@ -665,6 +666,7 @@ private:
void handleClientEvent_OverrideDayNigthRatio(ClientEvent *event,
CameraOrientation *cam);
void handleClientEvent_CloudParams(ClientEvent *event, CameraOrientation *cam);
void handleClientEvent_UpdateCamera(ClientEvent *event, CameraOrientation *cam);
void updateChat(f32 dtime);
@ -754,7 +756,6 @@ private:
f32 m_repeat_dig_time;
f32 m_cache_cam_smoothing;
bool m_enable_relative_mode = false;
bool m_invert_mouse;
bool m_enable_hotbar_mouse_wheel;
bool m_invert_hotbar_mouse_wheel;
@ -770,9 +771,10 @@ private:
bool m_is_paused = false;
bool m_touch_simulate_aux1 = false;
bool m_touch_use_crosshair;
inline bool isTouchCrosshairDisabled() {
return !m_touch_use_crosshair && camera->getCameraMode() == CAMERA_MODE_FIRST;
inline bool isTouchShootlineUsed()
{
return g_touchcontrols && g_touchcontrols->isShootlineAvailable() &&
camera->getCameraMode() == CAMERA_MODE_FIRST;
}
#ifdef __ANDROID__
bool m_android_chat_open;
@ -821,8 +823,6 @@ Game::Game() :
&settingChangedCallback, this);
g_settings->registerChangedCallback("pause_on_lost_focus",
&settingChangedCallback, this);
g_settings->registerChangedCallback("touch_use_crosshair",
&settingChangedCallback, this);
readSettings();
}
@ -899,15 +899,6 @@ bool Game::startup(bool *kill,
m_first_loop_after_window_activation = true;
// In principle we could always enable relative mouse mode, but it causes weird
// bugs on some setups (e.g. #14932), so we enable it only when it's required.
// That is: on Wayland or Android, because it does not support mouse repositioning
#ifdef __ANDROID__
m_enable_relative_mode = true;
#else
m_enable_relative_mode = device->isUsingWayland();
#endif
g_client_translations->clear();
// address can change if simple_singleplayer_mode
@ -968,7 +959,7 @@ void Game::run()
// Calculate dtime =
// m_rendering_engine->run() from this iteration
// + Sleep time until the wanted FPS are reached
draw_times.limit(device, &dtime, g_menumgr.pausesGame());
draw_times.limit(device, &dtime);
framemarker.start();
@ -1378,10 +1369,8 @@ bool Game::initGui()
gui_chat_console = make_irr<GUIChatConsole>(guienv, guienv->getRootGUIElement(),
-1, chat_backend, client, &g_menumgr);
if (shouldShowTouchControls()) {
if (shouldShowTouchControls())
g_touchcontrols = new TouchControls(device, texture_src);
g_touchcontrols->setUseCrosshair(!isTouchCrosshairDisabled());
}
return true;
}
@ -1921,6 +1910,9 @@ void Game::processKeyInput()
toggleFog();
} else if (wasKeyDown(KeyType::TOGGLE_UPDATE_CAMERA)) {
toggleUpdateCamera();
} else if (wasKeyPressed(KeyType::CAMERA_MODE)) {
camera->toggleCameraMode();
updateCameraMode();
} else if (wasKeyPressed(KeyType::TOGGLE_DEBUG)) {
toggleDebug();
} else if (wasKeyPressed(KeyType::TOGGLE_PROFILER)) {
@ -2359,10 +2351,8 @@ void Game::updateCameraDirection(CameraOrientation *cam, float dtime)
Since Minetest has its own code to synthesize mouse events from touch events,
this results in duplicated input. To avoid that, we don't enable relative
mouse mode if we're in touchscreen mode. */
if (cur_control) {
cur_control->setRelativeMode(m_enable_relative_mode &&
!g_touchcontrols && !isMenuActive());
}
if (cur_control)
cur_control->setRelativeMode(!g_touchcontrols && !isMenuActive());
if ((device->isWindowActive() && device->isWindowFocused()
&& !isMenuActive()) || input->isRandom()) {
@ -2433,7 +2423,7 @@ void Game::updateCameraOrientation(CameraOrientation *cam, float dtime)
cam->camera_pitch += input->joystick.getAxisWithoutDead(JA_FRUSTUM_VERTICAL) * c;
}
cam->camera_pitch = rangelim(cam->camera_pitch, -89.5, 89.5);
cam->camera_pitch = rangelim(cam->camera_pitch, -90, 90);
}
@ -2504,7 +2494,7 @@ inline void Game::step(f32 dtime)
ZoneScoped;
if (server) {
float fps_max = (!device->isWindowFocused() || g_menumgr.pausesGame()) ?
float fps_max = !device->isWindowFocused() && simple_singleplayer_mode ?
g_settings->getFloat("fps_max_unfocused") :
g_settings->getFloat("fps_max");
fps_max = std::max(fps_max, 1.0f);
@ -2575,6 +2565,7 @@ const ClientEventHandler Game::clientEventHandler[CLIENTEVENT_MAX] = {
{&Game::handleClientEvent_SetStars},
{&Game::handleClientEvent_OverrideDayNigthRatio},
{&Game::handleClientEvent_CloudParams},
{&Game::handleClientEvent_UpdateCamera},
};
void Game::handleClientEvent_None(ClientEvent *event, CameraOrientation *cam)
@ -2879,6 +2870,13 @@ void Game::handleClientEvent_CloudParams(ClientEvent *event, CameraOrientation *
clouds->setSpeed(v2f(event->cloud_params.speed_x, event->cloud_params.speed_y));
}
void Game::handleClientEvent_UpdateCamera(ClientEvent *event, CameraOrientation *cam)
{
// no parameters to update here, this just makes sure the camera is in the
// state it should be after something was changed.
updateCameraMode();
}
void Game::processClientEvents(CameraOrientation *cam)
{
while (client->hasClientEvents()) {
@ -2935,12 +2933,7 @@ void Game::updateCamera(f32 dtime)
ClientEnvironment &env = client->getEnv();
LocalPlayer *player = env.getLocalPlayer();
/*
For interaction purposes, get info about the held item
- What item is it?
- Is it a usable item?
- Can it point to liquids?
*/
// For interaction purposes, get info about the held item
ItemStack playeritem;
{
ItemStack selected, hand;
@ -2950,23 +2943,6 @@ void Game::updateCamera(f32 dtime)
ToolCapabilities playeritem_toolcap =
playeritem.getToolCapabilities(itemdef_manager);
if (wasKeyPressed(KeyType::CAMERA_MODE)) {
GenericCAO *playercao = player->getCAO();
// If playercao not loaded, don't change camera
if (!playercao)
return;
camera->toggleCameraMode();
if (g_touchcontrols)
g_touchcontrols->setUseCrosshair(!isTouchCrosshairDisabled());
// Make the player visible depending on camera mode.
playercao->updateMeshCulling();
playercao->setChildrenVisible(camera->getCameraMode() > CAMERA_MODE_FIRST);
}
float full_punch_interval = playeritem_toolcap.full_punch_interval;
float tool_reload_ratio = runData.time_from_last_punch / full_punch_interval;
@ -2981,6 +2957,22 @@ void Game::updateCamera(f32 dtime)
}
}
void Game::updateCameraMode()
{
LocalPlayer *player = client->getEnv().getLocalPlayer();
// Obey server choice
if (player->allowed_camera_mode != CAMERA_MODE_ANY)
camera->setCameraMode(player->allowed_camera_mode);
GenericCAO *playercao = player->getCAO();
if (playercao) {
// Make the player visible depending on camera mode.
playercao->updateMeshCulling();
playercao->setChildrenVisible(camera->getCameraMode() > CAMERA_MODE_FIRST);
}
}
void Game::updateCameraOffset()
{
ClientEnvironment &env = client->getEnv();
@ -2997,8 +2989,13 @@ void Game::updateCameraOffset()
if (!m_flags.disable_camera_update) {
auto *shadow = RenderingEngine::get_shadow_renderer();
if (shadow)
if (shadow) {
shadow->getDirectionalLight().updateCameraOffset(camera);
// FIXME: I bet we can be smarter about this and don't need to redraw
// the shadow map at all, but this is for someone else to figure out.
if (!g_settings->getFlag("performance_tradeoffs"))
shadow->setForceUpdateShadowMap();
}
env.getClientMap().updateCamera(camera->getPosition(),
camera->getDirection(), camera->getFovMax(), camera_offset,
@ -3057,6 +3054,9 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud)
core::line3d<f32> shootline;
switch (camera->getCameraMode()) {
case CAMERA_MODE_ANY:
assert(false);
break;
case CAMERA_MODE_FIRST:
// Shoot from camera position, with bobbing
shootline.start = camera->getPosition();
@ -3073,7 +3073,7 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud)
}
shootline.end = shootline.start + camera_direction * BS * d;
if (g_touchcontrols && isTouchCrosshairDisabled()) {
if (isTouchShootlineUsed()) {
shootline = g_touchcontrols->getShootline();
// Scale shootline to the acual distance the player can reach
shootline.end = shootline.start +
@ -3232,9 +3232,10 @@ PointedThing Game::updatePointedThing(
hud->setSelectionPos(pos, camera_offset);
GenericCAO* gcao = dynamic_cast<GenericCAO*>(runData.selected_object);
if (gcao != nullptr && gcao->getProperties().rotate_selectionbox)
hud->setSelectionRotation(gcao->getSceneNode()->getAbsoluteTransformation().getRotationDegrees());
hud->setSelectionRotationRadians(gcao->getSceneNode()
->getAbsoluteTransformation().getRotationRadians());
else
hud->setSelectionRotation(v3f());
hud->setSelectionRotationRadians(v3f());
}
hud->setSelectedFaceNormal(result.raw_intersection_normal);
} else if (result.type == POINTEDTHING_NODE) {
@ -3244,17 +3245,15 @@ PointedThing Game::updatePointedThing(
n.getSelectionBoxes(nodedef, &boxes,
n.getNeighbors(result.node_undersurface, &map));
f32 d = 0.002 * BS;
for (std::vector<aabb3f>::const_iterator i = boxes.begin();
i != boxes.end(); ++i) {
aabb3f box = *i;
f32 d = 0.002f * BS;
for (aabb3f box : boxes) {
box.MinEdge -= v3f(d, d, d);
box.MaxEdge += v3f(d, d, d);
selectionboxes->push_back(box);
}
hud->setSelectionPos(intToFloat(result.node_undersurface, BS),
camera_offset);
hud->setSelectionRotation(v3f());
hud->setSelectionRotationRadians(v3f());
hud->setSelectedFaceNormal(result.intersection_normal);
}
@ -3449,9 +3448,8 @@ bool Game::nodePlacement(const ItemDefinition &selected_def,
u8 predicted_param2 = dir.Y < 0 ? 1 : 0;
if (selected_def.wallmounted_rotate_vertical) {
bool rotate90 = false;
v3f fnodepos = v3f(neighborpos.X, neighborpos.Y, neighborpos.Z);
v3f ppos = client->getEnv().getLocalPlayer()->getPosition() / BS;
v3f pdir = fnodepos - ppos;
v3f pdir = v3f::from(neighborpos) - ppos;
switch (predicted_f.drawtype) {
case NDT_TORCHLIKE: {
rotate90 = !((pdir.X < 0 && pdir.Z > 0) ||
@ -4046,7 +4044,7 @@ void Game::drawScene(ProfilerGraph *graph, RunStats *stats)
(player->hud_flags & HUD_FLAG_CROSSHAIR_VISIBLE) &&
(this->camera->getCameraMode() != CAMERA_MODE_THIRD_FRONT));
if (g_touchcontrols && isTouchCrosshairDisabled())
if (isTouchShootlineUsed())
draw_crosshair = false;
this->m_rendering_engine->draw_scene(sky_color, this->m_game_ui->m_flags.show_hud,
@ -4126,10 +4124,6 @@ void Game::readSettings()
m_invert_hotbar_mouse_wheel = g_settings->getBool("invert_hotbar_mouse_wheel");
m_does_lost_focus_pause_game = g_settings->getBool("pause_on_lost_focus");
m_touch_use_crosshair = g_settings->getBool("touch_use_crosshair");
if (g_touchcontrols)
g_touchcontrols->setUseCrosshair(!isTouchCrosshairDisabled());
}
/****************************************************************************/

View file

@ -283,9 +283,7 @@ void GameFormSpec::showPauseMenuFormSpec(const std::string &formspec, const std:
&m_input->joystick, fs_src, txt_dst, "",
m_client->getSoundManager());
// FIXME: can't enable this for now because "fps_max_unfocused" also applies
// when the game is paused, making the settings menu much less enjoyable.
// m_formspec->doPause = true;
m_formspec->doPause = true;
}
void GameFormSpec::showNodeFormspec(const std::string &formspec, const v3s16 &nodepos)
@ -376,18 +374,18 @@ void GameFormSpec::showPauseMenu()
<< strgettext("Continue") << "]";
if (!simple_singleplayer_mode) {
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_change_password;"
os << "button[4," << (ypos++) << ";3,0.5;btn_change_password;"
<< strgettext("Change Password") << "]";
} else {
os << "field[4.95,0;5,1.5;;" << strgettext("Game paused") << ";]";
}
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_settings;"
os << "button[4," << (ypos++) << ";3,0.5;btn_settings;"
<< strgettext("Settings") << "]";
#ifndef __ANDROID__
#if USE_SOUND
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_sound;"
os << "button[4," << (ypos++) << ";3,0.5;btn_sound;"
<< strgettext("Sound Volume") << "]";
#endif
#endif

View file

@ -880,7 +880,7 @@ void Hud::drawSelectionMesh()
core::matrix4 translate;
translate.setTranslation(m_selection_pos_with_offset);
core::matrix4 rotation;
rotation.setRotationDegrees(m_selection_rotation);
rotation.setRotationRadians(m_selection_rotation_radians);
driver->setTransform(video::ETS_WORLD, translate * rotation);
if (m_mode == HIGHLIGHT_BOX) {
@ -965,8 +965,8 @@ void Hud::drawBlockBounds()
v3f pmax = v3f(x, y, 1 + radius) * MAP_BLOCKSIZE * BS;
driver->draw3DLine(
base_corner + v3f(pmin.X, pmin.Y, pmin.Z),
base_corner + v3f(pmax.X, pmax.Y, pmax.Z),
base_corner + pmin,
base_corner + pmax,
choose_color(block_pos.X, block_pos.Y)
);
driver->draw3DLine(

View file

@ -74,9 +74,15 @@ public:
v3f getSelectionPos() const { return m_selection_pos; }
void setSelectionRotation(v3f rotation) { m_selection_rotation = rotation; }
void setSelectionRotationRadians(v3f rotation)
{
m_selection_rotation_radians = rotation;
}
v3f getSelectionRotation() const { return m_selection_rotation; }
v3f getSelectionRotationRadians() const
{
return m_selection_rotation_radians;
}
void setSelectionMeshColor(const video::SColor &color)
{
@ -129,7 +135,7 @@ private:
std::vector<aabb3f> m_halo_boxes;
v3f m_selection_pos;
v3f m_selection_pos_with_offset;
v3f m_selection_rotation;
v3f m_selection_rotation_radians;
scene::IMesh *m_selection_mesh = nullptr;
video::SColor m_selection_mesh_color;

View file

@ -285,13 +285,13 @@ void imageScaleNNAA(video::IImage *src, const core::rect<s32> &srcrect, video::I
maxsx = minsx + sw / dim.Width;
maxsx = rangelim(maxsx, 0, sox + sw);
if (minsx > maxsx)
SWAP(double, minsx, maxsx);
std::swap(minsx, maxsx);
minsy = soy + (dy * sh / dim.Height);
minsy = rangelim(minsy, 0, soy + sh);
maxsy = minsy + sh / dim.Height;
maxsy = rangelim(maxsy, 0, soy + sh);
if (minsy > maxsy)
SWAP(double, minsy, maxsy);
std::swap(minsy, maxsy);
// Total area, and integral of r, g, b values over that area,
// initialized to zero, to be summed up in next loops.

View file

@ -426,20 +426,6 @@ void getNodeTile(MapNode mn, const v3s16 &p, const v3s16 &dir, MeshMakeData *dat
tile.rotation = tile.world_aligned ? TileRotation::None : dir_to_tile[facedir][dir_i].rotation;
}
static void applyTileColor(PreMeshBuffer &pmb)
{
video::SColor tc = pmb.layer.color;
if (tc == video::SColor(0xFFFFFFFF))
return;
for (video::S3DVertex &vertex : pmb.vertices) {
video::SColor *c = &vertex.Color;
c->set(c->getAlpha(),
c->getRed() * tc.getRed() / 255,
c->getGreen() * tc.getGreen() / 255,
c->getBlue() * tc.getBlue() / 255);
}
}
/*
MapBlockBspTree
*/
@ -668,7 +654,7 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data):
{
PreMeshBuffer &p = collector.prebuffers[layer][i];
applyTileColor(p);
p.applyTileColor();
// Generate animation data
// - Cracks
@ -701,28 +687,16 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data):
// Create material
video::SMaterial material;
material.BackfaceCulling = true;
material.FogEnable = true;
material.setTexture(0, p.layer.texture);
material.forEachTexture([] (auto &tex) {
tex.MinFilter = video::ETMINF_NEAREST_MIPMAP_NEAREST;
tex.MagFilter = video::ETMAGF_NEAREST;
});
/*
* The second layer is for overlays, but uses the same vertex positions
* as the first, which quickly leads to z-fighting.
* To fix this we can offset the polygons in the direction of the camera.
* This only affects the depth buffer and leads to no visual gaps in geometry.
*/
if (layer == 1) {
material.PolygonOffsetSlopeScale = -1;
material.PolygonOffsetDepthBias = -1;
}
{
material.MaterialType = m_shdrsrc->getShaderInfo(
p.layer.shader_id).material;
p.layer.applyMaterialOptionsWithShaders(material);
p.layer.applyMaterialOptions(material, layer);
}
scene::SMeshBuffer *buf = new scene::SMeshBuffer();

View file

@ -145,8 +145,7 @@ QueuedMeshUpdate *MeshUpdateQueue::pop()
MutexAutoLock lock(m_mutex);
bool must_be_urgent = !m_urgents.empty();
for (std::vector<QueuedMeshUpdate*>::iterator i = m_queue.begin();
i != m_queue.end(); ++i) {
for (auto i = m_queue.begin(); i != m_queue.end(); ++i) {
QueuedMeshUpdate *q = *i;
if (must_be_urgent && m_urgents.count(q->p) == 0)
continue;
@ -264,8 +263,8 @@ void MeshUpdateManager::updateBlock(Map *map, v3s16 p, bool ack_block_to_server,
g_settings->getBool("smooth_lighting")
&& !g_settings->getFlag("performance_tradeoffs");
if (!m_queue_in.addBlock(map, p, ack_block_to_server, urgent)) {
warningstream << "Update requested for non-existent block at ("
<< p.X << ", " << p.Y << ", " << p.Z << ")" << std::endl;
warningstream << "Update requested for non-existent block at "
<< p << std::endl;
return;
}
if (update_neighbors) {

View file

@ -18,6 +18,21 @@ struct PreMeshBuffer
PreMeshBuffer() = default;
explicit PreMeshBuffer(const TileLayer &layer) : layer(layer) {}
/// @brief Colorizes vertices as indicated by tile layer
void applyTileColor()
{
video::SColor tc = layer.color;
if (tc == video::SColor(0xFFFFFFFF))
return;
for (auto &vertex : vertices) {
video::SColor *c = &vertex.Color;
c->set(c->getAlpha(),
c->getRed() * tc.getRed() / 255U,
c->getGreen() * tc.getGreen() / 255U,
c->getBlue() * tc.getBlue() / 255U);
}
}
};
struct MeshCollector

View file

@ -78,15 +78,13 @@ void MinimapUpdateThread::doUpdate()
while (popBlockUpdate(&update)) {
if (update.data) {
// Swap two values in the map using single lookup
std::pair<std::map<v3s16, MinimapMapblock*>::iterator, bool>
result = m_blocks_cache.insert(std::make_pair(update.pos, update.data));
auto result = m_blocks_cache.insert(std::make_pair(update.pos, update.data));
if (!result.second) {
delete result.first->second;
result.first->second = update.data;
}
} else {
std::map<v3s16, MinimapMapblock *>::iterator it;
it = m_blocks_cache.find(update.pos);
auto it = m_blocks_cache.find(update.pos);
if (it != m_blocks_cache.end()) {
delete it->second;
m_blocks_cache.erase(it);
@ -124,8 +122,7 @@ void MinimapUpdateThread::getMap(v3s16 pos, s16 size, s16 height)
for (blockpos.Z = blockpos_min.Z; blockpos.Z <= blockpos_max.Z; ++blockpos.Z)
for (blockpos.Y = blockpos_min.Y; blockpos.Y <= blockpos_max.Y; ++blockpos.Y)
for (blockpos.X = blockpos_min.X; blockpos.X <= blockpos_max.X; ++blockpos.X) {
std::map<v3s16, MinimapMapblock *>::const_iterator pblock =
m_blocks_cache.find(blockpos);
auto pblock = m_blocks_cache.find(blockpos);
if (pblock == m_blocks_cache.end())
continue;
const MinimapMapblock &block = *pblock->second;
@ -647,8 +644,7 @@ void Minimap::drawMinimap(core::rect<s32> rect)
f32 sin_angle = std::sin(m_angle * core::DEGTORAD);
f32 cos_angle = std::cos(m_angle * core::DEGTORAD);
s32 marker_size2 = 0.025 * (float)rect.getWidth();;
for (std::list<v2f>::const_iterator
i = m_active_markers.begin();
for (auto i = m_active_markers.begin();
i != m_active_markers.end(); ++i) {
v2f posf = *i;
if (data->minimap_shape_round) {

View file

@ -193,7 +193,7 @@ void Particle::updateVertices(ClientEnvironment *env, video::SColor color)
video::S3DVertex *vertices = m_buffer->getVertices(m_index);
if (m_texture.tex != nullptr)
scale = m_texture.tex -> scale.blend(m_time / (m_expiration+0.1));
scale = m_texture.tex -> scale.blend(m_time / (m_expiration+0.1f));
else
scale = v2f(1.f, 1.f);
@ -203,7 +203,7 @@ void Particle::updateVertices(ClientEnvironment *env, video::SColor color)
v2u32 framesize;
texcoord = m_p.animation.getTextureCoords(texsize, m_animation_frame);
m_p.animation.determineParams(texsize, NULL, NULL, &framesize);
framesize_f = v2f(framesize.X / (float) texsize.X, framesize.Y / (float) texsize.Y);
framesize_f = v2f::from(framesize) / v2f::from(texsize);
tx0 = m_texpos.X + texcoord.X;
tx1 = m_texpos.X + texcoord.X + framesize_f.X * m_texsize.X;

View file

@ -34,9 +34,9 @@ void FpsControl::reset()
last_time = porting::getTimeUs();
}
void FpsControl::limit(IrrlichtDevice *device, f32 *dtime, bool assume_paused)
void FpsControl::limit(IrrlichtDevice *device, f32 *dtime)
{
const float fps_limit = (device->isWindowFocused() && !assume_paused)
const float fps_limit = device->isWindowFocused()
? g_settings->getFloat("fps_max")
: g_settings->getFloat("fps_max_unfocused");
const u64 frametime_min = 1000000.0f / std::max(fps_limit, 1.0f);

View file

@ -45,7 +45,7 @@ struct FpsControl {
void reset();
void limit(IrrlichtDevice *device, f32 *dtime, bool assume_paused = false);
void limit(IrrlichtDevice *device, f32 *dtime);
u32 getBusyMs() const { return busy_time / 1000; }

View file

@ -32,6 +32,7 @@ void DirectionalLight::createSplitMatrices(const Camera *cam)
// adjusted frustum boundaries
float sfNear = future_frustum.zNear;
float sfFar = adjustDist(future_frustum.zFar, cam->getFovY());
assert(sfFar - sfNear > 0);
// adjusted camera positions
v3f cam_pos_world = cam->getPosition();
@ -74,7 +75,6 @@ void DirectionalLight::createSplitMatrices(const Camera *cam)
future_frustum.ViewMat.buildCameraLookAtMatrixLH(eye, center_scene, v3f(0.0f, 1.0f, 0.0f));
future_frustum.ProjOrthMat.buildProjectionMatrixOrthoLH(radius, radius,
0.0f, length, false);
future_frustum.camera_offset = cam->getOffset();
}
DirectionalLight::DirectionalLight(const u32 shadowMapResolution,
@ -86,6 +86,8 @@ DirectionalLight::DirectionalLight(const u32 shadowMapResolution,
void DirectionalLight::updateCameraOffset(const Camera *cam)
{
if (future_frustum.zFar == 0.0f) // not initialized
return;
createSplitMatrices(cam);
should_update_map_shadow = true;
dirty = true;

View file

@ -22,7 +22,6 @@ struct shadowFrustum
core::matrix4 ViewMat;
v3f position;
v3f player;
v3s16 camera_offset;
};
class DirectionalLight
@ -85,6 +84,7 @@ public:
return mapRes;
}
/// If true, shadow map needs to be invalidated due to frustum change
bool should_update_map_shadow{true};
void commitFrustum();

View file

@ -177,14 +177,15 @@ void ShadowRenderer::removeNodeFromShadowList(scene::ISceneNode *node)
node->forEachMaterial([] (auto &mat) {
mat.setTexture(TEXTURE_LAYER_SHADOW, nullptr);
});
for (auto it = m_shadow_node_array.begin(); it != m_shadow_node_array.end();) {
if (it->node == node) {
it = m_shadow_node_array.erase(it);
break;
} else {
++it;
}
auto it = std::find(m_shadow_node_array.begin(), m_shadow_node_array.end(), node);
if (it == m_shadow_node_array.end()) {
infostream << "removeNodeFromShadowList: " << node << " not found" << std::endl;
return;
}
// swap with last, then remove
*it = m_shadow_node_array.back();
m_shadow_node_array.pop_back();
}
void ShadowRenderer::updateSMTextures()
@ -254,17 +255,14 @@ void ShadowRenderer::updateSMTextures()
if (!m_shadow_node_array.empty()) {
bool reset_sm_texture = false;
// detect if SM should be regenerated
// clear texture if requested
for (DirectionalLight &light : m_light_list) {
if (light.should_update_map_shadow)
m_force_update_shadow_map = true;
reset_sm_texture |= light.should_update_map_shadow;
light.should_update_map_shadow = false;
}
if (m_force_update_shadow_map) {
if (reset_sm_texture || m_force_update_shadow_map)
m_current_frame = 0;
reset_sm_texture = true;
}
video::ITexture* shadowMapTargetTexture = shadowMapClientMapFuture;
if (shadowMapTargetTexture == nullptr)
@ -273,7 +271,7 @@ void ShadowRenderer::updateSMTextures()
// Update SM incrementally:
for (DirectionalLight &light : m_light_list) {
// Static shader values.
for (auto cb : {m_shadow_depth_cb, m_shadow_depth_entity_cb, m_shadow_depth_trans_cb})
for (auto cb : {m_shadow_depth_cb, m_shadow_depth_entity_cb, m_shadow_depth_trans_cb}) {
if (cb) {
cb->MapRes = (f32)m_shadow_map_texture_size;
cb->MaxFar = (f32)m_shadow_map_max_distance * BS;
@ -281,12 +279,9 @@ void ShadowRenderer::updateSMTextures()
cb->PerspectiveBiasZ = getPerspectiveBiasZ();
cb->CameraPos = light.getFuturePlayerPos();
}
}
// set the Render Target
// right now we can only render in usual RTT, not
// Depth texture is available in irrlicth maybe we
// should put some gl* fn here
// Note that force_update means we're drawing everything one go.
if (m_current_frame < m_map_shadow_update_frames || m_force_update_shadow_map) {
m_driver->setRenderTarget(shadowMapTargetTexture, reset_sm_texture, true,

View file

@ -28,7 +28,8 @@ struct NodeToApply
E_SHADOW_MODE m = E_SHADOW_MODE::ESM_BOTH) :
node(n),
shadowMode(m){};
bool operator<(const NodeToApply &other) const { return node < other.node; };
bool operator==(scene::ISceneNode *n) const { return node == n; }
scene::ISceneNode *node;
@ -68,6 +69,7 @@ public:
void removeNodeFromShadowList(scene::ISceneNode *node);
void update(video::ITexture *outputTarget = nullptr);
/// Force shadow map to be re-drawn in one go next frame
void setForceUpdateShadowMap() { m_force_update_shadow_map = true; }
void drawDebug();

View file

@ -4,41 +4,10 @@
#include "tile.h"
// Sets everything else except the texture in the material
void TileLayer::applyMaterialOptions(video::SMaterial &material) const
void TileLayer::applyMaterialOptions(video::SMaterial &material, int layer) const
{
switch (material_type) {
case TILE_MATERIAL_OPAQUE:
case TILE_MATERIAL_LIQUID_OPAQUE:
case TILE_MATERIAL_WAVING_LIQUID_OPAQUE:
material.MaterialType = video::EMT_SOLID;
break;
case TILE_MATERIAL_BASIC:
case TILE_MATERIAL_WAVING_LEAVES:
case TILE_MATERIAL_WAVING_PLANTS:
case TILE_MATERIAL_WAVING_LIQUID_BASIC:
material.MaterialTypeParam = 0.5;
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
break;
case TILE_MATERIAL_ALPHA:
case TILE_MATERIAL_LIQUID_TRANSPARENT:
case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT:
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
break;
default:
break;
}
material.BackfaceCulling = (material_flags & MATERIAL_FLAG_BACKFACE_CULLING) != 0;
if (!(material_flags & MATERIAL_FLAG_TILEABLE_HORIZONTAL)) {
material.TextureLayers[0].TextureWrapU = video::ETC_CLAMP_TO_EDGE;
}
if (!(material_flags & MATERIAL_FLAG_TILEABLE_VERTICAL)) {
material.TextureLayers[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE;
}
}
material.setTexture(0, texture);
void TileLayer::applyMaterialOptionsWithShaders(video::SMaterial &material) const
{
material.BackfaceCulling = (material_flags & MATERIAL_FLAG_BACKFACE_CULLING) != 0;
if (!(material_flags & MATERIAL_FLAG_TILEABLE_HORIZONTAL)) {
material.TextureLayers[0].TextureWrapU = video::ETC_CLAMP_TO_EDGE;
@ -48,4 +17,15 @@ void TileLayer::applyMaterialOptionsWithShaders(video::SMaterial &material) cons
material.TextureLayers[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE;
material.TextureLayers[1].TextureWrapV = video::ETC_CLAMP_TO_EDGE;
}
/*
* The second layer is for overlays, but uses the same vertex positions
* as the first, which easily leads to Z-fighting.
* To fix this we can offset the polygons in the direction of the camera.
* This only affects the depth buffer and leads to no visual gaps in geometry.
*/
if (layer == 1) {
material.PolygonOffsetSlopeScale = -1;
material.PolygonOffsetDepthBias = -1;
}
}

View file

@ -9,7 +9,7 @@
#include <vector>
#include <SMaterial.h>
enum MaterialType{
enum MaterialType : u8 {
TILE_MATERIAL_BASIC,
TILE_MATERIAL_ALPHA,
TILE_MATERIAL_LIQUID_TRANSPARENT,
@ -84,9 +84,13 @@ struct TileLayer
return !(*this == other);
}
void applyMaterialOptions(video::SMaterial &material) const;
void applyMaterialOptionsWithShaders(video::SMaterial &material) const;
/**
* Set some material parameters accordingly.
* @note does not set `MaterialType`
* @param material material to mody
* @param layer index of this layer in the `TileSpec`
*/
void applyMaterialOptions(video::SMaterial &material, int layer) const;
/// @return is this layer semi-transparent?
bool isTransparent() const
@ -98,8 +102,9 @@ struct TileLayer
case TILE_MATERIAL_LIQUID_TRANSPARENT:
case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT:
return true;
default:
return false;
}
return false;
}
// Ordered for size, please do not reorder
@ -113,13 +118,14 @@ struct TileLayer
u16 animation_frame_length_ms = 0;
u16 animation_frame_count = 1;
u8 material_type = TILE_MATERIAL_BASIC;
MaterialType material_type = TILE_MATERIAL_BASIC;
u8 material_flags =
//0 // <- DEBUG, Use the one below
MATERIAL_FLAG_BACKFACE_CULLING |
MATERIAL_FLAG_TILEABLE_HORIZONTAL|
MATERIAL_FLAG_TILEABLE_VERTICAL;
/// @note not owned by this struct
std::vector<FrameSpec> *frames = nullptr;
/*!

View file

@ -154,8 +154,7 @@ public:
int maxdim = MYMAX(dim.Width, dim.Height);
std::map<int, scene::IMesh*>::iterator
it = m_extrusion_meshes.lower_bound(maxdim);
auto it = m_extrusion_meshes.lower_bound(maxdim);
if (it == m_extrusion_meshes.end()) {
// no viable resolution found; use largest one
@ -204,7 +203,6 @@ WieldMeshSceneNode::WieldMeshSceneNode(scene::ISceneManager *mgr, s32 id):
// Create the child scene node
scene::IMesh *dummymesh = g_extrusion_mesh_cache->createCube();
m_meshnode = SceneManager->addMeshSceneNode(dummymesh, this, -1);
m_meshnode->setReadOnlyMaterials(false);
m_meshnode->setVisible(false);
dummymesh->drop(); // m_meshnode grabbed it
@ -327,13 +325,8 @@ static scene::SMesh *createGenericNodeMesh(Client *client, MapNode n,
buf->append(&p.vertices[0], p.vertices.size(),
&p.indices[0], p.indices.size());
// Set up material
buf->Material.setTexture(0, p.layer.texture);
if (layer == 1) {
buf->Material.PolygonOffsetSlopeScale = -1;
buf->Material.PolygonOffsetDepthBias = -1;
}
p.layer.applyMaterialOptions(buf->Material);
// note: material type is left unset, overriden later
p.layer.applyMaterialOptions(buf->Material, layer);
mesh->addMeshBuffer(buf.get());
colors->emplace_back(p.layer.has_color, p.layer.color);
@ -433,7 +426,7 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che
u32 material_count = m_meshnode->getMaterialCount();
for (u32 i = 0; i < material_count; ++i) {
video::SMaterial &material = m_meshnode->getMaterial(i);
// FIXME: overriding this breaks different alpha modes the mesh may have
// FIXME: we should take different alpha modes of the mesh into account here
material.MaterialType = m_material_type;
material.MaterialTypeParam = 0.5f;
material.forEachTexture([this] (auto &tex) {

View file

@ -72,6 +72,14 @@ inline v3f truncate(const v3f vec, const f32 factor)
);
}
inline v3f rangelimv(const v3f vec, const f32 low, const f32 high)
{
return v3f(
rangelim(vec.X, low, high),
rangelim(vec.Y, low, high),
rangelim(vec.Z, low, high)
);
}
}
// Helper function:
@ -101,6 +109,8 @@ CollisionAxis axisAlignedCollision(
if (speed.Y) {
distance = relbox.MaxEdge.Y - relbox.MinEdge.Y;
// FIXME: The dtime calculation is inaccurate without acceleration information.
// Exact formula: `dtime = (-vel ± sqrt(vel² + 2 * acc * distance)) / acc`
*dtime = distance / std::abs(speed.Y);
time = std::max(*dtime, 0.0f);
@ -214,16 +224,50 @@ static bool add_area_node_boxes(const v3s16 min, const v3s16 max, IGameDef *game
thread_local std::vector<aabb3f> nodeboxes;
Map *map = &env->getMap();
const bool air_walkable = nodedef->get(CONTENT_AIR).walkable;
v3s16 last_bp(S16_MAX);
MapBlock *last_block = nullptr;
// Note: as the area used here is usually small, iterating entire blocks
// would actually be slower by factor of 10.
v3s16 p;
for (p.Z = min.Z; p.Z <= max.Z; p.Z++)
for (p.Y = min.Y; p.Y <= max.Y; p.Y++)
for (p.X = min.X; p.X <= max.X; p.X++) {
bool is_position_valid;
MapNode n = map->getNode(p, &is_position_valid);
v3s16 bp, relp;
getNodeBlockPosWithOffset(p, bp, relp);
if (bp != last_bp) {
last_block = map->getBlockNoCreateNoEx(bp);
last_bp = bp;
}
MapBlock *const block = last_block;
if (is_position_valid && n.getContent() != CONTENT_IGNORE) {
// Object collides into walkable nodes
if (!block) {
// Since we iterate with node precision we can only safely skip
// ahead in the "innermost" axis of the MapBlock (X).
// This still worth it as it reduces the number of nodes to look at
// and entries in `cinfo`.
v3s16 rowend(bp.X * MAP_BLOCKSIZE + MAP_BLOCKSIZE - 1, p.Y, p.Z);
aabb3f box = getNodeBox(p, BS);
box.addInternalBox(getNodeBox(rowend, BS));
// Collide with unloaded block
cinfo.emplace_back(true, 0, p, box);
p.X = rowend.X;
continue;
}
if (!air_walkable && block->isAir()) {
// Skip ahead if air, like above
any_position_valid = true;
p.X = bp.X * MAP_BLOCKSIZE + MAP_BLOCKSIZE - 1;
continue;
}
const MapNode n = block->getNodeNoCheck(relp);
if (n.getContent() != CONTENT_IGNORE) {
any_position_valid = true;
const ContentFeatures &f = nodedef->get(n);
@ -238,7 +282,6 @@ static bool add_area_node_boxes(const v3s16 min, const v3s16 max, IGameDef *game
nodeboxes.clear();
n.getCollisionBoxes(nodedef, &nodeboxes, neighbors);
// Calculate float position only once
v3f posf = intToFloat(p, BS);
for (auto box : nodeboxes) {
box.MinEdge += posf;
@ -246,12 +289,12 @@ static bool add_area_node_boxes(const v3s16 min, const v3s16 max, IGameDef *game
cinfo.emplace_back(false, n_bouncy_value, p, box);
}
} else {
// Collide with unloaded nodes (position invalid) and loaded
// CONTENT_IGNORE nodes (position valid)
// Collide with loaded CONTENT_IGNORE nodes
aabb3f box = getNodeBox(p, BS);
cinfo.emplace_back(true, 0, p, box);
}
}
return any_position_valid;
}
@ -335,6 +378,10 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
collisionMoveResult result;
// Assume no collisions when no velocity and no acceleration
if (*speed_f == v3f() && accel_f == v3f())
return result;
/*
Calculate new velocity
*/
@ -350,30 +397,19 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
time_notification_done = false;
}
v3f dpos_f = (*speed_f + accel_f * 0.5f * dtime) * dtime;
v3f newpos_f = *pos_f + dpos_f;
*speed_f += accel_f * dtime;
// If the object is static, there are no collisions
if (dpos_f == v3f())
return result;
// Average speed
v3f aspeed_f = *speed_f + accel_f * 0.5f * dtime;
// Limit speed for avoiding hangs
speed_f->Y = rangelim(speed_f->Y, -5000, 5000);
speed_f->X = rangelim(speed_f->X, -5000, 5000);
speed_f->Z = rangelim(speed_f->Z, -5000, 5000);
aspeed_f = truncate(rangelimv(aspeed_f, -5000.0f, 5000.0f), 10000.0f);
*speed_f = truncate(*speed_f, 10000.0f);
/*
Collect node boxes in movement range
*/
// Collect node boxes in movement range
// cached allocation
thread_local std::vector<NearbyCollisionInfo> cinfo;
cinfo.clear();
{
// Movement if no collisions
v3f newpos_f = *pos_f + aspeed_f * dtime;
v3f minpos_f(
MYMIN(pos_f->X, newpos_f.X),
MYMIN(pos_f->Y, newpos_f.Y) + 0.01f * BS, // bias rounding, player often at +/-n.5
@ -399,24 +435,14 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
}
}
/*
Collect object boxes in movement range
*/
// Collect object boxes in movement range
if (collide_with_objects) {
add_object_boxes(env, box_0, dtime, *pos_f, *speed_f, self, cinfo);
add_object_boxes(env, box_0, dtime, *pos_f, aspeed_f, self, cinfo);
}
/*
Collision detection
*/
// Collision detection
f32 d = 0.0f;
int loopcount = 0;
while(dtime > BS * 1e-10f) {
// Avoid infinite loop
loopcount++;
for (int loopcount = 0;; loopcount++) {
if (loopcount >= 100) {
warningstream << "collisionMoveSimple: Loop count exceeded, aborting to avoid infinite loop" << std::endl;
g_collision_problems_encountered = true;
@ -431,9 +457,7 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
f32 nearest_dtime = dtime;
int nearest_boxindex = -1;
/*
Go through every nodebox, find nearest collision
*/
// Go through every nodebox, find nearest collision
for (u32 boxindex = 0; boxindex < cinfo.size(); boxindex++) {
const NearbyCollisionInfo &box_info = cinfo[boxindex];
// Ignore if already stepped up this nodebox.
@ -443,8 +467,7 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
// Find nearest collision of the two boxes (raytracing-like)
f32 dtime_tmp = nearest_dtime;
CollisionAxis collided = axisAlignedCollision(box_info.box,
movingbox, *speed_f, &dtime_tmp);
movingbox, aspeed_f, &dtime_tmp);
if (collided == -1 || dtime_tmp >= nearest_dtime)
continue;
@ -455,95 +478,119 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
if (nearest_collided == COLLISION_AXIS_NONE) {
// No collision with any collision box.
*pos_f += truncate(*speed_f * dtime, 100.0f);
dtime = 0; // Set to 0 to avoid "infinite" loop due to small FP numbers
} else {
// Otherwise, a collision occurred.
NearbyCollisionInfo &nearest_info = cinfo[nearest_boxindex];
const aabb3f& cbox = nearest_info.box;
*pos_f += aspeed_f * dtime;
// Final speed:
*speed_f += accel_f * dtime;
// Limit speed for avoiding hangs
*speed_f = truncate(rangelimv(*speed_f, -5000.0f, 5000.0f), 10000.0f);
break;
}
// Otherwise, a collision occurred.
NearbyCollisionInfo &nearest_info = cinfo[nearest_boxindex];
const aabb3f& cbox = nearest_info.box;
//movingbox except moved to the horizontal position it would be after step up
//movingbox except moved to the horizontal position it would be after step up
bool step_up = false;
if (nearest_collided != COLLISION_AXIS_Y) {
aabb3f stepbox = movingbox;
stepbox.MinEdge.X += speed_f->X * dtime;
stepbox.MinEdge.Z += speed_f->Z * dtime;
stepbox.MaxEdge.X += speed_f->X * dtime;
stepbox.MaxEdge.Z += speed_f->Z * dtime;
// Look slightly ahead for checking the height when stepping
// to ensure we also check above the node we collided with
// otherwise, might allow glitches such as a stack of stairs
float extra_dtime = nearest_dtime + 0.1f * fabsf(dtime - nearest_dtime);
stepbox.MinEdge.X += aspeed_f.X * extra_dtime;
stepbox.MinEdge.Z += aspeed_f.Z * extra_dtime;
stepbox.MaxEdge.X += aspeed_f.X * extra_dtime;
stepbox.MaxEdge.Z += aspeed_f.Z * extra_dtime;
// Check for stairs.
bool step_up = (nearest_collided != COLLISION_AXIS_Y) && // must not be Y direction
(movingbox.MinEdge.Y < cbox.MaxEdge.Y) &&
(movingbox.MinEdge.Y + stepheight > cbox.MaxEdge.Y) &&
(!wouldCollideWithCeiling(cinfo, stepbox,
cbox.MaxEdge.Y - movingbox.MinEdge.Y,
d));
step_up = (movingbox.MinEdge.Y < cbox.MaxEdge.Y) &&
(movingbox.MinEdge.Y + stepheight > cbox.MaxEdge.Y) &&
(!wouldCollideWithCeiling(cinfo, stepbox,
cbox.MaxEdge.Y - movingbox.MinEdge.Y,
d));
}
// Get bounce multiplier
float bounce = -(float)nearest_info.bouncy / 100.0f;
// Get bounce multiplier
float bounce = -(float)nearest_info.bouncy / 100.0f;
// Move to the point of collision and reduce dtime by nearest_dtime
if (nearest_dtime < 0) {
// Handle negative nearest_dtime
if (!step_up) {
if (nearest_collided == COLLISION_AXIS_X)
pos_f->X += speed_f->X * nearest_dtime;
if (nearest_collided == COLLISION_AXIS_Y)
pos_f->Y += speed_f->Y * nearest_dtime;
if (nearest_collided == COLLISION_AXIS_Z)
pos_f->Z += speed_f->Z * nearest_dtime;
}
} else {
*pos_f += truncate(*speed_f * nearest_dtime, 100.0f);
dtime -= nearest_dtime;
// Move to the point of collision and reduce dtime by nearest_dtime
if (nearest_dtime < 0) {
// Handle negative nearest_dtime
// This largely means an "instant" collision, e.g., with the floor.
// We use aspeed and nearest_dtime to be consistent with above and resolve this collision
if (!step_up) {
if (nearest_collided == COLLISION_AXIS_X)
pos_f->X += aspeed_f.X * nearest_dtime;
if (nearest_collided == COLLISION_AXIS_Y)
pos_f->Y += aspeed_f.Y * nearest_dtime;
if (nearest_collided == COLLISION_AXIS_Z)
pos_f->Z += aspeed_f.Z * nearest_dtime;
}
} else if (nearest_dtime > 0) {
// updated average speed for the sub-interval up to nearest_dtime
aspeed_f = *speed_f + accel_f * 0.5f * nearest_dtime;
*pos_f += aspeed_f * nearest_dtime;
// Speed at (approximated) collision:
*speed_f += accel_f * nearest_dtime;
// Limit speed for avoiding hangs
*speed_f = truncate(rangelimv(*speed_f, -5000.0f, 5000.0f), 10000.0f);
dtime -= nearest_dtime;
}
bool is_collision = true;
if (nearest_info.is_unloaded)
is_collision = false;
v3f old_speed_f = *speed_f;
// Set the speed component that caused the collision to zero
if (step_up) {
// Special case: Handle stairs
nearest_info.is_step_up = true;
} else if (nearest_collided == COLLISION_AXIS_X) {
if (bounce < -1e-4 && fabsf(speed_f->X) > BS * 3) {
speed_f->X *= bounce;
} else {
speed_f->X = 0;
accel_f.X = 0; // avoid colliding in the next interations
}
} else if (nearest_collided == COLLISION_AXIS_Y) {
if (bounce < -1e-4 && fabsf(speed_f->Y) > BS * 3) {
speed_f->Y *= bounce;
} else {
if (speed_f->Y < 0.0f) {
// FIXME: This code is necessary until `axisAlignedCollision` takes acceleration
// into consideration for the time calculation. Otherwise, the colliding faces
// never line up, especially at high step (dtime) intervals.
result.touching_ground = true;
result.standing_on_object = nearest_info.isObject();
}
speed_f->Y = 0;
accel_f.Y = 0; // avoid colliding in the next interations
}
} else { /* nearest_collided == COLLISION_AXIS_Z */
if (bounce < -1e-4 && fabsf(speed_f->Z) > BS * 3) {
speed_f->Z *= bounce;
} else {
speed_f->Z = 0;
accel_f.Z = 0; // avoid colliding in the next interations
}
}
if (!nearest_info.is_unloaded && !step_up) {
CollisionInfo info;
if (nearest_info.isObject())
info.type = COLLISION_OBJECT;
else
info.type = COLLISION_NODE;
info.axis = nearest_collided;
info.type = nearest_info.isObject() ? COLLISION_OBJECT : COLLISION_NODE;
info.node_p = nearest_info.position;
info.object = nearest_info.obj;
info.new_pos = *pos_f;
info.old_speed = *speed_f;
// Set the speed component that caused the collision to zero
if (step_up) {
// Special case: Handle stairs
nearest_info.is_step_up = true;
is_collision = false;
} else if (nearest_collided == COLLISION_AXIS_X) {
if (fabs(speed_f->X) > BS * 3)
speed_f->X *= bounce;
else
speed_f->X = 0;
result.collides = true;
} else if (nearest_collided == COLLISION_AXIS_Y) {
if(fabs(speed_f->Y) > BS * 3)
speed_f->Y *= bounce;
else
speed_f->Y = 0;
result.collides = true;
} else if (nearest_collided == COLLISION_AXIS_Z) {
if (fabs(speed_f->Z) > BS * 3)
speed_f->Z *= bounce;
else
speed_f->Z = 0;
result.collides = true;
}
info.old_speed = old_speed_f;
info.new_speed = *speed_f;
if (info.new_speed.getDistanceFrom(info.old_speed) < 0.1f * BS)
is_collision = false;
if (is_collision) {
info.axis = nearest_collided;
result.collisions.push_back(std::move(info));
}
result.collisions.push_back(info);
}
if (dtime < BS * 1e-10f)
break;
// Speed for finding the next collision
aspeed_f = *speed_f + accel_f * 0.5f * dtime;
// Limit speed for avoiding hangs
aspeed_f = truncate(rangelimv(aspeed_f, -5000.0f, 5000.0f), 10000.0f);
}
/*
@ -573,14 +620,15 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
box.MaxEdge += *pos_f;
}
if (std::fabs(cbox.MaxEdge.Y - box.MinEdge.Y) < 0.05f) {
// This is code is technically only required if `box_info.is_step_up == true`.
// However, players rely on this check/condition to climb stairs faster. See PR #10587.
result.touching_ground = true;
if (box_info.isObject())
result.standing_on_object = true;
result.standing_on_object = box_info.isObject();
}
}
}
result.collides = !result.collisions.empty();
return result;
}

View file

@ -140,8 +140,6 @@ void ModConfiguration::addModsFromConfig(
*
* Alternative candidates for a modname are stored in `candidates`,
* and used in an error message later.
*
* If not enabled, add `load_mod_modname = false` to world.mt
*/
for (const auto &modPath : modPaths) {
std::vector<ModSpec> addon_mods_in_path = flattenMods(getModsInPath(modPath.second, modPath.first));
@ -154,7 +152,7 @@ void ModConfiguration::addModsFromConfig(
candidates[pair->first].emplace_back(mod.virtual_path);
}
} else {
conf.setBool("load_mod_" + mod.name, false);
conf.remove("load_mod_" + mod.name);
}
}
}

View file

@ -30,15 +30,13 @@ void Database_Dummy::loadBlock(const v3s16 &pos, std::string *block)
bool Database_Dummy::deleteBlock(const v3s16 &pos)
{
m_database.erase(getBlockAsInteger(pos));
return true;
return m_database.erase(getBlockAsInteger(pos)) > 0;
}
void Database_Dummy::listAllLoadableBlocks(std::vector<v3s16> &dst)
{
dst.reserve(m_database.size());
for (std::map<s64, std::string>::const_iterator x = m_database.begin();
x != m_database.end(); ++x) {
for (auto x = m_database.begin(); x != m_database.end(); ++x) {
dst.push_back(getIntegerAsBlock(x->first));
}
}

View file

@ -234,8 +234,7 @@ void PlayerDatabaseFiles::listPlayers(std::vector<std::string> &res)
{
std::vector<fs::DirListNode> files = fs::GetDirListing(m_savedir);
// list files into players directory
for (std::vector<fs::DirListNode>::const_iterator it = files.begin(); it !=
files.end(); ++it) {
for (auto it = files.begin(); it != files.end(); ++it) {
// Ignore directories
if (it->dir)
continue;

View file

@ -97,7 +97,7 @@ void Database_PostgreSQL::ping()
bool Database_PostgreSQL::initialized() const
{
return (PQstatus(m_conn) == CONNECTION_OK);
return m_conn && PQstatus(m_conn) == CONNECTION_OK;
}
PGresult *Database_PostgreSQL::checkResults(PGresult *result, bool clear)

View file

@ -9,20 +9,20 @@
#include "database.h"
#include "util/basic_macros.h"
class Settings;
class Database_PostgreSQL: public Database
// Template class for PostgreSQL based data storage
class Database_PostgreSQL : public Database
{
public:
Database_PostgreSQL(const std::string &connect_string, const char *type);
~Database_PostgreSQL();
void beginSave();
void endSave();
void beginSave() override;
void endSave() override;
void rollback();
bool initialized() const;
bool initialized() const override;
void verifyDatabase() override;
protected:
// Conversion helpers
@ -73,7 +73,6 @@ protected:
}
void createTableIfNotExists(const std::string &table_name, const std::string &definition);
void verifyDatabase();
// Database initialization
void connectToDatabase();
@ -99,6 +98,12 @@ private:
int m_pgversion = 0;
};
// Not sure why why we have to do this. can't C++ figure it out on its own?
#define PARENT_CLASS_FUNCS \
void beginSave() { Database_PostgreSQL::beginSave(); } \
void endSave() { Database_PostgreSQL::endSave(); } \
void verifyDatabase() { Database_PostgreSQL::verifyDatabase(); }
class MapDatabasePostgreSQL : private Database_PostgreSQL, public MapDatabase
{
public:
@ -110,8 +115,7 @@ public:
bool deleteBlock(const v3s16 &pos);
void listAllLoadableBlocks(std::vector<v3s16> &dst);
void beginSave() { Database_PostgreSQL::beginSave(); }
void endSave() { Database_PostgreSQL::endSave(); }
PARENT_CLASS_FUNCS
protected:
virtual void createDatabase();
@ -129,6 +133,8 @@ public:
bool removePlayer(const std::string &name);
void listPlayers(std::vector<std::string> &res);
PARENT_CLASS_FUNCS
protected:
virtual void createDatabase();
virtual void initStatements();
@ -143,8 +149,6 @@ public:
AuthDatabasePostgreSQL(const std::string &connect_string);
virtual ~AuthDatabasePostgreSQL() = default;
virtual void verifyDatabase() { Database_PostgreSQL::verifyDatabase(); }
virtual bool getAuth(const std::string &name, AuthEntry &res);
virtual bool saveAuth(const AuthEntry &authEntry);
virtual bool createAuth(AuthEntry &authEntry);
@ -152,6 +156,8 @@ public:
virtual void listNames(std::vector<std::string> &res);
virtual void reload();
PARENT_CLASS_FUNCS
protected:
virtual void createDatabase();
virtual void initStatements();
@ -176,10 +182,11 @@ public:
bool removeModEntries(const std::string &modname);
void listMods(std::vector<std::string> *res);
void beginSave() { Database_PostgreSQL::beginSave(); }
void endSave() { Database_PostgreSQL::endSave(); }
PARENT_CLASS_FUNCS
protected:
virtual void createDatabase();
virtual void initStatements();
};
#undef PARENT_CLASS_FUNCS

View file

@ -2,14 +2,6 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
// Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
/*
SQLite format specification:
blocks:
(PK) INT id
BLOB data
*/
#include "database-sqlite3.h"
#include "log.h"
@ -26,23 +18,19 @@ SQLite format specification:
// When to print messages when the database is being held locked by another process
// Note: I've seen occasional delays of over 250ms while running minetestmapper.
#define BUSY_INFO_TRESHOLD 100 // Print first informational message after 100ms.
#define BUSY_WARNING_TRESHOLD 250 // Print warning message after 250ms. Lag is increased.
#define BUSY_ERROR_TRESHOLD 1000 // Print error message after 1000ms. Significant lag.
#define BUSY_FATAL_TRESHOLD 3000 // Allow SQLITE_BUSY to be returned, which will cause a minetest crash.
#define BUSY_ERROR_INTERVAL 10000 // Safety net: report again every 10 seconds
enum {
BUSY_INFO_TRESHOLD = 100, // Print first informational message.
BUSY_WARNING_TRESHOLD = 250, // Print warning message. Significant lag.
BUSY_FATAL_TRESHOLD = 3000, // Allow SQLITE_BUSY to be returned back to the caller.
BUSY_ERROR_INTERVAL = 10000, // Safety net: report again every 10 seconds
};
#define SQLRES(s, r, m) \
if ((s) != (r)) { \
throw DatabaseException(std::string(m) + ": " +\
sqlite3_errmsg(m_database)); \
}
#define SQLRES(s, r, m) sqlite3_vrfy(s, m, r);
#define SQLOK(s, m) SQLRES(s, SQLITE_OK, m)
#define PREPARE_STATEMENT(name, query) \
SQLOK(sqlite3_prepare_v2(m_database, query, -1, &m_stmt_##name, NULL),\
"Failed to prepare query '" query "'")
SQLOK(sqlite3_prepare_v2(m_database, query, -1, &m_stmt_##name, NULL), \
std::string("Failed to prepare query \"").append(query).append("\""))
#define SQLOK_ERRSTREAM(s, m) \
if ((s) != SQLITE_OK) { \
@ -50,52 +38,49 @@ SQLite format specification:
<< sqlite3_errmsg(m_database) << std::endl; \
}
#define FINALIZE_STATEMENT(statement) SQLOK_ERRSTREAM(sqlite3_finalize(statement), \
"Failed to finalize " #statement)
#define FINALIZE_STATEMENT(name) \
sqlite3_finalize(m_stmt_##name); /* if this fails who cares */ \
m_stmt_##name = nullptr;
int Database_SQLite3::busyHandler(void *data, int count)
{
s64 &first_time = reinterpret_cast<s64 *>(data)[0];
s64 &prev_time = reinterpret_cast<s64 *>(data)[1];
s64 cur_time = porting::getTimeMs();
u64 &first_time = reinterpret_cast<u64*>(data)[0];
u64 &prev_time = reinterpret_cast<u64*>(data)[1];
u64 cur_time = porting::getTimeMs();
if (count == 0) {
first_time = cur_time;
prev_time = first_time;
} else {
while (cur_time < prev_time)
cur_time += s64(1)<<32;
}
if (cur_time - first_time < BUSY_INFO_TRESHOLD) {
; // do nothing
} else if (cur_time - first_time >= BUSY_INFO_TRESHOLD &&
prev_time - first_time < BUSY_INFO_TRESHOLD) {
const auto total_diff = cur_time - first_time; // time since first call
const auto this_diff = prev_time - first_time; // time since last call
if (total_diff < BUSY_INFO_TRESHOLD) {
// do nothing
} else if (total_diff >= BUSY_INFO_TRESHOLD &&
this_diff < BUSY_INFO_TRESHOLD) {
infostream << "SQLite3 database has been locked for "
<< cur_time - first_time << " ms." << std::endl;
} else if (cur_time - first_time >= BUSY_WARNING_TRESHOLD &&
prev_time - first_time < BUSY_WARNING_TRESHOLD) {
<< total_diff << " ms." << std::endl;
} else if (total_diff >= BUSY_WARNING_TRESHOLD &&
this_diff < BUSY_WARNING_TRESHOLD) {
warningstream << "SQLite3 database has been locked for "
<< cur_time - first_time << " ms." << std::endl;
} else if (cur_time - first_time >= BUSY_ERROR_TRESHOLD &&
prev_time - first_time < BUSY_ERROR_TRESHOLD) {
<< total_diff << " ms; this causes lag." << std::endl;
} else if (total_diff >= BUSY_FATAL_TRESHOLD &&
this_diff < BUSY_FATAL_TRESHOLD) {
errorstream << "SQLite3 database has been locked for "
<< cur_time - first_time << " ms; this causes lag." << std::endl;
} else if (cur_time - first_time >= BUSY_FATAL_TRESHOLD &&
prev_time - first_time < BUSY_FATAL_TRESHOLD) {
errorstream << "SQLite3 database has been locked for "
<< cur_time - first_time << " ms - giving up!" << std::endl;
} else if ((cur_time - first_time) / BUSY_ERROR_INTERVAL !=
(prev_time - first_time) / BUSY_ERROR_INTERVAL) {
<< total_diff << " ms - giving up!" << std::endl;
} else if (total_diff / BUSY_ERROR_INTERVAL !=
this_diff / BUSY_ERROR_INTERVAL) {
// Safety net: keep reporting every BUSY_ERROR_INTERVAL
errorstream << "SQLite3 database has been locked for "
<< (cur_time - first_time) / 1000 << " seconds!" << std::endl;
<< total_diff / 1000 << " seconds!" << std::endl;
}
prev_time = cur_time;
// Make sqlite transaction fail if delay exceeds BUSY_FATAL_TRESHOLD
return cur_time - first_time < BUSY_FATAL_TRESHOLD;
return total_diff < BUSY_FATAL_TRESHOLD;
}
@ -130,7 +115,7 @@ void Database_SQLite3::openDatabase()
// Open the database connection
if (!fs::CreateAllDirs(m_savedir)) {
infostream << "Database_SQLite3: Failed to create directory \""
errorstream << "Database_SQLite3: Failed to create directory \""
<< m_savedir << "\"" << std::endl;
throw FileNotGoodException("Failed to create database "
"save directory");
@ -138,8 +123,11 @@ void Database_SQLite3::openDatabase()
bool needs_create = !fs::PathExists(dbp);
SQLOK(sqlite3_open_v2(dbp.c_str(), &m_database,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL),
auto flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
#ifdef SQLITE_OPEN_EXRESCODE
flags |= SQLITE_OPEN_EXRESCODE;
#endif
SQLOK(sqlite3_open_v2(dbp.c_str(), &m_database, flags, NULL),
std::string("Failed to open SQLite3 database file ") + dbp);
SQLOK(sqlite3_busy_handler(m_database, Database_SQLite3::busyHandler,
@ -152,9 +140,9 @@ void Database_SQLite3::openDatabase()
std::string query_str = std::string("PRAGMA synchronous = ")
+ itos(g_settings->getU16("sqlite_synchronous"));
SQLOK(sqlite3_exec(m_database, query_str.c_str(), NULL, NULL, NULL),
"Failed to modify sqlite3 synchronous mode");
"Failed to set SQLite3 synchronous mode");
SQLOK(sqlite3_exec(m_database, "PRAGMA foreign_keys = ON", NULL, NULL, NULL),
"Failed to enable sqlite3 foreign key support");
"Failed to enable SQLite3 foreign key support");
}
void Database_SQLite3::verifyDatabase()
@ -171,10 +159,47 @@ void Database_SQLite3::verifyDatabase()
m_initialized = true;
}
bool Database_SQLite3::checkTable(const char *table)
{
assert(m_database);
// PRAGMA table_list would be cleaner here but it was only introduced in
// sqlite 3.37.0 (2021-11-27).
// So let's do this: https://stackoverflow.com/a/83195
sqlite3_stmt *m_stmt_tmp = nullptr;
PREPARE_STATEMENT(tmp, "SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ?;");
str_to_sqlite(m_stmt_tmp, 1, table);
bool ret = (sqlite3_step(m_stmt_tmp) == SQLITE_ROW);
FINALIZE_STATEMENT(tmp)
return ret;
}
bool Database_SQLite3::checkColumn(const char *table, const char *column)
{
assert(m_database);
sqlite3_stmt *m_stmt_tmp = nullptr;
auto query_str = std::string("PRAGMA table_info(").append(table).append(");");
PREPARE_STATEMENT(tmp, query_str.c_str());
bool ret = false;
while (sqlite3_step(m_stmt_tmp) == SQLITE_ROW) {
ret |= sqlite_to_string_view(m_stmt_tmp, 1) == column;
if (ret)
break;
}
FINALIZE_STATEMENT(tmp)
return ret;
}
Database_SQLite3::~Database_SQLite3()
{
FINALIZE_STATEMENT(m_stmt_begin)
FINALIZE_STATEMENT(m_stmt_end)
FINALIZE_STATEMENT(begin)
FINALIZE_STATEMENT(end)
SQLOK_ERRSTREAM(sqlite3_close(m_database), "Failed to close database");
}
@ -191,40 +216,68 @@ MapDatabaseSQLite3::MapDatabaseSQLite3(const std::string &savedir):
MapDatabaseSQLite3::~MapDatabaseSQLite3()
{
FINALIZE_STATEMENT(m_stmt_read)
FINALIZE_STATEMENT(m_stmt_write)
FINALIZE_STATEMENT(m_stmt_list)
FINALIZE_STATEMENT(m_stmt_delete)
FINALIZE_STATEMENT(read)
FINALIZE_STATEMENT(write)
FINALIZE_STATEMENT(list)
FINALIZE_STATEMENT(delete)
}
void MapDatabaseSQLite3::createDatabase()
{
assert(m_database); // Pre-condition
assert(m_database);
SQLOK(sqlite3_exec(m_database,
// Note: before 5.12.0 the format was blocks(pos INT, data BLOB).
// This function only runs for newly created databases.
const char *schema =
"CREATE TABLE IF NOT EXISTS `blocks` (\n"
" `pos` INT PRIMARY KEY,\n"
" `data` BLOB\n"
");\n",
NULL, NULL, NULL),
"`x` INTEGER,"
"`y` INTEGER,"
"`z` INTEGER,"
"`data` BLOB NOT NULL,"
// Declaring a primary key automatically creates an index and the
// order largely dictates which range operations can be sped up.
// see also: <https://www.sqlite.org/optoverview.html#skipscan>
// Putting XZ before Y matches our MapSector abstraction.
"PRIMARY KEY (`x`, `z`, `y`)"
");\n"
;
SQLOK(sqlite3_exec(m_database, schema, NULL, NULL, NULL),
"Failed to create database table");
}
void MapDatabaseSQLite3::initStatements()
{
PREPARE_STATEMENT(read, "SELECT `data` FROM `blocks` WHERE `pos` = ? LIMIT 1");
PREPARE_STATEMENT(write, "REPLACE INTO `blocks` (`pos`, `data`) VALUES (?, ?)");
PREPARE_STATEMENT(delete, "DELETE FROM `blocks` WHERE `pos` = ?");
PREPARE_STATEMENT(list, "SELECT `pos` FROM `blocks`");
assert(checkTable("blocks"));
m_new_format = checkColumn("blocks", "z");
infostream << "MapDatabaseSQLite3: split column format = "
<< (m_new_format ? "yes" : "no") << std::endl;
verbosestream << "ServerMap: SQLite3 database opened." << std::endl;
if (m_new_format) {
PREPARE_STATEMENT(read, "SELECT `data` FROM `blocks` WHERE `x` = ? AND `y` = ? AND `z` = ? LIMIT 1");
PREPARE_STATEMENT(write, "REPLACE INTO `blocks` (`x`, `y`, `z`, `data`) VALUES (?, ?, ?, ?)");
PREPARE_STATEMENT(delete, "DELETE FROM `blocks` WHERE `x` = ? AND `y` = ? AND `z` = ?");
PREPARE_STATEMENT(list, "SELECT `x`, `y`, `z` FROM `blocks`");
} else {
PREPARE_STATEMENT(read, "SELECT `data` FROM `blocks` WHERE `pos` = ? LIMIT 1");
PREPARE_STATEMENT(write, "REPLACE INTO `blocks` (`pos`, `data`) VALUES (?, ?)");
PREPARE_STATEMENT(delete, "DELETE FROM `blocks` WHERE `pos` = ?");
PREPARE_STATEMENT(list, "SELECT `pos` FROM `blocks`");
}
}
inline void MapDatabaseSQLite3::bindPos(sqlite3_stmt *stmt, const v3s16 &pos, int index)
inline int MapDatabaseSQLite3::bindPos(sqlite3_stmt *stmt, v3s16 pos, int index)
{
SQLOK(sqlite3_bind_int64(stmt, index, getBlockAsInteger(pos)),
"Internal error: failed to bind query at " __FILE__ ":" TOSTRING(__LINE__));
if (m_new_format) {
int_to_sqlite(stmt, index, pos.X);
int_to_sqlite(stmt, index + 1, pos.Y);
int_to_sqlite(stmt, index + 2, pos.Z);
return index + 3;
} else {
int64_to_sqlite(stmt, index, getBlockAsInteger(pos));
return index + 1;
}
}
bool MapDatabaseSQLite3::deleteBlock(const v3s16 &pos)
@ -237,7 +290,7 @@ bool MapDatabaseSQLite3::deleteBlock(const v3s16 &pos)
sqlite3_reset(m_stmt_delete);
if (!good) {
warningstream << "deleteBlock: Block failed to delete "
warningstream << "deleteBlock: Failed to delete block "
<< pos << ": " << sqlite3_errmsg(m_database) << std::endl;
}
return good;
@ -247,9 +300,8 @@ bool MapDatabaseSQLite3::saveBlock(const v3s16 &pos, std::string_view data)
{
verifyDatabase();
bindPos(m_stmt_write, pos);
SQLOK(sqlite3_bind_blob(m_stmt_write, 2, data.data(), data.size(), NULL),
"Internal error: failed to bind query at " __FILE__ ":" TOSTRING(__LINE__));
int col = bindPos(m_stmt_write, pos);
blob_to_sqlite(m_stmt_write, col, data);
SQLRES(sqlite3_step(m_stmt_write), SQLITE_DONE, "Failed to save block")
sqlite3_reset(m_stmt_write);
@ -264,6 +316,7 @@ void MapDatabaseSQLite3::loadBlock(const v3s16 &pos, std::string *block)
bindPos(m_stmt_read, pos);
if (sqlite3_step(m_stmt_read) != SQLITE_ROW) {
block->clear();
sqlite3_reset(m_stmt_read);
return;
}
@ -271,7 +324,6 @@ void MapDatabaseSQLite3::loadBlock(const v3s16 &pos, std::string *block)
auto data = sqlite_to_blob(m_stmt_read, 0);
block->assign(data);
sqlite3_step(m_stmt_read);
// We should never get more than 1 row, so ok to reset
sqlite3_reset(m_stmt_read);
}
@ -280,8 +332,17 @@ void MapDatabaseSQLite3::listAllLoadableBlocks(std::vector<v3s16> &dst)
{
verifyDatabase();
while (sqlite3_step(m_stmt_list) == SQLITE_ROW)
dst.push_back(getIntegerAsBlock(sqlite3_column_int64(m_stmt_list, 0)));
v3s16 p;
while (sqlite3_step(m_stmt_list) == SQLITE_ROW) {
if (m_new_format) {
p.X = sqlite_to_int(m_stmt_list, 0);
p.Y = sqlite_to_int(m_stmt_list, 1);
p.Z = sqlite_to_int(m_stmt_list, 2);
} else {
p = getIntegerAsBlock(sqlite_to_int64(m_stmt_list, 0));
}
dst.push_back(p);
}
sqlite3_reset(m_stmt_list);
}
@ -298,35 +359,38 @@ PlayerDatabaseSQLite3::PlayerDatabaseSQLite3(const std::string &savedir):
PlayerDatabaseSQLite3::~PlayerDatabaseSQLite3()
{
FINALIZE_STATEMENT(m_stmt_player_load)
FINALIZE_STATEMENT(m_stmt_player_add)
FINALIZE_STATEMENT(m_stmt_player_update)
FINALIZE_STATEMENT(m_stmt_player_remove)
FINALIZE_STATEMENT(m_stmt_player_list)
FINALIZE_STATEMENT(m_stmt_player_add_inventory)
FINALIZE_STATEMENT(m_stmt_player_add_inventory_items)
FINALIZE_STATEMENT(m_stmt_player_remove_inventory)
FINALIZE_STATEMENT(m_stmt_player_remove_inventory_items)
FINALIZE_STATEMENT(m_stmt_player_load_inventory)
FINALIZE_STATEMENT(m_stmt_player_load_inventory_items)
FINALIZE_STATEMENT(m_stmt_player_metadata_load)
FINALIZE_STATEMENT(m_stmt_player_metadata_add)
FINALIZE_STATEMENT(m_stmt_player_metadata_remove)
FINALIZE_STATEMENT(player_load)
FINALIZE_STATEMENT(player_add)
FINALIZE_STATEMENT(player_update)
FINALIZE_STATEMENT(player_remove)
FINALIZE_STATEMENT(player_list)
FINALIZE_STATEMENT(player_add_inventory)
FINALIZE_STATEMENT(player_add_inventory_items)
FINALIZE_STATEMENT(player_remove_inventory)
FINALIZE_STATEMENT(player_remove_inventory_items)
FINALIZE_STATEMENT(player_load_inventory)
FINALIZE_STATEMENT(player_load_inventory_items)
FINALIZE_STATEMENT(player_metadata_load)
FINALIZE_STATEMENT(player_metadata_add)
FINALIZE_STATEMENT(player_metadata_remove)
};
void PlayerDatabaseSQLite3::createDatabase()
{
assert(m_database); // Pre-condition
assert(m_database);
// When designing the schema remember that SQLite only has 5 basic data types
// and ignores length-limited types like "VARCHAR(32)".
SQLOK(sqlite3_exec(m_database,
"CREATE TABLE IF NOT EXISTS `player` ("
"`name` VARCHAR(50) NOT NULL,"
"`pitch` NUMERIC(11, 4) NOT NULL,"
"`yaw` NUMERIC(11, 4) NOT NULL,"
"`posX` NUMERIC(11, 4) NOT NULL,"
"`posY` NUMERIC(11, 4) NOT NULL,"
"`posZ` NUMERIC(11, 4) NOT NULL,"
"`name` TEXT NOT NULL,"
"`pitch` NUMERIC NOT NULL,"
"`yaw` NUMERIC NOT NULL,"
"`posX` NUMERIC NOT NULL,"
"`posY` NUMERIC NOT NULL,"
"`posZ` NUMERIC NOT NULL,"
"`hp` INT NOT NULL,"
"`breath` INT NOT NULL,"
"`creation_date` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,"
@ -337,9 +401,9 @@ void PlayerDatabaseSQLite3::createDatabase()
SQLOK(sqlite3_exec(m_database,
"CREATE TABLE IF NOT EXISTS `player_metadata` ("
" `player` VARCHAR(50) NOT NULL,"
" `metadata` VARCHAR(256) NOT NULL,"
" `value` TEXT,"
" `player` TEXT NOT NULL,"
" `metadata` TEXT NOT NULL,"
" `value` TEXT NOT NULL,"
" PRIMARY KEY(`player`, `metadata`),"
" FOREIGN KEY (`player`) REFERENCES player (`name`) ON DELETE CASCADE );",
NULL, NULL, NULL),
@ -347,7 +411,7 @@ void PlayerDatabaseSQLite3::createDatabase()
SQLOK(sqlite3_exec(m_database,
"CREATE TABLE IF NOT EXISTS `player_inventories` ("
" `player` VARCHAR(50) NOT NULL,"
" `player` TEXT NOT NULL,"
" `inv_id` INT NOT NULL,"
" `inv_width` INT NOT NULL,"
" `inv_name` TEXT NOT NULL DEFAULT '',"
@ -359,7 +423,7 @@ void PlayerDatabaseSQLite3::createDatabase()
SQLOK(sqlite3_exec(m_database,
"CREATE TABLE `player_inventory_items` ("
" `player` VARCHAR(50) NOT NULL,"
" `player` TEXT NOT NULL,"
" `inv_id` INT NOT NULL,"
" `slot_id` INT NOT NULL,"
" `item` TEXT NOT NULL DEFAULT '',"
@ -401,7 +465,6 @@ void PlayerDatabaseSQLite3::initStatements()
"(`player`, `metadata`, `value`) VALUES (?, ?, ?)")
PREPARE_STATEMENT(player_metadata_remove, "DELETE FROM `player_metadata` "
"WHERE `player` = ?")
verbosestream << "ServerEnvironment: SQLite3 database opened (players)." << std::endl;
}
bool PlayerDatabaseSQLite3::playerDataExists(const std::string &name)
@ -588,27 +651,27 @@ AuthDatabaseSQLite3::AuthDatabaseSQLite3(const std::string &savedir) :
AuthDatabaseSQLite3::~AuthDatabaseSQLite3()
{
FINALIZE_STATEMENT(m_stmt_read)
FINALIZE_STATEMENT(m_stmt_write)
FINALIZE_STATEMENT(m_stmt_create)
FINALIZE_STATEMENT(m_stmt_delete)
FINALIZE_STATEMENT(m_stmt_list_names)
FINALIZE_STATEMENT(m_stmt_read_privs)
FINALIZE_STATEMENT(m_stmt_write_privs)
FINALIZE_STATEMENT(m_stmt_delete_privs)
FINALIZE_STATEMENT(m_stmt_last_insert_rowid)
FINALIZE_STATEMENT(read)
FINALIZE_STATEMENT(write)
FINALIZE_STATEMENT(create)
FINALIZE_STATEMENT(delete)
FINALIZE_STATEMENT(list_names)
FINALIZE_STATEMENT(read_privs)
FINALIZE_STATEMENT(write_privs)
FINALIZE_STATEMENT(delete_privs)
FINALIZE_STATEMENT(last_insert_rowid)
}
void AuthDatabaseSQLite3::createDatabase()
{
assert(m_database); // Pre-condition
assert(m_database);
SQLOK(sqlite3_exec(m_database,
"CREATE TABLE IF NOT EXISTS `auth` ("
"`id` INTEGER PRIMARY KEY AUTOINCREMENT,"
"`name` VARCHAR(32) UNIQUE,"
"`password` VARCHAR(512),"
"`last_login` INTEGER"
"`name` TEXT UNIQUE NOT NULL,"
"`password` TEXT NOT NULL,"
"`last_login` INTEGER NOT NULL DEFAULT 0"
");",
NULL, NULL, NULL),
"Failed to create auth table");
@ -616,7 +679,7 @@ void AuthDatabaseSQLite3::createDatabase()
SQLOK(sqlite3_exec(m_database,
"CREATE TABLE IF NOT EXISTS `user_privileges` ("
"`id` INTEGER,"
"`privilege` VARCHAR(32),"
"`privilege` TEXT,"
"PRIMARY KEY (id, privilege)"
"CONSTRAINT fk_id FOREIGN KEY (id) REFERENCES auth (id) ON DELETE CASCADE"
");",
@ -751,18 +814,18 @@ ModStorageDatabaseSQLite3::ModStorageDatabaseSQLite3(const std::string &savedir)
ModStorageDatabaseSQLite3::~ModStorageDatabaseSQLite3()
{
FINALIZE_STATEMENT(m_stmt_remove_all)
FINALIZE_STATEMENT(m_stmt_remove)
FINALIZE_STATEMENT(m_stmt_set)
FINALIZE_STATEMENT(m_stmt_has)
FINALIZE_STATEMENT(m_stmt_get)
FINALIZE_STATEMENT(m_stmt_get_keys)
FINALIZE_STATEMENT(m_stmt_get_all)
FINALIZE_STATEMENT(remove_all)
FINALIZE_STATEMENT(remove)
FINALIZE_STATEMENT(set)
FINALIZE_STATEMENT(has)
FINALIZE_STATEMENT(get)
FINALIZE_STATEMENT(get_keys)
FINALIZE_STATEMENT(get_all)
}
void ModStorageDatabaseSQLite3::createDatabase()
{
assert(m_database); // Pre-condition
assert(m_database);
SQLOK(sqlite3_exec(m_database,
"CREATE TABLE IF NOT EXISTS `entries` (\n"
@ -825,8 +888,7 @@ bool ModStorageDatabaseSQLite3::getModEntry(const std::string &modname,
verifyDatabase();
str_to_sqlite(m_stmt_get, 1, modname);
SQLOK(sqlite3_bind_blob(m_stmt_get, 2, key.data(), key.size(), NULL),
"Internal error: failed to bind query at " __FILE__ ":" TOSTRING(__LINE__));
blob_to_sqlite(m_stmt_get, 2, key);
bool found = sqlite3_step(m_stmt_get) == SQLITE_ROW;
if (found) {
auto sv = sqlite_to_blob(m_stmt_get, 0);
@ -845,8 +907,7 @@ bool ModStorageDatabaseSQLite3::hasModEntry(const std::string &modname,
verifyDatabase();
str_to_sqlite(m_stmt_has, 1, modname);
SQLOK(sqlite3_bind_blob(m_stmt_has, 2, key.data(), key.size(), NULL),
"Internal error: failed to bind query at " __FILE__ ":" TOSTRING(__LINE__));
blob_to_sqlite(m_stmt_has, 2, key);
bool found = sqlite3_step(m_stmt_has) == SQLITE_ROW;
if (found)
sqlite3_step(m_stmt_has);
@ -862,10 +923,8 @@ bool ModStorageDatabaseSQLite3::setModEntry(const std::string &modname,
verifyDatabase();
str_to_sqlite(m_stmt_set, 1, modname);
SQLOK(sqlite3_bind_blob(m_stmt_set, 2, key.data(), key.size(), NULL),
"Internal error: failed to bind query at " __FILE__ ":" TOSTRING(__LINE__));
SQLOK(sqlite3_bind_blob(m_stmt_set, 3, value.data(), value.size(), NULL),
"Internal error: failed to bind query at " __FILE__ ":" TOSTRING(__LINE__));
blob_to_sqlite(m_stmt_set, 2, key);
blob_to_sqlite(m_stmt_set, 3, value);
SQLRES(sqlite3_step(m_stmt_set), SQLITE_DONE, "Failed to set mod entry")
sqlite3_reset(m_stmt_set);
@ -879,8 +938,7 @@ bool ModStorageDatabaseSQLite3::removeModEntry(const std::string &modname,
verifyDatabase();
str_to_sqlite(m_stmt_remove, 1, modname);
SQLOK(sqlite3_bind_blob(m_stmt_remove, 2, key.data(), key.size(), NULL),
"Internal error: failed to bind query at " __FILE__ ":" TOSTRING(__LINE__));
blob_to_sqlite(m_stmt_remove, 2, key);
sqlite3_vrfy(sqlite3_step(m_stmt_remove), SQLITE_DONE);
int changes = sqlite3_changes(m_database);
@ -906,6 +964,7 @@ void ModStorageDatabaseSQLite3::listMods(std::vector<std::string> *res)
{
verifyDatabase();
// FIXME: please don't do this. this should be sqlite3_step like all others.
char *errmsg;
int status = sqlite3_exec(m_database,
"SELECT `modname` FROM `entries` GROUP BY `modname`;",

View file

@ -13,27 +13,41 @@ extern "C" {
#include "sqlite3.h"
}
// Template class for SQLite3 based data storage
class Database_SQLite3 : public Database
{
public:
virtual ~Database_SQLite3();
void beginSave();
void endSave();
void beginSave() override;
void endSave() override;
bool initialized() const override { return m_initialized; }
/// @note not thread-safe
void verifyDatabase() override;
bool initialized() const { return m_initialized; }
protected:
Database_SQLite3(const std::string &savedir, const std::string &dbname);
// Open and initialize the database if needed
void verifyDatabase();
// Check if a specific table exists
bool checkTable(const char *table);
// Check if a table has a specific column
bool checkColumn(const char *table, const char *column);
/* Value conversion helpers */
// Convertors
inline void str_to_sqlite(sqlite3_stmt *s, int iCol, std::string_view str) const
{
sqlite3_vrfy(sqlite3_bind_text(s, iCol, str.data(), str.size(), NULL));
}
inline void blob_to_sqlite(sqlite3_stmt *s, int iCol, std::string_view str) const
{
sqlite3_vrfy(sqlite3_bind_blob(s, iCol, str.data(), str.size(), NULL));
}
inline void int_to_sqlite(sqlite3_stmt *s, int iCol, int val) const
{
sqlite3_vrfy(sqlite3_bind_int(s, iCol, val));
@ -104,12 +118,14 @@ protected:
sqlite_to_float(s, iCol + 2));
}
// Query verifiers helpers
// Helper for verifying result of sqlite3_step() and such
inline void sqlite3_vrfy(int s, std::string_view m = "", int r = SQLITE_OK) const
{
if (s != r) {
std::string msg(m);
msg.append(": ").append(sqlite3_errmsg(m_database));
if (!msg.empty())
msg.append(": ");
msg.append(sqlite3_errmsg(m_database));
throw DatabaseException(msg);
}
}
@ -119,28 +135,37 @@ protected:
sqlite3_vrfy(s, m, r);
}
// Create the database structure
// Called after opening a fresh database file. Should create tables and indices.
virtual void createDatabase() = 0;
// Should prepare the necessary statements.
virtual void initStatements() = 0;
sqlite3 *m_database = nullptr;
private:
// Open the database
void openDatabase();
bool m_initialized = false;
std::string m_savedir = "";
std::string m_dbname = "";
const std::string m_savedir;
const std::string m_dbname;
sqlite3_stmt *m_stmt_begin = nullptr;
sqlite3_stmt *m_stmt_end = nullptr;
s64 m_busy_handler_data[2];
u64 m_busy_handler_data[2];
static int busyHandler(void *data, int count);
};
// Not sure why why we have to do this. can't C++ figure it out on its own?
#define PARENT_CLASS_FUNCS \
void beginSave() { Database_SQLite3::beginSave(); } \
void endSave() { Database_SQLite3::endSave(); } \
void verifyDatabase() { Database_SQLite3::verifyDatabase(); }
class MapDatabaseSQLite3 : private Database_SQLite3, public MapDatabase
{
public:
@ -152,16 +177,19 @@ public:
bool deleteBlock(const v3s16 &pos);
void listAllLoadableBlocks(std::vector<v3s16> &dst);
void beginSave() { Database_SQLite3::beginSave(); }
void endSave() { Database_SQLite3::endSave(); }
PARENT_CLASS_FUNCS
protected:
virtual void createDatabase();
virtual void initStatements();
private:
void bindPos(sqlite3_stmt *stmt, const v3s16 &pos, int index = 1);
/// @brief Bind block position into statement at column index
/// @return index of next column after position
int bindPos(sqlite3_stmt *stmt, v3s16 pos, int index = 1);
bool m_new_format = false;
// Map
sqlite3_stmt *m_stmt_read = nullptr;
sqlite3_stmt *m_stmt_write = nullptr;
sqlite3_stmt *m_stmt_list = nullptr;
@ -179,6 +207,8 @@ public:
bool removePlayer(const std::string &name);
void listPlayers(std::vector<std::string> &res);
PARENT_CLASS_FUNCS
protected:
virtual void createDatabase();
virtual void initStatements();
@ -216,6 +246,8 @@ public:
virtual void listNames(std::vector<std::string> &res);
virtual void reload();
PARENT_CLASS_FUNCS
protected:
virtual void createDatabase();
virtual void initStatements();
@ -251,8 +283,7 @@ public:
virtual bool removeModEntries(const std::string &modname);
virtual void listMods(std::vector<std::string> *res);
virtual void beginSave() { Database_SQLite3::beginSave(); }
virtual void endSave() { Database_SQLite3::endSave(); }
PARENT_CLASS_FUNCS
protected:
virtual void createDatabase();
@ -267,3 +298,5 @@ private:
sqlite3_stmt *m_stmt_remove = nullptr;
sqlite3_stmt *m_stmt_remove_all = nullptr;
};
#undef PARENT_CLASS_FUNCS

View file

@ -16,7 +16,12 @@ class Database
public:
virtual void beginSave() = 0;
virtual void endSave() = 0;
/// @return true if database connection is open
virtual bool initialized() const { return true; }
/// Open and initialize the database if needed
virtual void verifyDatabase() {};
};
class MapDatabase : public Database

View file

@ -112,7 +112,7 @@ void set_default_settings()
settings->setDefault("screenshot_format", "png");
settings->setDefault("screenshot_quality", "0");
settings->setDefault("client_unload_unused_data_timeout", "600");
settings->setDefault("client_mapblock_limit", "7500");
settings->setDefault("client_mapblock_limit", "7500"); // about 120 MB
settings->setDefault("enable_build_where_you_stand", "false");
settings->setDefault("curl_timeout", "20000");
settings->setDefault("curl_parallel_limit", "8");
@ -243,7 +243,7 @@ void set_default_settings()
settings->setDefault("tooltip_show_delay", "400");
settings->setDefault("tooltip_append_itemname", "false");
settings->setDefault("fps_max", "60");
settings->setDefault("fps_max_unfocused", "20");
settings->setDefault("fps_max_unfocused", "10");
settings->setDefault("viewing_range", "190");
settings->setDefault("client_mesh_chunk", "1");
settings->setDefault("screen_w", "1024");
@ -270,7 +270,6 @@ void set_default_settings()
settings->setDefault("camera_smoothing", "0.0");
settings->setDefault("cinematic_camera_smoothing", "0.7");
settings->setDefault("view_bobbing_amount", "1.0");
settings->setDefault("fall_bobbing_amount", "0.03");
settings->setDefault("enable_3d_clouds", "true");
settings->setDefault("soft_clouds", "false");
settings->setDefault("cloud_radius", "12");
@ -422,7 +421,7 @@ void set_default_settings()
// Network
settings->setDefault("enable_ipv6", "true");
settings->setDefault("ipv6_server", "false");
settings->setDefault("ipv6_server", "true");
settings->setDefault("max_packets_per_iteration", "1024");
settings->setDefault("port", "30000");
settings->setDefault("strict_protocol_version_checking", "false");
@ -547,6 +546,7 @@ void set_default_settings()
settings->setDefault("virtual_joystick_triggers_aux1", "false");
settings->setDefault("touch_punch_gesture", "short_tap");
settings->setDefault("clickable_chat_weblinks", "true");
// Altered settings for Android
#ifdef __ANDROID__
settings->setDefault("screen_w", "0");
@ -558,9 +558,9 @@ void set_default_settings()
settings->setDefault("max_block_generate_distance", "5");
settings->setDefault("sqlite_synchronous", "1");
settings->setDefault("server_map_save_interval", "15");
settings->setDefault("client_mapblock_limit", "1000");
settings->setDefault("client_mapblock_limit", "1500");
settings->setDefault("active_block_range", "2");
settings->setDefault("viewing_range", "50");
settings->setDefault("viewing_range", "70");
settings->setDefault("leaves_style", "simple");
// Note: OpenGL ES 2.0 is not guaranteed to provide depth textures,
// which we would need for PP.
@ -568,6 +568,7 @@ void set_default_settings()
// still set these two settings in case someone wants to enable it
settings->setDefault("debanding", "false");
settings->setDefault("post_processing_texture_bits", "8");
// We don't have working certificate verification...
settings->setDefault("curl_verify_cert", "false");
// Apply settings according to screen size

View file

@ -106,9 +106,9 @@ EmergeManager::EmergeManager(Server *server, MetricsBackend *mb)
m_qlimit_generate = nthreads + 1;
// don't trust user input for something very important like this
m_qlimit_total = rangelim(m_qlimit_total, 1, 1000000);
m_qlimit_diskonly = rangelim(m_qlimit_diskonly, 1, 1000000);
m_qlimit_diskonly = rangelim(m_qlimit_diskonly, 2, 1000000);
m_qlimit_generate = rangelim(m_qlimit_generate, 1, 1000000);
m_qlimit_total = std::max(m_qlimit_diskonly, m_qlimit_generate);
for (s16 i = 0; i < nthreads; i++)
m_threads.push_back(new EmergeThread(server, i));
@ -375,8 +375,7 @@ bool EmergeManager::pushBlockEmergeData(
}
}
std::pair<std::map<v3s16, BlockEmergeData>::iterator, bool> findres;
findres = m_blocks_enqueued.insert(std::make_pair(pos, BlockEmergeData()));
auto findres = m_blocks_enqueued.insert(std::make_pair(pos, BlockEmergeData()));
BlockEmergeData &bedata = findres.first->second;
*entry_already_exists = !findres.second;
@ -707,6 +706,8 @@ void *EmergeThread::run()
{
ScopeProfiler sp(g_profiler, "EmergeThread: load block - async (sum)");
MutexAutoLock dblock(m_db.mutex);
// Note: this can throw an exception, but there isn't really
// a good, safe way to handle it.
m_db.loadBlock(pos, databuf);
}
// actually load it, then decide again

Some files were not shown because too many files have changed in this diff Show more