lua_bindings/spatial_update_queue: Initial half-working version
This commit is contained in:
parent
a2890529bf
commit
abad1e0e2f
@ -107,6 +107,7 @@ if(BUILD_CLIENT)
|
||||
src/lua_bindings/misc.cpp
|
||||
src/lua_bindings/cereal.cpp
|
||||
src/lua_bindings/voxel.cpp
|
||||
src/lua_bindings/spatial_update_queue.cpp
|
||||
)
|
||||
|
||||
add_executable(${CLIENT_EXE_NAME} ${CLIENT_SRCS})
|
||||
|
@ -213,14 +213,6 @@ local function SpatialUpdateQueue()
|
||||
near_weight=near_weight, near_trigger_d=near_trigger_d,
|
||||
far_weight=far_weight, far_trigger_d=far_trigger_d})
|
||||
end,
|
||||
-- Put something to be prioritized more the closer it is
|
||||
put_near_priority = function(self, p, trigger_d, weight, value)
|
||||
self:put(p, weight, trigger_d, nil, nil, value)
|
||||
end,
|
||||
-- Put something to be prioritized more the farther it is
|
||||
put_far_priority = function(self, p, trigger_d, weight, value)
|
||||
self:put(p, nil, nil, weight, trigger_d, value)
|
||||
end,
|
||||
get = function(self)
|
||||
local item = table.remove(self.queue)
|
||||
if not item then return nil end
|
||||
@ -241,6 +233,9 @@ local function SpatialUpdateQueue()
|
||||
if not item then return nil end
|
||||
return item.fw
|
||||
end,
|
||||
get_length = function(self)
|
||||
return #self.queue
|
||||
end,
|
||||
}
|
||||
return self
|
||||
end
|
||||
@ -268,7 +263,8 @@ function M.init()
|
||||
M.chunk_size_voxels:mul_components(M.section_size_chunks)
|
||||
end)
|
||||
|
||||
local node_update_queue = SpatialUpdateQueue()
|
||||
--local node_update_queue = SpatialUpdateQueue()
|
||||
local node_update_queue = buildat.SpatialUpdateQueue()
|
||||
|
||||
local function update_voxel_geometry(node)
|
||||
local data = node:GetVar("buildat_voxel_data"):GetBuffer()
|
||||
@ -381,7 +377,7 @@ function M.init()
|
||||
local node_update = node_update_queue:get()
|
||||
local node = replicate.main_scene:GetNode(node_update.node_id)
|
||||
log:verbose("Node update #"..
|
||||
#node_update_queue.queue..
|
||||
node_update_queue:get_length()..
|
||||
" (f="..(math.floor(f*100)/100)..""..
|
||||
", fw="..(math.floor(fw*100)/100)..")"..
|
||||
": "..node:GetName())
|
||||
@ -394,10 +390,10 @@ function M.init()
|
||||
did_update = true
|
||||
else
|
||||
log:verbose("Poked update #"..
|
||||
#node_update_queue.queue..
|
||||
node_update_queue:get_length()..
|
||||
" (f="..(math.floor((f or -1)*100)/100)..""..
|
||||
", fw="..(math.floor((fw or -1)*100)/100)..")")
|
||||
node_update_queue.queue = {}
|
||||
--node_update_queue.queue = {} -- For testing
|
||||
end
|
||||
-- Check this at the end of the loop so at least one is handled
|
||||
if not did_update or buildat.get_time_us() >= stop_at_us then
|
||||
|
@ -6,10 +6,53 @@ local log = buildat.Logger("__client/api")
|
||||
buildat.connect_server = __buildat_connect_server
|
||||
buildat.extension_path = __buildat_extension_path
|
||||
buildat.get_time_us = __buildat_get_time_us
|
||||
buildat.SpatialUpdateQueue = __buildat_SpatialUpdateQueue
|
||||
|
||||
buildat.safe.disconnect = __buildat_disconnect
|
||||
buildat.safe.get_time_us = __buildat_get_time_us
|
||||
|
||||
buildat.safe.SpatialUpdateQueue = function()
|
||||
local internal = __buildat_SpatialUpdateQueue()
|
||||
return {
|
||||
update = function(self, ...)
|
||||
return internal:update(...)
|
||||
end,
|
||||
set_p = function(self, ...)
|
||||
return internal:set_p(...)
|
||||
end,
|
||||
put = function(self, safe_p, near_weight, near_trigger_d,
|
||||
far_weight, far_trigger_d, value)
|
||||
if not getmetatable(safe_p) or
|
||||
getmetatable(safe_p).type_name ~= "Vector3" then
|
||||
error("p is not a sandboxed Vector3 instance")
|
||||
end
|
||||
p = getmetatable(safe_p).unsafe
|
||||
return internal:put(p, near_weight, near_trigger_d,
|
||||
far_weight, far_trigger_d, value)
|
||||
end,
|
||||
get = function(self, ...)
|
||||
return internal:get(...)
|
||||
end,
|
||||
peek_next_f = function(self, ...)
|
||||
return internal:peek_next_f(...)
|
||||
end,
|
||||
peek_next_fw = function(self, ...)
|
||||
return internal:peek_next_fw(...)
|
||||
end,
|
||||
get_length = function(self, ...)
|
||||
return internal:get_length(...)
|
||||
end,
|
||||
set_p = function(self, safe_p)
|
||||
if not getmetatable(safe_p) or
|
||||
getmetatable(safe_p).type_name ~= "Vector3" then
|
||||
error("p is not a sandboxed Vector3 instance")
|
||||
end
|
||||
p = getmetatable(safe_p).unsafe
|
||||
internal:set_p(p)
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
function buildat.safe.set_simple_voxel_model(safe_node, w, h, d, safe_buffer)
|
||||
if not getmetatable(safe_node) or
|
||||
getmetatable(safe_node).type_name ~= "Node" then
|
||||
|
@ -10,12 +10,14 @@ namespace lua_bindings {
|
||||
extern void init_misc(lua_State *L);
|
||||
extern void init_cereal(lua_State *L);
|
||||
extern void init_voxel(lua_State *L);
|
||||
extern void init_spatial_update_queue(lua_State *L);
|
||||
|
||||
void init(lua_State *L)
|
||||
{
|
||||
init_misc(L);
|
||||
init_cereal(L);
|
||||
init_voxel(L);
|
||||
init_spatial_update_queue(L);
|
||||
}
|
||||
|
||||
} // namespace lua_bindingss
|
||||
|
326
src/lua_bindings/spatial_update_queue.cpp
Normal file
326
src/lua_bindings/spatial_update_queue.cpp
Normal file
@ -0,0 +1,326 @@
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Copyright 2014 Perttu Ahola <celeron55@gmail.com>
|
||||
#include "lua_bindings/util.h"
|
||||
#include "core/log.h"
|
||||
#include <tolua++.h>
|
||||
#include <Vector3.h>
|
||||
#include <list>
|
||||
#include <algorithm>
|
||||
#define MODULE "lua_bindings"
|
||||
|
||||
#define DEF_METHOD(name){\
|
||||
lua_pushcfunction(L, l_##name);\
|
||||
lua_setfield(L, -2, #name);\
|
||||
}
|
||||
|
||||
#define GET_TOLUA_STUFF(result_name, index, type)\
|
||||
if(!tolua_isusertype(L, index, #type, 0, &tolua_err)){\
|
||||
tolua_error(L, __PRETTY_FUNCTION__, &tolua_err);\
|
||||
return 0;\
|
||||
}\
|
||||
type *result_name = (type*)tolua_tousertype(L, index, 0);
|
||||
#define TRY_GET_TOLUA_STUFF(result_name, index, type)\
|
||||
type *result_name = nullptr;\
|
||||
if(tolua_isusertype(L, index, #type, 0, &tolua_err)){\
|
||||
result_name = (type*)tolua_tousertype(L, index, 0);\
|
||||
}
|
||||
|
||||
// Just do this; Urho3D's stuff doesn't really clash with anything in buildat
|
||||
using namespace Urho3D;
|
||||
|
||||
namespace lua_bindings {
|
||||
|
||||
struct SpatialUpdateQueue
|
||||
{
|
||||
struct Value { // Describes an update
|
||||
ss_ type;
|
||||
uint32_t node_id = -1;
|
||||
};
|
||||
|
||||
struct Item { // Queue item
|
||||
Vector3 p = Vector3(0, 0, 0);
|
||||
Value value;
|
||||
float near_weight = -1.0f;
|
||||
float near_trigger_d = -1.0f;
|
||||
float far_weight = -1.0f;
|
||||
float far_trigger_d = -1.0f;
|
||||
float f = -1.0f;
|
||||
float fw = -1.0f;
|
||||
|
||||
bool operator>(const Item &other) const;
|
||||
};
|
||||
|
||||
Vector3 m_p;
|
||||
Vector3 m_queue_oldest_p;
|
||||
size_t m_queue_length = 0; // GCC std::list's size() is O(n)
|
||||
std::list<Item> m_queue;
|
||||
std::list<Item> m_old_queue;
|
||||
|
||||
void update(int max_operations)
|
||||
{
|
||||
if(m_old_queue.empty())
|
||||
return;
|
||||
log_d(MODULE, "SpatialUpdateQueue(): Items in old queue: %zu",
|
||||
m_old_queue.size());
|
||||
for(int i=0; i<max_operations; i++){
|
||||
if(m_old_queue.empty())
|
||||
break;
|
||||
Item &item = m_old_queue.back();
|
||||
put_item(item);
|
||||
m_old_queue.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void set_p(const Vector3 &p)
|
||||
{
|
||||
m_p = p;
|
||||
if(m_old_queue.empty() && (m_p - m_queue_oldest_p).Length() > 20){
|
||||
m_queue_length = 0;
|
||||
m_old_queue.swap(m_queue);
|
||||
m_queue_oldest_p = m_p;
|
||||
}
|
||||
}
|
||||
|
||||
void put_item(Item &item)
|
||||
{
|
||||
if(item.near_trigger_d == -1.0f && item.far_trigger_d == -1.0f)
|
||||
throw Exception("Item has neither trigger");
|
||||
float d = (item.p - m_p).Length();
|
||||
item.f = -1.0f;
|
||||
item.fw = -1.0f;
|
||||
if(item.near_trigger_d != -1.0f){
|
||||
float f_near = d / item.near_trigger_d;
|
||||
float fw_near = f_near / item.near_weight;
|
||||
if(item.fw == -1.0f || (fw_near < item.fw &&
|
||||
(item.f == -1.0f || f_near < item.f))){
|
||||
item.f = f_near;
|
||||
item.fw = fw_near;
|
||||
}
|
||||
}
|
||||
if(item.far_trigger_d != -1.0f){
|
||||
float f_far = item.far_trigger_d / d;
|
||||
float fw_far = f_far / item.far_weight;
|
||||
if(item.fw == -1.0f || (fw_far < item.fw &&
|
||||
(item.f == -1.0f || f_far < item.f))){
|
||||
item.f = f_far;
|
||||
item.fw = fw_far;
|
||||
}
|
||||
}
|
||||
if(item.f == -1.0f || item.fw == -1.0f)
|
||||
throw Exception("item.f == -1.0f || item.fw == -1.0f");
|
||||
|
||||
auto it = std::lower_bound(m_queue.begin(), m_queue.end(),
|
||||
item, std::greater<Item>()); // position in descending order
|
||||
m_queue.insert(it, item);
|
||||
m_queue_length++;
|
||||
}
|
||||
|
||||
void put(const Vector3 &p, float near_weight, float near_trigger_d,
|
||||
float far_weight, float far_trigger_d, const Value &value)
|
||||
{
|
||||
Item item;
|
||||
item.p = p;
|
||||
item.near_weight = near_weight;
|
||||
item.near_trigger_d = near_trigger_d;
|
||||
item.far_weight = far_weight;
|
||||
item.far_trigger_d = far_trigger_d;
|
||||
item.value = value;
|
||||
put_item(item);
|
||||
}
|
||||
|
||||
bool empty()
|
||||
{
|
||||
return m_queue.empty();
|
||||
}
|
||||
|
||||
void pop()
|
||||
{
|
||||
m_queue.pop_back();
|
||||
m_queue_length--;
|
||||
}
|
||||
|
||||
Value& get_value()
|
||||
{
|
||||
if(m_queue.empty())
|
||||
throw Exception("SpatialUpdateQueue::get_value(): Empty");
|
||||
return m_queue.back().value;
|
||||
}
|
||||
|
||||
float get_f()
|
||||
{
|
||||
if(m_queue.empty())
|
||||
throw Exception("SpatialUpdateQueue::get_f(): Empty");
|
||||
return m_queue.back().f;
|
||||
}
|
||||
|
||||
float get_fw()
|
||||
{
|
||||
if(m_queue.empty())
|
||||
throw Exception("SpatialUpdateQueue::get_fw(): Empty");
|
||||
return m_queue.back().fw;
|
||||
}
|
||||
|
||||
size_t get_length()
|
||||
{
|
||||
return m_queue_length;
|
||||
}
|
||||
};
|
||||
|
||||
bool SpatialUpdateQueue::Item::operator>(const Item &other) const
|
||||
{
|
||||
if(f > 1.0f && other.f <= 1.0f)
|
||||
return true;
|
||||
if(f <= 1.0f && other.f > 1.0f)
|
||||
return false;
|
||||
return fw > other.fw;
|
||||
}
|
||||
|
||||
struct LuaSUQ
|
||||
{
|
||||
static constexpr const char *class_name = "SpatialUpdateQueue";
|
||||
SpatialUpdateQueue internal;
|
||||
|
||||
static int gc_object(lua_State *L){
|
||||
delete *(LuaSUQ**)(lua_touserdata(L, 1));
|
||||
return 0;
|
||||
}
|
||||
static int l_update(lua_State *L){
|
||||
LuaSUQ *o = internal_checkobject(L, 1);
|
||||
int max_operations = luaL_checkinteger(L, 2);
|
||||
o->internal.update(max_operations);
|
||||
return 0;
|
||||
}
|
||||
static int l_set_p(lua_State *L){
|
||||
LuaSUQ *o = internal_checkobject(L, 1);
|
||||
tolua_Error tolua_err;
|
||||
GET_TOLUA_STUFF(p, 2, Vector3);
|
||||
o->internal.set_p(*p);
|
||||
return 0;
|
||||
}
|
||||
static int l_put(lua_State *L){
|
||||
LuaSUQ *o = internal_checkobject(L, 1);
|
||||
tolua_Error tolua_err;
|
||||
GET_TOLUA_STUFF(p, 2, Vector3);
|
||||
float near_weight = (lua_type(L, 3) == LUA_TNIL) ?
|
||||
-1.0f : luaL_checknumber(L, 3);
|
||||
float near_trigger_d = (lua_type(L, 4) == LUA_TNIL) ?
|
||||
-1.0f : luaL_checknumber(L, 4);
|
||||
float far_weight = (lua_type(L, 5) == LUA_TNIL) ?
|
||||
-1.0f : luaL_checknumber(L, 5);
|
||||
float far_trigger_d = (lua_type(L, 6) == LUA_TNIL) ?
|
||||
-1.0f : luaL_checknumber(L, 6);
|
||||
luaL_checktype(L, 7, LUA_TTABLE);
|
||||
SpatialUpdateQueue::Value value;
|
||||
lua_getfield(L, -1, "type");
|
||||
value.type = luaL_checkstring(L, -1);
|
||||
lua_pop(L, 1);
|
||||
lua_getfield(L, -1, "node_id");
|
||||
value.node_id = luaL_checkinteger(L, -1);
|
||||
lua_pop(L, 1);
|
||||
o->internal.put(*p, near_weight, near_trigger_d,
|
||||
far_weight, far_trigger_d, value);
|
||||
return 0;
|
||||
}
|
||||
static int l_get(lua_State *L){
|
||||
LuaSUQ *o = internal_checkobject(L, 1);
|
||||
if(o->internal.empty())
|
||||
return 0;
|
||||
SpatialUpdateQueue::Value &value = o->internal.get_value();
|
||||
lua_newtable(L);
|
||||
lua_pushstring(L, value.type.c_str());
|
||||
lua_setfield(L, -2, "type");
|
||||
lua_pushinteger(L, value.node_id);
|
||||
lua_setfield(L, -2, "node_id");
|
||||
o->internal.pop();
|
||||
return 1;
|
||||
}
|
||||
static int l_peek_next_f(lua_State *L){
|
||||
LuaSUQ *o = internal_checkobject(L, 1);
|
||||
if(o->internal.empty())
|
||||
return 0;
|
||||
float v = o->internal.get_f();
|
||||
lua_pushnumber(L, v);
|
||||
return 1;
|
||||
}
|
||||
static int l_peek_next_fw(lua_State *L){
|
||||
LuaSUQ *o = internal_checkobject(L, 1);
|
||||
if(o->internal.empty())
|
||||
return 0;
|
||||
float v = o->internal.get_fw();
|
||||
lua_pushnumber(L, v);
|
||||
return 1;
|
||||
}
|
||||
static int l_get_length(lua_State *L){
|
||||
LuaSUQ *o = internal_checkobject(L, 1);
|
||||
int l = o->internal.get_length();
|
||||
lua_pushinteger(L, l);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static LuaSUQ* internal_checkobject(lua_State *L, int narg){
|
||||
luaL_checktype(L, narg, LUA_TUSERDATA);
|
||||
void *ud = luaL_checkudata(L, narg, class_name);
|
||||
if(!ud) luaL_typerror(L, narg, class_name);
|
||||
return *(LuaSUQ**)ud;
|
||||
}
|
||||
static int l_create(lua_State *L){
|
||||
LuaSUQ *o = new LuaSUQ();
|
||||
*(void**)(lua_newuserdata(L, sizeof(void*))) = o;
|
||||
luaL_getmetatable(L, class_name);
|
||||
lua_setmetatable(L, -2);
|
||||
return 1;
|
||||
}
|
||||
static void register_metatable(lua_State *L){
|
||||
lua_newtable(L);
|
||||
int method_table_L = lua_gettop(L);
|
||||
luaL_newmetatable(L, class_name);
|
||||
int metatable_L = lua_gettop(L);
|
||||
|
||||
// hide metatable from Lua getmetatable()
|
||||
lua_pushliteral(L, "__metatable");
|
||||
lua_pushvalue(L, method_table_L);
|
||||
lua_settable(L, metatable_L);
|
||||
|
||||
lua_pushliteral(L, "__index");
|
||||
lua_pushvalue(L, method_table_L);
|
||||
lua_settable(L, metatable_L);
|
||||
|
||||
lua_pushliteral(L, "__gc");
|
||||
lua_pushcfunction(L, gc_object);
|
||||
lua_settable(L, metatable_L);
|
||||
|
||||
lua_pop(L, 1); // drop metatable_L
|
||||
|
||||
// fill method_table_L
|
||||
DEF_METHOD(update);
|
||||
DEF_METHOD(set_p);
|
||||
DEF_METHOD(put);
|
||||
DEF_METHOD(get);
|
||||
DEF_METHOD(peek_next_f);
|
||||
DEF_METHOD(peek_next_fw);
|
||||
DEF_METHOD(get_length);
|
||||
|
||||
// drop method_table_L
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
};
|
||||
|
||||
static int l_SpatialUpdateQueue(lua_State *L)
|
||||
{
|
||||
return LuaSUQ::l_create(L);
|
||||
}
|
||||
|
||||
void init_spatial_update_queue(lua_State *L)
|
||||
{
|
||||
#define DEF_BUILDAT_FUNC(name){ \
|
||||
lua_pushcfunction(L, l_##name); \
|
||||
lua_setglobal(L, "__buildat_" #name); \
|
||||
}
|
||||
LuaSUQ::register_metatable(L);
|
||||
|
||||
DEF_BUILDAT_FUNC(SpatialUpdateQueue);
|
||||
}
|
||||
|
||||
} // namespace lua_bindingss
|
||||
// vim: set noet ts=4 sw=4:
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "core/types.h"
|
||||
extern "C" {
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
}
|
||||
|
||||
namespace lua_bindings
|
||||
|
Loading…
x
Reference in New Issue
Block a user