]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/script/lua_api/l_noise.cpp
Change internal type for seeds to s32
[dragonfireclient.git] / src / script / lua_api / l_noise.cpp
index 4b0c7932ddb31ee83c29c06e94d20453f519c3fc..e0039371f0917aa9f4b3daa3ea87e97f6c1bb879 100644 (file)
@@ -22,73 +22,90 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "common/c_converter.h"
 #include "common/c_content.h"
 #include "log.h"
+#include "porting.h"
+#include "util/numeric.h"
 
-// garbage collector
-int LuaPerlinNoise::gc_object(lua_State *L)
+///////////////////////////////////////
+/*
+  LuaPerlinNoise
+*/
+
+LuaPerlinNoise::LuaPerlinNoise(NoiseParams *params) :
+       np(*params)
+{
+}
+
+
+LuaPerlinNoise::~LuaPerlinNoise()
 {
-       LuaPerlinNoise *o = *(LuaPerlinNoise **)(lua_touserdata(L, 1));
-       delete o;
-       return 0;
 }
 
+
 int LuaPerlinNoise::l_get2d(lua_State *L)
 {
        NO_MAP_LOCK_REQUIRED;
        LuaPerlinNoise *o = checkobject(L, 1);
-       v2f pos2d = read_v2f(L,2);
-       lua_Number val = noise2d_perlin(pos2d.X/o->scale, pos2d.Y/o->scale, o->seed, o->octaves, o->persistence);
+       v2f p = check_v2f(L, 2);
+       lua_Number val = NoisePerlin2D(&o->np, p.X, p.Y, 0);
        lua_pushnumber(L, val);
        return 1;
 }
+
+
 int LuaPerlinNoise::l_get3d(lua_State *L)
 {
        NO_MAP_LOCK_REQUIRED;
        LuaPerlinNoise *o = checkobject(L, 1);
-       v3f pos3d = read_v3f(L,2);
-       lua_Number val = noise3d_perlin(pos3d.X/o->scale, pos3d.Y/o->scale, pos3d.Z/o->scale, o->seed, o->octaves, o->persistence);
+       v3f p = check_v3f(L, 2);
+       lua_Number val = NoisePerlin3D(&o->np, p.X, p.Y, p.Z, 0);
        lua_pushnumber(L, val);
        return 1;
 }
 
 
-LuaPerlinNoise::LuaPerlinNoise(int a_seed, int a_octaves, float a_persistence,
-               float a_scale):
-       seed(a_seed),
-       octaves(a_octaves),
-       persistence(a_persistence),
-       scale(a_scale)
-{
-}
-
-LuaPerlinNoise::~LuaPerlinNoise()
-{
-}
-
-// LuaPerlinNoise(seed, octaves, persistence, scale)
-// Creates an LuaPerlinNoise and leaves it on top of stack
 int LuaPerlinNoise::create_object(lua_State *L)
 {
        NO_MAP_LOCK_REQUIRED;
-       int seed = luaL_checkint(L, 1);
-       int octaves = luaL_checkint(L, 2);
-       float persistence = luaL_checknumber(L, 3);
-       float scale = luaL_checknumber(L, 4);
-       LuaPerlinNoise *o = new LuaPerlinNoise(seed, octaves, persistence, scale);
+
+       NoiseParams params;
+
+       if (lua_istable(L, 1)) {
+               read_noiseparams(L, 1, &params);
+       } else {
+               params.seed    = luaL_checkint(L, 1);
+               params.octaves = luaL_checkint(L, 2);
+               params.persist = luaL_checknumber(L, 3);
+               params.spread  = v3f(1, 1, 1) * luaL_checknumber(L, 4);
+       }
+
+       LuaPerlinNoise *o = new LuaPerlinNoise(&params);
+
        *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
        luaL_getmetatable(L, className);
        lua_setmetatable(L, -2);
        return 1;
 }
 
-LuaPerlinNoise* LuaPerlinNoise::checkobject(lua_State *L, int narg)
+
+int LuaPerlinNoise::gc_object(lua_State *L)
+{
+       LuaPerlinNoise *o = *(LuaPerlinNoise **)(lua_touserdata(L, 1));
+       delete o;
+       return 0;
+}
+
+
+LuaPerlinNoise *LuaPerlinNoise::checkobject(lua_State *L, int narg)
 {
        NO_MAP_LOCK_REQUIRED;
        luaL_checktype(L, narg, LUA_TUSERDATA);
        void *ud = luaL_checkudata(L, narg, className);
-       if(!ud) luaL_typerror(L, narg, className);
-       return *(LuaPerlinNoise**)ud;  // unbox pointer
+       if (!ud)
+               luaL_typerror(L, narg, className);
+       return *(LuaPerlinNoise **)ud;
 }
 
