builtin/voxelworld: Use voxelworld:node_volume_updated instead of CommitHook for post-commit processing and continuously limit amount of loaded buffers
This commit is contained in:
parent
9fc9f846e2
commit
6384ff4d84
@ -163,18 +163,123 @@ struct GlobalYSTMap
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Y-seethrough commit hook
|
struct Module: public interface::Module, public ground_plane_lighting::Interface
|
||||||
struct YstCommitHook: public voxelworld::CommitHook
|
|
||||||
{
|
{
|
||||||
static constexpr const char *MODULE = "YstCommitHook";
|
|
||||||
interface::Server *m_server;
|
interface::Server *m_server;
|
||||||
|
|
||||||
YstCommitHook(interface::Server *server):
|
up_<GlobalYSTMap> m_global_yst;
|
||||||
m_server(server)
|
|
||||||
{}
|
|
||||||
|
|
||||||
void after_commit(voxelworld::Interface *ivoxelworld,
|
Module(interface::Server *server):
|
||||||
const pv::Vector3DInt32 &chunk_p)
|
interface::Module("ground_plane_lighting"),
|
||||||
|
m_server(server)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~Module()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void init()
|
||||||
|
{
|
||||||
|
m_server->sub_event(this, Event::t("core:start"));
|
||||||
|
m_server->sub_event(this, Event::t("core:unload"));
|
||||||
|
m_server->sub_event(this, Event::t("core:continue"));
|
||||||
|
m_server->sub_event(this, Event::t("core:tick"));
|
||||||
|
m_server->sub_event(this, Event::t("network:client_connected"));
|
||||||
|
m_server->sub_event(this, Event::t("client_file:files_transmitted"));
|
||||||
|
m_server->sub_event(this, Event::t("voxelworld:node_volume_updated"));
|
||||||
|
|
||||||
|
voxelworld::access(m_server, [&](voxelworld::Interface *ivoxelworld)
|
||||||
|
{
|
||||||
|
pv::Vector3DInt16 section_size =
|
||||||
|
ivoxelworld->get_section_size_voxels();
|
||||||
|
pv::Vector<2, int16_t> sector_size(
|
||||||
|
section_size.getX(), section_size.getZ());
|
||||||
|
m_global_yst.reset(new GlobalYSTMap(sector_size));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void event(const Event::Type &type, const Event::Private *p)
|
||||||
|
{
|
||||||
|
EVENT_VOIDN("core:start", on_start)
|
||||||
|
EVENT_VOIDN("core:unload", on_unload)
|
||||||
|
EVENT_VOIDN("core:continue", on_continue)
|
||||||
|
EVENT_TYPEN("core:tick", on_tick, interface::TickEvent)
|
||||||
|
EVENT_TYPEN("network:client_connected", on_client_connected,
|
||||||
|
network::NewClient)
|
||||||
|
EVENT_TYPEN("client_file:files_transmitted", on_files_transmitted,
|
||||||
|
client_file::FilesTransmitted)
|
||||||
|
EVENT_TYPEN("voxelworld:node_volume_updated",
|
||||||
|
on_node_volume_updated, voxelworld::NodeVolumeUpdated)
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_start()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_unload()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_continue()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_tick(const interface::TickEvent &event)
|
||||||
|
{
|
||||||
|
if(!m_global_yst->m_dirty_sectors.empty()){
|
||||||
|
sv_<YSTSector*> dirty_sectors;
|
||||||
|
dirty_sectors.swap(m_global_yst->m_dirty_sectors);
|
||||||
|
for(YSTSector *sector : dirty_sectors){
|
||||||
|
ss_ s = interface::serialize_volume_compressed(*sector->volume);
|
||||||
|
std::ostringstream os(std::ios::binary);
|
||||||
|
{
|
||||||
|
cereal::PortableBinaryOutputArchive ar(os);
|
||||||
|
ar(sector->sector_p);
|
||||||
|
ar(s);
|
||||||
|
}
|
||||||
|
network::access(m_server, [&](network::Interface *inetwork){
|
||||||
|
sv_<network::PeerInfo::Id> peers = inetwork->list_peers();
|
||||||
|
for(auto &peer: peers){
|
||||||
|
inetwork->send(peer, "ground_plane_lighting:update",
|
||||||
|
os.str());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_client_connected(const network::NewClient &client_connected)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_files_transmitted(const client_file::FilesTransmitted &event)
|
||||||
|
{
|
||||||
|
int peer = event.recipient;
|
||||||
|
network::access(m_server, [&](network::Interface *inetwork){
|
||||||
|
inetwork->send(peer, "core:run_script",
|
||||||
|
"require(\"buildat/module/ground_plane_lighting\")");
|
||||||
|
});
|
||||||
|
std::ostringstream os(std::ios::binary);
|
||||||
|
{
|
||||||
|
cereal::PortableBinaryOutputArchive ar(os);
|
||||||
|
ar(m_global_yst->m_sector_size);
|
||||||
|
}
|
||||||
|
network::access(m_server, [&](network::Interface *inetwork){
|
||||||
|
inetwork->send(peer, "ground_plane_lighting:init", os.str());
|
||||||
|
});
|
||||||
|
|
||||||
|
send_initial_sectors(peer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_node_volume_updated(const voxelworld::NodeVolumeUpdated &event)
|
||||||
|
{
|
||||||
|
if(!event.is_static_chunk)
|
||||||
|
return;
|
||||||
|
log_v(MODULE, "on_node_volume_updated(): " PV3I_FORMAT,
|
||||||
|
PV3I_PARAMS(event.chunk_p));
|
||||||
|
const pv::Vector3DInt32 &chunk_p = event.chunk_p;
|
||||||
|
voxelworld::access(m_server, [&](voxelworld::Interface *ivoxelworld)
|
||||||
{
|
{
|
||||||
interface::VoxelRegistry *voxel_reg = ivoxelworld->get_voxel_reg();
|
interface::VoxelRegistry *voxel_reg = ivoxelworld->get_voxel_reg();
|
||||||
//const auto &chunk_size_voxels = ivoxelworld->get_chunk_size_voxels();
|
//const auto &chunk_size_voxels = ivoxelworld->get_chunk_size_voxels();
|
||||||
@ -222,120 +327,9 @@ struct YstCommitHook: public voxelworld::CommitHook
|
|||||||
}
|
}
|
||||||
//log_v(MODULE, "]");
|
//log_v(MODULE, "]");
|
||||||
});
|
});
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Module: public interface::Module, public ground_plane_lighting::Interface
|
|
||||||
{
|
|
||||||
interface::Server *m_server;
|
|
||||||
|
|
||||||
up_<GlobalYSTMap> m_global_yst;
|
|
||||||
|
|
||||||
Module(interface::Server *server):
|
|
||||||
interface::Module("ground_plane_lighting"),
|
|
||||||
m_server(server)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
~Module()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void init()
|
|
||||||
{
|
|
||||||
m_server->sub_event(this, Event::t("core:start"));
|
|
||||||
m_server->sub_event(this, Event::t("core:unload"));
|
|
||||||
m_server->sub_event(this, Event::t("core:continue"));
|
|
||||||
m_server->sub_event(this, Event::t("network:client_connected"));
|
|
||||||
m_server->sub_event(this, Event::t("core:tick"));
|
|
||||||
m_server->sub_event(this, Event::t("client_file:files_transmitted"));
|
|
||||||
|
|
||||||
voxelworld::access(m_server, [&](voxelworld::Interface *ivoxelworld)
|
|
||||||
{
|
|
||||||
pv::Vector3DInt16 section_size =
|
|
||||||
ivoxelworld->get_section_size_voxels();
|
|
||||||
pv::Vector<2, int16_t> sector_size(
|
|
||||||
section_size.getX(), section_size.getZ());
|
|
||||||
m_global_yst.reset(new GlobalYSTMap(sector_size));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void event(const Event::Type &type, const Event::Private *p)
|
|
||||||
{
|
|
||||||
EVENT_VOIDN("core:start", on_start)
|
|
||||||
EVENT_VOIDN("core:unload", on_unload)
|
|
||||||
EVENT_VOIDN("core:continue", on_continue)
|
|
||||||
EVENT_TYPEN("network:client_connected", on_client_connected,
|
|
||||||
network::NewClient)
|
|
||||||
EVENT_TYPEN("core:tick", on_tick, interface::TickEvent)
|
|
||||||
EVENT_TYPEN("client_file:files_transmitted", on_files_transmitted,
|
|
||||||
client_file::FilesTransmitted)
|
|
||||||
}
|
|
||||||
|
|
||||||
void on_start()
|
|
||||||
{
|
|
||||||
voxelworld::access(m_server, [&](voxelworld::Interface *ivoxelworld)
|
|
||||||
{
|
|
||||||
ivoxelworld->add_commit_hook(
|
|
||||||
up_<YstCommitHook>(new YstCommitHook(m_server)));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void on_unload()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void on_continue()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void on_client_connected(const network::NewClient &client_connected)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void on_tick(const interface::TickEvent &event)
|
|
||||||
{
|
|
||||||
if(!m_global_yst->m_dirty_sectors.empty()){
|
|
||||||
sv_<YSTSector*> dirty_sectors;
|
|
||||||
dirty_sectors.swap(m_global_yst->m_dirty_sectors);
|
|
||||||
for(YSTSector *sector : dirty_sectors){
|
|
||||||
ss_ s = interface::serialize_volume_compressed(*sector->volume);
|
|
||||||
std::ostringstream os(std::ios::binary);
|
|
||||||
{
|
|
||||||
cereal::PortableBinaryOutputArchive ar(os);
|
|
||||||
ar(sector->sector_p);
|
|
||||||
ar(s);
|
|
||||||
}
|
|
||||||
network::access(m_server, [&](network::Interface *inetwork){
|
|
||||||
sv_<network::PeerInfo::Id> peers = inetwork->list_peers();
|
|
||||||
for(auto &peer: peers){
|
|
||||||
inetwork->send(peer, "ground_plane_lighting:update",
|
|
||||||
os.str());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void on_files_transmitted(const client_file::FilesTransmitted &event)
|
|
||||||
{
|
|
||||||
int peer = event.recipient;
|
|
||||||
network::access(m_server, [&](network::Interface *inetwork){
|
|
||||||
inetwork->send(peer, "core:run_script",
|
|
||||||
"require(\"buildat/module/ground_plane_lighting\")");
|
|
||||||
});
|
|
||||||
std::ostringstream os(std::ios::binary);
|
|
||||||
{
|
|
||||||
cereal::PortableBinaryOutputArchive ar(os);
|
|
||||||
ar(m_global_yst->m_sector_size);
|
|
||||||
}
|
|
||||||
network::access(m_server, [&](network::Interface *inetwork){
|
|
||||||
inetwork->send(peer, "ground_plane_lighting:init", os.str());
|
|
||||||
});
|
|
||||||
|
|
||||||
send_initial_sectors(peer);
|
|
||||||
}
|
|
||||||
|
|
||||||
void send_initial_sectors(int peer)
|
void send_initial_sectors(int peer)
|
||||||
{
|
{
|
||||||
for(auto &pair : m_global_yst->m_sectors){
|
for(auto &pair : m_global_yst->m_sectors){
|
||||||
|
@ -32,11 +32,16 @@ namespace voxelworld
|
|||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NodeVoxelDataUpdatedEvent: public interface::Event::Private
|
struct NodeVolumeUpdated: public interface::Event::Private
|
||||||
{
|
{
|
||||||
uint node_id;
|
uint node_id;
|
||||||
|
bool is_static_chunk = false;
|
||||||
|
pv::Vector3DInt32 chunk_p; // Only set if is_static_chunk == true
|
||||||
|
|
||||||
NodeVoxelDataUpdatedEvent(uint node_id): node_id(node_id){}
|
NodeVolumeUpdated(uint node_id, bool is_static_chunk,
|
||||||
|
const pv::Vector3DInt32 &chunk_p):
|
||||||
|
node_id(node_id), is_static_chunk(is_static_chunk), chunk_p(chunk_p)
|
||||||
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Interface;
|
struct Interface;
|
||||||
@ -46,12 +51,9 @@ namespace voxelworld
|
|||||||
virtual ~CommitHook(){}
|
virtual ~CommitHook(){}
|
||||||
virtual void in_thread(voxelworld::Interface *ivoxelworld,
|
virtual void in_thread(voxelworld::Interface *ivoxelworld,
|
||||||
const pv::Vector3DInt32 &chunk_p,
|
const pv::Vector3DInt32 &chunk_p,
|
||||||
sp_<pv::RawVolume<VoxelInstance>> volume){}
|
pv::RawVolume<VoxelInstance> &volume){}
|
||||||
virtual void in_scene(voxelworld::Interface *ivoxelworld,
|
virtual void in_scene(voxelworld::Interface *ivoxelworld,
|
||||||
const pv::Vector3DInt32 &chunk_p, magic::Node *n){}
|
const pv::Vector3DInt32 &chunk_p, magic::Node *n){}
|
||||||
// TODO: Remove this hook callback and use an event instead
|
|
||||||
virtual void after_commit(voxelworld::Interface *ivoxelworld,
|
|
||||||
const pv::Vector3DInt32 &chunk_p){}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Interface
|
struct Interface
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include "interface/polyvox_numeric.h"
|
#include "interface/polyvox_numeric.h"
|
||||||
#include "interface/polyvox_cereal.h"
|
#include "interface/polyvox_cereal.h"
|
||||||
#include "interface/polyvox_std.h"
|
#include "interface/polyvox_std.h"
|
||||||
|
#include "interface/os.h"
|
||||||
#include <PolyVoxCore/RawVolume.h>
|
#include <PolyVoxCore/RawVolume.h>
|
||||||
#include <cereal/archives/portable_binary.hpp>
|
#include <cereal/archives/portable_binary.hpp>
|
||||||
#include <cereal/types/string.hpp>
|
#include <cereal/types/string.hpp>
|
||||||
@ -46,12 +47,31 @@ namespace voxelworld {
|
|||||||
|
|
||||||
struct ChunkBuffer
|
struct ChunkBuffer
|
||||||
{
|
{
|
||||||
sp_<pv::RawVolume<VoxelInstance>> volume;
|
static constexpr const char *MODULE = "ChunkBuffer";
|
||||||
|
pv::Vector3DInt32 chunk_p; // For logging
|
||||||
|
up_<pv::RawVolume<VoxelInstance>> volume;
|
||||||
bool dirty = false; // If false, buffer has only been read from so far
|
bool dirty = false; // If false, buffer has only been read from so far
|
||||||
|
int64_t last_accessed_us = 0;
|
||||||
|
|
||||||
|
ChunkBuffer(){}
|
||||||
|
void timer_reset(const pv::Vector3DInt32 &chunk_p_){
|
||||||
|
chunk_p = chunk_p_;
|
||||||
|
last_accessed_us = interface::os::get_timeofday_us();
|
||||||
|
}
|
||||||
|
bool unload_if_old(int64_t timeout_us){ // True if not loaded
|
||||||
|
if(!volume)
|
||||||
|
return true;
|
||||||
|
if(interface::os::get_timeofday_us() < last_accessed_us + timeout_us)
|
||||||
|
return false;
|
||||||
|
log_d(MODULE, "Unloading chunk " PV3I_FORMAT, PV3I_PARAMS(chunk_p));
|
||||||
|
volume.reset();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Section
|
struct Section
|
||||||
{
|
{
|
||||||
|
static constexpr const char *MODULE = "Section";
|
||||||
pv::Vector3DInt16 section_p; // Position in sections
|
pv::Vector3DInt16 section_p; // Position in sections
|
||||||
pv::Vector3DInt16 chunk_size;
|
pv::Vector3DInt16 chunk_size;
|
||||||
pv::Region contained_chunks; // Position and size in chunks
|
pv::Region contained_chunks; // Position and size in chunks
|
||||||
@ -96,7 +116,7 @@ struct Section
|
|||||||
pv::Vector3DInt32 get_chunk_p(size_t chunk_p);
|
pv::Vector3DInt32 get_chunk_p(size_t chunk_p);
|
||||||
|
|
||||||
ChunkBuffer& get_buffer(const pv::Vector3DInt32 &chunk_p,
|
ChunkBuffer& get_buffer(const pv::Vector3DInt32 &chunk_p,
|
||||||
interface::Server *server);
|
interface::Server *server, size_t *total_buffers_loaded);
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t Section::get_chunk_i(const pv::Vector3DInt32 &chunk_p) // global chunk_p
|
size_t Section::get_chunk_i(const pv::Vector3DInt32 &chunk_p) // global chunk_p
|
||||||
@ -127,14 +147,16 @@ pv::Vector3DInt32 Section::get_chunk_p(size_t chunk_i)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ChunkBuffer& Section::get_buffer(const pv::Vector3DInt32 &chunk_p,
|
ChunkBuffer& Section::get_buffer(const pv::Vector3DInt32 &chunk_p,
|
||||||
interface::Server *server)
|
interface::Server *server, size_t *total_buffers_loaded)
|
||||||
{
|
{
|
||||||
size_t chunk_i = get_chunk_i(chunk_p);
|
size_t chunk_i = get_chunk_i(chunk_p);
|
||||||
ChunkBuffer &buf = chunk_buffers[chunk_i];
|
ChunkBuffer &buf = chunk_buffers[chunk_i];
|
||||||
|
buf.timer_reset(chunk_p);
|
||||||
// If loaded, return right away
|
// If loaded, return right away
|
||||||
if(buf.volume)
|
if(buf.volume)
|
||||||
return buf;
|
return buf;
|
||||||
// Not loaded.
|
// Not loaded.
|
||||||
|
log_d(MODULE, "Loading chunk " PV3I_FORMAT, PV3I_PARAMS(chunk_p));
|
||||||
// Get the static voxel node from the scene and read the volume from it
|
// Get the static voxel node from the scene and read the volume from it
|
||||||
int32_t node_id = node_ids->getVoxelAt(chunk_p);
|
int32_t node_id = node_ids->getVoxelAt(chunk_p);
|
||||||
if(node_id == 0){
|
if(node_id == 0){
|
||||||
@ -156,9 +178,7 @@ ChunkBuffer& Section::get_buffer(const pv::Vector3DInt32 &chunk_p,
|
|||||||
const Variant &var = n->GetVar(StringHash("buildat_voxel_data"));
|
const Variant &var = n->GetVar(StringHash("buildat_voxel_data"));
|
||||||
const PODVector<unsigned char> &rawbuf = var.GetBuffer();
|
const PODVector<unsigned char> &rawbuf = var.GetBuffer();
|
||||||
ss_ data((const char*)&rawbuf[0], rawbuf.Size());
|
ss_ data((const char*)&rawbuf[0], rawbuf.Size());
|
||||||
up_<pv::RawVolume<VoxelInstance>> volume =
|
buf.volume = interface::deserialize_volume(data);
|
||||||
interface::deserialize_volume(data);
|
|
||||||
buf.volume = sp_<pv::RawVolume<VoxelInstance>>(std::move(volume));
|
|
||||||
if(!buf.volume){
|
if(!buf.volume){
|
||||||
log_w("voxelworld",
|
log_w("voxelworld",
|
||||||
"Section::get_buffer(): Voxel volume could not be "
|
"Section::get_buffer(): Voxel volume could not be "
|
||||||
@ -168,17 +188,18 @@ ChunkBuffer& Section::get_buffer(const pv::Vector3DInt32 &chunk_p,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
(*total_buffers_loaded)++;
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct QueuedNodePhysicsUpdate
|
struct QueuedNodePhysicsUpdate
|
||||||
{
|
{
|
||||||
uint node_id = 0;
|
uint node_id = 0;
|
||||||
sp_<pv::RawVolume<VoxelInstance>> volume;
|
// TODO bool is_static_chunk = false;
|
||||||
|
// TODO pv::Vector3DInt32 chunk_p; // Only set if is_static_chunk == true
|
||||||
|
|
||||||
QueuedNodePhysicsUpdate(const uint &node_id,
|
QueuedNodePhysicsUpdate(const uint &node_id):
|
||||||
sp_<pv::RawVolume<VoxelInstance>> volume):
|
node_id(node_id){}
|
||||||
node_id(node_id), volume(volume){}
|
|
||||||
bool operator>(const QueuedNodePhysicsUpdate &other) const {
|
bool operator>(const QueuedNodePhysicsUpdate &other) const {
|
||||||
return node_id > other.node_id;
|
return node_id > other.node_id;
|
||||||
}
|
}
|
||||||
@ -204,6 +225,9 @@ struct Module: public interface::Module, public voxelworld::Interface
|
|||||||
// The world is loaded and unloaded by sections (eg. 2x2x2)
|
// The world is loaded and unloaded by sections (eg. 2x2x2)
|
||||||
pv::Vector3DInt16 m_section_size_chunks = pv::Vector3DInt16(2, 2, 2);
|
pv::Vector3DInt16 m_section_size_chunks = pv::Vector3DInt16(2, 2, 2);
|
||||||
|
|
||||||
|
int64_t m_buffer_unload_timeout = 5000000;
|
||||||
|
size_t m_max_buffers_loaded = 50;
|
||||||
|
|
||||||
// Sections (this(y,z)=sector, sector(x)=section)
|
// Sections (this(y,z)=sector, sector(x)=section)
|
||||||
sm_<pv::Vector<2, int16_t>, sm_<int16_t, Section>> m_sections;
|
sm_<pv::Vector<2, int16_t>, sm_<int16_t, Section>> m_sections;
|
||||||
// Cache of last used sections (add to end, remove from beginning)
|
// Cache of last used sections (add to end, remove from beginning)
|
||||||
@ -212,6 +236,7 @@ struct Module: public interface::Module, public voxelworld::Interface
|
|||||||
// Set of sections that have buffers allocated
|
// Set of sections that have buffers allocated
|
||||||
// (as a sorted array in descending order)
|
// (as a sorted array in descending order)
|
||||||
std::vector<Section*> m_sections_with_loaded_buffers;
|
std::vector<Section*> m_sections_with_loaded_buffers;
|
||||||
|
size_t m_total_buffers_loaded = 0;
|
||||||
|
|
||||||
// Set of nodes by node_id that need set_voxel_physics_boxes()
|
// Set of nodes by node_id that need set_voxel_physics_boxes()
|
||||||
// (as a sorted array in descending node_id order)
|
// (as a sorted array in descending node_id order)
|
||||||
@ -382,19 +407,27 @@ struct Module: public interface::Module, public voxelworld::Interface
|
|||||||
}
|
}
|
||||||
for(QueuedNodePhysicsUpdate &update: m_nodes_needing_physics_update){
|
for(QueuedNodePhysicsUpdate &update: m_nodes_needing_physics_update){
|
||||||
uint node_id = update.node_id;
|
uint node_id = update.node_id;
|
||||||
sp_<pv::RawVolume<VoxelInstance>> volume = update.volume;
|
|
||||||
Node *n = scene->GetNode(node_id);
|
Node *n = scene->GetNode(node_id);
|
||||||
if(!n){
|
if(!n){
|
||||||
log_w(MODULE, "on_tick(): Node physics update: "
|
log_w(MODULE, "on_tick(): Node physics update: "
|
||||||
"Node %i not found", node_id);
|
"Node %i not found", node_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Get volume
|
||||||
|
const Variant &var = n->GetVar(StringHash("buildat_voxel_data"));
|
||||||
|
const PODVector<unsigned char> &rawbuf = var.GetBuffer();
|
||||||
|
ss_ data((const char*)&rawbuf[0], rawbuf.Size());
|
||||||
|
up_<pv::RawVolume<VoxelInstance>> volume =
|
||||||
|
interface::deserialize_volume(data);
|
||||||
// Update collision shape
|
// Update collision shape
|
||||||
interface::mesh::set_voxel_physics_boxes(n, context, *volume,
|
interface::mesh::set_voxel_physics_boxes(n, context, *volume,
|
||||||
m_voxel_reg.get());
|
m_voxel_reg.get());
|
||||||
}
|
}
|
||||||
m_nodes_needing_physics_update.clear();
|
m_nodes_needing_physics_update.clear();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Unload stuff if needed
|
||||||
|
maintain_maximum_buffer_limit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_files_transmitted(const client_file::FilesTransmitted &event)
|
void on_files_transmitted(const client_file::FilesTransmitted &event)
|
||||||
@ -543,7 +576,7 @@ struct Module: public interface::Module, public voxelworld::Interface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
run_commit_hooks_in_thread(chunk_p, volume);
|
run_commit_hooks_in_thread(chunk_p, *volume);
|
||||||
|
|
||||||
ss_ data = interface::serialize_volume_compressed(*volume);
|
ss_ data = interface::serialize_volume_compressed(*volume);
|
||||||
n->SetVar(StringHash("buildat_voxel_data"), Variant(
|
n->SetVar(StringHash("buildat_voxel_data"), Variant(
|
||||||
@ -551,8 +584,8 @@ struct Module: public interface::Module, public voxelworld::Interface
|
|||||||
|
|
||||||
run_commit_hooks_in_scene(chunk_p, n);
|
run_commit_hooks_in_scene(chunk_p, n);
|
||||||
|
|
||||||
// TODO: Remove this hook callback and use an event instead
|
m_server->emit_event("voxelworld:node_volume_updated",
|
||||||
run_commit_hooks_after_commit(chunk_p);
|
new NodeVolumeUpdated(n->GetID(), true, chunk_p));
|
||||||
|
|
||||||
// There are no collision shapes initially, but add the rigid body now
|
// There are no collision shapes initially, but add the rigid body now
|
||||||
RigidBody *body = n->CreateComponent<RigidBody>(LOCAL);
|
RigidBody *body = n->CreateComponent<RigidBody>(LOCAL);
|
||||||
@ -603,10 +636,9 @@ struct Module: public interface::Module, public voxelworld::Interface
|
|||||||
new GenerationRequest(section_p));
|
new GenerationRequest(section_p));
|
||||||
}
|
}
|
||||||
|
|
||||||
void mark_node_for_physics_update(uint node_id,
|
void mark_node_for_physics_update(uint node_id)
|
||||||
sp_<pv::RawVolume<VoxelInstance>> volume)
|
|
||||||
{
|
{
|
||||||
QueuedNodePhysicsUpdate update(node_id, volume);
|
QueuedNodePhysicsUpdate update(node_id);
|
||||||
auto it = std::lower_bound(m_nodes_needing_physics_update.begin(),
|
auto it = std::lower_bound(m_nodes_needing_physics_update.begin(),
|
||||||
m_nodes_needing_physics_update.end(), update,
|
m_nodes_needing_physics_update.end(), update,
|
||||||
std::greater<QueuedNodePhysicsUpdate>());
|
std::greater<QueuedNodePhysicsUpdate>());
|
||||||
@ -623,7 +655,7 @@ struct Module: public interface::Module, public voxelworld::Interface
|
|||||||
// modify the volume
|
// modify the volume
|
||||||
void run_commit_hooks_in_thread(
|
void run_commit_hooks_in_thread(
|
||||||
const pv::Vector3DInt32 &chunk_p,
|
const pv::Vector3DInt32 &chunk_p,
|
||||||
sp_<pv::RawVolume<VoxelInstance>> volume)
|
pv::RawVolume<VoxelInstance> &volume)
|
||||||
{
|
{
|
||||||
for(up_<CommitHook> &hook : m_commit_hooks)
|
for(up_<CommitHook> &hook : m_commit_hooks)
|
||||||
hook->in_thread(this, chunk_p, volume);
|
hook->in_thread(this, chunk_p, volume);
|
||||||
@ -636,10 +668,38 @@ struct Module: public interface::Module, public voxelworld::Interface
|
|||||||
hook->in_scene(this, chunk_p, n);
|
hook->in_scene(this, chunk_p, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
void run_commit_hooks_after_commit(const pv::Vector3DInt32 &chunk_p)
|
void unload_old_buffers(int64_t unload_timeout, size_t max_buffers)
|
||||||
{
|
{
|
||||||
for(up_<CommitHook> &hook : m_commit_hooks)
|
// Swap out the current set
|
||||||
hook->after_commit(this, chunk_p);
|
std::vector<Section*> sections_with_loaded_buffers;
|
||||||
|
sections_with_loaded_buffers.swap(m_sections_with_loaded_buffers);
|
||||||
|
// Allocate a new set to put back stuff that is still loaded
|
||||||
|
m_sections_with_loaded_buffers.reserve(
|
||||||
|
sections_with_loaded_buffers.size());
|
||||||
|
// Go through the swapped set, putting back sections that are still loaded
|
||||||
|
m_total_buffers_loaded = 0;
|
||||||
|
for(Section *section : sections_with_loaded_buffers){
|
||||||
|
size_t num_loaded = 0;
|
||||||
|
for(size_t i = 0; i < section->chunk_buffers.size(); i++){
|
||||||
|
ChunkBuffer &chunk_buffer = section->chunk_buffers[i];
|
||||||
|
bool unloaded = chunk_buffer.unload_if_old(unload_timeout);
|
||||||
|
if(!unloaded){
|
||||||
|
num_loaded++;
|
||||||
|
m_total_buffers_loaded++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(num_loaded > 0)
|
||||||
|
m_sections_with_loaded_buffers.push_back(section);
|
||||||
|
}
|
||||||
|
// Call recursively if too many buffers are still loaded
|
||||||
|
if(unload_timeout > 1000 && m_total_buffers_loaded > max_buffers)
|
||||||
|
unload_old_buffers(unload_timeout / 4, max_buffers);
|
||||||
|
}
|
||||||
|
|
||||||
|
void maintain_maximum_buffer_limit()
|
||||||
|
{
|
||||||
|
if(m_total_buffers_loaded > m_max_buffers_loaded)
|
||||||
|
unload_old_buffers(m_buffer_unload_timeout, m_max_buffers_loaded);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interface
|
// Interface
|
||||||
@ -740,18 +800,14 @@ struct Module: public interface::Module, public voxelworld::Interface
|
|||||||
// TODO: Commit only the current chunk
|
// TODO: Commit only the current chunk
|
||||||
commit();
|
commit();
|
||||||
|
|
||||||
// Volume will be used after access_scene()
|
|
||||||
sp_<pv::RawVolume<VoxelInstance>> volume;
|
|
||||||
|
|
||||||
m_server->access_scene([&](Scene *scene)
|
m_server->access_scene([&](Scene *scene)
|
||||||
{
|
{
|
||||||
Node *n = scene->GetNode(node_id);
|
Node *n = scene->GetNode(node_id);
|
||||||
const Variant &var = n->GetVar(StringHash("buildat_voxel_data"));
|
const Variant &var = n->GetVar(StringHash("buildat_voxel_data"));
|
||||||
const PODVector<unsigned char> &buf = var.GetBuffer();
|
const PODVector<unsigned char> &buf = var.GetBuffer();
|
||||||
ss_ data((const char*)&buf[0], buf.Size());
|
ss_ data((const char*)&buf[0], buf.Size());
|
||||||
volume = sp_<pv::RawVolume<VoxelInstance>>(std::move(
|
up_<pv::RawVolume<VoxelInstance>> volume =
|
||||||
interface::deserialize_volume(data)
|
interface::deserialize_volume(data);
|
||||||
));
|
|
||||||
|
|
||||||
pv::Vector3DInt32 voxel_p(
|
pv::Vector3DInt32 voxel_p(
|
||||||
p.getX() - chunk_p.getX() * m_chunk_size_voxels.getX(),
|
p.getX() - chunk_p.getX() * m_chunk_size_voxels.getX(),
|
||||||
@ -765,7 +821,7 @@ struct Module: public interface::Module, public voxelworld::Interface
|
|||||||
PV3I_PARAMS(section_p), PV3I_PARAMS(voxel_p));
|
PV3I_PARAMS(section_p), PV3I_PARAMS(voxel_p));
|
||||||
volume->setVoxelAt(voxel_p, v);
|
volume->setVoxelAt(voxel_p, v);
|
||||||
|
|
||||||
run_commit_hooks_in_thread(chunk_p, volume);
|
run_commit_hooks_in_thread(chunk_p, *volume);
|
||||||
|
|
||||||
ss_ new_data = interface::serialize_volume_compressed(*volume);
|
ss_ new_data = interface::serialize_volume_compressed(*volume);
|
||||||
|
|
||||||
@ -777,10 +833,10 @@ struct Module: public interface::Module, public voxelworld::Interface
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Mark node for collision box update
|
// Mark node for collision box update
|
||||||
mark_node_for_physics_update(node_id, volume);
|
mark_node_for_physics_update(node_id);
|
||||||
|
|
||||||
// TODO: Remove this hook callback and use an event instead
|
m_server->emit_event("voxelworld:node_volume_updated",
|
||||||
run_commit_hooks_after_commit(chunk_p);
|
new NodeVolumeUpdated(node_id, true, chunk_p));
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_voxel(const pv::Vector3DInt32 &p, const interface::VoxelInstance &v,
|
void set_voxel(const pv::Vector3DInt32 &p, const interface::VoxelInstance &v,
|
||||||
@ -803,8 +859,12 @@ struct Module: public interface::Module, public voxelworld::Interface
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unload stuff if needed
|
||||||
|
maintain_maximum_buffer_limit();
|
||||||
|
|
||||||
// Set in buffer
|
// Set in buffer
|
||||||
ChunkBuffer &buf = section->get_buffer(chunk_p, m_server);
|
ChunkBuffer &buf = section->get_buffer(chunk_p, m_server,
|
||||||
|
&m_total_buffers_loaded);
|
||||||
if(!buf.volume){
|
if(!buf.volume){
|
||||||
if(!disable_warnings){
|
if(!disable_warnings){
|
||||||
log_w(MODULE, "set_voxel() p=" PV3I_FORMAT ", v=%i: Couldn't get "
|
log_w(MODULE, "set_voxel() p=" PV3I_FORMAT ", v=%i: Couldn't get "
|
||||||
@ -833,19 +893,20 @@ struct Module: public interface::Module, public voxelworld::Interface
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Commit and unload chunk buffer
|
// Commit and unload chunk buffer
|
||||||
// TODO: Unload after a timeout instead of always
|
|
||||||
void commit_chunk_buffer(Section *section, size_t chunk_i)
|
void commit_chunk_buffer(Section *section, size_t chunk_i)
|
||||||
{
|
{
|
||||||
ChunkBuffer &chunk_buffer = section->chunk_buffers[chunk_i];
|
ChunkBuffer &chunk_buffer = section->chunk_buffers[chunk_i];
|
||||||
if(!chunk_buffer.dirty){
|
if(!chunk_buffer.dirty){
|
||||||
// No changes made; unload buffer volume and return
|
// No changes
|
||||||
chunk_buffer.volume.reset();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pv::Vector3DInt32 chunk_p = section->get_chunk_p(chunk_i);
|
pv::Vector3DInt32 chunk_p = section->get_chunk_p(chunk_i);
|
||||||
|
|
||||||
uint node_id = section->node_ids->getVoxelAt(chunk_p);
|
uint node_id = section->node_ids->getVoxelAt(chunk_p);
|
||||||
|
|
||||||
|
log_d(MODULE, "commit_chunk_buffer(): Updating node %i volume (chunk "
|
||||||
|
PV3I_FORMAT ")", node_id, PV3I_PARAMS(chunk_p));
|
||||||
|
|
||||||
if(node_id == 0){
|
if(node_id == 0){
|
||||||
log_w(MODULE, "commit_chunk_buffer() chunk_i=%zu: "
|
log_w(MODULE, "commit_chunk_buffer() chunk_i=%zu: "
|
||||||
"No node found for chunk " PV3I_FORMAT
|
"No node found for chunk " PV3I_FORMAT
|
||||||
@ -855,7 +916,7 @@ struct Module: public interface::Module, public voxelworld::Interface
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
run_commit_hooks_in_thread(chunk_p, chunk_buffer.volume);
|
run_commit_hooks_in_thread(chunk_p, *chunk_buffer.volume);
|
||||||
|
|
||||||
ss_ new_data = interface::serialize_volume_compressed(
|
ss_ new_data = interface::serialize_volume_compressed(
|
||||||
*chunk_buffer.volume);
|
*chunk_buffer.volume);
|
||||||
@ -900,21 +961,19 @@ struct Module: public interface::Module, public voxelworld::Interface
|
|||||||
}
|
}
|
||||||
network::access(m_server, [&](network::Interface *inetwork){
|
network::access(m_server, [&](network::Interface *inetwork){
|
||||||
for(auto &peer_id: peers){
|
for(auto &peer_id: peers){
|
||||||
inetwork->send(peer_id, "voxelworld:node_voxel_data_updated",
|
inetwork->send(peer_id, "voxelworld:node_volume_updated",
|
||||||
os.str());
|
os.str());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Mark node for collision box update
|
// Mark node for collision box update
|
||||||
mark_node_for_physics_update(node_id, chunk_buffer.volume);
|
mark_node_for_physics_update(node_id);
|
||||||
|
|
||||||
// Reset dirty flag
|
// Reset dirty flag
|
||||||
chunk_buffer.dirty = false;
|
chunk_buffer.dirty = false;
|
||||||
// Unload buffer volume
|
|
||||||
chunk_buffer.volume.reset();
|
|
||||||
|
|
||||||
// TODO: Remove this hook callback and use an event instead
|
m_server->emit_event("voxelworld:node_volume_updated",
|
||||||
run_commit_hooks_after_commit(chunk_p);
|
new NodeVolumeUpdated(node_id, true, chunk_p));
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t num_buffers_loaded()
|
size_t num_buffers_loaded()
|
||||||
@ -926,14 +985,13 @@ struct Module: public interface::Module, public voxelworld::Interface
|
|||||||
{
|
{
|
||||||
if(m_sections_with_loaded_buffers.empty())
|
if(m_sections_with_loaded_buffers.empty())
|
||||||
return;
|
return;
|
||||||
log_v(MODULE, "commit(): %zu sections have loaded buffers",
|
log_d(MODULE, "commit(): %zu sections have loaded buffers",
|
||||||
m_sections_with_loaded_buffers.size());
|
m_sections_with_loaded_buffers.size());
|
||||||
for(Section *section : m_sections_with_loaded_buffers){
|
for(Section *section : m_sections_with_loaded_buffers){
|
||||||
for(size_t i = 0; i < section->chunk_buffers.size(); i++){
|
for(size_t i = 0; i < section->chunk_buffers.size(); i++){
|
||||||
commit_chunk_buffer(section, i);
|
commit_chunk_buffer(section, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_sections_with_loaded_buffers.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VoxelInstance get_voxel(const pv::Vector3DInt32 &p, bool disable_warnings)
|
VoxelInstance get_voxel(const pv::Vector3DInt32 &p, bool disable_warnings)
|
||||||
@ -952,8 +1010,12 @@ struct Module: public interface::Module, public voxelworld::Interface
|
|||||||
return VoxelInstance(interface::VOXELTYPEID_UNDEFINED);
|
return VoxelInstance(interface::VOXELTYPEID_UNDEFINED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unload stuff if needed
|
||||||
|
maintain_maximum_buffer_limit();
|
||||||
|
|
||||||
// Get from buffer
|
// Get from buffer
|
||||||
ChunkBuffer &buf = section->get_buffer(chunk_p, m_server);
|
ChunkBuffer &buf = section->get_buffer(chunk_p, m_server,
|
||||||
|
&m_total_buffers_loaded);
|
||||||
if(!buf.volume){
|
if(!buf.volume){
|
||||||
if(!disable_warnings){
|
if(!disable_warnings){
|
||||||
log_w(MODULE, "get_voxel() p=" PV3I_FORMAT ": Couldn't get "
|
log_w(MODULE, "get_voxel() p=" PV3I_FORMAT ": Couldn't get "
|
||||||
|
Loading…
x
Reference in New Issue
Block a user