PixelBullet  0.0.1
A C++ game engine
Loading...
Searching...
No Matches
behavior_state_machine_ops.h
1#pragma once
2
3#include "pixelbullet/scene/behavior_state_machine_types.h"
4
5#include <algorithm>
6#include <optional>
7#include <string>
8#include <string_view>
9#include <utility>
10#include <vector>
11
12namespace pixelbullet
13{
14inline void NormalizeBehaviorBindingSlots(std::vector<std::string>& binding_slots)
15{
16 std::vector<std::string> normalized;
17 normalized.reserve(binding_slots.size());
18 for (std::string& slot_name : binding_slots)
19 {
20 if (slot_name.empty())
21 {
22 continue;
23 }
24
25 if (std::find(normalized.begin(), normalized.end(), slot_name) == normalized.end())
26 {
27 normalized.push_back(std::move(slot_name));
28 }
29 }
30
31 binding_slots = std::move(normalized);
32}
33
34inline void NormalizeBehaviorStringParameters(std::vector<BehaviorStringParameterDeclaration>& parameters)
35{
36 std::vector<BehaviorStringParameterDeclaration> normalized;
37 normalized.reserve(parameters.size());
38 for (BehaviorStringParameterDeclaration& parameter : parameters)
39 {
40 if (parameter.name.empty())
41 {
42 continue;
43 }
44
45 const auto existing = std::find_if(normalized.begin(), normalized.end(),
46 [&](const BehaviorStringParameterDeclaration& candidate)
47 { return candidate.name == parameter.name; });
48 if (existing == normalized.end())
49 {
50 normalized.push_back(std::move(parameter));
51 }
52 else
53 {
54 *existing = std::move(parameter);
55 }
56 }
57
58 parameters = std::move(normalized);
59}
60
61inline void NormalizeBehaviorStringParameterOverrides(std::vector<BehaviorStringParameterValue>& overrides)
62{
63 std::vector<BehaviorStringParameterValue> normalized;
64 normalized.reserve(overrides.size());
65 for (BehaviorStringParameterValue& override_value : overrides)
66 {
67 if (override_value.name.empty())
68 {
69 continue;
70 }
71
72 const auto existing = std::find_if(normalized.begin(), normalized.end(),
73 [&](const BehaviorStringParameterValue& candidate)
74 { return candidate.name == override_value.name; });
75 if (existing == normalized.end())
76 {
77 normalized.push_back(std::move(override_value));
78 }
79 else
80 {
81 *existing = std::move(override_value);
82 }
83 }
84
85 overrides = std::move(normalized);
86}
87
88inline void NormalizeBehaviorBindings(std::vector<BehaviorBinding>& bindings)
89{
90 std::vector<BehaviorBinding> normalized;
91 normalized.reserve(bindings.size());
92 for (BehaviorBinding& binding : bindings)
93 {
94 if (binding.slot_name.empty())
95 {
96 continue;
97 }
98
99 const auto existing = std::find_if(normalized.begin(), normalized.end(),
100 [&](const BehaviorBinding& candidate) { return candidate.slot_name == binding.slot_name; });
101 if (existing == normalized.end())
102 {
103 normalized.push_back(std::move(binding));
104 }
105 else
106 {
107 *existing = std::move(binding);
108 }
109 }
110
111 bindings = std::move(normalized);
112}
113
114inline void NormalizeBehaviorEditorGraphLayout(BehaviorEditorGraphLayout& layout)
115{
116 std::vector<BehaviorEditorGraphNodeLayout> normalized;
117 normalized.reserve(layout.nodes.size());
118 for (BehaviorEditorGraphNodeLayout& node : layout.nodes)
119 {
120 if (node.state_name.empty())
121 {
122 continue;
123 }
124
125 const auto existing = std::find_if(normalized.begin(), normalized.end(), [&](const BehaviorEditorGraphNodeLayout& candidate)
126 { return candidate.state_name == node.state_name; });
127 if (existing == normalized.end())
128 {
129 normalized.push_back(std::move(node));
130 }
131 else
132 {
133 *existing = std::move(node);
134 }
135 }
136
137 layout.nodes = std::move(normalized);
138}
139
140inline void NormalizeBehaviorStateMachineAsset(BehaviorStateMachineAsset& asset)
141{
142 NormalizeBehaviorStringParameters(asset.string_parameters);
143 NormalizeBehaviorBindingSlots(asset.binding_slots);
144 if (asset.editor_graph)
145 {
146 NormalizeBehaviorEditorGraphLayout(*asset.editor_graph);
147 if (asset.editor_graph->Empty())
148 {
149 asset.editor_graph.reset();
150 }
151 }
152 if (asset.initial_state.empty() && !asset.states.empty())
153 {
154 asset.initial_state = asset.states.front().name;
155 }
156}
157
158[[nodiscard]] inline const BehaviorStringParameterDeclaration*
159FindBehaviorStringParameterDeclaration(const BehaviorStateMachineAsset& asset, const std::string_view parameter_name)
160{
161 const auto it = std::find_if(asset.string_parameters.begin(), asset.string_parameters.end(),
162 [&](const BehaviorStringParameterDeclaration& parameter) { return parameter.name == parameter_name; });
163 return it == asset.string_parameters.end() ? nullptr : &(*it);
164}
165
166[[nodiscard]] inline BehaviorStringParameterDeclaration* FindBehaviorStringParameterDeclaration(BehaviorStateMachineAsset& asset,
167 const std::string_view parameter_name)
168{
169 const auto it = std::find_if(asset.string_parameters.begin(), asset.string_parameters.end(),
170 [&](const BehaviorStringParameterDeclaration& parameter) { return parameter.name == parameter_name; });
171 return it == asset.string_parameters.end() ? nullptr : &(*it);
172}
173
174[[nodiscard]] inline const BehaviorVariableDeclaration*
175FindBehaviorVariableDeclaration(const BehaviorStateMachineAsset& asset, const std::string_view variable_name)
176{
177 const auto it = std::find_if(asset.variables.begin(), asset.variables.end(),
178 [&](const BehaviorVariableDeclaration& variable) { return variable.name == variable_name; });
179 return it == asset.variables.end() ? nullptr : &(*it);
180}
181
182[[nodiscard]] inline BehaviorVariableDeclaration* FindBehaviorVariableDeclaration(BehaviorStateMachineAsset& asset,
183 const std::string_view variable_name)
184{
185 const auto it = std::find_if(asset.variables.begin(), asset.variables.end(),
186 [&](const BehaviorVariableDeclaration& variable) { return variable.name == variable_name; });
187 return it == asset.variables.end() ? nullptr : &(*it);
188}
189
190[[nodiscard]] inline std::optional<std::size_t> FindBehaviorStateIndex(const BehaviorStateMachineAsset& asset,
191 const std::string_view state_name)
192{
193 for (std::size_t index = 0; index < asset.states.size(); ++index)
194 {
195 if (asset.states[index].name == state_name)
196 {
197 return index;
198 }
199 }
200
201 return std::nullopt;
202}
203
204[[nodiscard]] inline const BehaviorState* FindBehaviorState(const BehaviorStateMachineAsset& asset, const std::string_view state_name)
205{
206 const auto index = FindBehaviorStateIndex(asset, state_name);
207 return index ? &asset.states[*index] : nullptr;
208}
209
210[[nodiscard]] inline BehaviorState* FindBehaviorState(BehaviorStateMachineAsset& asset, const std::string_view state_name)
211{
212 const auto index = FindBehaviorStateIndex(asset, state_name);
213 return index ? &asset.states[*index] : nullptr;
214}
215
216[[nodiscard]] inline const BehaviorEditorGraphNodeLayout* FindBehaviorEditorGraphNodeLayout(const BehaviorStateMachineAsset& asset,
217 const std::string_view state_name)
218{
219 if (!asset.editor_graph)
220 {
221 return nullptr;
222 }
223
224 const auto it = std::find_if(asset.editor_graph->nodes.begin(), asset.editor_graph->nodes.end(),
225 [&](const BehaviorEditorGraphNodeLayout& node) { return node.state_name == state_name; });
226 return it == asset.editor_graph->nodes.end() ? nullptr : &(*it);
227}
228
229[[nodiscard]] inline BehaviorEditorGraphNodeLayout* FindBehaviorEditorGraphNodeLayout(BehaviorStateMachineAsset& asset,
230 const std::string_view state_name)
231{
232 if (!asset.editor_graph)
233 {
234 return nullptr;
235 }
236
237 const auto it = std::find_if(asset.editor_graph->nodes.begin(), asset.editor_graph->nodes.end(),
238 [&](const BehaviorEditorGraphNodeLayout& node) { return node.state_name == state_name; });
239 return it == asset.editor_graph->nodes.end() ? nullptr : &(*it);
240}
241
242inline BehaviorEditorGraphNodeLayout& EnsureBehaviorEditorGraphNodeLayout(BehaviorStateMachineAsset& asset, std::string state_name)
243{
244 if (!asset.editor_graph)
245 {
246 asset.editor_graph = BehaviorEditorGraphLayout{};
247 }
248
249 if (BehaviorEditorGraphNodeLayout* existing = FindBehaviorEditorGraphNodeLayout(asset, state_name))
250 {
251 return *existing;
252 }
253
254 asset.editor_graph->nodes.push_back(BehaviorEditorGraphNodeLayout{
255 .state_name = std::move(state_name),
256 .position = glm::vec2(0.0f),
257 });
258 return asset.editor_graph->nodes.back();
259}
260
261inline bool RenameBehaviorState(BehaviorStateMachineAsset& asset, const std::string_view old_name, std::string new_name)
262{
263 BehaviorState* state = FindBehaviorState(asset, old_name);
264 if (!state)
265 {
266 return false;
267 }
268
269 const std::string previous_name = state->name;
270 state->name = std::move(new_name);
271
272 if (asset.initial_state == previous_name)
273 {
274 asset.initial_state = state->name;
275 }
276
277 for (BehaviorState& candidate : asset.states)
278 {
279 for (BehaviorTransition& transition : candidate.transitions)
280 {
281 if (transition.target_state == previous_name)
282 {
283 transition.target_state = state->name;
284 }
285 }
286 }
287
288 if (BehaviorEditorGraphNodeLayout* layout = FindBehaviorEditorGraphNodeLayout(asset, previous_name))
289 {
290 layout->state_name = state->name;
291 }
292
293 return true;
294}
295
296inline bool DeleteBehaviorState(BehaviorStateMachineAsset& asset, const std::string_view state_name)
297{
298 const auto state_it =
299 std::find_if(asset.states.begin(), asset.states.end(), [&](const BehaviorState& state) { return state.name == state_name; });
300 if (state_it == asset.states.end())
301 {
302 return false;
303 }
304
305 const bool deleted_initial_state = asset.initial_state == state_it->name;
306 const std::string deleted_name = state_it->name;
307 asset.states.erase(state_it);
308
309 for (BehaviorState& state : asset.states)
310 {
311 std::erase_if(state.transitions, [&](const BehaviorTransition& transition) { return transition.target_state == deleted_name; });
312 }
313
314 if (asset.editor_graph)
315 {
316 std::erase_if(asset.editor_graph->nodes,
317 [&](const BehaviorEditorGraphNodeLayout& node) { return node.state_name == deleted_name; });
318 if (asset.editor_graph->nodes.empty())
319 {
320 asset.editor_graph.reset();
321 }
322 }
323
324 if (deleted_initial_state)
325 {
326 asset.initial_state = asset.states.empty() ? std::string{} : asset.states.front().name;
327 }
328
329 return true;
330}
331} // namespace pixelbullet
Definition behavior_state_machine_types.h:266
Definition behavior_state_machine_types.h:282
Definition behavior_state_machine_types.h:274
Definition behavior_state_machine_types.h:294
Definition behavior_state_machine_types.h:257
Definition behavior_state_machine_types.h:102
Definition behavior_state_machine_types.h:110
Definition behavior_state_machine_types.h:248
Definition behavior_state_machine_types.h:91