aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/crepe/Component.h17
-rw-r--r--src/crepe/api/BehaviorScript.h1
-rw-r--r--src/crepe/api/Engine.cpp7
-rw-r--r--src/crepe/api/Engine.h14
-rw-r--r--src/crepe/api/GameObject.h3
-rw-r--r--src/crepe/api/ParticleEmitter.cpp15
-rw-r--r--src/crepe/api/ParticleEmitter.h6
-rw-r--r--src/crepe/api/Script.hpp11
-rw-r--r--src/crepe/api/Transform.h1
-rw-r--r--src/crepe/manager/ComponentManager.h24
-rw-r--r--src/crepe/manager/ReplayManager.cpp7
-rw-r--r--src/crepe/manager/ReplayManager.h52
-rw-r--r--src/crepe/manager/SystemManager.h24
-rw-r--r--src/crepe/system/CMakeLists.txt1
-rw-r--r--src/crepe/system/EventSystem.h7
-rw-r--r--src/crepe/system/ReplaySystem.h15
-rw-r--r--src/example/replay.cpp4
17 files changed, 185 insertions, 24 deletions
diff --git a/src/crepe/Component.h b/src/crepe/Component.h
index fc0268c..52e06d5 100644
--- a/src/crepe/Component.h
+++ b/src/crepe/Component.h
@@ -39,10 +39,27 @@ protected:
virtual Component & operator=(Component &&) = delete;
protected:
+ /**
+ * \name ReplayManager (Memento) functions
+ * \{
+ */
+ /**
+ * \brief Save a snapshot of this component's state
+ * \note This function should only be implemented on components that should be saved/restored
+ * by ReplayManager.
+ * \returns Unique pointer to a deep copy of this component
+ */
virtual std::unique_ptr<Component> save() const;
+ //! Copy constructor (used by \c save())
Component(const Component &) = default;
+ /**
+ * \brief Restore this component from a snapshot
+ * \param snapshot Data to fill this component with (as returned by \c save())
+ */
virtual void restore(const Component & snapshot);
+ //! Copy assignment operator (used by \c restore())
virtual Component & operator=(const Component &);
+ //! \}
public:
virtual ~Component() = default;
diff --git a/src/crepe/api/BehaviorScript.h b/src/crepe/api/BehaviorScript.h
index 02d588a..3909b96 100644
--- a/src/crepe/api/BehaviorScript.h
+++ b/src/crepe/api/BehaviorScript.h
@@ -9,7 +9,6 @@
namespace crepe {
class ScriptSystem;
-class Mediator;
class ComponentManager;
class Script;
diff --git a/src/crepe/api/Engine.cpp b/src/crepe/api/Engine.cpp
index 7ae89b9..e8b7fd6 100644
--- a/src/crepe/api/Engine.cpp
+++ b/src/crepe/api/Engine.cpp
@@ -5,12 +5,12 @@
using namespace crepe;
using namespace std;
-void Engine::start() {
+int Engine::main() noexcept {
try {
this->setup();
} catch (const exception & e) {
Log::logf(Log::Level::ERROR, "Uncaught exception in setup: {}\n", e.what());
- return;
+ return EXIT_FAILURE;
}
try {
@@ -19,10 +19,11 @@ void Engine::start() {
Log::logf(Log::Level::ERROR, "Uncaught exception in main loop: {}\n", e.what());
this->event_manager.trigger_event<ShutDownEvent>();
}
+
+ return EXIT_SUCCESS;
}
void Engine::setup() {
- this->game_running = true;
this->loop_timer.start();
this->scene_manager.load_next_scene();
diff --git a/src/crepe/api/Engine.h b/src/crepe/api/Engine.h
index 5421d60..efe7853 100644
--- a/src/crepe/api/Engine.h
+++ b/src/crepe/api/Engine.h
@@ -20,13 +20,16 @@ namespace crepe {
*/
class Engine {
public:
- void start();
-
/**
- * \brief Add a new concrete scene to the scene manager
+ * \brief Engine entrypoint
+ *
+ * This function is called by the game programmer after registering all scenes
*
- * \tparam T Type of concrete scene
+ * \returns process exit code
*/
+ int main() noexcept;
+
+ //! \copydoc SceneManager::add_scene
template <typename T>
void add_scene();
@@ -44,7 +47,8 @@ private:
*/
void loop();
- bool game_running = false;
+ //! Game loop condition
+ bool game_running = true;
private:
//! Global context
diff --git a/src/crepe/api/GameObject.h b/src/crepe/api/GameObject.h
index 6203f81..0dabed1 100644
--- a/src/crepe/api/GameObject.h
+++ b/src/crepe/api/GameObject.h
@@ -39,8 +39,9 @@ private:
public:
//! The id of the GameObject
const game_object_id_t id;
-
+ //! This entity's transform
Transform & transform;
+ //! This entity's metadata
Metadata & metadata;
public:
diff --git a/src/crepe/api/ParticleEmitter.cpp b/src/crepe/api/ParticleEmitter.cpp
index 90b77a0..fd69e26 100644
--- a/src/crepe/api/ParticleEmitter.cpp
+++ b/src/crepe/api/ParticleEmitter.cpp
@@ -1,6 +1,7 @@
#include "ParticleEmitter.h"
using namespace crepe;
+using namespace std;
ParticleEmitter::ParticleEmitter(game_object_id_t game_object_id, const Data & data)
: Component(game_object_id),
@@ -9,3 +10,17 @@ ParticleEmitter::ParticleEmitter(game_object_id_t game_object_id, const Data & d
this->data.particles.emplace_back();
}
}
+
+unique_ptr<Component> ParticleEmitter::save() const {
+ return unique_ptr<Component>{new ParticleEmitter(*this)};
+}
+
+void ParticleEmitter::restore(const Component & snapshot) {
+ *this = static_cast<const ParticleEmitter &>(snapshot);
+}
+
+ParticleEmitter & ParticleEmitter::operator=(const ParticleEmitter & other) {
+ data.particles = other.data.particles;
+ return *this;
+}
+
diff --git a/src/crepe/api/ParticleEmitter.h b/src/crepe/api/ParticleEmitter.h
index b83fd61..5f563de 100644
--- a/src/crepe/api/ParticleEmitter.h
+++ b/src/crepe/api/ParticleEmitter.h
@@ -80,6 +80,12 @@ public:
public:
//! Configuration data for particle emission settings.
Data data;
+
+protected:
+ virtual std::unique_ptr<Component> save() const;
+ ParticleEmitter(const ParticleEmitter &) = default;
+ virtual void restore(const Component & snapshot);
+ virtual ParticleEmitter & operator=(const ParticleEmitter &);
};
} // namespace crepe
diff --git a/src/crepe/api/Script.hpp b/src/crepe/api/Script.hpp
index 2553fd1..b42a6df 100644
--- a/src/crepe/api/Script.hpp
+++ b/src/crepe/api/Script.hpp
@@ -40,10 +40,17 @@ void Script::subscribe_internal(const EventHandler<EventType> & callback,
EventManager & mgr = this->mediator->event_manager;
subscription_t listener = mgr.subscribe<EventType>(
[this, callback](const EventType & data) -> bool {
+ // check if (parent) BehaviorScript component is active
bool & active = this->active;
if (!active) return false;
- ReplayManager & replay = this->mediator->replay_manager;
- if (replay.get_state() == ReplayManager::PLAYING) return false;
+
+ // check if replay manager is playing (if initialized)
+ try {
+ ReplayManager & replay = this->mediator->replay_manager;
+ if (replay.get_state() == ReplayManager::PLAYING) return false;
+ } catch (const std::runtime_error &) {}
+
+ // call user-provided callback
return callback(data);
},
channel);
diff --git a/src/crepe/api/Transform.h b/src/crepe/api/Transform.h
index bbd23e0..a6f3486 100644
--- a/src/crepe/api/Transform.h
+++ b/src/crepe/api/Transform.h
@@ -41,7 +41,6 @@ protected:
Transform(const Transform &) = default;
virtual void restore(const Component & snapshot);
virtual Transform & operator=(const Transform &) = default;
-
};
} // namespace crepe
diff --git a/src/crepe/manager/ComponentManager.h b/src/crepe/manager/ComponentManager.h
index 457a196..c3a5b4a 100644
--- a/src/crepe/manager/ComponentManager.h
+++ b/src/crepe/manager/ComponentManager.h
@@ -142,19 +142,39 @@ public:
template <typename T>
RefVector<T> get_components_by_tag(const std::string & tag) const;
+ //! Snapshot of single component (including path in \c components)
struct SnapshotComponent {
+ //! \c components path
std::type_index type;
+ //! \c components path
game_object_id_t id;
+ //! \c components path
size_t index;
+ //! Actual component snapshot
std::unique_ptr<Component> component;
};
+ //! Snapshot of the entire component manager state
struct Snapshot {
+ //! All components
+ std::vector<SnapshotComponent> components;
// TODO: some kind of hash code that ensures components exist in all the same places as
// this snapshot
- std::vector<SnapshotComponent> components;
};
+ /**
+ * \name ReplayManager (Memento) functions
+ * \{
+ */
+ /**
+ * \brief Save a snapshot of the component manager state
+ * \returns Deep copy of the component manager's internal state
+ */
Snapshot save();
- void restore(const Snapshot &);
+ /**
+ * \brief Restore component manager from a snapshot
+ * \param snapshot Snapshot to restore from (as returned by \c save())
+ */
+ void restore(const Snapshot & snapshot);
+ //! \}
private:
/**
diff --git a/src/crepe/manager/ReplayManager.cpp b/src/crepe/manager/ReplayManager.cpp
index ab8a5a0..db6acb0 100644
--- a/src/crepe/manager/ReplayManager.cpp
+++ b/src/crepe/manager/ReplayManager.cpp
@@ -38,6 +38,9 @@ void ReplayManager::release(recording_t handle) {
}
void ReplayManager::frame_record() {
+ if (this->state != RECORDING)
+ throw runtime_error("ReplayManager: frame_step called while not playing");
+
ComponentManager & components = this->mediator.component_manager;
Recording & recording = this->recording;
@@ -46,6 +49,9 @@ void ReplayManager::frame_record() {
}
bool ReplayManager::frame_step() {
+ if (this->state != PLAYING)
+ throw runtime_error("ReplayManager: frame_step called while not playing");
+
ComponentManager & components = this->mediator.component_manager;
Recording & recording = this->recording;
@@ -58,6 +64,7 @@ bool ReplayManager::frame_step() {
// end of recording
recording.frame = 0;
this->state = IDLE;
+ this->recording.clear();
return true;
}
diff --git a/src/crepe/manager/ReplayManager.h b/src/crepe/manager/ReplayManager.h
index 7be18f3..d3af879 100644
--- a/src/crepe/manager/ReplayManager.h
+++ b/src/crepe/manager/ReplayManager.h
@@ -8,13 +8,14 @@
namespace crepe {
-class ReplaySystem;
-
typedef size_t recording_t;
/**
* \brief Replay manager
*
+ * The replay manager is responsible for creating, storing and restoring ComponentManager
+ * snapshots. Sequential snapshots can be recorded and replayed in combination with
+ * ReplaySystem.
*/
class ReplayManager : public Manager {
// TODO: Delete recordings at end of scene
@@ -22,31 +23,70 @@ public:
ReplayManager(Mediator & mediator);
public:
+ //! Start a new recording
void record_start();
+ /**
+ * \brief End the latest recording started by \c record_start()
+ * \returns Handle to recording
+ */
recording_t record_end();
+ /**
+ * \brief Play a recording
+ * \param handle Handle to recording (as returned by \c record_end())
+ */
void play(recording_t handle);
+ /**
+ * \brief Delete a recording from memory
+ * \param handle Handle to recording (as returned by \c record_end())
+ */
void release(recording_t handle);
public:
+ //! Internal state
enum State {
- IDLE,
- RECORDING,
- PLAYING,
+ IDLE, //!< Not doing anything
+ RECORDING, //!< Currently recording
+ PLAYING, //!< Currently playing back a recording
};
+ //! Get current internal state
State get_state() const;
public:
+ /**
+ * \brief Record a single frame to the current recording
+ *
+ * This function is called by ReplaySystem after the game programmer has called \c
+ * record_start()
+ */
void frame_record();
+ /**
+ * \brief Play the next frame of the current recording
+ *
+ * \returns `true` if the recording is finished playing
+ * \returns `false` if there are more frames
+ *
+ * This function also automatically resets the internal state from PLAYING to IDLE at the end
+ * of a recording.
+ */
bool frame_step();
private:
+ /**
+ * \brief Recording data
+ */
struct Recording {
+ //! Current frame being shown
size_t frame = 0;
+ //! All frames in recording
std::vector<ComponentManager::Snapshot> frames;
};
+ //! Internal state
State state = IDLE;
- OptionalRef<Recording> recording;
+ //! Current recording handle
recording_t id = -1;
+ //! Current recording data
+ OptionalRef<Recording> recording;
+ //! Recording storage
std::unordered_map<recording_t, std::unique_ptr<Recording>> memory;
};
diff --git a/src/crepe/manager/SystemManager.h b/src/crepe/manager/SystemManager.h
index 6cf7f2b..a47961b 100644
--- a/src/crepe/manager/SystemManager.h
+++ b/src/crepe/manager/SystemManager.h
@@ -1,11 +1,21 @@
#pragma once
+#include <typeindex>
+#include <unordered_map>
+#include <memory>
+
#include "../system/System.h"
#include "Manager.h"
namespace crepe {
+/**
+ * \brief Collection of all systems
+ *
+ * This manager aggregates all systems and provides utility functions to retrieve references to
+ * and update systems.
+ */
class SystemManager : public Manager {
public:
SystemManager(Mediator &);
@@ -50,9 +60,23 @@ public:
T & get_system();
public:
+ /**
+ * \brief SystemManager snapshot
+ *
+ * The SystemManager snapshot only stores which systems are active
+ */
typedef std::unordered_map<std::type_index, bool> Snapshot;
+ /**
+ * \brief Save a snapshot of the systems' state
+ * \returns Copy of each system's active property
+ */
Snapshot save();
+ /**
+ * \brief Restore system active state from a snapshot
+ * \param snapshot Snapshot to restore from (as returned by \c save())
+ */
void restore(const Snapshot & snapshot);
+ //! Disable all systems
void disable_all();
};
diff --git a/src/crepe/system/CMakeLists.txt b/src/crepe/system/CMakeLists.txt
index 3473876..52369d0 100644
--- a/src/crepe/system/CMakeLists.txt
+++ b/src/crepe/system/CMakeLists.txt
@@ -23,5 +23,6 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES
AnimatorSystem.h
InputSystem.h
EventSystem.h
+ ReplaySystem.h
AISystem.h
)
diff --git a/src/crepe/system/EventSystem.h b/src/crepe/system/EventSystem.h
index a179d00..ff3ca4e 100644
--- a/src/crepe/system/EventSystem.h
+++ b/src/crepe/system/EventSystem.h
@@ -4,10 +4,17 @@
namespace crepe {
+/**
+ * \brief EventManager dispatch helper system
+ */
class EventSystem : public System {
public:
using System::System;
+ /**
+ * \brief Dispatch queued events
+ * \see EventManager::dispatch_events
+ */
void fixed_update() override;
};
diff --git a/src/crepe/system/ReplaySystem.h b/src/crepe/system/ReplaySystem.h
index 919c554..8ba60d5 100644
--- a/src/crepe/system/ReplaySystem.h
+++ b/src/crepe/system/ReplaySystem.h
@@ -7,6 +7,11 @@
namespace crepe {
+/**
+ * \brief ReplayManager helper system
+ *
+ * This system records and replays recordings using ReplayManager.
+ */
class ReplaySystem : public System {
public:
using System::System;
@@ -14,15 +19,25 @@ public:
void fixed_update() override;
private:
+ //! Last ReplayManager state
ReplayManager::State last_state = ReplayManager::IDLE;
+ /**
+ * \brief Playback snapshot
+ *
+ * When starting playback, the component state is saved and most systems are disabled. This
+ * struct stores the engine state before ReplayManager::play is called.
+ */
struct Snapshot {
ComponentManager::Snapshot components;
SystemManager::Snapshot systems;
};
+ //! Before playback snapshot
Snapshot playback;
+ //! Snapshot state and disable systems during playback
void playback_begin();
+ //! Restore state from before \c playback_begin()
void playback_end();
};
diff --git a/src/example/replay.cpp b/src/example/replay.cpp
index 7faf6cb..130c0d3 100644
--- a/src/example/replay.cpp
+++ b/src/example/replay.cpp
@@ -83,7 +83,5 @@ int main(int argc, char * argv[]) {
Engine engine;
engine.add_scene<TestScene>();
- engine.start();
-
- return 0;
+ return engine.main();
}