libecs-cpp 2.1.0
Entity Component System library in C++
Loading...
Searching...
No Matches
Container.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <string>
4#include <vector>
5#include <unordered_map>
6#include <thread>
7#include <memory>
8#include <type_traits>
9#include <mutex>
10#include <atomic>
11#include <functional>
12#include <condition_variable>
13#include <libecs-cpp/json.hpp>
14#include <libecs-cpp/Uuid.hpp>
17#include <libecs-cpp/Clock.hpp>
18#include <libecs-cpp/Timing.hpp>
19#include <chrono>
20#include <cstddef>
21#include <cstdint>
22#include <stdexcept>
23#include <utility>
24
25namespace ecs
26{
27 class Manager;
28 class System;
29 class Component;
30 class Entity;
31 struct Mailbox;
32
70 {
71 friend class Manager;
72
73 public:
79 Container(ecs::Manager *manager, const std::string &handle);
100 void Start();
107 void Start(std::chrono::microseconds interval);
110 void Start(uint32_t);
120 void ClockSet(const ecs::Clock *clock);
152 void Stop();
200 ecs::System *System(std::unique_ptr<ecs::System> system);
216 std::shared_ptr<ecs::Component> Component(std::unique_ptr<ecs::Component> component);
231 template <class T = ecs::Component>
232 std::shared_ptr<T> ComponentGet(const std::string &entity, const std::string &type) const
233 {
234 const std::shared_ptr<ecs::Component> *found = this->componentFind(entity, type);
235 if(found == nullptr)
236 {
237 return nullptr;
238 }
239 if constexpr(std::is_same_v<T, ecs::Component>)
240 {
241 return *found;
242 }
243 else
244 {
245 return std::dynamic_pointer_cast<T>(*found);
246 }
247 }
255 bool ComponentHas(const std::string &entity, const std::string &type) const;
260 void ComponentDestroy(const std::string &entity, const std::string &type);
265 ecs::Entity *Entity(const std::string &handle);
275 void EntityDestroy(const std::string &handle);
295 void SystemDestroy(const std::string &handle);
300 nlohmann::json Export() const;
331 void Update();
344 void MessageSubmit(const nlohmann::json &message);
360 void Defer(std::function<void()> fn);
368 void ResourceAdd(const std::string &name, ecs::Resource r);
373 void Resources(const std::unordered_map<std::string, std::shared_ptr<ecs::Resource>> &resources);
381 std::shared_ptr<const ecs::Resource> ResourceGet(const std::string &name) const;
386 std::unordered_map<std::string, std::unique_ptr<ecs::Entity>> Entities;
395 const std::string Handle;
410 std::unordered_map<std::string, std::unique_ptr<ecs::System>> Systems;
426 void Log(const std::string &message, const std::string &level = "info");
433 void LoggerSet(std::function<void(const std::string &, const std::string &)> fn);
434 private:
436 std::mutex mailboxesLock;
437 std::unordered_map<std::string, std::shared_ptr<ecs::Mailbox>> mailboxes;
438 using LogFunction = std::function<void(const std::string &, const std::string &)>;
440 std::mutex loggerLock;
441 std::shared_ptr<const LogFunction> logger;
443 struct SystemSlot
444 {
445 std::string handle;
446 ecs::System *system;
448 bool started = false;
450 bool shutdown = false;
451 };
452 class WalkScope;
453 std::vector<SystemSlot> systemOrder;
454 uint32_t walkDepth = 0;
456 std::mutex deferredLock;
457 std::vector<std::function<void()>> deferred;
459 std::atomic<std::size_t> deferredCount{0};
460 bool deferredClosed = false;
461 bool draining = false;
462 void deferredRun();
463 bool orderHasGaps = false;
464 void walkFinish();
466 struct RetiredSystem
467 {
468 std::unique_ptr<ecs::System> system;
470 bool notify = false;
471 };
472 std::vector<RetiredSystem> retiredSystems;
475 void systemRetire(std::unique_ptr<ecs::System> system, bool notify);
477 void systemNotify(ecs::System *system);
479 void retiredRelease();
480 void deferredClose();
482 std::chrono::microseconds sleepInterval = ecs::DEFAULT_INTERVAL;
484 const ecs::Clock *clock = &ecs::SteadyClock::Instance();
485
486 std::jthread containerThread;
487 void threadFunc(std::stop_token stopToken);
488 ecs::Entity *entityCreate(const std::string &handle);
490 const std::shared_ptr<ecs::Component> *componentFind(const std::string &entity, const std::string &type) const
491 {
492 auto byType = this->Components.find(type);
493 if(byType == this->Components.end())
494 {
495 return nullptr;
496 }
497 auto byEntity = byType->second.find(entity);
498 if(byEntity == byType->second.end())
499 {
500 return nullptr;
501 }
502 return byEntity->second ? &byEntity->second : nullptr;
503 }
504
505 std::unordered_map<std::string, std::shared_ptr<ecs::Resource>> resources;
506
508 bool startPending = false;
510 void systemsStart();
513 bool tearingDown = false;
514 bool tornDown = false;
516 void teardown();
517
520 std::mutex lifecycleLock;
521 std::condition_variable_any lifecycleChanged;
523 bool threadStarted = false;
525 std::atomic<bool> stopRequested{false};
527 bool stopDone = false;
529 bool joining = false;
531 bool joined = false;
533 std::atomic<bool> ownsThread{false};
535 void threadStart(const std::chrono::microseconds *interval);
537 void requestStop();
540 void waitStopped();
543 bool managerStopRequest();
546 void managerStopWait();
547 };
548}
A source of time for systems and containers.
Definition Clock.hpp:21
A container: the entities, components, systems and resources that are updated together.
Definition Container.hpp:70
std::shared_ptr< T > ComponentGet(const std::string &entity, const std::string &type) const
Looks up the component with the given type name on the given entity, as class T.
Definition Container.hpp:232
void ResourceAdd(const std::string &name, ecs::Resource r)
Stores a resource under a name, replacing any resource of that name.
bool ComponentHas(const std::string &entity, const std::string &type) const
Says whether the given entity has a component stored under the given type name.
void SystemDestroy(const std::string &handle)
Removes a system.
std::unordered_map< std::string, std::unique_ptr< ecs::System > > Systems
The systems of the container, by handle.
Definition Container.hpp:410
~Container()
Stops the container as Stop() does, then releases it.
std::unordered_map< std::string, std::unique_ptr< ecs::Entity > > Entities
The entities of the container, by handle.
Definition Container.hpp:386
void Defer(std::function< void()> fn)
Hands a function to the container thread, which runs it at the start of the next pass.
void Update()
Runs one pass: the deferred functions, then the start of new systems, then one update of each system.
ecs::TypeEntityComponentList Components
The components of the container, by type name and then by entity handle.
Definition Container.hpp:401
Container(ecs::Manager *manager)
Creates a container with a generated handle.
void LoggerSet(std::function< void(const std::string &, const std::string &)> fn)
Replaces the log destination.
void EntityDestroy(const std::string &handle)
Removes an entity and its components.
Container(ecs::Manager *manager, const std::string &handle)
Creates a container with the given handle.
void ClockSet(const ecs::Clock *clock)
Replaces the clock that the systems of this container read.
ecs::Entity * Entity(const std::string &handle)
Returns the entity with this handle, creating it if it does not exist.
void Start(std::chrono::microseconds interval)
Starts the container's own thread with the given time between passes.
void ComponentDestroy(const std::string &entity, const std::string &type)
Removes the component with the given type name from the given entity.
const std::string Handle
The container's handle: the name given to Manager::Container(), or a generated UUID.
Definition Container.hpp:395
void Log(const std::string &message, const std::string &level="info")
Sends a line to the log destination.
ecs::Entity * Entity()
Creates an entity with a generated handle.
void SystemsInitialize()
Calls System::Initialize() on every registered system that has not been started, in registration orde...
void Start(uint32_t)
Starts the container's own thread with the interval given as a number of microseconds.
std::shared_ptr< ecs::Component > Component(std::unique_ptr< ecs::Component > component)
Attaches a component to the entity named by its EntityHandle and returns the stored component.
void Start()
Starts the container's own thread, which runs 30 passes a second.
std::shared_ptr< const ecs::Resource > ResourceGet(const std::string &name) const
Returns the resource stored under a name as a shared read-only view, without copying its bytes.
ecs::System * System(std::unique_ptr< ecs::System > system)
Registers a system and returns a pointer to it.
nlohmann::json Export() const
Describes the container, its entities and its systems as JSON.
void Stop()
Stops the container and calls System::Shutdown() on every started system, last registered first.
void MessageSubmit(const nlohmann::json &message)
Sends a message to the system named in message["destination"]["system"].
ecs::Uuid UuidGet()
Generates a new identifier.
void Resources(const std::unordered_map< std::string, std::shared_ptr< ecs::Resource > > &resources)
Stores every resource in the given map under its name, replacing resources of the same names.
One thing in a container, to which components are attached.
Definition Entity.hpp:22
Creates and owns containers, routes messages between them and shuts them down.
Definition Manager.hpp:32
static const SteadyClock & Instance()
The shared instance, which lives until the process ends.
Definition Clock.hpp:41
Base class for the logic that runs in a container.
Definition System.hpp:178
A 128-bit random identifier in the standard version 4 text form (for example "550e8400-e29b-41d4-a716...
Definition Uuid.hpp:14
Definition Clock.hpp:10
constexpr std::chrono::microseconds DEFAULT_INTERVAL
The interval of a new schedule: 33 333 microseconds, about 30 updates a second.
Definition Timing.hpp:17
std::unordered_map< std::string, ecs::EntityComponentList > TypeEntityComponentList
The components of a container, by type name and then by entity handle.
Definition Component.hpp:48
A block of bytes that a container stores under a name with Container::ResourceAdd().
Definition Resource.hpp:16