Line data Source code
1 : /**
2 : Copyright (c) 2022 Roman Katuntsev <sbkarr@stappler.org>
3 : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
4 :
5 : Permission is hereby granted, free of charge, to any person obtaining a copy
6 : of this software and associated documentation files (the "Software"), to deal
7 : in the Software without restriction, including without limitation the rights
8 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 : copies of the Software, and to permit persons to whom the Software is
10 : furnished to do so, subject to the following conditions:
11 :
12 : The above copyright notice and this permission notice shall be included in
13 : all copies or substantial portions of the Software.
14 :
15 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 : THE SOFTWARE.
22 : **/
23 :
24 : #include "XLActionManager.h"
25 : #include "XLNode.h"
26 :
27 : namespace STAPPLER_VERSIONIZED stappler::xenolith {
28 :
29 3479 : ActionContainer::~ActionContainer() { }
30 :
31 3479 : ActionContainer::ActionContainer(Node *t) : target(t) { }
32 :
33 42 : ActionManager::~ActionManager() {
34 21 : removeAllActions();
35 42 : }
36 :
37 21 : ActionManager::ActionManager() { }
38 :
39 21 : bool ActionManager::init() {
40 21 : return true;
41 : }
42 :
43 7913 : void ActionManager::addAction(Action *action, Node *target, bool paused) {
44 7913 : if (_inUpdate) {
45 2811 : _pending.emplace_back(PendingAction{action, target, paused});
46 2811 : return;
47 : }
48 :
49 5102 : XLASSERT(action != nullptr, "");
50 5102 : XLASSERT(target != nullptr, "");
51 :
52 5102 : auto it = _actions.find(target);
53 5102 : if (it == _actions.end()) {
54 3479 : it = _actions.emplace(target).first;
55 3479 : it->paused = paused;
56 : }
57 :
58 5102 : action->setContainer(target);
59 5102 : it->addItem(action);
60 5102 : action->startWithTarget(target);
61 : }
62 :
63 42 : void ActionManager::removeAllActions() {
64 42 : if (_inUpdate) {
65 21 : auto it = _actions.begin();
66 104 : while (it != _actions.end()) {
67 83 : it->foreach([&] (Action *a) {
68 80 : a->invalidate();
69 80 : return true;
70 : });
71 83 : ++ it;
72 : }
73 : } else {
74 21 : _actions.clear();
75 : }
76 42 : }
77 :
78 69625 : void ActionManager::removeAllActionsFromTarget(Node *target) {
79 69625 : if (target == nullptr) {
80 0 : return;
81 : }
82 :
83 69625 : if (_current && _current->target == target) {
84 21 : _current->foreach([&] (Action *a) {
85 42 : a->invalidate();
86 42 : return true;
87 : });
88 : } else {
89 69604 : auto it = _actions.find(target);
90 69604 : if (it != _actions.end()) {
91 362 : if (_inUpdate) {
92 294 : it->foreach([&] (Action *a) {
93 399 : a->invalidate();
94 399 : return true;
95 : });
96 : } else {
97 68 : _actions.erase(it);
98 : }
99 : }
100 : }
101 :
102 69625 : auto it = _pending.begin();
103 73973 : while (it != _pending.end()) {
104 4348 : if (it->target == target) {
105 0 : it = _pending.erase(it);
106 : } else {
107 4348 : ++ it;
108 : }
109 : }
110 : }
111 :
112 21 : void ActionManager::removeAction(Action *action) {
113 21 : auto target = action->getContainer();
114 21 : if (_current && _current->target == target) {
115 0 : action->invalidate();
116 : } else {
117 21 : auto it = _actions.find(target);
118 21 : if (it != _actions.end()) {
119 21 : it->removeItem(action);
120 : }
121 : }
122 :
123 21 : auto it = _pending.begin();
124 42 : while (it != _pending.end()) {
125 21 : if (it->action == action) {
126 0 : it = _pending.erase(it);
127 0 : break;
128 : } else {
129 21 : ++ it;
130 : }
131 : }
132 21 : }
133 :
134 2499 : void ActionManager::removeActionByTag(uint32_t tag, Node *target) {
135 2499 : if (_current && _current->target == target) {
136 0 : if (_current->invalidateItemByTag(tag)) {
137 1904 : return;
138 : }
139 : } else {
140 2499 : auto it = _actions.find(target);
141 2499 : if (it != _actions.end()) {
142 2115 : if (it->removeItemByTag(tag)) {
143 1904 : return;
144 : }
145 : }
146 : }
147 :
148 595 : auto it = _pending.begin();
149 620 : while (it != _pending.end()) {
150 26 : if (it->target == target && it->action->getTag() == tag) {
151 1 : it = _pending.erase(it);
152 1 : break;
153 : } else {
154 25 : ++ it;
155 : }
156 : }
157 : }
158 :
159 996 : void ActionManager::removeAllActionsByTag(uint32_t tag, Node *target) {
160 996 : if (_current && _current->target == target) {
161 0 : _current->invalidateAllItemsByTag(tag);
162 : } else {
163 996 : auto it = _actions.find(target);
164 996 : if (it != _actions.end()) {
165 70 : it->removeAllItemsByTag(tag);
166 : }
167 : }
168 :
169 996 : auto it = _pending.begin();
170 996 : while (it != _pending.end()) {
171 0 : if (it->target == target && it->action->getTag() == tag) {
172 0 : it = _pending.erase(it);
173 : } else {
174 0 : ++ it;
175 : }
176 : }
177 996 : }
178 :
179 1506 : Action *ActionManager::getActionByTag(uint32_t tag, const Node *target) const {
180 1506 : if (_current && _current->target == target) {
181 0 : return _current->getItemByTag(tag);
182 : } else {
183 1506 : auto it = _actions.find(target);
184 1506 : if (it != _actions.end()) {
185 167 : return it->getItemByTag(tag);
186 : }
187 : }
188 :
189 1339 : auto it = _pending.begin();
190 1339 : while (it != _pending.end()) {
191 0 : if (it->target == target && it->action->getTag() == tag) {
192 0 : return it->action;
193 : } else {
194 0 : ++ it;
195 : }
196 : }
197 :
198 1339 : return nullptr;
199 : }
200 :
201 21 : size_t ActionManager::getNumberOfRunningActionsInTarget(const Node *target) const {
202 21 : size_t pending = 0;
203 :
204 21 : auto it = _pending.begin();
205 21 : while (it != _pending.end()) {
206 0 : if (it->target == target) {
207 0 : ++ pending;
208 : }
209 0 : ++ it;
210 : }
211 :
212 21 : if (_current && _current->target == target) {
213 21 : return _current->size() + pending;
214 : } else {
215 0 : auto it = _actions.find(target);
216 0 : if (it != _actions.end()) {
217 0 : return it->size() + pending;
218 : }
219 : }
220 0 : return 0;
221 : }
222 :
223 126 : void ActionManager::pauseTarget(Node *target) {
224 126 : auto it = _actions.find(target);
225 126 : if (it != _actions.end()) {
226 42 : it->paused = true;
227 : }
228 126 : }
229 :
230 21 : void ActionManager::resumeTarget(Node *target) {
231 21 : auto it = _actions.find(target);
232 21 : if (it != _actions.end()) {
233 21 : it->paused = false;
234 : }
235 21 : }
236 :
237 21 : Vector<Node *> ActionManager::pauseAllRunningActions() {
238 21 : Vector<Node *> ret;
239 141 : for (auto &it : _actions) {
240 120 : it.paused = true;
241 120 : ret.emplace_back(it.target);
242 : }
243 21 : return ret;
244 0 : }
245 :
246 21 : void ActionManager::resumeTargets(const Vector<Node*> &targetsToResume) {
247 141 : for (auto &target : targetsToResume) {
248 120 : auto it = _actions.find(target);
249 120 : if (it != _actions.end()) {
250 120 : it->paused = false;
251 : }
252 : }
253 21 : }
254 :
255 : /** Main loop of ActionManager. */
256 9538 : void ActionManager::update(const UpdateTime &time) {
257 9538 : float dt = float(time.delta) / 1'000'000.0f;
258 9538 : _inUpdate = true;
259 9538 : auto it = _actions.begin();
260 53597 : while (it != _actions.end()) {
261 44059 : _current = &(*it);
262 44059 : _current->foreach([&] (Action *a) {
263 50694 : if (a->getTarget()) {
264 49170 : a->step(dt);
265 49170 : if (a->isDone()) {
266 2586 : a->stop();
267 : }
268 : } else {
269 1524 : a->stop();
270 : }
271 50694 : return true;
272 : });
273 44059 : _current = nullptr;
274 44059 : ++ it;
275 : }
276 9538 : _inUpdate = false;
277 :
278 9538 : it = _actions.begin();
279 53597 : while (it != _actions.end()) {
280 44059 : if (it->cleanup()) {
281 3345 : auto iit = _actions.find(it->target);
282 3345 : if (iit != _actions.end()) {
283 3345 : it = _actions.erase(it);
284 : } else {
285 0 : log::debug("ActionManager", "update: ", time.app, " erase: ", (void *)it->target.get());
286 : }
287 : } else {
288 40714 : ++ it;
289 : }
290 : }
291 :
292 12348 : for (auto &it : _pending) {
293 2810 : addAction(it.action, it.target, it.paused);
294 : }
295 9538 : _pending.clear();
296 9538 : }
297 :
298 9538 : bool ActionManager::empty() const {
299 9538 : return _actions.empty() && _pending.empty();
300 : }
301 :
302 : }
|