everything: voxelworld::Interface::set_voxel() and everything from there to updating geometry and physics on the client
This commit is contained in:
parent
8f196bb0e6
commit
12465d8e3b
@ -251,8 +251,9 @@ struct Module: public interface::Module, public network::Interface
|
||||
// Grab Peer (which contains socket)
|
||||
auto it = m_peers.find(recipient);
|
||||
if(it == m_peers.end()){
|
||||
throw Exception(ss_()+"network::send(): Peer "+itos(recipient) +
|
||||
" doesn't exist");
|
||||
log_w(MODULE, "network::send(): Peer %i doesn't exist",
|
||||
recipient);
|
||||
return;
|
||||
}
|
||||
Peer &peer = it->second;
|
||||
|
||||
|
@ -15,9 +15,15 @@ namespace Urho3D
|
||||
namespace replicate
|
||||
{
|
||||
namespace magic = Urho3D;
|
||||
using interface::Event;
|
||||
|
||||
typedef size_t PeerId;
|
||||
|
||||
struct Interface
|
||||
{
|
||||
virtual sv_<PeerId> find_peers_that_know_node(uint node_id) = 0;
|
||||
|
||||
virtual void emit_after_next_sync(Event event) = 0;
|
||||
};
|
||||
|
||||
inline bool access(interface::Server *server,
|
||||
|
@ -55,7 +55,9 @@ struct Module: public interface::Module, public replicate::Interface
|
||||
// NOTE: We use pointers to SceneReplicationStates as Connection pointers in
|
||||
// other replication states in order to scene->CleanupConnection()
|
||||
// without an actual Connection object (which we don't want to use)
|
||||
sm_<network::PeerInfo::Id, magic::SceneReplicationState> m_scene_states;
|
||||
sm_<PeerId, magic::SceneReplicationState> m_scene_states;
|
||||
|
||||
sv_<Event> m_events_to_emit_after_next_sync;
|
||||
|
||||
Module(interface::Server *server):
|
||||
interface::Module("replicate"),
|
||||
@ -137,11 +139,16 @@ struct Module: public interface::Module, public replicate::Interface
|
||||
log_d(MODULE, "replicate::on_tick");
|
||||
|
||||
sync_changes();
|
||||
|
||||
for(Event &event : m_events_to_emit_after_next_sync){
|
||||
m_server->emit_event(std::move(event));
|
||||
}
|
||||
m_events_to_emit_after_next_sync.clear();
|
||||
}
|
||||
|
||||
void sync_changes()
|
||||
{
|
||||
sv_<network::PeerInfo::Id> peers;
|
||||
sv_<PeerId> peers;
|
||||
network::access(m_server, [&](network::Interface *inetwork){
|
||||
peers = inetwork->list_peers();
|
||||
});
|
||||
@ -175,7 +182,7 @@ struct Module: public interface::Module, public replicate::Interface
|
||||
});
|
||||
}
|
||||
|
||||
void sync_node(network::PeerInfo::Id peer,
|
||||
void sync_node(PeerId peer,
|
||||
uint node_id, magic::HashSet<uint> &nodes_to_process,
|
||||
magic::Scene *scene, magic::SceneReplicationState &scene_state)
|
||||
{
|
||||
@ -209,7 +216,7 @@ struct Module: public interface::Module, public replicate::Interface
|
||||
}
|
||||
}
|
||||
|
||||
void sync_create_node(network::PeerInfo::Id peer, Node *node,
|
||||
void sync_create_node(PeerId peer, Node *node,
|
||||
magic::HashSet<uint> &nodes_to_process,
|
||||
Scene *scene, magic::SceneReplicationState &scene_state)
|
||||
{
|
||||
@ -264,7 +271,7 @@ struct Module: public interface::Module, public replicate::Interface
|
||||
scene_state.dirtyNodes_.Erase(node->GetID());
|
||||
}
|
||||
|
||||
void sync_existing_node(network::PeerInfo::Id peer,
|
||||
void sync_existing_node(PeerId peer,
|
||||
Node *node, magic::NodeReplicationState &node_state,
|
||||
magic::HashSet<uint> &nodes_to_process,
|
||||
Scene *scene, magic::SceneReplicationState &scene_state)
|
||||
@ -278,9 +285,9 @@ struct Module: public interface::Module, public replicate::Interface
|
||||
}
|
||||
|
||||
// Handle changed attributes
|
||||
if(node_state.dirtyAttributes_.Count()){
|
||||
log_d(MODULE, "sync_existing_node(): %zu: Changed attributes",
|
||||
node->GetID());
|
||||
if(node_state.dirtyAttributes_.Count() || node_state.dirtyVars_.Size()){
|
||||
log_d(MODULE, "sync_existing_node(): %zu: Changed attributes "
|
||||
"or variables", node->GetID());
|
||||
const magic::Vector<magic::AttributeInfo> &attributes =
|
||||
*node->GetNetworkAttributes();
|
||||
uint num = attributes.Size();
|
||||
@ -428,8 +435,7 @@ struct Module: public interface::Module, public replicate::Interface
|
||||
scene_state.dirtyNodes_.Erase(node->GetID());
|
||||
}
|
||||
|
||||
void send_to_peer(network::PeerInfo::Id peer,
|
||||
const ss_ &name, const magic::VectorBuffer &buf)
|
||||
void send_to_peer(PeerId peer, const ss_ &name, const magic::VectorBuffer &buf)
|
||||
{
|
||||
log_d(MODULE, "%s: Update size: %zu, data=%s",
|
||||
cs(name), buf.GetBuffer().Size());
|
||||
@ -453,6 +459,26 @@ struct Module: public interface::Module, public replicate::Interface
|
||||
|
||||
// Interface
|
||||
|
||||
sv_<PeerId> find_peers_that_know_node(uint node_id)
|
||||
{
|
||||
sv_<PeerId> result;
|
||||
for(auto &pair: m_scene_states){
|
||||
PeerId peer_id = pair.first;
|
||||
magic::SceneReplicationState &scene_state = pair.second;
|
||||
auto &node_states = scene_state.nodeStates_;
|
||||
auto it = node_states.Find(node_id);
|
||||
if(it != node_states.End()){
|
||||
result.push_back(peer_id);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void emit_after_next_sync(Event event)
|
||||
{
|
||||
m_events_to_emit_after_next_sync.push_back(std::move(event));
|
||||
}
|
||||
|
||||
void* get_interface()
|
||||
{
|
||||
return dynamic_cast<Interface*>(this);
|
||||
|
@ -31,6 +31,13 @@ namespace voxelworld
|
||||
{}
|
||||
};
|
||||
|
||||
struct NodeVoxelDataUpdatedEvent: public interface::Event::Private
|
||||
{
|
||||
uint node_id;
|
||||
|
||||
NodeVoxelDataUpdatedEvent(uint node_id): node_id(node_id){}
|
||||
};
|
||||
|
||||
struct Interface
|
||||
{
|
||||
virtual void load_or_generate_section(
|
||||
|
@ -42,6 +42,25 @@ M.section_size_voxels = nil
|
||||
function M.init()
|
||||
log:info("voxelworld.init()")
|
||||
|
||||
local node_update_queue = buildat.SpatialUpdateQueue()
|
||||
|
||||
local function queue_initial_node_update(node)
|
||||
-- TODO: node:GetWorldPosition() is not at center of node
|
||||
node_update_queue:put(node:GetWorldPosition(),
|
||||
INITIAL_GEOMETRY_NEAR_WEIGHT, camera_far_clip * 1.2,
|
||||
nil, nil, {
|
||||
type = "geometry",
|
||||
current_lod = 0,
|
||||
node_id = node:GetID(),
|
||||
})
|
||||
-- TODO: node:GetWorldPosition() is not at center of node
|
||||
node_update_queue:put(node:GetWorldPosition(),
|
||||
INITIAL_PHYSICS_NEAR_WEIGHT, PHYSICS_DISTANCE, nil, nil, {
|
||||
type = "physics",
|
||||
node_id = node:GetID(),
|
||||
})
|
||||
end
|
||||
|
||||
buildat.sub_packet("voxelworld:init", function(data)
|
||||
local values = cereal.binary_input(data, {"object",
|
||||
{"chunk_size_voxels", {"object",
|
||||
@ -55,15 +74,21 @@ function M.init()
|
||||
{"z", "int32_t"},
|
||||
}},
|
||||
})
|
||||
log:info(dump(values))
|
||||
log:info("voxelworld:init: "..dump(values))
|
||||
M.chunk_size_voxels = buildat.Vector3(values.chunk_size_voxels)
|
||||
M.section_size_chunks = buildat.Vector3(values.section_size_chunks)
|
||||
M.section_size_voxels =
|
||||
M.chunk_size_voxels:mul_components(M.section_size_chunks)
|
||||
end)
|
||||
|
||||
--local node_update_queue = SpatialUpdateQueue()
|
||||
local node_update_queue = buildat.SpatialUpdateQueue()
|
||||
buildat.sub_packet("voxelworld:node_voxel_data_updated", function(data)
|
||||
local values = cereal.binary_input(data, {"object",
|
||||
{"node_id", "int32_t"},
|
||||
})
|
||||
log:info("voxelworld:node_voxel_data_updated: "..dump(values))
|
||||
local node = replicate.main_scene:GetNode(values.node_id)
|
||||
queue_initial_node_update(node)
|
||||
end)
|
||||
|
||||
local function update_voxel_geometry(node)
|
||||
local data = node:GetVar("buildat_voxel_data"):GetBuffer()
|
||||
@ -258,21 +283,7 @@ function M.init()
|
||||
|
||||
replicate.sub_sync_node_added({}, function(node)
|
||||
if not node:GetVar("buildat_voxel_data"):IsEmpty() then
|
||||
-- TODO: node:GetWorldPosition() is not at center of node
|
||||
node_update_queue:put(node:GetWorldPosition(),
|
||||
INITIAL_GEOMETRY_NEAR_WEIGHT, camera_far_clip * 1.2,
|
||||
nil, nil, {
|
||||
type = "geometry",
|
||||
current_lod = 0,
|
||||
node_id = node:GetID(),
|
||||
})
|
||||
-- Create physics stuff when node comes closer than 100
|
||||
-- TODO: node:GetWorldPosition() is not at center of node
|
||||
node_update_queue:put(node:GetWorldPosition(),
|
||||
INITIAL_PHYSICS_NEAR_WEIGHT, PHYSICS_DISTANCE, nil, nil, {
|
||||
type = "physics",
|
||||
node_id = node:GetID(),
|
||||
})
|
||||
queue_initial_node_update(node)
|
||||
end
|
||||
--local name = node:GetName()
|
||||
end)
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "voxelworld/api.h"
|
||||
#include "network/api.h"
|
||||
#include "client_file/api.h"
|
||||
#include "replicate/api.h"
|
||||
#include "core/log.h"
|
||||
#include "interface/module.h"
|
||||
#include "interface/server.h"
|
||||
@ -309,6 +310,7 @@ struct Module: public interface::Module, public voxelworld::Interface
|
||||
m_server->sub_event(this, Event::t("client_file:files_transmitted"));
|
||||
m_server->sub_event(this, Event::t(
|
||||
"network:packet_received/voxelworld:get_section"));
|
||||
m_server->sub_event(this, Event::t("voxelworld:node_voxel_data_updated"));
|
||||
|
||||
m_server->access_scene([&](Scene *scene)
|
||||
{
|
||||
@ -427,6 +429,8 @@ struct Module: public interface::Module, public voxelworld::Interface
|
||||
client_file::FilesTransmitted)
|
||||
EVENT_TYPEN("network:packet_received/voxelworld:get_section",
|
||||
on_get_section, network::Packet)
|
||||
EVENT_TYPEN("voxelworld:node_voxel_data_updated",
|
||||
on_node_voxel_data_updated, voxelworld::NodeVoxelDataUpdatedEvent)
|
||||
}
|
||||
|
||||
void on_start()
|
||||
@ -566,6 +570,29 @@ struct Module: public interface::Module, public voxelworld::Interface
|
||||
packet.sender, PV3I_PARAMS(section_p));
|
||||
}
|
||||
|
||||
void on_node_voxel_data_updated(const NodeVoxelDataUpdatedEvent &event)
|
||||
{
|
||||
// NOTE: This delayed event is used so that when this is received,
|
||||
// replicate has already sent the data to clients
|
||||
|
||||
// Notify clients that know the node
|
||||
sv_<replicate::PeerId> peers;
|
||||
replicate::access(m_server, [&](replicate::Interface *ireplicate){
|
||||
peers = ireplicate->find_peers_that_know_node(event.node_id);
|
||||
});
|
||||
std::ostringstream os(std::ios::binary);
|
||||
{
|
||||
cereal::PortableBinaryOutputArchive ar(os);
|
||||
ar((int32_t)event.node_id);
|
||||
}
|
||||
network::access(m_server, [&](network::Interface *inetwork){
|
||||
for(auto &peer_id : peers){
|
||||
inetwork->send(peer_id, "voxelworld:node_voxel_data_updated",
|
||||
os.str());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Get section if exists
|
||||
Section* get_section(const pv::Vector3DInt16 §ion_p)
|
||||
{
|
||||
@ -929,6 +956,13 @@ struct Module: public interface::Module, public voxelworld::Interface
|
||||
new_data.size())));
|
||||
});
|
||||
|
||||
// Tell replicate to emit events once it has done its job
|
||||
replicate::access(m_server, [&](replicate::Interface *ireplicate){
|
||||
ireplicate->emit_after_next_sync(Event(
|
||||
"voxelworld:node_voxel_data_updated",
|
||||
new NodeVoxelDataUpdatedEvent(node_id)));
|
||||
});
|
||||
|
||||
// Mark node for collision box update
|
||||
mark_node_for_physics_update(node_id, chunk_buffer.volume);
|
||||
|
||||
|
@ -95,6 +95,24 @@ magic.SubscribeToEvent("KeyDown", function(event_type, event_data)
|
||||
end
|
||||
end)
|
||||
|
||||
magic.SubscribeToEvent("MouseButtonDown", function(event_type, event_data)
|
||||
local button = event_data:GetInt("Button")
|
||||
log:info(""..button)
|
||||
if button == 1 then
|
||||
local p = player_node.position
|
||||
local data = cereal.binary_output({
|
||||
p = {x = p.x, y = p.y, z = p.z},
|
||||
}, {"object",
|
||||
{"p", {"object",
|
||||
{"x", "int32_t"},
|
||||
{"y", "int32_t"},
|
||||
{"z", "int32_t"},
|
||||
}},
|
||||
})
|
||||
buildat.send_packet("main:place_voxel", data)
|
||||
end
|
||||
end)
|
||||
|
||||
magic.SubscribeToEvent("Update", function(event_type, event_data)
|
||||
--log:info("Update")
|
||||
if player_node then
|
||||
|
@ -23,14 +23,34 @@
|
||||
#include <cereal/types/unordered_map.hpp>
|
||||
#include <cereal/types/vector.hpp>
|
||||
|
||||
namespace digger {
|
||||
|
||||
namespace magic = Urho3D;
|
||||
namespace pv = PolyVox;
|
||||
|
||||
using interface::Event;
|
||||
using interface::VoxelInstance;
|
||||
|
||||
// TODO: Move to a header (core/types_polyvox.h or something)
|
||||
#define PV3I_FORMAT "(%i, %i, %i)"
|
||||
#define PV3I_PARAMS(p) p.getX(), p.getY(), p.getZ()
|
||||
|
||||
// TODO: Move to a header (core/cereal_polyvox.h or something)
|
||||
namespace cereal {
|
||||
|
||||
template<class Archive>
|
||||
void save(Archive &archive, const pv::Vector3DInt32 &v){
|
||||
archive((int32_t)v.getX(), (int32_t)v.getY(), (int32_t)v.getZ());
|
||||
}
|
||||
template<class Archive>
|
||||
void load(Archive &archive, pv::Vector3DInt32 &v){
|
||||
int32_t x, y, z;
|
||||
archive(x, y, z);
|
||||
v.setX(x); v.setY(y); v.setZ(z);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace digger {
|
||||
|
||||
using namespace Urho3D;
|
||||
|
||||
struct Module: public interface::Module
|
||||
@ -53,6 +73,8 @@ struct Module: public interface::Module
|
||||
m_server->sub_event(this, Event::t("core:tick"));
|
||||
m_server->sub_event(this, Event::t("client_file:files_transmitted"));
|
||||
m_server->sub_event(this, Event::t("voxelworld:generation_request"));
|
||||
m_server->sub_event(this, Event::t(
|
||||
"network:packet_received/main:place_voxel"));
|
||||
}
|
||||
|
||||
void event(const Event::Type &type, const Event::Private *p)
|
||||
@ -64,6 +86,8 @@ struct Module: public interface::Module
|
||||
on_files_transmitted, client_file::FilesTransmitted)
|
||||
EVENT_TYPEN("voxelworld:generation_request",
|
||||
on_generation_request, voxelworld::GenerationRequest)
|
||||
EVENT_TYPEN("network:packet_received/main:place_voxel",
|
||||
on_place_voxel, network::Packet)
|
||||
}
|
||||
|
||||
void on_start()
|
||||
@ -251,20 +275,37 @@ struct Module: public interface::Module
|
||||
|
||||
for(int y1=y; y1<y+4; y1++){
|
||||
pv::Vector3DInt32 p(x, y1, z);
|
||||
ivoxelworld->set_voxel(p, VoxelInstance(3));
|
||||
ivoxelworld->set_voxel(p, VoxelInstance(3), true);
|
||||
}
|
||||
|
||||
for(int x1 = x-2; x1 <= x+2; x1++){
|
||||
for(int y1 = y+3; y1 <= y+7; y1++){
|
||||
for(int z1 = z-2; z1 <= z+2; z1++){
|
||||
pv::Vector3DInt32 p(x1, y1, z1);
|
||||
ivoxelworld->set_voxel(p, VoxelInstance(5));
|
||||
ivoxelworld->set_voxel(p, VoxelInstance(5), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void on_place_voxel(const network::Packet &packet)
|
||||
{
|
||||
pv::Vector3DInt32 voxel_p;
|
||||
{
|
||||
std::istringstream is(packet.data, std::ios::binary);
|
||||
cereal::PortableBinaryInputArchive ar(is);
|
||||
ar(voxel_p);
|
||||
}
|
||||
log_v(MODULE, "C%i: on_place_voxel(): p=" PV3I_FORMAT,
|
||||
packet.sender, PV3I_PARAMS(voxel_p));
|
||||
|
||||
voxelworld::access(m_server, [&](voxelworld::Interface *ivoxelworld)
|
||||
{
|
||||
ivoxelworld->set_voxel(voxel_p, VoxelInstance(2));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
|
@ -417,10 +417,11 @@ void CState::setup_packet_handlers()
|
||||
uint node_id = msg.ReadNetID();
|
||||
Node *node = scene->GetNode(node_id);
|
||||
if(node){
|
||||
log_d(MODULE, "Updating node %i", node_id);
|
||||
log_d(MODULE, "Updating node %i (LatestDataUpdate)", node_id);
|
||||
node->ReadLatestDataUpdate(msg);
|
||||
} else {
|
||||
log_w(MODULE, "Out-of-order node data ignored for %i", node_id);
|
||||
// Note: Network/Connection.cpp would buffer this
|
||||
}
|
||||
};
|
||||
|
||||
@ -432,36 +433,55 @@ void CState::setup_packet_handlers()
|
||||
uint c_id = msg.ReadNetID();
|
||||
Component *c = scene->GetComponent(c_id);
|
||||
if(c){
|
||||
log_d(MODULE, "Updating component %i", c_id);
|
||||
log_d(MODULE, "Updating component %i (LatestDataUpdate)", c_id);
|
||||
c->ReadLatestDataUpdate(msg);
|
||||
c->ApplyAttributes();
|
||||
} else {
|
||||
log_w(MODULE, "Out-of-order component data ignored for %i", c_id);
|
||||
// Note: Network/Connection.cpp would buffer this
|
||||
}
|
||||
};
|
||||
|
||||
m_packet_handlers["replicate:node_delta_update"] =
|
||||
[this](const ss_ &packet_name, const ss_ &data)
|
||||
{
|
||||
log_w("TODO: %s", cs(packet_name));
|
||||
magic::Scene *scene = m_app->get_scene();
|
||||
magic::MemoryBuffer msg(data.c_str(), data.size());
|
||||
uint node_id = msg.ReadNetID();
|
||||
Node *node = scene->GetNode(node_id);
|
||||
if(node){
|
||||
log_d(MODULE, "Updating node %i (DeltaUpdate)", node_id);
|
||||
node->ReadDeltaUpdate(msg);
|
||||
} else {
|
||||
log_w(MODULE, "Out-of-order node data ignored for %i", node_id);
|
||||
// Note: Network/Connection.cpp would NOT buffer this
|
||||
}
|
||||
// Read user variables
|
||||
uint num_vars = msg.ReadVLE();
|
||||
while(num_vars){
|
||||
auto key = msg.ReadStringHash();
|
||||
node->SetVar(key, msg.ReadVariant());
|
||||
num_vars--;
|
||||
}
|
||||
};
|
||||
|
||||
m_packet_handlers["replicate:component_delta_update"] =
|
||||
[this](const ss_ &packet_name, const ss_ &data)
|
||||
{
|
||||
log_w("TODO: %s", cs(packet_name));
|
||||
log_w(MODULE, "TODO: %s", cs(packet_name));
|
||||
// Note: Network/Connection.cpp would NOT buffer this
|
||||
};
|
||||
|
||||
m_packet_handlers["replicate:remove_node"] =
|
||||
[this](const ss_ &packet_name, const ss_ &data)
|
||||
{
|
||||
log_w("TODO: %s", cs(packet_name));
|
||||
log_w(MODULE, "TODO: %s", cs(packet_name));
|
||||
};
|
||||
|
||||
m_packet_handlers["replicate:remove_component"] =
|
||||
[this](const ss_ &packet_name, const ss_ &data)
|
||||
{
|
||||
log_w("TODO: %s", cs(packet_name));
|
||||
log_w(MODULE, "TODO: %s", cs(packet_name));
|
||||
};
|
||||
|
||||
m_packet_handlers[""] =
|
||||
|
@ -472,7 +472,7 @@ void set_voxel_geometry(CustomGeometry *cg, Context *context,
|
||||
AtlasSegmentReference seg_ref = voxel_def0->textures[face_id];
|
||||
if(seg_ref.atlas_id == interface::ATLAS_UNDEFINED){
|
||||
// This is usually intentional for invisible voxels
|
||||
log_t(MODULE, "Voxel %i face %i atlas undefined", voxel_id0, face_id);
|
||||
//log_t(MODULE, "Voxel %i face %i atlas undefined", voxel_id0, face_id);
|
||||
continue;
|
||||
}
|
||||
const AtlasSegmentCache *aseg = atlas_reg->get_texture(seg_ref);
|
||||
@ -686,7 +686,7 @@ void set_voxel_lod_geometry(int lod, CustomGeometry *cg, Context *context,
|
||||
AtlasSegmentReference seg_ref = voxel_def0->lod_textures[lod_i][face_id];
|
||||
if(seg_ref.atlas_id == interface::ATLAS_UNDEFINED){
|
||||
// This is usually intentional for invisible voxels
|
||||
log_t(MODULE, "Voxel %i face %i atlas undefined", voxel_id0, face_id);
|
||||
//log_t(MODULE, "Voxel %i face %i atlas undefined", voxel_id0, face_id);
|
||||
continue;
|
||||
}
|
||||
const AtlasSegmentCache *aseg = atlas_reg->get_texture(seg_ref);
|
||||
|
@ -20,7 +20,7 @@ void PacketStream::input(std::deque<char> &socket_buffer,
|
||||
(socket_buffer[3] & 0xff)<<8 |
|
||||
(socket_buffer[4] & 0xff)<<16 |
|
||||
(socket_buffer[5] & 0xff)<<24;
|
||||
log_d(MODULE, "size=%zu", size);
|
||||
//log_d(MODULE, "size=%zu", size);
|
||||
if(socket_buffer.size() < 6 + size)
|
||||
return;
|
||||
log_d(MODULE, "Received full packet; type=%zu, "
|
||||
|
@ -24,6 +24,8 @@
|
||||
|
||||
namespace interface
|
||||
{
|
||||
// NOTE: Event has no copy constructor due to up_<Private> p; just pass it
|
||||
// by non-const value if it will be placed in a container by the receiver.
|
||||
struct Event
|
||||
{
|
||||
typedef size_t Type;
|
||||
|
@ -46,7 +46,7 @@ static int l_mkdir(lua_State *L)
|
||||
// pcall(function) -> status, error
|
||||
static int l_pcall(lua_State *L)
|
||||
{
|
||||
log_d(MODULE, "l_pcall()");
|
||||
log_t(MODULE, "l_pcall() begin");
|
||||
lua_pushcfunction(L, handle_error);
|
||||
int handle_error_stack_i = lua_gettop(L);
|
||||
|
||||
@ -54,7 +54,7 @@ static int l_pcall(lua_State *L)
|
||||
int r = lua_pcall(L, 0, 0, handle_error_stack_i);
|
||||
int error_stack_i = lua_gettop(L);
|
||||
if(r == 0){
|
||||
log_d(MODULE, "l_pcall() returned 0 (no error)");
|
||||
log_t(MODULE, "l_pcall() returned 0 (no error)");
|
||||
lua_pushboolean(L, true);
|
||||
return 1;
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ namespace lua_bindings {
|
||||
|
||||
struct SpatialUpdateQueue
|
||||
{
|
||||
struct Value { // Describes an update
|
||||
struct Value {
|
||||
ss_ type;
|
||||
uint32_t node_id = -1;
|
||||
};
|
||||
@ -50,12 +50,75 @@ struct SpatialUpdateQueue
|
||||
bool operator>(const Item &other) const;
|
||||
};
|
||||
|
||||
// Set of values with iterators for fast access of items, so that items
|
||||
// can be removed quickly by value
|
||||
struct ValueSet
|
||||
{
|
||||
struct Entry
|
||||
{
|
||||
Value value;
|
||||
std::list<Item>::iterator it;
|
||||
|
||||
Entry(const Value &value, std::list<Item>::iterator it =
|
||||
std::list<Item>::iterator()):
|
||||
value(value), it(it)
|
||||
{}
|
||||
bool operator>(const Entry &other) const {
|
||||
if(value.node_id > other.value.node_id)
|
||||
return true;
|
||||
if(value.node_id < other.value.node_id)
|
||||
return false;
|
||||
return value.type > other.value.type;
|
||||
}
|
||||
};
|
||||
|
||||
// sorted list in descending node_id and type order
|
||||
std::list<Entry> m_set;
|
||||
|
||||
void clear(){
|
||||
m_set.clear();
|
||||
}
|
||||
void insert(const Value &value, std::list<Item>::iterator queue_it){
|
||||
Entry entry(value, queue_it);
|
||||
auto it = std::lower_bound(m_set.begin(), m_set.end(), entry,
|
||||
std::greater<Entry>());
|
||||
if(it == m_set.end())
|
||||
m_set.insert(it, entry);
|
||||
else if(it->value.node_id != value.node_id ||
|
||||
it->value.type != value.type)
|
||||
m_set.insert(it, entry);
|
||||
else
|
||||
*it = entry;
|
||||
}
|
||||
void remove(const Value &value){
|
||||
Entry entry(value);
|
||||
auto it = std::lower_bound(m_set.begin(), m_set.end(), entry,
|
||||
std::greater<Entry>());
|
||||
if(it == m_set.end())
|
||||
return;
|
||||
m_set.erase(it);
|
||||
}
|
||||
std::list<Item>::iterator* find(const Value &value){
|
||||
Entry entry(value);
|
||||
auto it = std::lower_bound(m_set.begin(), m_set.end(), entry,
|
||||
std::greater<Entry>());
|
||||
if(it == m_set.end())
|
||||
return nullptr;
|
||||
if(it->value.node_id != value.node_id ||
|
||||
it->value.type != value.type)
|
||||
return nullptr;
|
||||
return &(it->it);
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
ValueSet m_value_set;
|
||||
|
||||
void update(int max_operations)
|
||||
{
|
||||
if(m_old_queue.empty())
|
||||
@ -76,6 +139,7 @@ struct SpatialUpdateQueue
|
||||
m_p = p;
|
||||
if(m_old_queue.empty() && (m_p - m_queue_oldest_p).Length() > 20){
|
||||
m_queue_length = 0;
|
||||
m_value_set.clear();
|
||||
m_old_queue.swap(m_queue);
|
||||
m_queue_oldest_p = m_p;
|
||||
}
|
||||
@ -109,10 +173,27 @@ struct SpatialUpdateQueue
|
||||
if(item.f == -1.0f || item.fw == -1.0f)
|
||||
throw Exception("item.f == -1.0f || item.fw == -1.0f");
|
||||
|
||||
// Find old entry; if the old entry is more important, discard the new
|
||||
// one; if the old entry is less important, remove the old entry
|
||||
std::list<Item>::iterator *itp = m_value_set.find(item.value);
|
||||
if(itp != nullptr){
|
||||
Item &old_item = **itp;
|
||||
if(old_item.fw < item.fw){
|
||||
// Old item is more important
|
||||
return;
|
||||
} else {
|
||||
// New item is more important
|
||||
m_value_set.remove(item.value);
|
||||
m_queue.erase(*itp);
|
||||
m_queue_length--;
|
||||
}
|
||||
}
|
||||
|
||||
auto it = std::lower_bound(m_queue.begin(), m_queue.end(),
|
||||
item, std::greater<Item>()); // position in descending order
|
||||
m_queue.insert(it, item);
|
||||
auto inserted_it = m_queue.insert(it, item);
|
||||
m_queue_length++;
|
||||
m_value_set.insert(item.value, inserted_it);
|
||||
}
|
||||
|
||||
void put(const Vector3 &p, float near_weight, float near_trigger_d,
|
||||
@ -135,6 +216,10 @@ struct SpatialUpdateQueue
|
||||
|
||||
void pop()
|
||||
{
|
||||
if(m_queue.empty())
|
||||
throw Exception("SpatialUpdateQueue::pop(): Empty");
|
||||
Item &item = m_queue.back();
|
||||
m_value_set.remove(item.value);
|
||||
m_queue.pop_back();
|
||||
m_queue_length--;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user