#include <msp/fs/dir.h>
#include <msp/fs/stat.h>
#include <msp/game/setups.h>
+#include "stageplan.h"
using namespace std;
add_type<CameraSetup>().suffix(".camera.setup");
add_type<HeightmapTerrainSetup>().suffix(".hmap.setup");
add_type<LightSetup>().suffix(".light.setup");
+ add_type<StagePlan>().suffix(".stage");
}
#include "accessguard.h"
#include "camera.h"
#include "root.h"
+#include "stageplan.h"
#include "system.h"
using namespace std;
namespace Msp::Game {
+struct Stage::Content
+{
+ vector<Owned<Entity>> entities;
+};
+
+
Stage::Stage(const string &n, ThreadPool &t, Reflection::Reflector &f, DataFile::Collection &r):
name(n),
threads(t),
Stage::~Stage()
{ }
+void Stage::apply_plan(const StagePlan &plan)
+{
+ vector<Owned<Entity>> new_entities = plan.create_entities(*this);
+ if(new_entities.empty())
+ return;
+
+ if(!content)
+ content = make_unique<Content>();
+ content->entities.reserve(content->entities.size()+new_entities.size());
+ for(Owned<Entity> &e: new_entities)
+ content->entities.push_back(move(e));
+}
+
void Stage::remove_system(System &s)
{
scheduler.remove_system(s);
class Camera;
class Root;
+class StagePlan;
class System;
class MSPGAME_API Stage
Events::RemotePlayerEntered, Events::RemotePlayerExited>;
private:
+ struct Content;
+
std::string name;
ThreadPool &threads;
Reflection::Reflector &reflector;
/* Use unique_ptr because there's only one root per stage so it's pointless
to put it in a pool. */
std::unique_ptr<Root> root;
+ std::unique_ptr<Content> content;
std::vector<std::unique_ptr<System>> systems;
SystemScheduler scheduler;
Handle<Camera> active_camera;
template<typename T, typename F>
void iterate_objects(const F &);
+ void apply_plan(const StagePlan &);
+
template<typename T, typename... Args>
T &add_system(Args &&...);
--- /dev/null
+#include "stageplan.h"
+#include "entity.h"
+#include "root.h"
+
+using namespace std;
+
+namespace Msp::Game {
+
+vector<Owned<Entity>> StagePlan::create_entities(Stage &stage) const
+{
+ vector<Owned<Entity>> result;
+ result.reserve(entities.size());
+ for(const unique_ptr<EntityBase> &e: entities)
+ {
+ Handle<Entity> parent = (e->parent_index>=0 ? static_cast<Handle<Entity>>(result[e->parent_index]) : stage.get_root());
+ result.push_back(e->create(parent));
+ }
+ return result;
+}
+
+auto StagePlan::get_entity_registry() -> EntityRegistry &
+{
+ static EntityRegistry registry;
+ return registry;
+}
+
+
+StagePlan::Loader::Loader(StagePlan &p, DataFile::Collection &c):
+ CollectionObjectLoader(p, &c)
+{
+ static ActionMap shared_actions;
+ set_actions(shared_actions);
+}
+
+void StagePlan::Loader::init_actions()
+{
+ get_entity_registry().invoke_all(*this);
+}
+
+
+StagePlan::EntityBase::Loader::Loader(EntityBase &e):
+ ObjectLoader(e)
+{
+ static ActionMap shared_actions;
+ set_actions(shared_actions);
+}
+
+void StagePlan::EntityBase::Loader::init_actions()
+{
+ add("transform", &Loader::transform);
+}
+
+void StagePlan::EntityBase::Loader::transform()
+{
+ TransformLoader ldr(obj);
+ load_sub_with(ldr);
+}
+
+
+StagePlan::EntityBase::TransformLoader::TransformLoader(EntityBase &e):
+ ObjectLoader(e)
+{
+ static ActionMap shared_actions;
+ set_actions(shared_actions);
+}
+
+void StagePlan::EntityBase::TransformLoader::init_actions()
+{
+ add("euler", &TransformLoader::euler);
+ add("position", &TransformLoader::position);
+ add("rotation", &TransformLoader::rotation);
+}
+
+void StagePlan::EntityBase::TransformLoader::euler(float x, float y, float z)
+{
+ obj.transform.rotation = Geometry::make_quat(z*Geometry::degrees, { 0.0f, 0.0f, 1.0f })*
+ Geometry::make_quat(y*Geometry::degrees, { 0.0f, 1.0f, 0.0f })*
+ Geometry::make_quat(x*Geometry::degrees, { 1.0f, 0.0f, 0.0f });
+}
+
+void StagePlan::EntityBase::TransformLoader::position(float x, float y, float z)
+{
+ obj.transform.position = { x, y, z };
+}
+
+void StagePlan::EntityBase::TransformLoader::rotation(float a, float x, float y, float z)
+{
+ obj.transform.rotation = Geometry::make_quat(a*Geometry::degrees, { x, y, z });
+}
+
+} // namespace Msp::Game
--- /dev/null
+#ifndef STAGEPLAN_H_
+#define STAGEPLAN_H_
+
+#include <msp/core/typeregistry.h>
+#include <msp/datafile/objectloader.h>
+#include "mspgame_api.h"
+#include "owned.h"
+#include "transform.h"
+
+namespace Msp::Game {
+
+class Entity;
+
+class MSPGAME_API StagePlan
+{
+public:
+ class MSPGAME_API Loader: public DataFile::CollectionObjectLoader<StagePlan>
+ {
+ friend class StagePlan;
+
+ private:
+ template<typename T>
+ struct AddEntityType
+ {
+ void operator()(const std::string &kw, Loader &l) const { l.add(kw, &Loader::entity<T>); }
+ };
+
+ public:
+ Loader(StagePlan &, DataFile::Collection &);
+
+ private:
+ void init_actions() override;
+
+ template<typename T>
+ void entity(const std::string &);
+ };
+
+private:
+ struct EntityBase
+ {
+ class MSPGAME_API Loader: public DataFile::ObjectLoader<EntityBase>
+ {
+ public:
+ Loader(EntityBase &);
+
+ private:
+ void init_actions() override;
+
+ public:
+ void transform();
+ };
+
+ class TransformLoader: public DataFile::ObjectLoader<EntityBase>
+ {
+ public:
+ TransformLoader(EntityBase &);
+
+ private:
+ void init_actions() override;
+
+ void euler(float, float, float);
+ void position(float, float, float);
+ void rotation(float, float, float, float);
+ };
+
+ int parent_index = -1;
+ TransformValues transform;
+
+ virtual ~EntityBase() = default;
+
+ virtual Owned<Entity> create(Handle<Entity>) const = 0;
+ };
+
+ template<typename T>
+ struct PlannedEntity: EntityBase
+ {
+ const T::Setup &setup = nullptr;
+
+ PlannedEntity(const T::Setup &s): setup(s) { }
+
+ Owned<Entity> create(Handle<Entity>) const override;
+ };
+
+ using EntityRegistry = TypeRegistry<Loader::AddEntityType, Loader &>;
+
+ std::vector<std::unique_ptr<EntityBase>> entities;
+
+public:
+ StagePlan() = default;
+ StagePlan(StagePlan &&) = default;
+ StagePlan &operator=(StagePlan &&) = default;
+
+ std::vector<Owned<Entity>> create_entities(Stage &) const;
+
+ template<typename T>
+ static void register_entity_type(const std::string &);
+
+private:
+ static EntityRegistry &get_entity_registry();
+};
+
+
+template<typename T>
+void StagePlan::register_entity_type(const std::string &n)
+{
+ get_entity_registry().register_type<T>(n);
+}
+
+
+template<typename T>
+Owned<Entity> StagePlan::PlannedEntity<T>::create(Handle<Entity> p) const
+{
+ return Owned<T>(p, setup, transform);
+}
+
+
+template<typename T>
+void StagePlan::Loader::entity(const std::string &sn)
+{
+ const typename T::Setup &setup = get_collection().get<typename T::Setup>(sn);
+ obj.entities.push_back(make_sub<PlannedEntity<T>>(setup).load());
+}
+
+} // namespace Msp::Game
+
+#endif