Ember
Loading...
Searching...
No Matches
StateManager.cpp
Go to the documentation of this file.
2
3#include <algorithm>
4
5namespace Ember {
6namespace Network {
7
8StateManager::StateManager(std::shared_ptr<EmberCore::BehaviorTree> tree) : m_tree(std::move(tree)) {}
9
10void StateManager::ApplyTickUpdate(const Protocol::TickUpdate *update) {
11 if (!update) {
12 return;
13 }
14
15 std::lock_guard<std::mutex> lock(m_mutex);
16
17 m_currentTick = update->tick_number();
18
19 if (update->execution_path()) {
20 m_executionPath.clear();
21 m_executionPath.reserve(update->execution_path()->size());
22 for (auto id : *update->execution_path()) {
23 m_executionPath.push_back(id);
24 }
25 }
26
27 if (update->states()) {
28 bool isDelta = update->is_delta();
29
30 if (!isDelta) {
31 for (auto &pair : m_nodeStates) {
32 pair.second = Protocol::NodeStatus_Idle;
33 }
34 }
35
36 for (const auto *state : *update->states()) {
37 if (!state) {
38 continue;
39 }
40
41 int64_t nodeId = state->id();
42 NodeStatus newStatus = state->status();
43
44 auto it = m_nodeStates.find(nodeId);
45 NodeStatus oldStatus = (it != m_nodeStates.end()) ? it->second : Protocol::NodeStatus_Idle;
46
47 m_nodeStates[nodeId] = newStatus;
48
49 if (oldStatus != newStatus) {
50 m_changedNodeIds.push_back(nodeId);
51 NotifyStateChange(nodeId, oldStatus, newStatus);
52 }
53 }
54 }
55
56 if (m_historyEnabled) {
58 }
59
61}
62
63void StateManager::ApplyBlackboardUpdate(const Protocol::BlackboardUpdate *update) {
64 if (!update || !m_tree) {
65 return;
66 }
67
68 std::lock_guard<std::mutex> lock(m_mutex);
69
70 if (!update->blackboard_id()) {
71 return;
72 }
73
74 auto *blackboard = m_tree->GetBlackboard(update->blackboard_id()->str());
75 if (!blackboard) {
76 return;
77 }
78
79 if (update->updates()) {
80 for (const auto *entryUpdate : *update->updates()) {
81 if (!entryUpdate || !entryUpdate->key()) {
82 continue;
83 }
84
85 auto *entry = blackboard->GetEntry(entryUpdate->key()->str());
86 if (entry && entryUpdate->value()) {
87 entry->SetValue(entryUpdate->value()->str());
88 }
89 }
90 }
91}
92
94 std::lock_guard<std::mutex> lock(m_mutex);
95
96 for (auto &pair : m_nodeStates) {
97 NodeStatus oldStatus = pair.second;
98 pair.second = Protocol::NodeStatus_Idle;
99
100 if (oldStatus != Protocol::NodeStatus_Idle) {
101 NotifyStateChange(pair.first, oldStatus, Protocol::NodeStatus_Idle);
102 }
103 }
104
105 m_executionPath.clear();
106 m_currentTick = 0;
107
108 NotifyTick(0);
109}
110
112 std::lock_guard<std::mutex> lock(m_mutex);
113
114 auto it = m_nodeStates.find(node_id);
115 if (it != m_nodeStates.end()) {
116 return it->second;
117 }
119}
120
122 std::lock_guard<std::mutex> lock(m_mutex);
123 std::vector<int64_t> result;
124 result.swap(m_changedNodeIds);
125 return result;
126}
127
128void StateManager::EnableHistory(size_t max_ticks) {
129 std::lock_guard<std::mutex> lock(m_mutex);
130 m_historyEnabled = true;
131 m_maxHistoryTicks = max_ticks;
132}
133
135 std::lock_guard<std::mutex> lock(m_mutex);
136 m_historyEnabled = false;
137 m_history.clear();
138}
139
140void StateManager::SeekToTick(int64_t tick_number) {
141 std::lock_guard<std::mutex> lock(m_mutex);
142
143 auto it = std::find_if(m_history.begin(), m_history.end(),
144 [tick_number](const TickSnapshot &s) { return s.tick_number == tick_number; });
145
146 if (it == m_history.end()) {
147 return;
148 }
149
150 m_currentTick = it->tick_number;
151 m_nodeStates = it->states;
152 m_executionPath = it->execution_path;
153}
154
156 std::lock_guard<std::mutex> lock(m_mutex);
157 m_stateCallbacks.push_back(std::move(callback));
158}
159
161 std::lock_guard<std::mutex> lock(m_mutex);
162 m_tickCallbacks.push_back(std::move(callback));
163}
164
166 std::lock_guard<std::mutex> lock(m_mutex);
167 m_stateCallbacks.clear();
168 m_tickCallbacks.clear();
169}
170
171void StateManager::NotifyStateChange(int64_t node_id, NodeStatus old_status, NodeStatus new_status) {
172 for (const auto &callback : m_stateCallbacks) {
173 if (callback) {
174 callback(node_id, old_status, new_status);
175 }
176 }
177}
178
179void StateManager::NotifyTick(int64_t tick_number) {
180 for (const auto &callback : m_tickCallbacks) {
181 if (callback) {
182 callback(tick_number);
183 }
184 }
185}
186
188 TickSnapshot snapshot;
189 snapshot.tick_number = m_currentTick;
190 snapshot.states = m_nodeStates;
192
193 m_history.push_back(std::move(snapshot));
194
195 while (m_history.size() > m_maxHistoryTicks) {
196 m_history.erase(m_history.begin());
197 }
198}
199
200} // namespace Network
201} // namespace Ember
std::function< void(int64_t tick_number)> TickCallback
NodeStatus GetNodeStatus(int64_t node_id) const
void ApplyBlackboardUpdate(const Protocol::BlackboardUpdate *update)
void ApplyTickUpdate(const Protocol::TickUpdate *update)
std::vector< int64_t > m_changedNodeIds
void SeekToTick(int64_t tick_number)
std::vector< int64_t > GetAndClearChangedNodes()
std::unordered_map< int64_t, NodeStatus > m_nodeStates
void AddTickCallback(TickCallback callback)
std::vector< TickCallback > m_tickCallbacks
std::function< void(int64_t node_id, NodeStatus old_status, NodeStatus new_status)> StateChangeCallback
void AddStateChangeCallback(StateChangeCallback callback)
void NotifyStateChange(int64_t node_id, NodeStatus old_status, NodeStatus new_status)
void EnableHistory(size_t max_ticks=1000)
std::vector< int64_t > m_executionPath
std::vector< TickSnapshot > m_history
Protocol::NodeStatus NodeStatus
StateManager(std::shared_ptr< EmberCore::BehaviorTree > tree)
std::shared_ptr< EmberCore::BehaviorTree > m_tree
void NotifyTick(int64_t tick_number)
std::vector< StateChangeCallback > m_stateCallbacks
std::unordered_map< int64_t, NodeStatus > states