Olympe Engine 2.0
2D Game Engine with ECS Architecture
Loading...
Searching...
No Matches
ConditionPresetRegistry.cpp
Go to the documentation of this file.
1/**
2 * @file ConditionPresetRegistry.cpp
3 * @brief Implementation of ConditionPresetRegistry (Phase 24.0).
4 * @author Olympe Engine
5 * @date 2026-03-17
6 *
7 * C++14 compliant — no std::optional, structured bindings, std::filesystem.
8 */
9
11
12#include <algorithm>
13#include <cctype>
14#include <cstdlib>
15#include <ctime>
16#include <fstream>
17#include <iostream>
18#include <sstream>
19#include <iomanip>
20
21namespace Olympe {
22
23// ============================================================================
24// CRUD
25// ============================================================================
26
28{
29 // If the ID is already in the registry, return it unchanged (no-op)
30 if (!preset.id.empty() && m_presets.count(preset.id) != 0)
31 return preset.id;
32
34
35 if (toStore.id.empty())
37
39 m_order.push_back(toStore.id);
40 return toStore.id;
41}
42
44{
45 auto it = m_presets.find(id);
46 if (it == m_presets.end())
47 return nullptr;
48 return &it->second;
49}
50
51const ConditionPreset*
52ConditionPresetRegistry::GetPreset(const std::string& id) const
53{
54 auto it = m_presets.find(id);
55 if (it == m_presets.end())
56 return nullptr;
57 return &it->second;
58}
59
60void ConditionPresetRegistry::UpdatePreset(const std::string& id,
62{
63 auto it = m_presets.find(id);
64 if (it == m_presets.end())
65 {
66 m_errors.push_back("UpdatePreset: ID not found: " + id);
67 return;
68 }
70 copy.id = id; // force ID to match
71 it->second = copy;
72}
73
74void ConditionPresetRegistry::DeletePreset(const std::string& id)
75{
76 auto it = m_presets.find(id);
77 if (it == m_presets.end())
78 return;
79
80 m_presets.erase(it);
81 m_order.erase(std::remove(m_order.begin(), m_order.end(), id), m_order.end());
82}
83
84std::string ConditionPresetRegistry::DuplicatePreset(const std::string& id)
85{
86 const ConditionPreset* src = GetPreset(id);
87 if (!src)
88 return "";
89
91 copy.id = ""; // will be re-assigned
92 // Keep the same name without " (Copy)" suffix for clean nomenclature
93 copy.name = src->name;
94 return CreatePreset(copy);
95}
96
97// ============================================================================
98// Query
99// ============================================================================
100
101std::vector<std::string> ConditionPresetRegistry::GetAllPresetIDs() const
102{
103 return m_order;
104}
105
107{
108 return m_presets.size();
109}
110
111std::vector<std::string>
113{
114 std::vector<std::string> result;
115 for (const auto& id : m_order)
116 {
117 auto it = m_presets.find(id);
118 if (it == m_presets.end())
119 continue;
120
121 const std::string& name = it->second.name;
122 if (name.find(substring) != std::string::npos)
123 result.push_back(id);
124 }
125 return result;
126}
127
128std::vector<ConditionPreset>
130{
131 std::vector<ConditionPreset> result;
132
133 for (const auto& id : m_order)
134 {
135 auto it = m_presets.find(id);
136 if (it == m_presets.end())
137 continue;
138
139 const ConditionPreset& preset = it->second;
140
141 // If filter is empty, include all presets
142 // Otherwise, check if the preset name contains the filter substring
143 if (filter.empty() || preset.name.find(filter) != std::string::npos)
144 {
145 result.push_back(preset);
146 }
147 }
148
149 return result;
150}
151
152// ============================================================================
153// Validation
154// ============================================================================
155
156bool ConditionPresetRegistry::ValidatePresetID(const std::string& id) const
157{
158 return m_presets.count(id) != 0;
159}
160
161std::vector<std::string> ConditionPresetRegistry::GetAllErrors() const
162{
163 return m_errors;
164}
165
167{
168 m_presets.clear();
169 m_order.clear();
170 m_errors.clear();
171}
172
173// ============================================================================
174// Persistence
175// ============================================================================
176
177bool ConditionPresetRegistry::Load(const std::string& filepath)
178{
179 m_errors.clear();
180
181 std::ifstream file(filepath);
182 if (!file.is_open())
183 {
184 m_errors.push_back("Load: cannot open file: " + filepath);
185 return false;
186 }
187
188 // Read file content
189 std::string content((std::istreambuf_iterator<char>(file)),
190 std::istreambuf_iterator<char>());
191 file.close();
192
194 try
195 {
196 root = nlohmann::json::parse(content);
197 }
198 catch (...)
199 {
200 m_errors.push_back("Load: JSON parse error in file: " + filepath);
201 return false;
202 }
203
204 Clear();
205
206 if (!root.is_object() || !root.contains("presets"))
207 {
208 m_errors.push_back("Load: missing 'presets' key in: " + filepath);
209 return false;
210 }
211
212 const auto& presetsArr = root["presets"];
213 if (!presetsArr.is_array())
214 {
215 m_errors.push_back("Load: 'presets' is not an array in: " + filepath);
216 return false;
217 }
218
219 for (const auto& item : presetsArr)
220 {
222 if (!p.id.empty())
223 {
224 m_presets[p.id] = p;
225 m_order.push_back(p.id);
226 }
227 }
228
229 return true;
230}
231
232bool ConditionPresetRegistry::Save(const std::string& filepath) const
233{
234 m_errors.clear();
235
236 nlohmann::json root = nlohmann::json::object();
237 root["version"] = 1;
238
239 nlohmann::json arr = nlohmann::json::array();
240 for (const auto& id : m_order)
241 {
242 auto it = m_presets.find(id);
243 if (it != m_presets.end())
244 arr.push_back(it->second.ToJson());
245 }
246 root["presets"] = arr;
247
248 std::ofstream file(filepath);
249 if (!file.is_open())
250 {
251 m_errors.push_back("Save: cannot open file for writing: " + filepath);
252 return false;
253 }
254
255 file << root.dump(4);
256 return file.good();
257}
258
259// ============================================================================
260// Phase 24 — Load from preset list (graph-embedded presets)
261// ============================================================================
262
263void ConditionPresetRegistry::LoadFromPresetList(const std::vector<ConditionPreset>& presets)
264{
265 // Clear existing data
266 Clear();
267
268 // Add each preset to the registry
269 for (size_t i = 0; i < presets.size(); ++i)
270 {
272 if (!preset.id.empty())
273 {
274 m_presets[preset.id] = preset;
275 m_order.push_back(preset.id);
276 }
277 }
278}
279
280// ============================================================================
281// UUID generation
282// ============================================================================
283
284/*static*/
286{
287 static bool seeded = false;
288 if (!seeded)
289 {
290 std::srand(static_cast<unsigned int>(std::time(nullptr)));
291 seeded = true;
292 }
293
294 unsigned int b[16];
295 for (int i = 0; i < 16; ++i)
296 b[i] = static_cast<unsigned int>(std::rand()) & 0xFF;
297
298 b[6] = (b[6] & 0x0F) | 0x40; // version 4
299 b[8] = (b[8] & 0x3F) | 0x80; // variant
300
301 std::ostringstream oss;
302 oss << std::hex << std::setfill('0');
303 for (int i = 0; i < 16; ++i)
304 {
305 if (i == 4 || i == 6 || i == 8 || i == 10)
306 oss << '-';
307 oss << std::setw(2) << b[i];
308 }
309
310 return "preset_" + oss.str();
311}
312
313} // namespace Olympe
Global registry for ConditionPreset objects, with CRUD, persistence, and validation.
ComponentTypeID GetComponentTypeID_Static()
Definition ECS_Entity.h:56
void LoadFromPresetList(const std::vector< ConditionPreset > &presets)
Loads presets from a vector of ConditionPreset objects (clears existing data first).
size_t GetPresetCount() const
Returns the total number of presets in the registry.
void DeletePreset(const std::string &id)
Removes a preset from the registry.
static std::string GenerateID()
Generates a new UUID suitable for a preset ID.
std::map< std::string, ConditionPreset > m_presets
UUID -> ConditionPreset.
std::vector< std::string > m_order
UUIDs in insertion order.
void UpdatePreset(const std::string &id, const ConditionPreset &updated)
Replaces the data of an existing preset (id must already exist).
void Clear()
Clears all presets and resets error state.
std::vector< std::string > GetAllPresetIDs() const
Returns all preset UUIDs in display order.
bool ValidatePresetID(const std::string &id) const
Returns true when a preset with the given UUID exists.
std::vector< std::string > m_errors
Accumulated error messages.
std::string CreatePreset(const ConditionPreset &preset)
Adds a preset to the registry.
std::string DuplicatePreset(const std::string &id)
Creates an independent copy of an existing preset with a new UUID.
bool Save(const std::string &filepath) const
Saves all presets to a JSON file.
std::vector< ConditionPreset > GetFilteredPresets(const std::string &filter) const
Returns all presets whose name contains the filter substring.
std::vector< std::string > GetAllErrors() const
Returns all error messages accumulated since the last Clear().
bool Load(const std::string &filepath)
Loads presets from a JSON file (clears existing data first).
std::vector< std::string > FindPresetsByName(const std::string &substring) const
Returns UUIDs of all presets whose name contains a substring.
ConditionPreset * GetPreset(const std::string &id)
Returns a mutable pointer to the preset, or nullptr if not found.
< Provides AssetID and INVALID_ASSET_ID
nlohmann::json json
A globally-stored, reusable condition expression.
static ConditionPreset FromJson(const nlohmann::json &data)
Deserializes a ConditionPreset from a JSON object.
std::string id
Global unique UUID (e.g. "preset_001")