Files
DarkRP2D/include/entityx/System.h
2017-10-22 14:26:55 +02:00

180 lines
4.4 KiB
C++

/*
* Copyright (C) 2012 Alec Thomas <alec@swapoff.org>
* All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution.
*
* Author: Alec Thomas <alec@swapoff.org>
*/
#pragma once
#include <cstdint>
#include <unordered_map>
#include <utility>
#include <cassert>
#include "entityx/config.h"
#include "entityx/Entity.h"
#include "entityx/Event.h"
#include "entityx/help/NonCopyable.h"
namespace entityx {
class SystemManager;
/**
* Base System class. Generally should not be directly used, instead see System<Derived>.
*/
class BaseSystem : entityx::help::NonCopyable {
public:
typedef size_t Family;
virtual ~BaseSystem();
/**
* Called once all Systems have been added to the SystemManager.
*
* Typically used to set up event handlers.
*/
virtual void configure(EntityManager &entities, EventManager &events) {
configure(events);
}
/**
* Legacy configure(). Called by default implementation of configure(EntityManager&, EventManager&).
*/
virtual void configure(EventManager &events) {}
/**
* Apply System behavior.
*
* Called every game step.
*/
virtual void update(EntityManager &entities, EventManager &events, TimeDelta dt) = 0;
static Family family_counter_;
protected:
};
/**
* Use this class when implementing Systems.
*
* struct MovementSystem : public System<MovementSystem> {
* void update(EntityManager &entities, EventManager &events, TimeDelta dt) {
* // Do stuff to/with entities...
* }
* }
*/
template <typename Derived>
class System : public BaseSystem {
public:
virtual ~System() {}
private:
friend class SystemManager;
static Family family() {
static Family family = family_counter_++;
return family;
}
};
class SystemManager : entityx::help::NonCopyable {
public:
SystemManager(EntityManager &entity_manager,
EventManager &event_manager) :
entity_manager_(entity_manager),
event_manager_(event_manager) {}
/**
* Add a System to the SystemManager.
*
* Must be called before Systems can be used.
*
* eg.
* std::shared_ptr<MovementSystem> movement = entityx::make_shared<MovementSystem>();
* system.add(movement);
*/
template <typename S>
void add(std::shared_ptr<S> system) {
systems_.insert(std::make_pair(S::family(), system));
}
/**
* Add a System to the SystemManager.
*
* Must be called before Systems can be used.
*
* eg.
* auto movement = system.add<MovementSystem>();
*/
template <typename S, typename ... Args>
std::shared_ptr<S> add(Args && ... args) {
std::shared_ptr<S> s(new S(std::forward<Args>(args) ...));
add(s);
return s;
}
/**
* Retrieve the registered System instance, if any.
*
* std::shared_ptr<CollisionSystem> collisions = systems.system<CollisionSystem>();
*
* @return System instance or empty shared_std::shared_ptr<S>.
*/
template <typename S>
std::shared_ptr<S> system() {
auto it = systems_.find(S::family());
assert(it != systems_.end());
return it == systems_.end()
? std::shared_ptr<S>()
: std::shared_ptr<S>(std::static_pointer_cast<S>(it->second));
}
/**
* Call the System::update() method for a registered system.
*/
template <typename S>
void update(TimeDelta dt) {
assert(initialized_ && "SystemManager::configure() not called");
std::shared_ptr<S> s = system<S>();
s->update(entity_manager_, event_manager_, dt);
}
/**
* Call System::update() on all registered systems.
*
* The order which the registered systems are updated is arbitrary but consistent,
* meaning the order which they will be updated cannot be specified, but that order
* will stay the same as long no systems are added or removed.
*
* If the order in which systems update is important, use SystemManager::update()
* to manually specify the update order. EntityX does not yet support a way of
* specifying priority for update_all().
*/
void update_all(TimeDelta dt);
/**
* Configure the system. Call after adding all Systems.
*
* This is typically used to set up event handlers.
*/
void configure();
private:
bool initialized_ = false;
EntityManager &entity_manager_;
EventManager &event_manager_;
std::unordered_map<BaseSystem::Family, std::shared_ptr<BaseSystem>> systems_;
};
} // namespace entityx