From eb760e1776e4f09690d5d3a2fb7ebaf93e3538c1 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 16 Sep 2025 19:01:47 +0300 Subject: [PATCH 1/5] add 'random' library --- src/logic/scripting/lua/libs/api_lua.hpp | 1 + src/logic/scripting/lua/libs/librandom.cpp | 46 ++++++++++++++++++++++ src/logic/scripting/lua/lua_engine.cpp | 1 + src/util/random.cpp | 44 +++++++++++++++++++++ src/util/random.hpp | 19 +++++++++ 5 files changed, 111 insertions(+) create mode 100644 src/logic/scripting/lua/libs/librandom.cpp create mode 100644 src/util/random.cpp create mode 100644 src/util/random.hpp diff --git a/src/logic/scripting/lua/libs/api_lua.hpp b/src/logic/scripting/lua/libs/api_lua.hpp index c1d9f933..6c24d9d4 100644 --- a/src/logic/scripting/lua/libs/api_lua.hpp +++ b/src/logic/scripting/lua/libs/api_lua.hpp @@ -42,6 +42,7 @@ extern const luaL_Reg pathfindinglib[]; extern const luaL_Reg playerlib[]; extern const luaL_Reg posteffectslib[]; // gfx.posteffects extern const luaL_Reg quatlib[]; +extern const luaL_Reg randomlib[]; extern const luaL_Reg text3dlib[]; // gfx.text3d extern const luaL_Reg timelib[]; extern const luaL_Reg tomllib[]; diff --git a/src/logic/scripting/lua/libs/librandom.cpp b/src/logic/scripting/lua/libs/librandom.cpp new file mode 100644 index 00000000..fce0d62b --- /dev/null +++ b/src/logic/scripting/lua/libs/librandom.cpp @@ -0,0 +1,46 @@ +#include "api_lua.hpp" + +#include "util/random.hpp" + +static std::random_device random_device; + +static int l_random(lua::State* L) { + int argc = lua::gettop(L); + + auto randomEngine = util::seeded_random_engine(random_device); + if (argc == 0) { + std::uniform_real_distribution<> dist(0.0, 1.0); + return lua::pushnumber(L, dist(randomEngine)); + } else if (argc == 1) { + std::uniform_int_distribution dist(0, lua::tointeger(L, 1) - 1); + return lua::pushinteger(L, dist(randomEngine)); + } else { + std::uniform_int_distribution dist( + lua::tointeger(L, 1), lua::tointeger(L, 2) - 1 + ); + return lua::pushinteger(L, dist(randomEngine)); + } +} + +static int l_bytes(lua::State* L) { + size_t size = lua::tointeger(L, 1); + + auto randomEngine = util::seeded_random_engine(random_device); + static std::uniform_int_distribution dist(0, 0xFF); + std::vector bytes (size); + for (size_t i = 0; i < bytes.size(); i++) { + bytes[i] = dist(randomEngine); + } + return lua::create_bytearray(L, bytes); +} + +static int l_uuid(lua::State* L) { + return lua::pushlstring(L, util::generate_uuid()); +} + +const luaL_Reg randomlib[] = { + {"random", lua::wrap}, + {"bytes", lua::wrap}, + {"uuid", lua::wrap}, + {NULL, NULL} +}; diff --git a/src/logic/scripting/lua/lua_engine.cpp b/src/logic/scripting/lua/lua_engine.cpp index f6ce4fe3..891614f0 100644 --- a/src/logic/scripting/lua/lua_engine.cpp +++ b/src/logic/scripting/lua/lua_engine.cpp @@ -51,6 +51,7 @@ static void create_libs(State* L, StateType stateType) { openlib(L, "mat4", mat4lib); openlib(L, "pack", packlib); openlib(L, "quat", quatlib); + openlib(L, "random", randomlib); openlib(L, "toml", tomllib); openlib(L, "utf8", utf8lib); openlib(L, "vec2", vec2lib); diff --git a/src/util/random.cpp b/src/util/random.cpp new file mode 100644 index 00000000..a1ffb66c --- /dev/null +++ b/src/util/random.cpp @@ -0,0 +1,44 @@ +#include "random.hpp" + +#include + +static std::random_device random_device; + +static const char* uuid_hex_chars = "0123456789abcdef"; +static const char* uuid_hex_variant_chars = "89ab"; + +std::string util::generate_uuid() { + auto randomEngine = seeded_random_engine(random_device); + static std::uniform_int_distribution<> dist(0, 15); + static std::uniform_int_distribution<> dist2(0, 3); + + std::string uuid; + uuid.resize(36); + + for (int i = 0; i < 8; i++) { + uuid[i] = uuid_hex_chars[dist(randomEngine)]; + } + uuid[8] = '-'; + for (int i = 9; i < 13; i++) { + uuid[i] = uuid_hex_chars[dist(randomEngine)]; + } + uuid[13] = '-'; + uuid[14] = '4'; + + for (int i = 15; i < 18; i++) { + uuid[i] = uuid_hex_chars[dist(randomEngine)]; + } + + uuid[18] = '-'; + uuid[19] = uuid_hex_variant_chars[dist2(randomEngine)]; + + for (int i = 20; i < 23; i++) { + uuid[i] = uuid_hex_chars[dist(randomEngine)]; + } + + uuid[23] = '-'; + for (int i = 24; i < 36; i++) { + uuid[i] = uuid_hex_chars[dist(randomEngine)]; + } + return uuid; +} diff --git a/src/util/random.hpp b/src/util/random.hpp new file mode 100644 index 00000000..fc79317d --- /dev/null +++ b/src/util/random.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include +#include +#include + +namespace util { + template + typename std::enable_if::type seeded_random_engine( + std::random_device& source + ) { + std::random_device::result_type randomData[(N - 1) / sizeof(source()) + 1]; + std::generate(std::begin(randomData), std::end(randomData), std::ref(source)); + std::seed_seq seeds(std::begin(randomData), std::end(randomData)); + return T(seeds); + } + + std::string generate_uuid(); +} From dc21a8ea5156de3db88f71d1a240e4285242b3ee Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 16 Sep 2025 19:12:25 +0300 Subject: [PATCH 2/5] update random.hpp --- src/util/random.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/util/random.hpp b/src/util/random.hpp index fc79317d..075d5aa7 100644 --- a/src/util/random.hpp +++ b/src/util/random.hpp @@ -5,10 +5,10 @@ #include namespace util { - template - typename std::enable_if::type seeded_random_engine( - std::random_device& source - ) { + template < + class T = std::mt19937, + std::size_t N = T::state_size * sizeof(typename T::result_type)> + auto seeded_random_engine(std::random_device& source) { std::random_device::result_type randomData[(N - 1) / sizeof(source()) + 1]; std::generate(std::begin(randomData), std::end(randomData), std::ref(source)); std::seed_seq seeds(std::begin(randomData), std::end(randomData)); From 28afa4b6bf651caa6efa74d8cef35b43a74e38d1 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 16 Sep 2025 19:24:38 +0300 Subject: [PATCH 3/5] fix random.random range --- src/logic/scripting/lua/libs/librandom.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/logic/scripting/lua/libs/librandom.cpp b/src/logic/scripting/lua/libs/librandom.cpp index fce0d62b..0560d6f2 100644 --- a/src/logic/scripting/lua/libs/librandom.cpp +++ b/src/logic/scripting/lua/libs/librandom.cpp @@ -12,11 +12,11 @@ static int l_random(lua::State* L) { std::uniform_real_distribution<> dist(0.0, 1.0); return lua::pushnumber(L, dist(randomEngine)); } else if (argc == 1) { - std::uniform_int_distribution dist(0, lua::tointeger(L, 1) - 1); + std::uniform_int_distribution dist(0, lua::tointeger(L, 1)); return lua::pushinteger(L, dist(randomEngine)); } else { std::uniform_int_distribution dist( - lua::tointeger(L, 1), lua::tointeger(L, 2) - 1 + lua::tointeger(L, 1), lua::tointeger(L, 2) ); return lua::pushinteger(L, dist(randomEngine)); } From 532c4887bc01e8e4fbf2c0f43e421e7a315a28f4 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 16 Sep 2025 20:27:07 +0300 Subject: [PATCH 4/5] add Random class --- res/modules/internal/random_generator.lua | 35 ++++++++++++++++++++++ res/scripts/stdmin.lua | 2 ++ src/logic/scripting/lua/libs/librandom.cpp | 2 +- 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 res/modules/internal/random_generator.lua diff --git a/res/modules/internal/random_generator.lua b/res/modules/internal/random_generator.lua new file mode 100644 index 00000000..0c9073cc --- /dev/null +++ b/res/modules/internal/random_generator.lua @@ -0,0 +1,35 @@ +local Random = {} + +local M = 2 ^ 31 +local A = 1103515245 +local C = 12345 + +function Random.randint(self) + self._seed = (A * self._seed + C) % M + return self._seed +end + +function Random.random(self, a, b) + local num = self:randint() % M / M + if b then + return math.floor(num * (b - a + 1) + a) + elseif a then + return math.floor(num * a + 1) + else + return num + end +end + +function Random.seed(self, number) + if type(number) ~= "number" then + error("number expected") + end + self._seed = number +end + +return function(seed) + if seed and type(seed) ~= "number" then + error("number expected") + end + return setmetatable({_seed = seed or random.random(M)}, {__index = Random}) +end diff --git a/res/scripts/stdmin.lua b/res/scripts/stdmin.lua index 669d5874..742c9506 100644 --- a/res/scripts/stdmin.lua +++ b/res/scripts/stdmin.lua @@ -668,3 +668,5 @@ end bit.compile = require "core:bitwise/compiler" bit.execute = require "core:bitwise/executor" + +random.Random = require "core:internal/random_generator" diff --git a/src/logic/scripting/lua/libs/librandom.cpp b/src/logic/scripting/lua/libs/librandom.cpp index 0560d6f2..192f83d1 100644 --- a/src/logic/scripting/lua/libs/librandom.cpp +++ b/src/logic/scripting/lua/libs/librandom.cpp @@ -12,7 +12,7 @@ static int l_random(lua::State* L) { std::uniform_real_distribution<> dist(0.0, 1.0); return lua::pushnumber(L, dist(randomEngine)); } else if (argc == 1) { - std::uniform_int_distribution dist(0, lua::tointeger(L, 1)); + std::uniform_int_distribution dist(1, lua::tointeger(L, 1)); return lua::pushinteger(L, dist(randomEngine)); } else { std::uniform_int_distribution dist( From eeddf894b327762c8c9f9d14539e42aabadf1fbf Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 16 Sep 2025 20:27:35 +0300 Subject: [PATCH 5/5] add 'random' library docs --- doc/en/scripting.md | 1 + doc/en/scripting/builtins/librandom.md | 38 ++++++++++++++++++++++++++ doc/ru/scripting.md | 1 + doc/ru/scripting/builtins/librandom.md | 38 ++++++++++++++++++++++++++ 4 files changed, 78 insertions(+) create mode 100644 doc/en/scripting/builtins/librandom.md create mode 100644 doc/ru/scripting/builtins/librandom.md diff --git a/doc/en/scripting.md b/doc/en/scripting.md index c68d6b0c..9b2a0297 100644 --- a/doc/en/scripting.md +++ b/doc/en/scripting.md @@ -35,6 +35,7 @@ Subsections: - [pathfinding](scripting/builtins/libpathfinding.md) - [player](scripting/builtins/libplayer.md) - [quat](scripting/builtins/libquat.md) + - [random](scripting/builtins/librandom.md) - [rules](scripting/builtins/librules.md) - [time](scripting/builtins/libtime.md) - [utf8](scripting/builtins/libutf8.md) diff --git a/doc/en/scripting/builtins/librandom.md b/doc/en/scripting/builtins/librandom.md new file mode 100644 index 00000000..0ae52155 --- /dev/null +++ b/doc/en/scripting/builtins/librandom.md @@ -0,0 +1,38 @@ +# *random* library + +A library of functions for generating random numbers. + +## Non-deterministic numbers + +```lua +-- Generates a random number in the range [0..1) +random.random() --> number + +-- Generates a random integer in the range [0..n] +random.random(n) --> number + +-- Generates a random integer in the range [a..b] +random.random(a, b) --> number + +-- Generates a random byte array of length n +random.bytes(n: number) -> Bytearray + +-- Generates a UUID version 4 +random.uuid() -> str +``` + +## Pseudorandom numbers + +The library provides the Random class - a generator with its own isolated state. + +```lua +local rng = random.Random() + +-- Used similarly to math.random +local a = rng:random() --> [0..1) +local b = rng:random(10) --> [0..10] +local c = rng:random(5, 20) --> [5..20] + +-- Sets the generator state to generate a reproducible sequence of random numbers +rng:seed(42) +``` diff --git a/doc/ru/scripting.md b/doc/ru/scripting.md index 40cac325..d8f1b3be 100644 --- a/doc/ru/scripting.md +++ b/doc/ru/scripting.md @@ -35,6 +35,7 @@ - [pathfinding](scripting/builtins/libpathfinding.md) - [player](scripting/builtins/libplayer.md) - [quat](scripting/builtins/libquat.md) + - [random](scripting/builtins/librandom.md) - [rules](scripting/builtins/librules.md) - [time](scripting/builtins/libtime.md) - [utf8](scripting/builtins/libutf8.md) diff --git a/doc/ru/scripting/builtins/librandom.md b/doc/ru/scripting/builtins/librandom.md new file mode 100644 index 00000000..8aa58592 --- /dev/null +++ b/doc/ru/scripting/builtins/librandom.md @@ -0,0 +1,38 @@ +# Библиотека *random* + +Библиотека функций для генерации случайный чисел. + +## Недетерминированные числа + +```lua +-- Генерирует случайное число в диапазоне [0..1) +random.random() --> number + +-- Генерирует случайное целое число в диапазоне [0..n] +random.random(n) --> number + +-- Генерирует случайное целое число в диапазоне [a..b] +random.random(a, b) --> number + +-- Генерирует случайный массив байт длиной n +random.bytes(n: number) -> Bytearray + +-- Генерирует UUID версии 4 +random.uuid() -> str +``` + +## Псевдослучайные числа + +Библиотека предоставляет класс Random - генератор с собственным изолированным состоянием. + +```lua +local rng = random.Random() + +-- Используется аналогично math.random +local a = rng:random() --> [0..1) +local b = rng:random(10) --> [0..10] +local c = rng:random(5, 20) --> [5..20] + +-- Устанавливает состояние генератора для генерации воспроизводимой последовательности случайных чисел +rng:seed(42) +```