aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/crepe/Component.cpp9
-rw-r--r--src/crepe/Component.h13
-rw-r--r--src/crepe/api/GameObject.cpp10
-rw-r--r--src/crepe/api/GameObject.h13
-rw-r--r--src/crepe/api/LoopManager.cpp2
-rw-r--r--src/crepe/api/Transform.cpp10
-rw-r--r--src/crepe/api/Transform.h7
-rw-r--r--src/crepe/manager/ComponentManager.cpp26
-rw-r--r--src/crepe/manager/ComponentManager.h9
-rw-r--r--src/crepe/manager/Mediator.h2
-rw-r--r--src/crepe/manager/ReplayManager.cpp25
-rw-r--r--src/crepe/manager/ReplayManager.h24
-rw-r--r--src/crepe/system/ReplaySystem.cpp70
-rw-r--r--src/crepe/system/ReplaySystem.h11
-rw-r--r--src/test/ECSTest.cpp14
15 files changed, 209 insertions, 36 deletions
diff --git a/src/crepe/Component.cpp b/src/crepe/Component.cpp
index 141e1a8..8086492 100644
--- a/src/crepe/Component.cpp
+++ b/src/crepe/Component.cpp
@@ -1,6 +1,7 @@
#include "Component.h"
using namespace crepe;
+using namespace std;
Component::Component(game_object_id_t id) : game_object_id(id) {}
@@ -8,3 +9,11 @@ Component & Component::operator=(const Component &) {
return *this;
}
+unique_ptr<Component> Component::save() const {
+ return unique_ptr<Component>(new Component(*this));
+}
+
+void Component::restore(const Component & snapshot) {
+ *this = snapshot;
+}
+
diff --git a/src/crepe/Component.h b/src/crepe/Component.h
index 47c5c34..fc0268c 100644
--- a/src/crepe/Component.h
+++ b/src/crepe/Component.h
@@ -1,5 +1,7 @@
#pragma once
+#include <memory>
+
#include "types.h"
namespace crepe {
@@ -32,15 +34,16 @@ protected:
//! Only ComponentManager can create components
friend class ComponentManager;
- // create snapshot
- Component(const Component &) = default;
- // restore snapshot
- virtual Component & operator=(const Component &);
-
// components are never moved
Component(Component &&) = delete;
virtual Component & operator=(Component &&) = delete;
+protected:
+ virtual std::unique_ptr<Component> save() const;
+ Component(const Component &) = default;
+ virtual void restore(const Component & snapshot);
+ virtual Component & operator=(const Component &);
+
public:
virtual ~Component() = default;
diff --git a/src/crepe/api/GameObject.cpp b/src/crepe/api/GameObject.cpp
index ea9c425..68b074e 100644
--- a/src/crepe/api/GameObject.cpp
+++ b/src/crepe/api/GameObject.cpp
@@ -11,13 +11,9 @@ GameObject::GameObject(Mediator & mediator, game_object_id_t id,
const std::string & name, const std::string & tag,
const vec2 & position, double rotation, double scale)
: id(id),
- mediator(mediator) {
-
- // Add Transform and Metadata components
- ComponentManager & mgr = this->mediator.component_manager;
- mgr.add_component<Transform>(this->id, position, rotation, scale);
- mgr.add_component<Metadata>(this->id, name, tag);
-}
+ mediator(mediator),
+ transform(mediator.component_manager->add_component<Transform>(this->id, position, rotation, scale)),
+ metadata(mediator.component_manager->add_component<Metadata>(this->id, name, tag)) { }
void GameObject::set_parent(const GameObject & parent) {
ComponentManager & mgr = this->mediator.component_manager;
diff --git a/src/crepe/api/GameObject.h b/src/crepe/api/GameObject.h
index a311c21..6203f81 100644
--- a/src/crepe/api/GameObject.h
+++ b/src/crepe/api/GameObject.h
@@ -7,6 +7,8 @@
namespace crepe {
class Mediator;
+class Transform;
+class Metadata;
/**
* \brief Represents a GameObject
@@ -35,6 +37,13 @@ private:
friend class ComponentManager;
public:
+ //! The id of the GameObject
+ const game_object_id_t id;
+
+ Transform & transform;
+ Metadata & metadata;
+
+public:
/**
* \brief Set the parent of this GameObject
*
@@ -68,10 +77,6 @@ public:
*/
void set_persistent(bool persistent = true);
-public:
- //! The id of the GameObject
- const game_object_id_t id;
-
protected:
Mediator & mediator;
};
diff --git a/src/crepe/api/LoopManager.cpp b/src/crepe/api/LoopManager.cpp
index 3511bca..2855455 100644
--- a/src/crepe/api/LoopManager.cpp
+++ b/src/crepe/api/LoopManager.cpp
@@ -25,6 +25,8 @@ LoopManager::LoopManager() {
this->load_system<InputSystem>();
this->load_system<EventSystem>();
this->load_system<AudioSystem>();
+
+ this->mediator.loop_manager = *this;
}
void LoopManager::start() {
diff --git a/src/crepe/api/Transform.cpp b/src/crepe/api/Transform.cpp
index a85b792..5fc886b 100644
--- a/src/crepe/api/Transform.cpp
+++ b/src/crepe/api/Transform.cpp
@@ -3,6 +3,7 @@
#include "Transform.h"
using namespace crepe;
+using namespace std;
Transform::Transform(game_object_id_t id, const vec2 & point, double rotation, double scale)
: Component(id),
@@ -11,3 +12,12 @@ Transform::Transform(game_object_id_t id, const vec2 & point, double rotation, d
scale(scale) {
dbg_trace();
}
+
+unique_ptr<Component> Transform::save() const {
+ return unique_ptr<Component>{new Transform(*this)};
+}
+
+void Transform::restore(const Component & snapshot) {
+ *this = static_cast<const Transform &>(snapshot);
+}
+
diff --git a/src/crepe/api/Transform.h b/src/crepe/api/Transform.h
index 7ee6d65..bbd23e0 100644
--- a/src/crepe/api/Transform.h
+++ b/src/crepe/api/Transform.h
@@ -35,6 +35,13 @@ protected:
virtual int get_instances_max() const { return 1; }
//! ComponentManager instantiates all components
friend class ComponentManager;
+
+protected:
+ virtual std::unique_ptr<Component> save() const;
+ 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.cpp b/src/crepe/manager/ComponentManager.cpp
index 24ba0d7..5f5c050 100644
--- a/src/crepe/manager/ComponentManager.cpp
+++ b/src/crepe/manager/ComponentManager.cpp
@@ -72,3 +72,29 @@ set<game_object_id_t> ComponentManager::get_objects_by_tag(const string & tag) c
return this->get_objects_by_predicate<Metadata>(
[tag](const Metadata & data) { return data.tag == tag; });
}
+
+ComponentManager::Snapshot ComponentManager::save() {
+ Snapshot snapshot{};
+ for (const auto & [type, by_id_index] : this->components) {
+ for (game_object_id_t id = 0; id < by_id_index.size(); id++) {
+ const auto & components = by_id_index[id];
+ for (size_t index = 0; index < components.size(); index++) {
+ const Component & component = *components[index];
+ snapshot.components.push_back(SnapshotComponent{
+ .type = type,
+ .id = id,
+ .index = index,
+ .component = component.save(),
+ });
+ }
+ }
+ }
+ return snapshot;
+}
+
+void ComponentManager::restore(const Snapshot & snapshot) {
+ for (const SnapshotComponent & info : snapshot.components) {
+ this->components[info.type][info.id][info.index]->restore(*info.component);
+ }
+}
+
diff --git a/src/crepe/manager/ComponentManager.h b/src/crepe/manager/ComponentManager.h
index dd7c154..457a196 100644
--- a/src/crepe/manager/ComponentManager.h
+++ b/src/crepe/manager/ComponentManager.h
@@ -143,10 +143,15 @@ public:
RefVector<T> get_components_by_tag(const std::string & tag) const;
struct SnapshotComponent {
- Component component;
+ std::type_index type;
+ game_object_id_t id;
+ size_t index;
+ std::unique_ptr<Component> component;
};
struct Snapshot {
-
+ // TODO: some kind of hash code that ensures components exist in all the same places as
+ // this snapshot
+ std::vector<SnapshotComponent> components;
};
Snapshot save();
void restore(const Snapshot &);
diff --git a/src/crepe/manager/Mediator.h b/src/crepe/manager/Mediator.h
index eef4432..f5864e7 100644
--- a/src/crepe/manager/Mediator.h
+++ b/src/crepe/manager/Mediator.h
@@ -14,6 +14,7 @@ class ResourceManager;
class SDLContext;
class LoopTimer;
class ReplayManager;
+class LoopManager;
/**
* Struct to pass references to classes that would otherwise need to be singletons down to
@@ -36,6 +37,7 @@ struct Mediator {
OptionalRef<ResourceManager> resource_manager;
OptionalRef<LoopTimer> timer;
OptionalRef<ReplayManager> replay_manager;
+ OptionalRef<LoopManager> loop_manager;
};
} // namespace crepe
diff --git a/src/crepe/manager/ReplayManager.cpp b/src/crepe/manager/ReplayManager.cpp
index 82c2275..81ff114 100644
--- a/src/crepe/manager/ReplayManager.cpp
+++ b/src/crepe/manager/ReplayManager.cpp
@@ -1,4 +1,4 @@
-#include "../util/Log.h"
+#include <format>
#include "ReplayManager.h"
#include "Manager.h"
@@ -11,26 +11,29 @@ ReplayManager::ReplayManager(Mediator & mediator) : Manager(mediator) {
}
void ReplayManager::record_start() {
- if (this->recording) this->release(this->current_recording);
- this->current_recording++;
- this->recording = true;
+ if (this->state == RECORDING) this->release(this->id);
+ this->id++;
+ this->memory[this->id] = make_unique<Recording>();
+ this->recording = *this->memory.at(this->id);
+ this->state = RECORDING;
}
recording_t ReplayManager::record_end() {
- this->recording = false;
- return this->current_recording;
+ this->state = IDLE;
+ return this->id;
}
void ReplayManager::play(recording_t handle) {
if (!this->memory.contains(handle))
throw out_of_range(format("ReplayManager: no recording for handle {}", handle));
- Recording & recording = *this->memory.at(handle);
-
- dbg_log("TODO: magic");
+ this->recording = *this->memory.at(handle);
+ this->recording->frame = 0;
+ this->state = PLAYING;
}
void ReplayManager::release(recording_t handle) {
- dbg_log("release");
-
+ if (!this->memory.contains(handle))
+ return;
+ this->memory.erase(handle);
}
diff --git a/src/crepe/manager/ReplayManager.h b/src/crepe/manager/ReplayManager.h
index c50196c..672d093 100644
--- a/src/crepe/manager/ReplayManager.h
+++ b/src/crepe/manager/ReplayManager.h
@@ -1,13 +1,14 @@
#pragma once
+#include <unordered_map>
+
#include "Manager.h"
#include "ComponentManager.h"
-#include <unordered_map>
+#include "util/OptionalRef.h"
namespace crepe {
class ReplaySystem;
-class Memento;
typedef size_t recording_t;
@@ -20,11 +21,20 @@ protected:
void record_frame();
private:
- typedef std::vector<ComponentManager::Snapshot> Recording;
-
- bool recording = false;
- recording_t current_recording = -1;
-
+ struct Recording {
+ size_t frame = 0;
+ std::vector<ComponentManager::Snapshot> frames;
+ };
+
+ enum State {
+ IDLE,
+ RECORDING,
+ PLAYING,
+ };
+
+ State state = IDLE;
+ OptionalRef<Recording> recording;
+ recording_t id = -1;
std::unordered_map<recording_t, std::unique_ptr<Recording>> memory;
public:
diff --git a/src/crepe/system/ReplaySystem.cpp b/src/crepe/system/ReplaySystem.cpp
index 3aabb58..85595a2 100644
--- a/src/crepe/system/ReplaySystem.cpp
+++ b/src/crepe/system/ReplaySystem.cpp
@@ -1,7 +1,77 @@
+#include "system/ScriptSystem.h"
+
+#include "../manager/ReplayManager.h"
+
#include "ReplaySystem.h"
+#include "../api/LoopManager.h"
+
using namespace crepe;
+using namespace std;
void ReplaySystem::fixed_update() {
+ ReplayManager & replay = this->mediator.replay_manager;
+
+ switch (replay.state) {
+ case ReplayManager::IDLE: break;
+ case ReplayManager::RECORDING: {
+ this->update_recording();
+ break;
+ }
+ case ReplayManager::PLAYING: {
+ this->update_playing();
+ break;
+ }
+ }
+
+ this->last_state = replay.state;
+}
+
+void ReplaySystem::update_recording() {
+ ReplayManager & replay = this->mediator.replay_manager;
+ ComponentManager & components = this->mediator.component_manager;
+
+ ReplayManager::Recording & recording = replay.recording;
+ recording.frames.push_back(components.save());
+ recording.frame++;
+}
+
+void ReplaySystem::update_playing() {
+ ReplayManager & replay = this->mediator.replay_manager;
+
+ if (this->last_state != ReplayManager::PLAYING) {
+ this->playback_begin();
+ }
+
+ ReplayManager::Recording & recording = replay.recording;
+
+ if (recording.frames.size() == recording.frame) {
+ this->playback_end();
+ return;
+ }
+
+ ComponentManager & components = this->mediator.component_manager;
+ ComponentManager::Snapshot & frame = recording.frames.at(recording.frame);
+
+ components.restore(frame);
+ recording.frame++;
+}
+
+void ReplaySystem::playback_begin() {
+ LoopManager & loop_manager = this->mediator.loop_manager;
+ // TODO: store system active state
+ // TODO: disable most systems
+ // TODO: store components snapshot
+}
+
+void ReplaySystem::playback_end() {
+ ReplayManager & replay = this->mediator.replay_manager;
+
+ replay.state = ReplayManager::IDLE;
+
+ LoopManager & loop_manager = this->mediator.loop_manager;
+
+ // TODO: restore system active state snapshot
+ // TODO: restore components snapshot
}
diff --git a/src/crepe/system/ReplaySystem.h b/src/crepe/system/ReplaySystem.h
index 15ef3fc..fb40176 100644
--- a/src/crepe/system/ReplaySystem.h
+++ b/src/crepe/system/ReplaySystem.h
@@ -1,5 +1,7 @@
#pragma once
+#include "../manager/ReplayManager.h"
+
#include "System.h"
namespace crepe {
@@ -9,6 +11,15 @@ public:
using System::System;
void fixed_update() override;
+
+private:
+ ReplayManager::State last_state = ReplayManager::IDLE;
+ void update_recording();
+ void update_playing();
+
+ std::unordered_map<std::type_index, bool> system_active_snapshot;
+ void playback_begin();
+ void playback_end();
};
}
diff --git a/src/test/ECSTest.cpp b/src/test/ECSTest.cpp
index af2b7b0..8f86a91 100644
--- a/src/test/ECSTest.cpp
+++ b/src/test/ECSTest.cpp
@@ -466,3 +466,17 @@ TEST_F(ECSTest, ComponentsByTag) {
EXPECT_EQ(objects.size(), 3);
}
}
+
+TEST_F(ECSTest, Snapshot) {
+ GameObject foo = mgr.new_object("foo");
+
+ foo.transform.position = {1, 1};
+
+ ComponentManager::Snapshot snapshot = mgr.save();
+
+ foo.transform.position = {0, 0};
+
+ mgr.restore(snapshot);
+
+ EXPECT_EQ(foo.transform.position, (vec2{1, 1}));
+}