builtin/voxelworld: Update to new scene handling
This commit is contained in:
parent
3f6bcb6228
commit
4bfcd1057e
@ -17,46 +17,58 @@ namespace Urho3D
|
|||||||
class Node;
|
class Node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace main_context
|
||||||
|
{
|
||||||
|
struct OpaqueSceneReference;
|
||||||
|
typedef OpaqueSceneReference* SceneReference;
|
||||||
|
};
|
||||||
|
|
||||||
namespace voxelworld
|
namespace voxelworld
|
||||||
{
|
{
|
||||||
namespace magic = Urho3D;
|
namespace magic = Urho3D;
|
||||||
namespace pv = PolyVox;
|
namespace pv = PolyVox;
|
||||||
using interface::VoxelInstance;
|
using interface::VoxelInstance;
|
||||||
|
using main_context::SceneReference;
|
||||||
|
|
||||||
struct GenerationRequest: public interface::Event::Private
|
struct GenerationRequest: public interface::Event::Private
|
||||||
{
|
{
|
||||||
|
SceneReference scene;
|
||||||
pv::Vector3DInt16 section_p;
|
pv::Vector3DInt16 section_p;
|
||||||
|
|
||||||
GenerationRequest(const pv::Vector3DInt16 §ion_p):
|
GenerationRequest(SceneReference scene,
|
||||||
|
const pv::Vector3DInt16 §ion_p):
|
||||||
|
scene(scene),
|
||||||
section_p(section_p)
|
section_p(section_p)
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NodeVolumeUpdated: public interface::Event::Private
|
struct NodeVolumeUpdated: public interface::Event::Private
|
||||||
{
|
{
|
||||||
|
SceneReference scene;
|
||||||
uint node_id;
|
uint node_id;
|
||||||
bool is_static_chunk = false;
|
bool is_static_chunk = false;
|
||||||
pv::Vector3DInt32 chunk_p; // Only set if is_static_chunk == true
|
pv::Vector3DInt32 chunk_p; // Only set if is_static_chunk == true
|
||||||
|
|
||||||
NodeVolumeUpdated(uint node_id, bool is_static_chunk,
|
NodeVolumeUpdated(SceneReference scene, uint node_id,
|
||||||
const pv::Vector3DInt32 &chunk_p):
|
bool is_static_chunk, const pv::Vector3DInt32 &chunk_p):
|
||||||
node_id(node_id), is_static_chunk(is_static_chunk), chunk_p(chunk_p)
|
scene(scene), node_id(node_id),
|
||||||
|
is_static_chunk(is_static_chunk), chunk_p(chunk_p)
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Interface;
|
struct Instance;
|
||||||
|
|
||||||
struct CommitHook
|
struct CommitHook
|
||||||
{
|
{
|
||||||
virtual ~CommitHook(){}
|
virtual ~CommitHook(){}
|
||||||
virtual void in_thread(voxelworld::Interface *ivoxelworld,
|
virtual void in_thread(voxelworld::Instance *world,
|
||||||
const pv::Vector3DInt32 &chunk_p,
|
const pv::Vector3DInt32 &chunk_p,
|
||||||
pv::RawVolume<VoxelInstance> &volume){}
|
pv::RawVolume<VoxelInstance> &volume){}
|
||||||
virtual void in_scene(voxelworld::Interface *ivoxelworld,
|
virtual void in_scene(voxelworld::Instance *world,
|
||||||
const pv::Vector3DInt32 &chunk_p, magic::Node *n){}
|
const pv::Vector3DInt32 &chunk_p, magic::Node *n){}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Interface
|
struct Instance
|
||||||
{
|
{
|
||||||
virtual interface::VoxelRegistry* get_voxel_reg() = 0;
|
virtual interface::VoxelRegistry* get_voxel_reg() = 0;
|
||||||
|
|
||||||
@ -92,6 +104,16 @@ namespace voxelworld
|
|||||||
// robust interface.
|
// robust interface.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Interface
|
||||||
|
{
|
||||||
|
virtual void create_instance(SceneReference scene_ref) = 0;
|
||||||
|
virtual void delete_instance(SceneReference scene_ref) = 0;
|
||||||
|
|
||||||
|
virtual Instance* get_instance(SceneReference scene_ref) = 0;
|
||||||
|
|
||||||
|
virtual void commit() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
inline bool access(interface::Server *server,
|
inline bool access(interface::Server *server,
|
||||||
std::function<void(voxelworld::Interface*)> cb)
|
std::function<void(voxelworld::Interface*)> cb)
|
||||||
{
|
{
|
||||||
@ -101,6 +123,15 @@ namespace voxelworld
|
|||||||
iface->commit();
|
iface->commit();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool access(interface::Server *server, SceneReference scene_ref,
|
||||||
|
std::function<void(voxelworld::Instance *instance)> cb)
|
||||||
|
{
|
||||||
|
return access(server, [&](voxelworld::Interface *i){
|
||||||
|
voxelworld::Instance *instance = i->get_instance(scene_ref);
|
||||||
|
cb(instance);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// vim: set noet ts=4 sw=4:
|
// vim: set noet ts=4 sw=4:
|
||||||
|
@ -88,6 +88,10 @@ buildat.sub_packet("voxelworld:init", function(data)
|
|||||||
M.section_size_chunks = buildat.Vector3(values.section_size_chunks)
|
M.section_size_chunks = buildat.Vector3(values.section_size_chunks)
|
||||||
M.section_size_voxels =
|
M.section_size_voxels =
|
||||||
M.chunk_size_voxels:mul_components(M.section_size_chunks)
|
M.chunk_size_voxels:mul_components(M.section_size_chunks)
|
||||||
|
|
||||||
|
-- Clear caches
|
||||||
|
node_volume_cache = {}
|
||||||
|
static_node_cache = {}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
buildat.sub_packet("voxelworld:voxel_registry", function(data)
|
buildat.sub_packet("voxelworld:voxel_registry", function(data)
|
||||||
|
@ -70,6 +70,7 @@ struct ChunkBuffer
|
|||||||
|
|
||||||
struct Section
|
struct Section
|
||||||
{
|
{
|
||||||
|
SceneReference m_scene_ref;
|
||||||
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
|
||||||
@ -92,9 +93,11 @@ struct Section
|
|||||||
Section(): // Needed for containers
|
Section(): // Needed for containers
|
||||||
chunk_size(0, 0, 0) // This is used to detect uninitialized instance
|
chunk_size(0, 0, 0) // This is used to detect uninitialized instance
|
||||||
{}
|
{}
|
||||||
Section(pv::Vector3DInt16 section_p,
|
Section(SceneReference scene_ref,
|
||||||
|
pv::Vector3DInt16 section_p,
|
||||||
pv::Vector3DInt16 chunk_size,
|
pv::Vector3DInt16 chunk_size,
|
||||||
pv::Region contained_chunks):
|
pv::Region contained_chunks):
|
||||||
|
m_scene_ref(scene_ref),
|
||||||
section_p(section_p),
|
section_p(section_p),
|
||||||
chunk_size(chunk_size),
|
chunk_size(chunk_size),
|
||||||
contained_chunks(contained_chunks),
|
contained_chunks(contained_chunks),
|
||||||
@ -167,7 +170,7 @@ ChunkBuffer& Section::get_buffer(const pv::Vector3DInt32 &chunk_p,
|
|||||||
|
|
||||||
main_context::access(server, [&](main_context::Interface *imc)
|
main_context::access(server, [&](main_context::Interface *imc)
|
||||||
{
|
{
|
||||||
Scene *scene = imc->get_scene();
|
Scene *scene = imc->get_scene(m_scene_ref);
|
||||||
Node *n = scene->GetNode(node_id);
|
Node *n = scene->GetNode(node_id);
|
||||||
if(!n){
|
if(!n){
|
||||||
log_w(MODULE,
|
log_w(MODULE,
|
||||||
@ -206,10 +209,15 @@ struct QueuedNodePhysicsUpdate
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Module: public interface::Module, public voxelworld::Interface
|
struct CInstance: public voxelworld::Instance
|
||||||
{
|
{
|
||||||
interface::Server *m_server;
|
interface::Server *m_server;
|
||||||
|
|
||||||
|
SceneReference m_scene_ref;
|
||||||
|
|
||||||
|
// Clients that are ready to receive things (by peer id)
|
||||||
|
set_<int> m_clients_initialized;
|
||||||
|
|
||||||
// Accessing any of these outside of Server::access_scene is disallowed
|
// Accessing any of these outside of Server::access_scene is disallowed
|
||||||
sp_<interface::AtlasRegistry> m_atlas_reg;
|
sp_<interface::AtlasRegistry> m_atlas_reg;
|
||||||
sp_<interface::VoxelRegistry> m_voxel_reg;
|
sp_<interface::VoxelRegistry> m_voxel_reg;
|
||||||
@ -244,55 +252,19 @@ struct Module: public interface::Module, public voxelworld::Interface
|
|||||||
// (as a sorted array in descending node_id order)
|
// (as a sorted array in descending node_id order)
|
||||||
std::vector<QueuedNodePhysicsUpdate> m_nodes_needing_physics_update;
|
std::vector<QueuedNodePhysicsUpdate> m_nodes_needing_physics_update;
|
||||||
|
|
||||||
// Clients that are ready to receive things (by peer id)
|
CInstance(interface::Server *server, SceneReference scene_ref):
|
||||||
set_<int> m_clients_initialized;
|
m_server(server),
|
||||||
|
m_scene_ref(scene_ref)
|
||||||
Module(interface::Server *server):
|
|
||||||
interface::Module(MODULE),
|
|
||||||
m_server(server)
|
|
||||||
{
|
{
|
||||||
m_voxel_reg.reset(interface::createVoxelRegistry());
|
m_voxel_reg.reset(interface::createVoxelRegistry());
|
||||||
m_block_reg.reset(interface::createBlockRegistry(m_voxel_reg.get()));
|
m_block_reg.reset(interface::createBlockRegistry(m_voxel_reg.get()));
|
||||||
}
|
|
||||||
|
|
||||||
~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"));
|
|
||||||
m_server->sub_event(this, Event::t(
|
|
||||||
"network:packet_received/voxelworld:get_section"));
|
|
||||||
|
|
||||||
main_context::access(m_server, [&](main_context::Interface *imc){
|
main_context::access(m_server, [&](main_context::Interface *imc){
|
||||||
Context *context = imc->get_context();
|
Context *context = imc->get_context();
|
||||||
|
|
||||||
m_atlas_reg.reset(interface::createAtlasRegistry(context));
|
m_atlas_reg.reset(interface::createAtlasRegistry(context));
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
EVENT_TYPEN("network:packet_received/voxelworld:get_section",
|
|
||||||
on_get_section, network::Packet)
|
|
||||||
}
|
|
||||||
|
|
||||||
void on_start()
|
|
||||||
{
|
|
||||||
// TODO: Load from disk or something
|
// TODO: Load from disk or something
|
||||||
|
|
||||||
//pv::Region region(0, 0, 0, 0, 0, 0); // Use this for valgrind
|
//pv::Region region(0, 0, 0, 0, 0, 0); // Use this for valgrind
|
||||||
@ -313,97 +285,33 @@ struct Module: public interface::Module, public voxelworld::Interface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
log_w(MODULE, "TODO: Send initialization stuff to clients that already"
|
||||||
|
" were on this scene");
|
||||||
}
|
}
|
||||||
|
|
||||||
void unload_node(Scene *scene, uint node_id)
|
~CInstance()
|
||||||
{
|
|
||||||
log_d(MODULE, "Unloading node %i", node_id);
|
|
||||||
Node *n = scene->GetNode(node_id);
|
|
||||||
if(!n){
|
|
||||||
log_w(MODULE, "Cannot unload node %i: Not found in scene", node_id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Remove RigidBody first to speed up removal of CollisionShapes
|
|
||||||
RigidBody *body = n->GetComponent<RigidBody>();
|
|
||||||
if(body)
|
|
||||||
n->RemoveComponent(body);
|
|
||||||
// Remove everything else
|
|
||||||
n->RemoveAllComponents();
|
|
||||||
n->Remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
void on_unload()
|
|
||||||
{
|
|
||||||
log_v(MODULE, "on_unload()");
|
|
||||||
|
|
||||||
commit();
|
|
||||||
|
|
||||||
// Remove everything managed by us from the scene
|
|
||||||
main_context::access(m_server, [&](main_context::Interface *imc){
|
|
||||||
Scene *scene = imc->get_scene();
|
|
||||||
size_t progress = 0;
|
|
||||||
for(auto §or_pair: m_sections){
|
|
||||||
log_v(MODULE, "Unloading nodes... %i%%",
|
|
||||||
100 * progress / m_sections.size());
|
|
||||||
progress++;
|
|
||||||
for(auto §ion_pair: sector_pair.second){
|
|
||||||
Section §ion = section_pair.second;
|
|
||||||
|
|
||||||
auto region = section.node_ids->getEnclosingRegion();
|
|
||||||
auto lc = region.getLowerCorner();
|
|
||||||
auto uc = region.getUpperCorner();
|
|
||||||
for(int z = lc.getZ(); z <= uc.getZ(); z++){
|
|
||||||
for(int y = lc.getY(); y <= uc.getY(); y++){
|
|
||||||
for(int x = lc.getX(); x <= uc.getX(); x++){
|
|
||||||
uint id = section.node_ids->getVoxelAt(x, y, z);
|
|
||||||
section.node_ids->setVoxelAt(x, y, z, 0);
|
|
||||||
unload_node(scene, id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log_v(MODULE, "Unloading nodes... 100%%");
|
|
||||||
});
|
|
||||||
|
|
||||||
// Store voxel registry and stuff
|
|
||||||
std::ostringstream os(std::ios::binary);
|
|
||||||
{
|
|
||||||
cereal::PortableBinaryOutputArchive ar(os);
|
|
||||||
ar(m_voxel_reg->serialize());
|
|
||||||
}
|
|
||||||
m_server->tmp_store_data("voxelworld:restore_info", os.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void on_continue()
|
|
||||||
{
|
|
||||||
// Restore voxel registry and stuff
|
|
||||||
ss_ data = m_server->tmp_restore_data("voxelworld:restore_info");
|
|
||||||
ss_ voxel_reg_data;
|
|
||||||
{
|
|
||||||
std::istringstream is(data, std::ios::binary);
|
|
||||||
cereal::PortableBinaryInputArchive ar(is);
|
|
||||||
ar(voxel_reg_data);
|
|
||||||
}
|
|
||||||
m_voxel_reg->deserialize(voxel_reg_data);
|
|
||||||
|
|
||||||
// Start up normally
|
|
||||||
on_start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void on_client_connected(const network::NewClient &client_connected)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_client_disconnected(const network::OldClient &old_client)
|
void event(const Event::Type &type, const Event::Private *p)
|
||||||
{
|
{
|
||||||
m_clients_initialized.erase(old_client.info.id);
|
EVENT_TYPEN("core:tick", on_tick, interface::TickEvent)
|
||||||
|
EVENT_TYPEN("replicate:peer_joined_scene", on_peer_joined_scene,
|
||||||
|
replicate::PeerJoinedScene);
|
||||||
|
EVENT_TYPEN("replicate:peer_left_scene", on_peer_left_scene,
|
||||||
|
replicate::PeerLeftScene);
|
||||||
|
EVENT_TYPEN("client_file:files_transmitted", on_files_transmitted,
|
||||||
|
client_file::FilesTransmitted)
|
||||||
|
/*EVENT_TYPEN("network:packet_received/voxelworld:get_section",
|
||||||
|
on_get_section, network::Packet)*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_tick(const interface::TickEvent &event)
|
void on_tick(const interface::TickEvent &event)
|
||||||
{
|
{
|
||||||
main_context::access(m_server, [&](main_context::Interface *imc){
|
main_context::access(m_server, [&](main_context::Interface *imc){
|
||||||
Scene *scene = imc->get_scene();
|
Scene *scene = imc->get_scene(m_scene_ref);
|
||||||
Context *context = imc->get_context();
|
Context *context = imc->get_context();
|
||||||
|
|
||||||
// Update node collision boxes
|
// Update node collision boxes
|
||||||
@ -439,32 +347,10 @@ struct Module: public interface::Module, public voxelworld::Interface
|
|||||||
send_voxel_registry_if_dirty();
|
send_voxel_registry_if_dirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
void send_voxel_registry_if_dirty()
|
void on_peer_joined_scene(const replicate::PeerJoinedScene &event)
|
||||||
{
|
{
|
||||||
// Send updated voxel registry if needed
|
int peer = event.peer;
|
||||||
// NOTE: This probably really only supports additions
|
// Load the client-side module (can be called multiple times)
|
||||||
if(m_voxel_reg->is_dirty()){
|
|
||||||
m_voxel_reg->clear_dirty();
|
|
||||||
log_v(MODULE, "Sending updated voxel registry to peers");
|
|
||||||
|
|
||||||
ss_ voxel_reg_data = m_voxel_reg->serialize();
|
|
||||||
|
|
||||||
network::access(m_server, [&](network::Interface *inetwork){
|
|
||||||
sv_<network::PeerInfo::Id> peers = inetwork->list_peers();
|
|
||||||
for(auto &peer: peers){
|
|
||||||
if(!m_clients_initialized.count(peer))
|
|
||||||
continue;
|
|
||||||
inetwork->send(peer, "voxelworld:voxel_registry",
|
|
||||||
voxel_reg_data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void on_files_transmitted(const client_file::FilesTransmitted &event)
|
|
||||||
{
|
|
||||||
int peer = event.recipient;
|
|
||||||
// Load the client-side module
|
|
||||||
network::access(m_server, [&](network::Interface *inetwork){
|
network::access(m_server, [&](network::Interface *inetwork){
|
||||||
inetwork->send(peer, "core:run_script",
|
inetwork->send(peer, "core:run_script",
|
||||||
"require(\"buildat/module/voxelworld\")");
|
"require(\"buildat/module/voxelworld\")");
|
||||||
@ -485,10 +371,19 @@ struct Module: public interface::Module, public voxelworld::Interface
|
|||||||
m_clients_initialized.insert(peer);
|
m_clients_initialized.insert(peer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void on_peer_left_scene(const replicate::PeerLeftScene &event)
|
||||||
|
{
|
||||||
|
m_clients_initialized.erase(event.peer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_files_transmitted(const client_file::FilesTransmitted &event)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: How should nodes be filtered for replication?
|
// TODO: How should nodes be filtered for replication?
|
||||||
// TODO: Generally the client wants roughly one section, but isn't
|
// TODO: Generally the client wants roughly one section, but isn't
|
||||||
// positioned at the middle of a section
|
// positioned at the middle of a section
|
||||||
void on_get_section(const network::Packet &packet)
|
/*void on_get_section(const network::Packet &packet)
|
||||||
{
|
{
|
||||||
pv::Vector3DInt16 section_p;
|
pv::Vector3DInt16 section_p;
|
||||||
{
|
{
|
||||||
@ -498,6 +393,42 @@ struct Module: public interface::Module, public voxelworld::Interface
|
|||||||
}
|
}
|
||||||
log_v(MODULE, "C%i: on_get_section(): " PV3I_FORMAT,
|
log_v(MODULE, "C%i: on_get_section(): " PV3I_FORMAT,
|
||||||
packet.sender, PV3I_PARAMS(section_p));
|
packet.sender, PV3I_PARAMS(section_p));
|
||||||
|
}*/
|
||||||
|
|
||||||
|
void unload_node(Scene *scene, uint node_id)
|
||||||
|
{
|
||||||
|
log_d(MODULE, "Unloading node %i", node_id);
|
||||||
|
Node *n = scene->GetNode(node_id);
|
||||||
|
if(!n){
|
||||||
|
log_w(MODULE, "Cannot unload node %i: Not found in scene", node_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Remove RigidBody first to speed up removal of CollisionShapes
|
||||||
|
RigidBody *body = n->GetComponent<RigidBody>();
|
||||||
|
if(body)
|
||||||
|
n->RemoveComponent(body);
|
||||||
|
// Remove everything else
|
||||||
|
n->RemoveAllComponents();
|
||||||
|
n->Remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
void send_voxel_registry_if_dirty()
|
||||||
|
{
|
||||||
|
// Send updated voxel registry if needed
|
||||||
|
// NOTE: This probably really only supports additions
|
||||||
|
if(m_voxel_reg->is_dirty()){
|
||||||
|
m_voxel_reg->clear_dirty();
|
||||||
|
log_v(MODULE, "Sending updated voxel registry to peers");
|
||||||
|
|
||||||
|
ss_ voxel_reg_data = m_voxel_reg->serialize();
|
||||||
|
|
||||||
|
network::access(m_server, [&](network::Interface *inetwork){
|
||||||
|
for(auto &peer : m_clients_initialized){
|
||||||
|
inetwork->send(peer, "voxelworld:voxel_registry",
|
||||||
|
voxel_reg_data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get section if exists
|
// Get section if exists
|
||||||
@ -541,7 +472,8 @@ struct Module: public interface::Module, public voxelworld::Interface
|
|||||||
(section_p.getY()+1) * m_section_size_chunks.getY() - 1,
|
(section_p.getY()+1) * m_section_size_chunks.getY() - 1,
|
||||||
(section_p.getZ()+1) * m_section_size_chunks.getZ() - 1
|
(section_p.getZ()+1) * m_section_size_chunks.getZ() - 1
|
||||||
);
|
);
|
||||||
section = Section(section_p, m_chunk_size_voxels, contained_chunks);
|
section = Section(m_scene_ref, section_p, m_chunk_size_voxels,
|
||||||
|
contained_chunks);
|
||||||
}
|
}
|
||||||
return section;
|
return section;
|
||||||
}
|
}
|
||||||
@ -619,7 +551,7 @@ struct Module: public interface::Module, public voxelworld::Interface
|
|||||||
run_commit_hooks_in_scene(chunk_p, n);
|
run_commit_hooks_in_scene(chunk_p, n);
|
||||||
|
|
||||||
m_server->emit_event("voxelworld:node_volume_updated",
|
m_server->emit_event("voxelworld:node_volume_updated",
|
||||||
new NodeVolumeUpdated(n->GetID(), true, chunk_p));
|
new NodeVolumeUpdated(m_scene_ref, 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);
|
||||||
@ -629,7 +561,7 @@ struct Module: public interface::Module, public voxelworld::Interface
|
|||||||
void create_section(Section §ion)
|
void create_section(Section §ion)
|
||||||
{
|
{
|
||||||
main_context::access(m_server, [&](main_context::Interface *imc){
|
main_context::access(m_server, [&](main_context::Interface *imc){
|
||||||
Scene *scene = imc->get_scene();
|
Scene *scene = imc->get_scene(m_scene_ref);
|
||||||
auto lc = section.contained_chunks.getLowerCorner();
|
auto lc = section.contained_chunks.getLowerCorner();
|
||||||
auto uc = section.contained_chunks.getUpperCorner();
|
auto uc = section.contained_chunks.getUpperCorner();
|
||||||
for(int z = 0; z <= uc.getZ() - lc.getZ(); z++){
|
for(int z = 0; z <= uc.getZ() - lc.getZ(); z++){
|
||||||
@ -668,7 +600,7 @@ struct Module: public interface::Module, public voxelworld::Interface
|
|||||||
log_v(MODULE, "Section will be generated: " PV3I_FORMAT,
|
log_v(MODULE, "Section will be generated: " PV3I_FORMAT,
|
||||||
PV3I_PARAMS(section_p));
|
PV3I_PARAMS(section_p));
|
||||||
m_server->emit_event("voxelworld:generation_request",
|
m_server->emit_event("voxelworld:generation_request",
|
||||||
new GenerationRequest(section_p));
|
new GenerationRequest(m_scene_ref, section_p));
|
||||||
}
|
}
|
||||||
|
|
||||||
void mark_node_for_physics_update(uint node_id)
|
void mark_node_for_physics_update(uint node_id)
|
||||||
@ -839,7 +771,7 @@ struct Module: public interface::Module, public voxelworld::Interface
|
|||||||
commit();
|
commit();
|
||||||
|
|
||||||
main_context::access(m_server, [&](main_context::Interface *imc){
|
main_context::access(m_server, [&](main_context::Interface *imc){
|
||||||
Scene *scene = imc->get_scene();
|
Scene *scene = imc->get_scene(m_scene_ref);
|
||||||
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();
|
||||||
@ -874,7 +806,7 @@ struct Module: public interface::Module, public voxelworld::Interface
|
|||||||
mark_node_for_physics_update(node_id);
|
mark_node_for_physics_update(node_id);
|
||||||
|
|
||||||
m_server->emit_event("voxelworld:node_volume_updated",
|
m_server->emit_event("voxelworld:node_volume_updated",
|
||||||
new NodeVolumeUpdated(node_id, true, chunk_p));
|
new NodeVolumeUpdated(m_scene_ref, 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,
|
||||||
@ -961,7 +893,7 @@ struct Module: public interface::Module, public voxelworld::Interface
|
|||||||
*chunk_buffer.volume);
|
*chunk_buffer.volume);
|
||||||
|
|
||||||
main_context::access(m_server, [&](main_context::Interface *imc){
|
main_context::access(m_server, [&](main_context::Interface *imc){
|
||||||
Scene *scene = imc->get_scene();
|
Scene *scene = imc->get_scene(m_scene_ref);
|
||||||
Context *context = scene->GetContext();
|
Context *context = scene->GetContext();
|
||||||
|
|
||||||
Node *n = scene->GetNode(node_id);
|
Node *n = scene->GetNode(node_id);
|
||||||
@ -992,8 +924,8 @@ struct Module: public interface::Module, public voxelworld::Interface
|
|||||||
// Then synchronize node and notify clients about it
|
// Then synchronize node and notify clients about it
|
||||||
sv_<replicate::PeerId> peers;
|
sv_<replicate::PeerId> peers;
|
||||||
replicate::access(m_server, [&](replicate::Interface *ireplicate){
|
replicate::access(m_server, [&](replicate::Interface *ireplicate){
|
||||||
ireplicate->sync_node_immediate(node_id);
|
ireplicate->sync_node_immediate(m_scene_ref, node_id);
|
||||||
peers = ireplicate->find_peers_that_know_node(node_id);
|
peers = ireplicate->find_peers_that_know_node(m_scene_ref, node_id);
|
||||||
});
|
});
|
||||||
std::ostringstream os(std::ios::binary);
|
std::ostringstream os(std::ios::binary);
|
||||||
{
|
{
|
||||||
@ -1017,7 +949,7 @@ struct Module: public interface::Module, public voxelworld::Interface
|
|||||||
m_total_buffers_dirty--;
|
m_total_buffers_dirty--;
|
||||||
|
|
||||||
m_server->emit_event("voxelworld:node_volume_updated",
|
m_server->emit_event("voxelworld:node_volume_updated",
|
||||||
new NodeVolumeUpdated(node_id, true, chunk_p));
|
new NodeVolumeUpdated(m_scene_ref, node_id, true, chunk_p));
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t num_buffers_loaded()
|
size_t num_buffers_loaded()
|
||||||
@ -1084,6 +1016,211 @@ struct Module: public interface::Module, public voxelworld::Interface
|
|||||||
|
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Module: public interface::Module, public voxelworld::Interface
|
||||||
|
{
|
||||||
|
interface::Server *m_server;
|
||||||
|
|
||||||
|
sm_<SceneReference, up_<CInstance>> m_instances;
|
||||||
|
|
||||||
|
Module(interface::Server *server):
|
||||||
|
interface::Module(MODULE),
|
||||||
|
m_server(server)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~Module()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void init()
|
||||||
|
{
|
||||||
|
// NOTE: These also apply to CInstances
|
||||||
|
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("replicate:peer_joined_scene"));
|
||||||
|
m_server->sub_event(this, Event::t("replicate:peer_left_scene"));
|
||||||
|
m_server->sub_event(this, Event::t("client_file:files_transmitted"));
|
||||||
|
/*m_server->sub_event(this, Event::t(
|
||||||
|
"network:packet_received/voxelworld:get_section"));*/
|
||||||
|
}
|
||||||
|
|
||||||
|
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("replicate:peer_joined_scene", on_peer_joined_scene,
|
||||||
|
replicate::PeerJoinedScene);
|
||||||
|
EVENT_TYPEN("replicate:peer_left_scene", on_peer_left_scene,
|
||||||
|
replicate::PeerLeftScene);
|
||||||
|
EVENT_TYPEN("client_file:files_transmitted", on_files_transmitted,
|
||||||
|
client_file::FilesTransmitted)
|
||||||
|
|
||||||
|
for(auto &pair : m_instances){
|
||||||
|
up_<CInstance> &instance = pair.second;
|
||||||
|
instance->event(type, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_start()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void unload_node(Scene *scene, uint node_id)
|
||||||
|
{
|
||||||
|
log_d(MODULE, "Unloading node %i", node_id);
|
||||||
|
Node *n = scene->GetNode(node_id);
|
||||||
|
if(!n){
|
||||||
|
log_w(MODULE, "Cannot unload node %i: Not found in scene", node_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Remove RigidBody first to speed up removal of CollisionShapes
|
||||||
|
RigidBody *body = n->GetComponent<RigidBody>();
|
||||||
|
if(body)
|
||||||
|
n->RemoveComponent(body);
|
||||||
|
// Remove everything else
|
||||||
|
n->RemoveAllComponents();
|
||||||
|
n->Remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_unload()
|
||||||
|
{
|
||||||
|
log_v(MODULE, "on_unload()");
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
/*commit();
|
||||||
|
|
||||||
|
// Remove everything managed by us from the scene
|
||||||
|
main_context::access(m_server, [&](main_context::Interface *imc){
|
||||||
|
Scene *scene = imc->get_scene();
|
||||||
|
size_t progress = 0;
|
||||||
|
for(auto §or_pair: m_sections){
|
||||||
|
log_v(MODULE, "Unloading nodes... %i%%",
|
||||||
|
100 * progress / m_sections.size());
|
||||||
|
progress++;
|
||||||
|
for(auto §ion_pair: sector_pair.second){
|
||||||
|
Section §ion = section_pair.second;
|
||||||
|
|
||||||
|
auto region = section.node_ids->getEnclosingRegion();
|
||||||
|
auto lc = region.getLowerCorner();
|
||||||
|
auto uc = region.getUpperCorner();
|
||||||
|
for(int z = lc.getZ(); z <= uc.getZ(); z++){
|
||||||
|
for(int y = lc.getY(); y <= uc.getY(); y++){
|
||||||
|
for(int x = lc.getX(); x <= uc.getX(); x++){
|
||||||
|
uint id = section.node_ids->getVoxelAt(x, y, z);
|
||||||
|
section.node_ids->setVoxelAt(x, y, z, 0);
|
||||||
|
unload_node(scene, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log_v(MODULE, "Unloading nodes... 100%%");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Store voxel registry and stuff
|
||||||
|
std::ostringstream os(std::ios::binary);
|
||||||
|
{
|
||||||
|
cereal::PortableBinaryOutputArchive ar(os);
|
||||||
|
ar(m_voxel_reg->serialize());
|
||||||
|
}
|
||||||
|
m_server->tmp_store_data("voxelworld:restore_info", os.str());*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_continue()
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
/*// Restore voxel registry and stuff
|
||||||
|
ss_ data = m_server->tmp_restore_data("voxelworld:restore_info");
|
||||||
|
ss_ voxel_reg_data;
|
||||||
|
{
|
||||||
|
std::istringstream is(data, std::ios::binary);
|
||||||
|
cereal::PortableBinaryInputArchive ar(is);
|
||||||
|
ar(voxel_reg_data);
|
||||||
|
}
|
||||||
|
m_voxel_reg->deserialize(voxel_reg_data);*/
|
||||||
|
|
||||||
|
// Start up normally
|
||||||
|
on_start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_tick(const interface::TickEvent &event)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_peer_joined_scene(const replicate::PeerJoinedScene &event)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_peer_left_scene(const replicate::PeerLeftScene &event)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_files_transmitted(const client_file::FilesTransmitted &event)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: How should nodes be filtered for replication?
|
||||||
|
// TODO: Generally the client wants roughly one section, but isn't
|
||||||
|
// positioned at the middle of a section
|
||||||
|
void on_get_section(const network::Packet &packet)
|
||||||
|
{
|
||||||
|
pv::Vector3DInt16 section_p;
|
||||||
|
{
|
||||||
|
std::istringstream is(packet.data, std::ios::binary);
|
||||||
|
cereal::PortableBinaryInputArchive ar(is);
|
||||||
|
ar(section_p);
|
||||||
|
}
|
||||||
|
log_v(MODULE, "C%i: on_get_section(): " PV3I_FORMAT,
|
||||||
|
packet.sender, PV3I_PARAMS(section_p));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interface
|
||||||
|
|
||||||
|
void create_instance(SceneReference scene_ref)
|
||||||
|
{
|
||||||
|
auto it = m_instances.find(scene_ref);
|
||||||
|
// TODO: Is an exception the best way to handle this?
|
||||||
|
if(it != m_instances.end())
|
||||||
|
throw Exception("create_instance(): Scene already has a voxel"
|
||||||
|
" world instance");
|
||||||
|
|
||||||
|
up_<CInstance> instance(new CInstance(m_server, scene_ref));
|
||||||
|
m_instances[scene_ref] = std::move(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void delete_instance(SceneReference scene_ref)
|
||||||
|
{
|
||||||
|
auto it = m_instances.find(scene_ref);
|
||||||
|
if(it == m_instances.end())
|
||||||
|
throw Exception("delete_instance(): Scene does not have a voxel"
|
||||||
|
" world instance");
|
||||||
|
m_instances.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
Instance* get_instance(SceneReference scene_ref)
|
||||||
|
{
|
||||||
|
auto it = m_instances.find(scene_ref);
|
||||||
|
if(it == m_instances.end())
|
||||||
|
throw Exception("get_instance(): Scene does not have a voxel"
|
||||||
|
" world instance");
|
||||||
|
return it->second.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void commit()
|
||||||
|
{
|
||||||
|
for(auto &pair : m_instances){
|
||||||
|
up_<CInstance> &instance = pair.second;
|
||||||
|
instance->commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void* get_interface()
|
void* get_interface()
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user