builtin/main_context: Fix scene reference handling

master
Perttu Ahola 2014-10-29 21:33:20 +02:00
parent 8ae01fc502
commit 7ebce17fbd
7 changed files with 69 additions and 55 deletions

View File

@ -21,6 +21,13 @@ namespace main_context
struct OpaqueSceneReference;
typedef OpaqueSceneReference* SceneReference;
struct SceneDeleted: public interface::Event::Private
{
SceneReference scene;
SceneDeleted(SceneReference scene): scene(scene) {}
};
struct Interface
{
// NOTE: Do not store Urho3D::SharedPtr<>s or any other kinds of pointers
@ -29,7 +36,7 @@ namespace main_context
virtual magic::Context* get_context() = 0;
virtual magic::Scene* find_scene(SceneReference ref) = 0;
virtual magic::Scene* get_scene(SceneReference ref) = 0;
virtual magic::Scene* check_scene(SceneReference ref) = 0;
virtual SceneReference create_scene() = 0;
virtual void delete_scene(SceneReference ref) = 0;

View File

@ -57,21 +57,11 @@ public:
}
};
struct SceneSetItem
struct OpaqueSceneReference
{
SharedPtr<Scene> scene;
void *raw_ptr = nullptr; // If scene is not set, this is used for searching
SceneSetItem() {}
SceneSetItem(SharedPtr<Scene> scene): scene(scene) {}
SceneSetItem(void *raw_ptr): raw_ptr(raw_ptr) {}
void* get_raw_ptr() const {
if(scene) return scene.Get();
return raw_ptr;
}
bool operator>(const SceneSetItem &other) const {
return get_raw_ptr() > other.get_raw_ptr();
}
OpaqueSceneReference(const SharedPtr<Scene> &scene): scene(scene) {}
};
struct Module: public interface::Module, public main_context::Interface
@ -82,8 +72,9 @@ struct Module: public interface::Module, public main_context::Interface
SharedPtr<Context> m_context;
SharedPtr<Engine> m_engine;
// Set of scenes as a sorted array in descending address order
sv_<SceneSetItem> m_scenes;
// OpaqueSceneReferences are never dropped from memory so that they stay
// unique, but the scenes itself are dropped.
sm_<SceneReference, up_<OpaqueSceneReference>> m_scenes;
sm_<Event::Type, SharedPtr<
interface::MagicEventHandler>> m_magic_event_handlers;
@ -216,25 +207,24 @@ struct Module: public interface::Module, public main_context::Interface
Scene* find_scene(SceneReference ref)
{
SceneSetItem item((void*)ref);
auto it = std::lower_bound(m_scenes.begin(), m_scenes.end(), item,
std::greater<SceneSetItem>());
auto it = m_scenes.find(ref);
if(it == m_scenes.end())
return nullptr;
return it->scene.Get();
return it->second->scene.Get();
}
Scene* get_scene(SceneReference ref)
Scene* check_scene(SceneReference ref)
{
Scene *scene = find_scene(ref);
if(!scene)
throw Exception("get_scene(): Scene not found");
throw Exception("check_scene(): Scene not found");
return scene;
}
SceneReference create_scene()
{
SharedPtr<Scene> scene(new Scene(m_context));
log_d(MODULE, "create_scene() -> %p", scene.Get());
auto *physics = scene->CreateComponent<PhysicsWorld>(LOCAL);
physics->SetFps(30);
@ -245,24 +235,20 @@ struct Module: public interface::Module, public main_context::Interface
scene->CreateComponent<Octree>(LOCAL);
// Insert into m_scenes
SceneSetItem item(scene);
auto it = std::lower_bound(m_scenes.begin(), m_scenes.end(), item,
std::greater<SceneSetItem>());
if(it == m_scenes.end())
m_scenes.insert(it, item);
return (SceneReference)scene.Get();
OpaqueSceneReference *ref = new OpaqueSceneReference(scene);
m_scenes[ref] = std::move(up_<OpaqueSceneReference>(ref));
return ref;
}
void delete_scene(SceneReference ref)
{
// Erase from m_scenes
SceneSetItem item((void*)ref);
auto it = std::lower_bound(m_scenes.begin(), m_scenes.end(), item,
std::greater<SceneSetItem>());
log_d(MODULE, "delete_scene(%p)", ref);
// Drop scene, but not the reference
auto it = m_scenes.find(ref);
if(it == m_scenes.end())
throw Exception("delete_scene(): Scene not found");
m_scenes.erase(it);
return;
it->second->scene.Reset();
m_server->emit_event("main_context:scene_deleted", new SceneDeleted(ref));
}
void sub_magic_event(

View File

@ -170,7 +170,7 @@ ChunkBuffer& Section::get_buffer(const pv::Vector3DInt32 &chunk_p,
main_context::access(server, [&](main_context::Interface *imc)
{
Scene *scene = imc->get_scene(m_scene_ref);
Scene *scene = imc->check_scene(m_scene_ref);
Node *n = scene->GetNode(node_id);
if(!n){
log_w(MODULE,
@ -310,7 +310,12 @@ struct CInstance: public voxelworld::Instance
void on_tick(const interface::TickEvent &event)
{
main_context::access(m_server, [&](main_context::Interface *imc){
Scene *scene = imc->get_scene(m_scene_ref);
Scene *scene = imc->find_scene(m_scene_ref);
if(!scene){
// Scene was deleted; hope that Module deletes us at some point
return;
}
Context *context = imc->get_context();
// Update node collision boxes
@ -565,7 +570,7 @@ struct CInstance: public voxelworld::Instance
void create_section(Section &section)
{
main_context::access(m_server, [&](main_context::Interface *imc){
Scene *scene = imc->get_scene(m_scene_ref);
Scene *scene = imc->check_scene(m_scene_ref);
auto lc = section.contained_chunks.getLowerCorner();
auto uc = section.contained_chunks.getUpperCorner();
for(int z = 0; z <= uc.getZ() - lc.getZ(); z++){
@ -775,7 +780,7 @@ struct CInstance: public voxelworld::Instance
commit();
main_context::access(m_server, [&](main_context::Interface *imc){
Scene *scene = imc->get_scene(m_scene_ref);
Scene *scene = imc->check_scene(m_scene_ref);
Node *n = scene->GetNode(node_id);
const Variant &var = n->GetVar(StringHash("buildat_voxel_data"));
const PODVector<unsigned char> &buf = var.GetBuffer();
@ -897,7 +902,7 @@ struct CInstance: public voxelworld::Instance
*chunk_buffer.volume);
main_context::access(m_server, [&](main_context::Interface *imc){
Scene *scene = imc->get_scene(m_scene_ref);
Scene *scene = imc->check_scene(m_scene_ref);
Context *context = scene->GetContext();
Node *n = scene->GetNode(node_id);
@ -1050,6 +1055,7 @@ struct Module: public interface::Module, public voxelworld::Interface
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("main_context:scene_deleted"));
/*m_server->sub_event(this, Event::t(
"network:packet_received/voxelworld:get_section"));*/
}
@ -1066,6 +1072,8 @@ struct Module: public interface::Module, public voxelworld::Interface
replicate::PeerLeftScene);
EVENT_TYPEN("client_file:files_transmitted", on_files_transmitted,
client_file::FilesTransmitted)
EVENT_TYPEN("main_context:scene_deleted", on_scene_deleted,
main_context::SceneDeleted);
for(auto &pair : m_instances){
up_<CInstance> &instance = pair.second;
@ -1104,7 +1112,7 @@ struct Module: public interface::Module, public voxelworld::Interface
// Remove everything managed by us from the scene
main_context::access(m_server, [&](main_context::Interface *imc){
Scene *scene = imc->get_scene();
Scene *scene = imc->check_scene();
size_t progress = 0;
for(auto &sector_pair: m_sections){
log_v(MODULE, "Unloading nodes... %i%%",
@ -1173,7 +1181,20 @@ struct Module: public interface::Module, public voxelworld::Interface
{
}
// TODO: How should nodes be filtered for replication?
void on_scene_deleted(const main_context::SceneDeleted &event)
{
// Drop instance of the deleted scene (there should be only one, but
// loop through all of them just for robustness)
for(auto it = m_instances.begin(); it != m_instances.end(); ){
auto current_it = it++;
up_<CInstance> &instance = current_it->second;
if(instance->m_scene_ref == event.scene){
m_instances.erase(current_it);
}
}
}
/*// 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)
@ -1186,7 +1207,7 @@ struct Module: public interface::Module, public voxelworld::Interface
}
log_v(MODULE, "C%i: on_get_section(): " PV3I_FORMAT,
packet.sender, PV3I_PARAMS(section_p));
}
}*/
// Interface

View File

@ -389,7 +389,7 @@ struct Module: public interface::Module
{
main_context::access(m_server, [&](main_context::Interface *imc)
{
Scene *scene = imc->get_scene(m_main_scene);
Scene *scene = imc->check_scene(m_main_scene);
Context *context = imc->get_context();
ResourceCache *cache = context->GetSubsystem<ResourceCache>();
@ -457,7 +457,7 @@ struct Module: public interface::Module
{
/*main_context::access(m_server, [&](main_context::Interface *imc)
{
Scene *scene = imc->get_scene(m_main_scene);
Scene *scene = imc->check_scene(m_main_scene);
Node *n = scene->GetChild("Testbox");
auto p = n->GetPosition();
log_v(MODULE, "Testbox: (%f, %f, %f)", p.x_, p.y_, p.z_);
@ -466,7 +466,7 @@ struct Module: public interface::Module
if(((a++) % 150) == 0){
main_context::access(m_server, [&](main_context::Interface *imc)
{
Scene *scene = imc->get_scene(m_main_scene);
Scene *scene = imc->check_scene(m_main_scene);
Node *n = scene->GetChild("Testbox");
if(n){
n->SetRotation(Quaternion(30, 60, 90));

View File

@ -74,7 +74,7 @@ struct Module: public interface::Module
main_context::access(m_server, [&](main_context::Interface *imc){
m_main_scene = imc->create_scene();
Scene *scene = imc->get_scene(m_main_scene);
Scene *scene = imc->check_scene(m_main_scene);
Context *context = scene->GetContext();
ResourceCache *cache = context->GetSubsystem<ResourceCache>();
auto *m = cache->GetResource<Material>("Materials/Stone.xml");
@ -145,7 +145,7 @@ struct Module: public interface::Module
static uint a = 0;
if(((a++) % 100) == 0){
main_context::access(m_server, [&](main_context::Interface *imc){
Scene *scene = imc->get_scene(m_main_scene);
Scene *scene = imc->check_scene(m_main_scene);
Node *n = scene->GetChild("Box");
n->SetPosition(Vector3(0.0f, 6.0f, 0.0f));
n->SetRotation(Quaternion(30, 60, 90));
@ -168,7 +168,7 @@ struct Module: public interface::Module
return;
}
main_context::access(m_server, [&](main_context::Interface *imc){
Scene *scene = imc->get_scene(m_main_scene);
Scene *scene = imc->check_scene(m_main_scene);
Node *n = scene->GetChild("Box");
//n->Translate(Vector3(0.1f, 0, 0));
Vector3 p = n->GetPosition();

View File

@ -66,7 +66,7 @@ struct Module: public interface::Module
main_context::access(m_server, [&](main_context::Interface *imc){
m_main_scene = imc->create_scene();
Scene *scene = imc->get_scene(m_main_scene);
Scene *scene = imc->check_scene(m_main_scene);
Context *context = scene->GetContext();
ResourceCache *cache = context->GetSubsystem<ResourceCache>();
@ -124,7 +124,7 @@ struct Module: public interface::Module
void update_scene()
{
main_context::access(m_server, [&](main_context::Interface *imc){
Scene *scene = imc->get_scene(m_main_scene);
Scene *scene = imc->check_scene(m_main_scene);
Context *context = scene->GetContext();
ResourceCache *cache = context->GetSubsystem<ResourceCache>();
@ -178,7 +178,7 @@ struct Module: public interface::Module
float ry = (float)rand() / RAND_MAX * 180;
float rz = (float)rand() / RAND_MAX * 180;
main_context::access(m_server, [&](main_context::Interface *imc){
Scene *scene = imc->get_scene(m_main_scene);
Scene *scene = imc->check_scene(m_main_scene);
Node *n = scene->GetChild("Testbox");
n->SetRotation(Quaternion(rx, ry, rz));
n->SetPosition(Vector3(-0.5f, 8.0f, 0.0f));

View File

@ -59,7 +59,7 @@ struct Module: public interface::Module
main_context::access(m_server, [&](main_context::Interface *imc){
m_main_scene = imc->create_scene();
Scene *scene = imc->get_scene(m_main_scene);
Scene *scene = imc->check_scene(m_main_scene);
Context *context = scene->GetContext();
m_atlas_reg.reset(interface::createAtlasRegistry(context));
{
@ -134,7 +134,7 @@ struct Module: public interface::Module
{
main_context::access(m_server, [&](main_context::Interface *imc)
{
Scene *scene = imc->get_scene(m_main_scene);
Scene *scene = imc->check_scene(m_main_scene);
Context *context = scene->GetContext();
ResourceCache *cache = context->GetSubsystem<ResourceCache>();
@ -201,7 +201,7 @@ struct Module: public interface::Module
{
main_context::access(m_server, [&](main_context::Interface *imc)
{
Scene *scene = imc->get_scene(m_main_scene);
Scene *scene = imc->check_scene(m_main_scene);
Context *context = scene->GetContext();
ResourceCache *cache = context->GetSubsystem<ResourceCache>();
@ -260,7 +260,7 @@ struct Module: public interface::Module
static uint a = 0;
if(((a++) % 100) == 0){
main_context::access(m_server, [&](main_context::Interface *imc){
Scene *scene = imc->get_scene(m_main_scene);
Scene *scene = imc->check_scene(m_main_scene);
Node *n = scene->GetChild("Testbox");
//n->SetPosition(Vector3(0.0f, 8.0f, 0.0f));
n->SetRotation(Quaternion(30, 60, 90));