Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,14 @@ add_library(ecs_engine STATIC
src/engine/FrameClock.h
src/engine/WorldQuery.h
src/engine/CommandBuffer.h
src/engine/UpdatePhase.h
src/engine/TriggerPolicy.h
src/engine/SystemDescriptor.h
src/engine/SystemScheduler.h
src/engine/EntityRegistry.cpp
src/engine/EngineRuntime.cpp
src/engine/FrameClock.cpp
src/engine/SystemScheduler.cpp
)

target_include_directories(ecs_engine
Expand Down Expand Up @@ -112,6 +117,7 @@ if (BUILD_TESTING)
tests/FacilityLayoutBuilderTests.cpp
tests/WorldQueryTests.cpp
tests/CommandBufferTests.cpp
tests/SystemSchedulerTests.cpp
)

target_include_directories(safecrowd_tests
Expand Down
48 changes: 36 additions & 12 deletions src/engine/EngineRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,14 @@ EngineConfig normalizeConfig(EngineConfig config) {

EngineRuntime::EngineRuntime(EngineConfig config)
: config_(normalizeConfig(config)),
scheduler_(core_, buffer_),
world_(core_, buffer_),
frameClock_(config_) {
}

void EngineRuntime::addSystem(std::unique_ptr<EngineSystem> system) {
systems_.push_back(std::move(system));
void EngineRuntime::addSystem(std::unique_ptr<EngineSystem> system,
SystemDescriptor descriptor) {
scheduler_.registerSystem(std::move(system), descriptor);
}

void EngineRuntime::initialize() {
Expand All @@ -39,10 +41,16 @@ void EngineRuntime::initialize() {
stats_.state = EngineState::Ready;
++runIndex_;

for (auto& system : systems_) {
system->configure(world_);
buffer_.flush(core_);
}
scheduler_.configure(world_);

const EngineStepContext startupCtx{
.frameIndex = stats_.frameIndex,
.fixedStepIndex = stats_.fixedStepIndex,
.alpha = 0.0,
.runIndex = runIndex_,
.derivedSeed = 0,
};
scheduler_.executeStartup(world_, startupCtx);
}

void EngineRuntime::play() {
Expand Down Expand Up @@ -82,27 +90,43 @@ void EngineRuntime::stepFrame(double deltaSeconds) {
++stats_.frameIndex;
stats_.fixedStepsThisFrame = 0;

EngineStepContext ctx{
.frameIndex = stats_.frameIndex,
.fixedStepIndex = stats_.fixedStepIndex,
.alpha = frameClock_.alpha(),
.runIndex = runIndex_,
.derivedSeed = 0,
};

scheduler_.executePhase(UpdatePhase::PreSimulation, TriggerPolicy::EveryFrame,
world_, ctx);

while (frameClock_.shouldRunFixedStep()) {
frameClock_.consumeFixedStep();
++stats_.fixedStepIndex;
++stats_.fixedStepsThisFrame;

const EngineStepContext ctx{
ctx = EngineStepContext{
.frameIndex = stats_.frameIndex,
.fixedStepIndex = stats_.fixedStepIndex,
.alpha = frameClock_.alpha(),
.runIndex = runIndex_,
.derivedSeed = 0,
};

for (auto& system : systems_) {
system->update(world_, ctx);
}

buffer_.flush(core_);
scheduler_.executePhase(UpdatePhase::FixedSimulation, TriggerPolicy::FixedStep,
world_, ctx);
}

ctx.alpha = frameClock_.alpha();
scheduler_.executePhase(UpdatePhase::PostSimulation, TriggerPolicy::EveryFrame,
world_, ctx);

stats_.alpha = frameClock_.alpha();

ctx.alpha = stats_.alpha;
scheduler_.executePhase(UpdatePhase::RenderSync, TriggerPolicy::EveryFrame,
world_, ctx);
}

EngineWorld& EngineRuntime::world() noexcept {
Expand Down
22 changes: 12 additions & 10 deletions src/engine/EngineRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,24 @@

#include <cstdint>
#include <memory>
#include <vector>

#include "engine/CommandBuffer.h"
#include "engine/EcsCore.h"
#include "engine/EngineConfig.h"
#include "engine/EngineStats.h"
#include "engine/EngineSystem.h"
#include "engine/FrameClock.h"
#include "engine/SystemDescriptor.h"
#include "engine/SystemScheduler.h"

namespace safecrowd::engine {

class EngineRuntime {
public:
explicit EngineRuntime(EngineConfig config = {});

void addSystem(std::unique_ptr<EngineSystem> system);
void addSystem(std::unique_ptr<EngineSystem> system,
SystemDescriptor descriptor = {});

void initialize();
void play();
Expand All @@ -33,14 +35,14 @@ class EngineRuntime {
std::uint64_t runIndex() const noexcept;

private:
EngineConfig config_;
EngineStats stats_;
EcsCore core_;
CommandBuffer buffer_;
EngineWorld world_;
FrameClock frameClock_;
std::uint64_t runIndex_{0};
std::vector<std::unique_ptr<EngineSystem>> systems_;
EngineConfig config_;
EngineStats stats_;
EcsCore core_;
CommandBuffer buffer_;
SystemScheduler scheduler_;
EngineWorld world_;
FrameClock frameClock_;
std::uint64_t runIndex_{0};
};

} // namespace safecrowd::engine
14 changes: 14 additions & 0 deletions src/engine/SystemDescriptor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#pragma once

#include "engine/TriggerPolicy.h"
#include "engine/UpdatePhase.h"

namespace safecrowd::engine {

struct SystemDescriptor {
UpdatePhase phase{UpdatePhase::FixedSimulation};
int order{0};
TriggerPolicy triggerPolicy{TriggerPolicy::FixedStep};
};

} // namespace safecrowd::engine
69 changes: 69 additions & 0 deletions src/engine/SystemScheduler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#include "engine/SystemScheduler.h"

#include <algorithm>
#include <stdexcept>

namespace safecrowd::engine {
namespace {

void validateDescriptor(const SystemDescriptor& descriptor) {
if (descriptor.triggerPolicy == TriggerPolicy::Interval) {
throw std::invalid_argument("TriggerPolicy::Interval is not supported yet.");
}

if (descriptor.phase == UpdatePhase::FixedSimulation &&
descriptor.triggerPolicy != TriggerPolicy::FixedStep) {
throw std::invalid_argument(
"FixedSimulation systems must use TriggerPolicy::FixedStep.");
}

if (descriptor.phase != UpdatePhase::FixedSimulation &&
descriptor.phase != UpdatePhase::Startup &&
descriptor.triggerPolicy != TriggerPolicy::EveryFrame) {
throw std::invalid_argument(
"Frame phases must use TriggerPolicy::EveryFrame.");
}
}

} // namespace

void SystemScheduler::registerSystem(std::unique_ptr<EngineSystem> system,
SystemDescriptor descriptor) {
validateDescriptor(descriptor);
entries_.push_back({std::move(system), descriptor});
std::stable_sort(entries_.begin(), entries_.end(), [](const Entry& a, const Entry& b) {
if (a.descriptor.phase != b.descriptor.phase) {
return static_cast<int>(a.descriptor.phase) < static_cast<int>(b.descriptor.phase);
}
return a.descriptor.order < b.descriptor.order;
});
}

void SystemScheduler::configure(EngineWorld& world) {
for (auto& e : entries_) {
e.system->configure(world);
buffer_.flush(core_);
}
}

void SystemScheduler::executeStartup(EngineWorld& world, const EngineStepContext& ctx) {
for (auto& e : entries_) {
if (e.descriptor.phase == UpdatePhase::Startup) {
e.system->update(world, ctx);
}
}
buffer_.flush(core_);
}

void SystemScheduler::executePhase(UpdatePhase phase, TriggerPolicy triggerPolicy,
EngineWorld& world, const EngineStepContext& ctx) {
for (auto& e : entries_) {
if (e.descriptor.phase == phase &&
e.descriptor.triggerPolicy == triggerPolicy) {
e.system->update(world, ctx);
}
}
buffer_.flush(core_);
}

} // namespace safecrowd::engine
35 changes: 35 additions & 0 deletions src/engine/SystemScheduler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#pragma once

#include <memory>
#include <vector>

#include "engine/EcsCore.h"
#include "engine/EngineSystem.h"
#include "engine/SystemDescriptor.h"
#include "engine/UpdatePhase.h"

namespace safecrowd::engine {

class SystemScheduler {
public:
SystemScheduler(EcsCore& core, CommandBuffer& buffer)
: core_(core), buffer_(buffer) {}

void registerSystem(std::unique_ptr<EngineSystem> system, SystemDescriptor descriptor);
void configure(EngineWorld& world);
void executeStartup(EngineWorld& world, const EngineStepContext& ctx);
void executePhase(UpdatePhase phase, TriggerPolicy triggerPolicy,
EngineWorld& world, const EngineStepContext& ctx);

private:
struct Entry {
std::unique_ptr<EngineSystem> system;
SystemDescriptor descriptor;
};

EcsCore& core_;
CommandBuffer& buffer_;
std::vector<Entry> entries_;
};

} // namespace safecrowd::engine
11 changes: 11 additions & 0 deletions src/engine/TriggerPolicy.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#pragma once

namespace safecrowd::engine {

enum class TriggerPolicy {
EveryFrame,
FixedStep,
Interval,
};

} // namespace safecrowd::engine
13 changes: 13 additions & 0 deletions src/engine/UpdatePhase.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#pragma once

namespace safecrowd::engine {

enum class UpdatePhase {
Startup,
PreSimulation,
FixedSimulation,
PostSimulation,
RenderSync,
};

} // namespace safecrowd::engine
Loading
Loading