From 088bf63f3f336dd16267f2a59b3c4b725853531a Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 25 Sep 2025 23:53:11 +0300 Subject: [PATCH] replace lua Random implementation with usertype --- res/modules/internal/random_generator.lua | 35 ------------- res/scripts/stdmin.lua | 31 +++++++++++- src/logic/scripting/lua/libs/librandom.cpp | 4 +- src/logic/scripting/lua/lua_custom_types.hpp | 17 +++++++ src/logic/scripting/lua/lua_engine.cpp | 8 +++ src/logic/scripting/lua/lua_util.hpp | 9 ++++ .../lua/usertypes/lua_type_random.cpp | 49 +++++++++++++++++++ 7 files changed, 115 insertions(+), 38 deletions(-) delete mode 100644 res/modules/internal/random_generator.lua create mode 100644 src/logic/scripting/lua/usertypes/lua_type_random.cpp diff --git a/res/modules/internal/random_generator.lua b/res/modules/internal/random_generator.lua deleted file mode 100644 index 0c9073cc..00000000 --- a/res/modules/internal/random_generator.lua +++ /dev/null @@ -1,35 +0,0 @@ -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 742c9506..7fb2eca8 100644 --- a/res/scripts/stdmin.lua +++ b/res/scripts/stdmin.lua @@ -669,4 +669,33 @@ end bit.compile = require "core:bitwise/compiler" bit.execute = require "core:bitwise/executor" -random.Random = require "core:internal/random_generator" +function __vc_create_random_methods(random_methods) + local index = 1 + local buffer = nil + local buffer_size = 64 + + function random_methods:bytes(n) + local bytes = Bytearray(n) + for i=1,n do + bytes[i] = self:random(255) + end + return bytes + end + + function random_methods:random(a, b) + if not buffer or index > #buffer then + buffer = self:generate(buffer_size) + index = 1 + end + local value = buffer[index] + if b then + value = math.floor(value * (b - a + 1) + a) + elseif a then + value = math.floor(value * a + 1) + end + + index = index + 4 + return value + end + return random_methods +end diff --git a/src/logic/scripting/lua/libs/librandom.cpp b/src/logic/scripting/lua/libs/librandom.cpp index 192f83d1..b86bda58 100644 --- a/src/logic/scripting/lua/libs/librandom.cpp +++ b/src/logic/scripting/lua/libs/librandom.cpp @@ -22,7 +22,7 @@ static int l_random(lua::State* L) { } } -static int l_bytes(lua::State* L) { +static int l_generate(lua::State* L) { size_t size = lua::tointeger(L, 1); auto randomEngine = util::seeded_random_engine(random_device); @@ -40,7 +40,7 @@ static int l_uuid(lua::State* L) { const luaL_Reg randomlib[] = { {"random", lua::wrap}, - {"bytes", lua::wrap}, + {"bytes", lua::wrap}, {"uuid", lua::wrap}, {NULL, NULL} }; diff --git a/src/logic/scripting/lua/lua_custom_types.hpp b/src/logic/scripting/lua/lua_custom_types.hpp index 87080274..c17a78bc 100644 --- a/src/logic/scripting/lua/lua_custom_types.hpp +++ b/src/logic/scripting/lua/lua_custom_types.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "lua_commons.hpp" @@ -114,4 +115,20 @@ namespace lua { std::shared_ptr mData; }; static_assert(!std::is_abstract()); + + class LuaRandom : public Userdata { + public: + std::mt19937 rng; + + explicit LuaRandom(uint64_t seed) : rng(seed) {} + virtual ~LuaRandom() override = default; + + const std::string& getTypeName() const override { + return TYPENAME; + } + + static int createMetatable(lua::State*); + inline static std::string TYPENAME = "__vc_Random"; + }; + static_assert(!std::is_abstract()); } diff --git a/src/logic/scripting/lua/lua_engine.cpp b/src/logic/scripting/lua/lua_engine.cpp index 891614f0..6ffa9057 100644 --- a/src/logic/scripting/lua/lua_engine.cpp +++ b/src/logic/scripting/lua/lua_engine.cpp @@ -169,5 +169,13 @@ State* lua::create_state(const EnginePaths& paths, StateType stateType) { auto file = "res:scripts/stdmin.lua"; auto src = io::read_string(file); lua::pop(L, lua::execute(L, 0, src, "core:scripts/stdmin.lua")); + + newusertype(L); + if (getglobal(L, "random")) { + if (getglobal(L, "__vc_Random")) { + setfield(L, "Random"); + } + pop(L); + } return L; } diff --git a/src/logic/scripting/lua/lua_util.hpp b/src/logic/scripting/lua/lua_util.hpp index 121ebe29..75f30b54 100644 --- a/src/logic/scripting/lua/lua_util.hpp +++ b/src/logic/scripting/lua/lua_util.hpp @@ -275,6 +275,15 @@ namespace lua { } return nullptr; } + + template + inline T& require_userdata(lua::State* L, int idx) { + if (void* rawptr = lua_touserdata(L, idx)) { + return *static_cast(rawptr); + } + throw std::runtime_error("invalid 'self' value"); + } + template inline int newuserdata(lua::State* L, Args&&... args) { const auto& found = usertypeNames.find(typeid(T)); diff --git a/src/logic/scripting/lua/usertypes/lua_type_random.cpp b/src/logic/scripting/lua/usertypes/lua_type_random.cpp new file mode 100644 index 00000000..4d6a876c --- /dev/null +++ b/src/logic/scripting/lua/usertypes/lua_type_random.cpp @@ -0,0 +1,49 @@ +#include "../lua_custom_types.hpp" +#include "../lua_util.hpp" + +#include + +using namespace lua; +using namespace std::chrono; + +static int l_generate(lua::State* L) { + std::uniform_int_distribution<> dist(0, std::numeric_limits::max()); + + auto& rng = require_userdata(L, 1).rng; + size_t n = touinteger(L, 2); + createtable(L, n, 0); + + for (size_t i = 0; i < n; i++) { + pushnumber(L, dist(rng) / (double)std::numeric_limits::max()); + rawseti(L, i + 1); + } + return 1; +} + +static int l_meta_meta_call(lua::State* L) { + integer_t seed; + if (lua::isnoneornil(L, 1)) { + seed = system_clock::now().time_since_epoch().count(); + } else { + seed = tointeger(L, 1); + } + return newuserdata(L, seed); +} + +int LuaRandom::createMetatable(lua::State* L) { + createtable(L, 0, 3); + + requireglobal(L, "__vc_create_random_methods"); + createtable(L, 0, 0); + pushcfunction(L, wrap); + setfield(L, "generate"); + call(L, 1, 1); + + setfield(L, "__index"); + + createtable(L, 0, 1); + pushcfunction(L, wrap); + setfield(L, "__call"); + setmetatable(L); + return 1; +}