diff --git a/doc/en/scripting/extensions.md b/doc/en/scripting/extensions.md index 94a55ef00..9ba99f1ef 100644 --- a/doc/en/scripting/extensions.md +++ b/doc/en/scripting/extensions.md @@ -139,6 +139,12 @@ string.left_pad(str: string, size: int, char: string) -> string -- Adds a char to the right of the string until its size equals size. -- By default, char is equal to the space character. string.right_pad(str: string, size: int, char: string) -> string + +-- Encodes a string into URL format, replacing special characters with their hexadecimal representations. +string.url_encode(str: string) -> string + +-- Decodes a string from URL format, replacing hexadecimal representations with their corresponding characters. +string.url_decode(str: string) -> string ``` ## Math extensions diff --git a/doc/en/world-generator.md b/doc/en/world-generator.md index 3c0a774f3..6432cb421 100644 --- a/doc/en/world-generator.md +++ b/doc/en/world-generator.md @@ -284,6 +284,14 @@ A method that generates simplex noise, adding it to the existing values. The noise seed can be specified in the `map.noiseSeed` field. +By default, noise octaves are mixed using addition: + +$noise_{out} = noise_{source} + noise_{applied} * 2^{-{octave}}$ + +To obtain more normalized multi-octave noise, you can enable the `map.normalNoise = true` flag, which changes the scheme: + +$noise_{out} = noise_{source} * (1 - 2^{-{octave}}) + noise_{applied} * 2^{-{octave}}$ + ```lua map:noise( -- coordinate offset @@ -313,6 +321,10 @@ The noise seed can be specified in the `map.noiseSeed` field. ![image](../images/cell-noise.gif) +> [!NOTE] cell noise looks better with `map.normalNoise = true` + +![image](../images/normal-cell-noise.png) + ### heightmap:resize(...) ```lua diff --git a/doc/images/normal-cell-noise.png b/doc/images/normal-cell-noise.png new file mode 100644 index 000000000..c1c103185 Binary files /dev/null and b/doc/images/normal-cell-noise.png differ diff --git a/doc/ru/scripting/extensions.md b/doc/ru/scripting/extensions.md index 91859fbf1..3a372a9a5 100644 --- a/doc/ru/scripting/extensions.md +++ b/doc/ru/scripting/extensions.md @@ -141,6 +141,12 @@ string.left_pad(str: string, size: int, char: string) -> string -- Добавляет char справа от строки, пока её размер не будет равен size. -- По стандарту char равен символу пробела. string.right_pad(str: string, size: int, char: string) -> string + +-- Кодирует строку в формат URL, заменяя специальные символы на их шестнадцатеричные представления. +string.url_encode(str: string) -> string + +-- Декодирует строку из формата URL, заменяя шестнадцатеричные представления на соответствующие символы. +string.url_decode(str: string) -> string ``` ## Расширения для math diff --git a/doc/ru/world-generator.md b/doc/ru/world-generator.md index 3415a81d6..34738d4b3 100644 --- a/doc/ru/world-generator.md +++ b/doc/ru/world-generator.md @@ -287,6 +287,14 @@ map:dump('export:test.png') Зерно шума может быть указано в поле `map.noiseSeed`. +По-умолчанию октавы шума совмещаются через сложение: + +$шум_{результат} = шум_{исходный} + шум_{применяемый} * 2^{-{октава}}$ + +Для более получения нормализованного многооктавного шума можно включить флаг `map.normalNoise = true`, меняющий схему на: + +$шум_{результат} = шум_{исходный} * (1 - 2^{-{октава}}) + шум_{применяемый} * 2^{-{октава}}$ + ```lua map:noise( -- смещение координат @@ -316,6 +324,10 @@ map:noise( ![image](../images/cell-noise.gif) +> [!NOTE] клеточный шум выглядит лучше с `map.normalNoise = true` + +![image](../images/normal-cell-noise.png) + ### heightmap:resize(...) ```lua diff --git a/res/modules/internal/extensions/string.lua b/res/modules/internal/extensions/string.lua index 313ae57bd..eb3668687 100644 --- a/res/modules/internal/extensions/string.lua +++ b/res/modules/internal/extensions/string.lua @@ -125,3 +125,18 @@ end function string.ends_with(str, endStr) return endStr == "" or string.sub(str, -string.len(endStr)) == endStr end + +function string.url_encode(str) + str = string.gsub(str, "([^%w%-%.%_%~])", function(c) + return string.format("%%%02X", string.byte(c)) + end) + return str +end + +function string.url_decode(str) + str = string.gsub(str, "+", " ") + str = string.gsub(str, "%%(%x%x)", function(hex) + return string.char(tonumber(hex, 16)) + end) + return str +end diff --git a/src/graphics/ui/elements/Panel.cpp b/src/graphics/ui/elements/Panel.cpp index 26401ee10..8f023fbd6 100644 --- a/src/graphics/ui/elements/Panel.cpp +++ b/src/graphics/ui/elements/Panel.cpp @@ -39,15 +39,24 @@ glm::vec2 Panel::getContentSize() const { } void Panel::cropToContent() { + int maxInt = std::numeric_limits::max(); + bool isHorizontal = orientation == Orientation::HORIZONTAL; + + int minLengthX = isHorizontal ? minLength : 0; + int maxLengthX = isHorizontal ? maxLength : maxInt; + + int minLengthY = isHorizontal ? 0 : minLength; + int maxLengthY = isHorizontal ? maxInt : maxLength; + if (maxLength > 0.0f) { setSize(glm::vec2( - glm::max(minLength, glm::min(maxLength, actualLengthX)), - glm::max(minLength, glm::min(maxLength, actualLengthY)) + glm::max(minLengthX, glm::min(maxLengthX, actualLengthX)), + glm::max(minLengthY, glm::min(maxLengthY, actualLengthY)) )); } else { setSize(glm::vec2( - glm::max(minLength, actualLengthX), - glm::max(minLength, actualLengthY) + glm::max(minLengthX, actualLengthX), + glm::max(minLengthY, actualLengthY) )); } } diff --git a/src/logic/scripting/lua/libs/libtime.cpp b/src/logic/scripting/lua/libs/libtime.cpp index ae6fc6fed..88f49a6c0 100644 --- a/src/logic/scripting/lua/libs/libtime.cpp +++ b/src/logic/scripting/lua/libs/libtime.cpp @@ -22,7 +22,7 @@ static int l_utc_time(lua::State* L) { } static int l_precise_utc_time(lua::State* L) { - auto now = std::chrono::steady_clock::now(); + auto now = std::chrono::system_clock::now(); return lua::pushnumber( L, std::chrono::duration(now.time_since_epoch()).count() ); diff --git a/src/logic/scripting/lua/usertypes/lua_type_heightmap.cpp b/src/logic/scripting/lua/usertypes/lua_type_heightmap.cpp index df2af6106..6ae6a0d8d 100644 --- a/src/logic/scripting/lua/usertypes/lua_type_heightmap.cpp +++ b/src/logic/scripting/lua/usertypes/lua_type_heightmap.cpp @@ -110,6 +110,7 @@ static int l_noise(lua::State* L) { if (gettop(L) > 6) { shiftMapY = touserdata(L, 7); } + bool normalizedNoise = heightmap->normalizedNoise; noise->noise_type = noise_type; for (uint y = 0; y < h; y++) { for (uint x = 0; x < w; x++) { @@ -126,8 +127,14 @@ static int l_noise(lua::State* L) { v += shiftMapY->getValues()[i]; } - value += fnlGetNoise2D(noise, u, v) / - static_cast(1 << c) * multiplier; + float noiseValue = fnlGetNoise2D(noise, u, v); + if (normalizedNoise) { + float t = 1.0f / (static_cast(1 << c) * multiplier); + value = value * (1.0f - t) + noiseValue * t; + } else { + float t = 1.0f / static_cast(1 << c) * multiplier; + value += noiseValue * t; + } heights[i] = value; } } @@ -317,6 +324,8 @@ static int l_meta_newindex(lua::State* L) { auto fieldname = tostring(L, 2); if (!std::strcmp(fieldname, "noiseSeed")) { map->setSeed(tointeger(L, 3)); + } else if (!std::strcmp(fieldname, "normalNoise")) { + map->normalizedNoise = toboolean(L, 3); } } return 0; diff --git a/src/logic/scripting/lua/usertypes/lua_type_heightmap.hpp b/src/logic/scripting/lua/usertypes/lua_type_heightmap.hpp index 4109be675..5e74547d8 100644 --- a/src/logic/scripting/lua/usertypes/lua_type_heightmap.hpp +++ b/src/logic/scripting/lua/usertypes/lua_type_heightmap.hpp @@ -10,6 +10,8 @@ namespace lua { std::shared_ptr map; std::unique_ptr noise; public: + bool normalizedNoise = false; + LuaHeightmap(const std::shared_ptr& map); LuaHeightmap(uint width, uint height); diff --git a/src/maths/util.hpp b/src/maths/util.hpp index c5a576f0d..08f0f4585 100644 --- a/src/maths/util.hpp +++ b/src/maths/util.hpp @@ -18,49 +18,66 @@ namespace util { constexpr inline float EPSILON = 1e-6f; class PseudoRandom { - unsigned short seed; + uint32_t seed; + public: - PseudoRandom(unsigned short seed) : seed(seed) {} + explicit PseudoRandom(uint32_t seed) : seed(seed) {} - PseudoRandom() { - seed = static_cast(time(nullptr)); - } + PseudoRandom() + : seed(static_cast(time(nullptr))) {} - int rand() { - seed = (seed + 0x7ed5 + (seed << 6)); - seed = (seed ^ 0xc23c ^ (seed >> 9)); - seed = (seed + 0x1656 + (seed << 3)); - seed = ((seed + 0xa264) ^ (seed << 4)); - seed = (seed + 0xfd70 - (seed << 3)); - seed = (seed ^ 0xba49 ^ (seed >> 8)); + uint32_t rand() { + seed += 0x7ed55d16u; + seed ^= seed >> 16; + seed *= 0x21f0aaadu; + seed ^= seed >> 15; + seed *= 0x735a2d97u; + seed ^= seed >> 15; - return static_cast(seed); - } - - void rand(unsigned char* dst, size_t n) { - for (size_t i = 0; i < n; i++) { - dst[i] = rand(); - } - } - - int32_t rand32() { - return (rand() << 16) | rand(); + return seed; } uint32_t randU32() { - return (rand() << 16) | rand(); - } - - int64_t rand64() { - uint64_t x = randU32(); - uint64_t y = randU32(); - return (x << 32ULL) | y; + return rand(); } uint64_t randU64() { uint64_t x = randU32(); uint64_t y = randU32(); - return (x << 32ULL) | y; + return (x << 32) | y; + } + + int32_t rand32() { + return static_cast(randU32()); + } + + int64_t rand64() { + uint64_t x = randU32(); + uint64_t y = randU32(); + return static_cast((x << 32) | y); + } + + void setSeed(uint32_t value) { + seed = value; + if (seed == 0) { + seed = 0x6d2b79f5u; + } + rand(); + } + + void setSeed(int32_t number1, int32_t number2) { + uint32_t a = static_cast(number1); + uint32_t b = static_cast(number2); + + uint32_t x = a * 23729u; + uint32_t y = b * 16786u; + + seed = (x ^ y ^ (a * b)); + + if (seed == 0) { + seed = 0x6d2b79f5u; + } + rand(); } float randFloat() { @@ -70,21 +87,6 @@ namespace util { double randDouble() { return randU64() / static_cast(UINT64_MAX); } - - void setSeed(int number1, int number2) { - seed = ((static_cast(number1 * 23729) | - static_cast(number2 % 16786)) ^ - static_cast(number2 * number1)); - rand(); - } - - void setSeed(long number) { - number = shuffle_bits_step(number, 0x2222222222222222ull, 1); - number = shuffle_bits_step(number, 0x0c0c0c0c0c0c0c0cull, 2); - number = shuffle_bits_step(number, 0x00f000f000f000f0ull, 4); - seed = number; - rand(); - } }; template diff --git a/src/objects/Entities.cpp b/src/objects/Entities.cpp index 110f792a3..1158c68a0 100644 --- a/src/objects/Entities.cpp +++ b/src/objects/Entities.cpp @@ -301,15 +301,14 @@ void Entities::preparePhysics(float delta) { auto& physics = *level.physics; auto& hitboxes = physics.getHitboxesWriteable(); auto& solidHitboxes = physics.getSolidHitboxesWriteable(); + auto& sensors = physics.getSensorsWriteable(); + sensors.clear(); if (int parts = sensorsTickClock.update(delta)) { for (int i = 0; i < parts; i++) { auto part = sensorsTickClock.convertPart(i); auto allParts = sensorsTickClock.getParts(); - auto& sensors = physics.getSensorsWriteable(); - sensors.clear(); - auto view = registry->view(); for (auto [entity, eid, transform, rigidbody] : view.each()) { if (!rigidbody.enabled) {