Repository navigation
Expand file tree
/
Copy pathFeatureRunner.h
More file actions
95 lines (85 loc) · 2.88 KB
/
Copy pathFeatureRunner.h
File metadata and controls
95 lines (85 loc) · 2.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#pragma once
/// @file
/// The feature registry container and the per-feature tick/lifecycle loop
/// (RunFeature) plus the per-frame render pass (Execute). Depends only on
/// Feature.h so it stays unit-testable; Features.h layers concrete features on top.
#include <vector>
#include <memory>
#include <algorithm>
#include "Feature.h"
// The feature registry and per-frame execution loop, kept in a header that only
// depends on Feature.h (no game-specific feature includes) so it can be unit
// tested in isolation. Features.h includes this and adds the concrete feature
// registration on top.
/// Feature registry plus execution loop. Owns every registered Feature and
/// drives them from the render hook and the event bus.
namespace Features
{
/// The registry: owns every registered feature for the lifetime of the DLL.
inline std::vector<std::unique_ptr<Feature>> Features;
// Drives a single feature once: init on first use, refresh Enabled, skip if
// idle-disabled, then Run() while enabled (once, if OneTime) or Destroy()
// exactly once on the enabled -> disabled edge. Used both by the per-frame
// render loop and by the event bus (for event-driven features). The triggering
// @p event and @p payload are forwarded to Run() (defaulting to the Render loop's
// empty payload). Features whose Check() still returns Enabled keep their previous
// behavior (they just skip on disable and never reach Destroy).
inline void RunFeature(Feature& feature, Events::Type event = Events::Type::Render, const Events::Payload& payload = {})
{
try
{
if (!feature.Initialized)
{
feature.Init();
};
// Enabled is refreshed reactively on Events::Type::SettingsChanged
// (see Features::Init), not polled here every frame.
// Idle disabled features have nothing to run and nothing applied to
// revert, so skip their per-frame validity work entirely.
if (!feature.Enabled && !feature.applied)
{
return;
};
if (!feature.Check())
{
return;
};
if (feature.Enabled)
{
if ((!feature.OneTime || !feature.hasRun) && feature.ThrottleReady())
{
feature.Run(event, payload);
feature.hasRun = true;
}
feature.applied = true;
}
else
{
if (feature.applied)
{
feature.Destroy();
feature.applied = false;
}
feature.hasRun = false;
}
}
catch (char* e)
{
Logger::Log("ERROR", "Failed to execute feature: " + std::string(e));
}
}
// Runs every render-driven feature. Called once per rendered frame from
// PostRender. Features without a Render trigger are skipped here and run from
// the event bus instead (a feature may have both).
inline void Execute()
{
for (const auto& feature : Features)
{
const auto& triggers = feature->Triggers;
if (std::find(triggers.begin(), triggers.end(), Events::Type::Render) != triggers.end())
{
RunFeature(*feature);
}
}
}
}; // namespace Features