diff --git a/games/digger/worldgen/api.h b/games/digger/worldgen/api.h new file mode 100644 index 0000000..f1e3fac --- /dev/null +++ b/games/digger/worldgen/api.h @@ -0,0 +1,35 @@ +// http://www.apache.org/licenses/LICENSE-2.0 +// Copyright 2014 Perttu Ahola +#pragma once +#include "interface/event.h" +#include "interface/server.h" +#include "interface/module.h" +#include + +namespace worldgen +{ + struct QueueModifiedEvent: public interface::Event::Private + { + size_t queue_size; + + QueueModifiedEvent(size_t queue_size): + queue_size(queue_size) + {} + }; + + struct Interface + { + virtual size_t get_num_sections_queued() = 0; + }; + + inline bool access(interface::Server *server, + std::function cb) + { + return server->access_module("worldgen", [&](interface::Module *module){ + cb((worldgen::Interface*)module->check_interface()); + }); + } +} + +// vim: set noet ts=4 sw=4: + diff --git a/games/digger/worldgen/worldgen.cpp b/games/digger/worldgen/worldgen.cpp index 0fadf65..af8c0ec 100644 --- a/games/digger/worldgen/worldgen.cpp +++ b/games/digger/worldgen/worldgen.cpp @@ -1,9 +1,6 @@ #include "core/log.h" -#include "client_file/api.h" -#include "network/api.h" -#include "replicate/api.h" #include "voxelworld/api.h" -#include "main_context/api.h" +#include "worldgen/api.h" #include "interface/module.h" #include "interface/server.h" #include "interface/event.h" @@ -11,19 +8,14 @@ #include "interface/voxel.h" #include "interface/noise.h" #include "interface/voxel_volume.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "interface/thread.h" +#include "interface/semaphore.h" +#include "interface/os.h" +#include #include #include #include +#include #define MODULE "worldgen" namespace magic = Urho3D; @@ -54,20 +46,39 @@ void load(Archive &archive, pv::Vector3DInt32 &v){ namespace worldgen { -using namespace Urho3D; +struct Module; -struct Module: public interface::Module +struct GenerateThread: public interface::ThreadedThing +{ + Module *m_module = nullptr; + + GenerateThread(Module *module): + m_module(module) + {} + + void run(interface::Thread *thread); +}; + +struct Module: public interface::Module, public Interface { interface::Server *m_server; + std::deque m_queued_sections; + interface::Semaphore m_queued_sections_sem; + sp_ m_thread; Module(interface::Server *server): interface::Module(MODULE), m_server(server) { + m_thread.reset(interface::createThread(new GenerateThread(this))); + m_thread->start(); } ~Module() - {} + { + m_thread->request_stop(); + m_queued_sections_sem.post(); + } void init() { @@ -81,6 +92,7 @@ struct Module: public interface::Module { EVENT_VOIDN("core:start", on_start) EVENT_VOIDN("core:continue", on_continue) + EVENT_TYPEN("core:tick", on_tick, interface::TickEvent) EVENT_TYPEN("voxelworld:generation_request", on_generation_request, voxelworld::GenerationRequest) } @@ -215,18 +227,38 @@ struct Module: public interface::Module { } - void update_scene() + void on_tick(const interface::TickEvent &event) { } void on_generation_request(const voxelworld::GenerationRequest &event) { - log_v(MODULE, "on_generation_request(): section_p: (%i, %i, %i)", + m_queued_sections.push_back(event.section_p); + m_queued_sections_sem.post(); + log_v(MODULE, "Queued section (%i, %i, %i); queue size: %zu", event.section_p.getX(), event.section_p.getY(), - event.section_p.getZ()); + event.section_p.getZ(), m_queued_sections.size()); + m_server->emit_event("worldgen:queue_modified", + new QueueModifiedEvent(m_queued_sections.size())); + } + + // Interface for GenerateThread + + // NOTE: on_tick() cannot be used here, because as this takes much longer + // than a tick, the ticks accumulate and result in nothing getting + // queued but instead sectors get queued in the event queue. + void generate_next_section() + { + if(m_queued_sections.empty()) + return; + const pv::Vector3DInt16 section_p = m_queued_sections.front(); + m_queued_sections.pop_front(); + + log_v(MODULE, "Generating section (%i, %i, %i); queue size: %zu", + section_p.getX(), section_p.getY(), section_p.getZ(), + m_queued_sections.size()); voxelworld::access(m_server, [&](voxelworld::Interface *ivoxelworld) { - const pv::Vector3DInt16 §ion_p = event.section_p; pv::Region region = ivoxelworld->get_section_region_voxels( section_p); @@ -328,9 +360,42 @@ struct Module: public interface::Module } } }); + + m_server->emit_event("worldgen:queue_modified", + new QueueModifiedEvent(m_queued_sections.size())); + } + + // Interface + + size_t get_num_sections_queued() + { + return m_queued_sections.size(); + } + + void* get_interface() + { + return dynamic_cast(this); } }; +void GenerateThread::run(interface::Thread *thread) +{ + for(;;){ + // Give some time for accumulating the section queue + interface::os::sleep_us(5000); + m_module->m_queued_sections_sem.wait(); + if(thread->stop_requested()) + break; + // We can avoid implementing our own mutex locking in Module by using + // interface::Server::access_module() instead of directly accessing it. + worldgen::access(m_module->m_server, + [&](worldgen::Interface *iworldgen) + { + m_module->generate_next_section(); + }); + } +} + extern "C" { BUILDAT_EXPORT void* createModule_worldgen(interface::Server *server){ return (void*)(new Module(server));