+
 void LuaPerlinNoise::Register(lua_State *L)
 {
        lua_newtable(L);
@@ -98,7 +115,7 @@ void LuaPerlinNoise::Register(lua_State *L)
 
        lua_pushliteral(L, "__metatable");
        lua_pushvalue(L, methodtable);
-       lua_settable(L, metatable);  // hide metatable from Lua getmetatable()
+       lua_settable(L, metatable);
 
        lua_pushliteral(L, "__index");
        lua_pushvalue(L, methodtable);
@@ -108,15 +125,15 @@ void LuaPerlinNoise::Register(lua_State *L)
        lua_pushcfunction(L, gc_object);
        lua_settable(L, metatable);
 
-       lua_pop(L, 1);  // drop metatable
+       lua_pop(L, 1);
 
-       luaL_openlib(L, 0, methods, 0);  // fill methodtable
-       lua_pop(L, 1);  // drop methodtable
+       luaL_openlib(L, 0, methods, 0);
+       lua_pop(L, 1);
 
-       // Can be created from Lua (PerlinNoise(seed, octaves, persistence)
        lua_register(L, className, create_object);
 }
 
+
 const char LuaPerlinNoise::className[] = "PerlinNoise";
 const luaL_reg LuaPerlinNoise::methods[] = {
        luamethod(LuaPerlinNoise, get2d),
@@ -124,35 +141,45 @@ const luaL_reg LuaPerlinNoise::methods[] = {
        {0,0}
 };
 
+///////////////////////////////////////
 /*
-  PerlinNoiseMap
- */
+  LuaPerlinNoiseMap
+*/
+
+LuaPerlinNoiseMap::LuaPerlinNoiseMap(NoiseParams *params, s32 seed, v3s16 size)
+{
+       m_is3d = size.Z > 1;
+       np = *params;
+       try {
+               noise = new Noise(&np, seed, size.X, size.Y, size.Z);
+       } catch (InvalidNoiseParamsException &e) {
+               throw LuaError(e.what());
+       }
+}
 
 
-int LuaPerlinNoiseMap::gc_object(lua_State *L)
+LuaPerlinNoiseMap::~LuaPerlinNoiseMap()
 {
-       LuaPerlinNoiseMap *o = *(LuaPerlinNoiseMap **)(lua_touserdata(L, 1));
-       delete o;
-       return 0;
+       delete noise;
 }
 
+
 int LuaPerlinNoiseMap::l_get2dMap(lua_State *L)
 {
        NO_MAP_LOCK_REQUIRED;
-       int i = 0;
+       size_t i = 0;
 
        LuaPerlinNoiseMap *o = checkobject(L, 1);
-       v2f p = read_v2f(L, 2);
+       v2f p = check_v2f(L, 2);
 
        Noise *n = o->noise;
        n->perlinMap2D(p.X, p.Y);
 
        lua_newtable(L);
-       for (int y = 0; y != n->sy; y++) {
+       for (u32 y = 0; y != n->sy; y++) {
                lua_newtable(L);
-               for (int x = 0; x != n->sx; x++) {
-                       float noiseval = n->np->offset + n->np->scale * n->result[i++];
-                       lua_pushnumber(L, noiseval);
+               for (u32 x = 0; x != n->sx; x++) {
+                       lua_pushnumber(L, n->result[i++]);
                        lua_rawseti(L, -2, x + 1);
                }
                lua_rawseti(L, -2, y + 1);
@@ -160,45 +187,54 @@ int LuaPerlinNoiseMap::l_get2dMap(lua_State *L)
        return 1;
 }
 
+
 int LuaPerlinNoiseMap::l_get2dMap_flat(lua_State *L)
 {
        NO_MAP_LOCK_REQUIRED;
 
        LuaPerlinNoiseMap *o = checkobject(L, 1);
-       v2f p = read_v2f(L, 2);
+       v2f p                = check_v2f(L, 2);
+       bool use_buffer      = lua_istable(L, 3);
 
        Noise *n = o->noise;
        n->perlinMap2D(p.X, p.Y);
 
-       int maplen = n->sx * n->sy;
-       
-       lua_newtable(L);
-       for (int i = 0; i != maplen; i++) {
-               float noiseval = n->np->offset + n->np->scale * n->result[i];
-               lua_pushnumber(L, noiseval);
+       size_t maplen = n->sx * n->sy;
+
+       if (use_buffer)
+               lua_pushvalue(L, 3);
+       else
+               lua_newtable(L);
+
+       for (size_t i = 0; i != maplen; i++) {
+               lua_pushnumber(L, n->result[i]);
                lua_rawseti(L, -2, i + 1);
        }
        return 1;
 }
 
+
 int LuaPerlinNoiseMap::l_get3dMap(lua_State *L)
 {
        NO_MAP_LOCK_REQUIRED;
-       int i = 0;
+       size_t i = 0;
 
        LuaPerlinNoiseMap *o = checkobject(L, 1);
-       v3f p = read_v3f(L, 2);
+       v3f p = check_v3f(L, 2);
+
+       if (!o->m_is3d)
+               return 0;
 
        Noise *n = o->noise;
        n->perlinMap3D(p.X, p.Y, p.Z);
 
        lua_newtable(L);
-       for (int z = 0; z != n->sz; z++) {
+       for (u32 z = 0; z != n->sz; z++) {
                lua_newtable(L);
-               for (int y = 0; y != n->sy; y++) {
+               for (u32 y = 0; y != n->sy; y++) {
                        lua_newtable(L);
-                       for (int x = 0; x != n->sx; x++) {
-                               lua_pushnumber(L, n->np->offset + n->np->scale * n->result[i++]);
+                       for (u32 x = 0; x != n->sx; x++) {
+                               lua_pushnumber(L, n->result[i++]);
                                lua_rawseti(L, -2, x + 1);
                        }
                        lua_rawseti(L, -2, y + 1);
@@ -208,55 +244,115 @@ int LuaPerlinNoiseMap::l_get3dMap(lua_State *L)
        return 1;
 }
 
+
 int LuaPerlinNoiseMap::l_get3dMap_flat(lua_State *L)
 {
        NO_MAP_LOCK_REQUIRED;
 
        LuaPerlinNoiseMap *o = checkobject(L, 1);
-       v3f p = read_v3f(L, 2);
+       v3f p                = check_v3f(L, 2);
+       bool use_buffer      = lua_istable(L, 3);
+
+       if (!o->m_is3d)
+               return 0;
 
        Noise *n = o->noise;
        n->perlinMap3D(p.X, p.Y, p.Z);
 
+       size_t maplen = n->sx * n->sy * n->sz;
 
-       int maplen = n->sx * n->sy * n->sz;
-       
-       lua_newtable(L);
-       for (int i = 0; i != maplen; i++) {
-               float noiseval = n->np->offset + n->np->scale * n->result[i];
-               lua_pushnumber(L, noiseval);
+       if (use_buffer)
+               lua_pushvalue(L, 3);
+       else
+               lua_newtable(L);
+
+       for (size_t i = 0; i != maplen; i++) {
+               lua_pushnumber(L, n->result[i]);
                lua_rawseti(L, -2, i + 1);
        }
        return 1;
 }
 
-LuaPerlinNoiseMap::LuaPerlinNoiseMap(NoiseParams *np, int seed, v3s16 size) {
-       noise = new Noise(np, seed, size.X, size.Y, size.Z);
+
+int LuaPerlinNoiseMap::l_calc2dMap(lua_State *L)
+{
+       NO_MAP_LOCK_REQUIRED;
+
+       LuaPerlinNoiseMap *o = checkobject(L, 1);
+       v2f p                = check_v2f(L, 2);
+
+       Noise *n = o->noise;
+       n->perlinMap2D(p.X, p.Y);
+
+       return 0;
+}
+
+int LuaPerlinNoiseMap::l_calc3dMap(lua_State *L)
+{
+       NO_MAP_LOCK_REQUIRED;
+
+       LuaPerlinNoiseMap *o = checkobject(L, 1);
+       v3f p                = check_v3f(L, 2);
+
+       if (!o->m_is3d)
+               return 0;
+
+       Noise *n = o->noise;
+       n->perlinMap3D(p.X, p.Y, p.Z);
+
+       return 0;
 }
 
-LuaPerlinNoiseMap::~LuaPerlinNoiseMap()
+
+int LuaPerlinNoiseMap::l_getMapSlice(lua_State *L)
 {
-       delete noise->np;
-       delete noise;
+       NO_MAP_LOCK_REQUIRED;
+
+       LuaPerlinNoiseMap *o = checkobject(L, 1);
+       v3s16 slice_offset   = read_v3s16(L, 2);
+       v3s16 slice_size     = read_v3s16(L, 3);
+       bool use_buffer      = lua_istable(L, 4);
+
+       Noise *n = o->noise;
+
+       if (use_buffer)
+               lua_pushvalue(L, 3);
+       else
+               lua_newtable(L);
+
+       write_array_slice_float(L, lua_gettop(L), n->result,
+               v3u16(n->sx, n->sy, n->sz),
+               v3u16(slice_offset.X, slice_offset.Y, slice_offset.Z),
+               v3u16(slice_size.X, slice_size.Y, slice_size.Z));
+
+       return 1;
 }
 
-// LuaPerlinNoiseMap(np, size)
-// Creates an LuaPerlinNoiseMap and leaves it on top of stack
+
 int LuaPerlinNoiseMap::create_object(lua_State *L)
 {
-       NoiseParams *np = read_noiseparams(L, 1);
-       if (!np)
+       NoiseParams np;
+       if (!read_noiseparams(L, 1, &np))
                return 0;
        v3s16 size = read_v3s16(L, 2);
 
-       LuaPerlinNoiseMap *o = new LuaPerlinNoiseMap(np, 0, size);
+       LuaPerlinNoiseMap *o = new LuaPerlinNoiseMap(&np, 0, size);
        *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
        luaL_getmetatable(L, className);
        lua_setmetatable(L, -2);
        return 1;
 }
 
-LuaPerlinNoiseMap* LuaPerlinNoiseMap::checkobject(lua_State *L, int narg)
+
+int LuaPerlinNoiseMap::gc_object(lua_State *L)
+{
+       LuaPerlinNoiseMap *o = *(LuaPerlinNoiseMap **)(lua_touserdata(L, 1));
+       delete o;
+       return 0;
+}
+
+
+LuaPerlinNoiseMap *LuaPerlinNoiseMap::checkobject(lua_State *L, int narg)
 {
        luaL_checktype(L, narg, LUA_TUSERDATA);
 
@@ -264,9 +360,10 @@ LuaPerlinNoiseMap* LuaPerlinNoiseMap::checkobject(lua_State *L, int narg)
        if (!ud)
                luaL_typerror(L, narg, className);
 
-       return *(LuaPerlinNoiseMap **)ud;  // unbox pointer
+       return *(LuaPerlinNoiseMap **)ud;
 }
 
+
 void LuaPerlinNoiseMap::Register(lua_State *L)
 {
        lua_newtable(L);
@@ -276,7 +373,7 @@ void LuaPerlinNoiseMap::Register(lua_State *L)
 
        lua_pushliteral(L, "__metatable");
        lua_pushvalue(L, methodtable);
-       lua_settable(L, metatable);  // hide metatable from Lua getmetatable()
+       lua_settable(L, metatable);
 
        lua_pushliteral(L, "__index");
        lua_pushvalue(L, methodtable);
@@ -286,54 +383,50 @@ void LuaPerlinNoiseMap::Register(lua_State *L)
        lua_pushcfunction(L, gc_object);
        lua_settable(L, metatable);
 
-       lua_pop(L, 1);  // drop metatable
+       lua_pop(L, 1);
 
-       luaL_openlib(L, 0, methods, 0);  // fill methodtable
-       lua_pop(L, 1);  // drop methodtable
+       luaL_openlib(L, 0, methods, 0);
+       lua_pop(L, 1);
 
-       // Can be created from Lua (PerlinNoiseMap(np, size)
        lua_register(L, className, create_object);
 }
 
+
 const char LuaPerlinNoiseMap::className[] = "PerlinNoiseMap";
 const luaL_reg LuaPerlinNoiseMap::methods[] = {
        luamethod(LuaPerlinNoiseMap, get2dMap),
        luamethod(LuaPerlinNoiseMap, get2dMap_flat),
+       luamethod(LuaPerlinNoiseMap, calc2dMap),
        luamethod(LuaPerlinNoiseMap, get3dMap),
        luamethod(LuaPerlinNoiseMap, get3dMap_flat),
+       luamethod(LuaPerlinNoiseMap, calc3dMap),
+       luamethod(LuaPerlinNoiseMap, getMapSlice),
        {0,0}
 };
 
+///////////////////////////////////////
 /*
        LuaPseudoRandom
 */
 
-// garbage collector
-int LuaPseudoRandom::gc_object(lua_State *L)
-{
-       LuaPseudoRandom *o = *(LuaPseudoRandom **)(lua_touserdata(L, 1));
-       delete o;
-       return 0;
-}
-
-// next(self, min=0, max=32767) -> get next value
 int LuaPseudoRandom::l_next(lua_State *L)
 {
        NO_MAP_LOCK_REQUIRED;
+
        LuaPseudoRandom *o = checkobject(L, 1);
        int min = 0;
        int max = 32767;
-       lua_settop(L, 3); // Fill 2 and 3 with nil if they don't exist
-       if(!lua_isnil(L, 2))
+       lua_settop(L, 3);
+       if (lua_isnumber(L, 2))
                min = luaL_checkinteger(L, 2);
-       if(!lua_isnil(L, 3))
+       if (lua_isnumber(L, 3))
                max = luaL_checkinteger(L, 3);
-       if(max < min){
+       if (max < min) {
                errorstream<<"PseudoRandom.next(): max="<<max<<" min="<<min<<std::endl;
-               throw LuaError(L, "PseudoRandom.next(): max < min");
+               throw LuaError("PseudoRandom.next(): max < min");
        }
        if(max - min != 32767 && max - min > 32767/5)
-               throw LuaError(L, "PseudoRandom.next() max-min is not 32767"
+               throw LuaError("PseudoRandom.next() max-min is not 32767"
                                " and is > 32768/5. This is disallowed due to"
                                " the bad random distribution the"
                                " implementation would otherwise make.");
@@ -345,45 +438,252 @@ int LuaPseudoRandom::l_next(lua_State *L)
 }
 
 
-LuaPseudoRandom::LuaPseudoRandom(int seed):
-       m_pseudo(seed)
+int LuaPseudoRandom::create_object(lua_State *L)
+{
+       NO_MAP_LOCK_REQUIRED;
+
+       u64 seed = luaL_checknumber(L, 1);
+       LuaPseudoRandom *o = new LuaPseudoRandom(seed);
+       *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+       luaL_getmetatable(L, className);
+       lua_setmetatable(L, -2);
+       return 1;
+}
+
+
+int LuaPseudoRandom::gc_object(lua_State *L)
+{
+       LuaPseudoRandom *o = *(LuaPseudoRandom **)(lua_touserdata(L, 1));
+       delete o;
+       return 0;
+}
+
+
+LuaPseudoRandom *LuaPseudoRandom::checkobject(lua_State *L, int narg)
+{
+       luaL_checktype(L, narg, LUA_TUSERDATA);
+       void *ud = luaL_checkudata(L, narg, className);
+       if (!ud)
+               luaL_typerror(L, narg, className);
+       return *(LuaPseudoRandom **)ud;
+}
+
+
+void LuaPseudoRandom::Register(lua_State *L)
+{
+       lua_newtable(L);
+       int methodtable = lua_gettop(L);
+       luaL_newmetatable(L, className);
+       int metatable = lua_gettop(L);
+
+       lua_pushliteral(L, "__metatable");
+       lua_pushvalue(L, methodtable);
+       lua_settable(L, metatable);
+
+       lua_pushliteral(L, "__index");
+       lua_pushvalue(L, methodtable);
+       lua_settable(L, metatable);
+
+       lua_pushliteral(L, "__gc");
+       lua_pushcfunction(L, gc_object);
+       lua_settable(L, metatable);
+
+       lua_pop(L, 1);
+
+       luaL_openlib(L, 0, methods, 0);
+       lua_pop(L, 1);
+
+       lua_register(L, className, create_object);
+}
+
+
+const char LuaPseudoRandom::className[] = "PseudoRandom";
+const luaL_reg LuaPseudoRandom::methods[] = {
+       luamethod(LuaPseudoRandom, next),
+       {0,0}
+};
+
+///////////////////////////////////////
+/*
+       LuaPcgRandom
+*/
+
+int LuaPcgRandom::l_next(lua_State *L)
+{
+       NO_MAP_LOCK_REQUIRED;
+
+       LuaPcgRandom *o = checkobject(L, 1);
+       u32 min = lua_isnumber(L, 2) ? lua_tointeger(L, 2) : o->m_rnd.RANDOM_MIN;
+       u32 max = lua_isnumber(L, 3) ? lua_tointeger(L, 3) : o->m_rnd.RANDOM_MAX;
+
+       lua_pushinteger(L, o->m_rnd.range(min, max));
+       return 1;
+}
+
+
+int LuaPcgRandom::l_rand_normal_dist(lua_State *L)
+{
+       NO_MAP_LOCK_REQUIRED;
+
+       LuaPcgRandom *o = checkobject(L, 1);
+       u32 min = lua_isnumber(L, 2) ? lua_tointeger(L, 2) : o->m_rnd.RANDOM_MIN;
+       u32 max = lua_isnumber(L, 3) ? lua_tointeger(L, 3) : o->m_rnd.RANDOM_MAX;
+       int num_trials = lua_isnumber(L, 4) ? lua_tointeger(L, 4) : 6;
+
+       lua_pushinteger(L, o->m_rnd.randNormalDist(min, max, num_trials));
+       return 1;
+}
+
+
+int LuaPcgRandom::create_object(lua_State *L)
+{
+       NO_MAP_LOCK_REQUIRED;
+
+       u64 seed = luaL_checknumber(L, 1);
+       LuaPcgRandom *o = lua_isnumber(L, 2) ?
+               new LuaPcgRandom(seed, lua_tointeger(L, 2)) :
+               new LuaPcgRandom(seed);
+       *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+       luaL_getmetatable(L, className);
+       lua_setmetatable(L, -2);
+       return 1;
+}
+
+
+int LuaPcgRandom::gc_object(lua_State *L)
+{
+       LuaPcgRandom *o = *(LuaPcgRandom **)(lua_touserdata(L, 1));
+       delete o;
+       return 0;
+}
+
+
+LuaPcgRandom *LuaPcgRandom::checkobject(lua_State *L, int narg)
 {
+       luaL_checktype(L, narg, LUA_TUSERDATA);
+       void *ud = luaL_checkudata(L, narg, className);
+       if (!ud)
+               luaL_typerror(L, narg, className);
+       return *(LuaPcgRandom **)ud;
 }
 
-LuaPseudoRandom::~LuaPseudoRandom()
+
+void LuaPcgRandom::Register(lua_State *L)
 {
+       lua_newtable(L);
+       int methodtable = lua_gettop(L);
+       luaL_newmetatable(L, className);
+       int metatable = lua_gettop(L);
+
+       lua_pushliteral(L, "__metatable");
+       lua_pushvalue(L, methodtable);
+       lua_settable(L, metatable);
+
+       lua_pushliteral(L, "__index");
+       lua_pushvalue(L, methodtable);
+       lua_settable(L, metatable);
+
+       lua_pushliteral(L, "__gc");
+       lua_pushcfunction(L, gc_object);
+       lua_settable(L, metatable);
+
+       lua_pop(L, 1);
+
+       luaL_openlib(L, 0, methods, 0);
+       lua_pop(L, 1);
+
+       lua_register(L, className, create_object);
 }
 
-const PseudoRandom& LuaPseudoRandom::getItem() const
+
+const char LuaPcgRandom::className[] = "PcgRandom";
+const luaL_reg LuaPcgRandom::methods[] = {
+       luamethod(LuaPcgRandom, next),
+       luamethod(LuaPcgRandom, rand_normal_dist),
+       {0,0}
+};
+
+///////////////////////////////////////
+/*
+       LuaSecureRandom
+*/
+
+bool LuaSecureRandom::fillRandBuf()
 {
-       return m_pseudo;
+       return porting::secure_rand_fill_buf(m_rand_buf, RAND_BUF_SIZE);
 }
-PseudoRandom& LuaPseudoRandom::getItem()
+
+int LuaSecureRandom::l_next_bytes(lua_State *L)
 {
-       return m_pseudo;
+       NO_MAP_LOCK_REQUIRED;
+
+       LuaSecureRandom *o = checkobject(L, 1);
+       u32 count = lua_isnumber(L, 2) ? lua_tointeger(L, 2) : 1;
+
+       // Limit count
+       count = MYMIN(RAND_BUF_SIZE, count);
+
+       // Find out whether we can pass directly from our array, or have to do some gluing
+       size_t count_remaining = RAND_BUF_SIZE - o->m_rand_idx;
+       if (count_remaining >= count) {
+               lua_pushlstring(L, o->m_rand_buf + o->m_rand_idx, count);
+               o->m_rand_idx += count;
+       } else {
+               char output_buf[RAND_BUF_SIZE];
+
+               // Copy over with what we have left from our current buffer
+               memcpy(output_buf, o->m_rand_buf + o->m_rand_idx, count_remaining);
+
+               // Refill buffer and copy over the remainder of what was requested
+               o->fillRandBuf();
+               memcpy(output_buf + count_remaining, o->m_rand_buf, count - count_remaining);
+
+               // Update index
+               o->m_rand_idx = count - count_remaining;
+
+               lua_pushlstring(L, output_buf, count);
+       }
+
+       return 1;
 }
 
-// LuaPseudoRandom(seed)
-// Creates an LuaPseudoRandom and leaves it on top of stack
-int LuaPseudoRandom::create_object(lua_State *L)
+
+int LuaSecureRandom::create_object(lua_State *L)
 {
-       int seed = luaL_checknumber(L, 1);
-       LuaPseudoRandom *o = new LuaPseudoRandom(seed);
+       LuaSecureRandom *o = new LuaSecureRandom();
+
+       // Fail and return nil if we can't securely fill the buffer
+       if (!o->fillRandBuf()) {
+               delete o;
+               return 0;
+       }
+
        *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
        luaL_getmetatable(L, className);
        lua_setmetatable(L, -2);
        return 1;
 }
 
-LuaPseudoRandom* LuaPseudoRandom::checkobject(lua_State *L, int narg)
+
+int LuaSecureRandom::gc_object(lua_State *L)
+{
+       LuaSecureRandom *o = *(LuaSecureRandom **)(lua_touserdata(L, 1));
+       delete o;
+       return 0;
+}
+
+
+LuaSecureRandom *LuaSecureRandom::checkobject(lua_State *L, int narg)
 {
        luaL_checktype(L, narg, LUA_TUSERDATA);
        void *ud = luaL_checkudata(L, narg, className);
-       if(!ud) luaL_typerror(L, narg, className);
-       return *(LuaPseudoRandom**)ud;  // unbox pointer
+       if (!ud)
+               luaL_typerror(L, narg, className);
+       return *(LuaSecureRandom **)ud;
 }
 
-void LuaPseudoRandom::Register(lua_State *L)
+
+void LuaSecureRandom::Register(lua_State *L)
 {
        lua_newtable(L);
        int methodtable = lua_gettop(L);
@@ -392,7 +692,7 @@ void LuaPseudoRandom::Register(lua_State *L)
 
        lua_pushliteral(L, "__metatable");
        lua_pushvalue(L, methodtable);
-       lua_settable(L, metatable);  // hide metatable from Lua getmetatable()
+       lua_settable(L, metatable);
 
        lua_pushliteral(L, "__index");
        lua_pushvalue(L, methodtable);
@@ -402,17 +702,16 @@ void LuaPseudoRandom::Register(lua_State *L)
        lua_pushcfunction(L, gc_object);
        lua_settable(L, metatable);
 
-       lua_pop(L, 1);  // drop metatable
+       lua_pop(L, 1);
 
-       luaL_openlib(L, 0, methods, 0);  // fill methodtable
-       lua_pop(L, 1);  // drop methodtable
+       luaL_openlib(L, 0, methods, 0);
+       lua_pop(L, 1);
 
-       // Can be created from Lua (LuaPseudoRandom(seed))
        lua_register(L, className, create_object);
 }
 
-const char LuaPseudoRandom::className[] = "PseudoRandom";
-const luaL_reg LuaPseudoRandom::methods[] = {
-       luamethod(LuaPseudoRandom, next),
+const char LuaSecureRandom::className[] = "SecureRandom";
+const luaL_reg LuaSecureRandom::methods[] = {
+       luamethod(LuaSecureRandom, next_bytes),
        {0,0}
 };