CommonLibSSE NG
Loading...
Searching...
No Matches
RegistrationMapUnique.h
Go to the documentation of this file.
1#pragma once
2
3#include "RE/A/ActiveEffect.h"
4#include "RE/B/BGSRefAlias.h"
8#include "RE/T/TESForm.h"
10#include "RE/T/TypeTraits.h"
11#include "RE/V/VirtualMachine.h"
12
13#include "SKSE/API.h"
15#include "SKSE/Interfaces.h"
16#include "SKSE/Logger.h"
17
18namespace SKSE
19{
20 namespace Impl
21 {
22 template <class Filter>
24 {
25 public:
26 using EventFilter = std::pair<Filter, bool>;
27 using EventFilterHandleMap = std::map<EventFilter, std::set<RE::VMHandle>>;
28
29 using PassFilterFunc = std::function<bool(const Filter&, bool)>;
30
32 {
33 public:
35 RegistrationMapUniqueBase(const std::string_view& a_eventName);
39
42
43 bool Register(RE::TESForm* a_form, const Filter& a_filter, bool a_matchFilter);
44 bool Register(RE::ActiveEffect* a_activeEffect, const Filter& a_filter, bool a_matchFilter);
45 bool Register(RE::BGSRefAlias* a_alias, const Filter& a_filter, bool a_matchFilter);
46 bool Unregister(RE::TESForm* a_form, const Filter& a_filter, bool a_matchFilter);
47 bool Unregister(RE::ActiveEffect* a_activeEffect, const Filter& a_filter, bool a_matchFilter);
48 bool Unregister(RE::BGSRefAlias* a_alias, const Filter& a_filter, bool a_matchFilter);
49 void UnregisterAll(const RE::TESForm* a_form);
50 void UnregisterAll(RE::ActiveEffect* a_activeEffect);
51 void UnregisterAll(RE::BGSRefAlias* a_alias);
52 void UnregisterAll(RE::VMHandle a_handle);
53 void UnregisterAll(RE::FormID a_uniqueID);
54 void Clear();
55 bool Save(SerializationInterface* a_intfc, std::uint32_t a_type, std::uint32_t a_version);
56 bool Save(SerializationInterface* a_intfc);
57 bool Load(SerializationInterface* a_intfc);
59
60 protected:
61 using Lock = std::recursive_mutex;
62 using Locker = std::lock_guard<Lock>;
63
64 bool Register(const void* a_object, RE::FormID a_formID, EventFilter a_filter, RE::VMTypeID a_typeID);
65 bool Unregister(const void* a_object, RE::FormID a_formID, EventFilter a_filter, RE::VMTypeID a_typeID);
66 void UnregisterAll(const void* a_object, RE::FormID a_formID, RE::VMTypeID a_typeID);
67
68 std::map<RE::FormID, EventFilterHandleMap> _regs;
69 std::string _eventName;
70 mutable Lock _lock;
71 };
72
73 template <class Enable, class... Args>
75
76 template <class... Args>
78 std::enable_if_t<
79 std::conjunction_v<
80 RE::BSScript::is_return_convertible<Args>...>>,
81 Args...> :
83 {
84 private:
86
87 public:
91
92 inline RegistrationMapUnique(const std::string_view& a_eventName) :
93 super(a_eventName)
94 {}
95
97
100
101 inline void SendEvent(const RE::TESObjectREFR* a_target, PassFilterFunc a_callback, Args... a_args)
102 {
103 RE::BSFixedString eventName(this->_eventName);
104
106 const auto targetFormID = a_target->GetFormID();
107 if (auto it = this->_regs.find(targetFormID); it != this->_regs.end()) {
108 for (auto& [eventFilter, handles] : it->second) {
109 if (a_callback(eventFilter.first, eventFilter.second)) {
110 for (auto& handle : handles) {
111 auto args = RE::MakeFunctionArguments(std::forward<Args>(a_args)...);
112 vm->SendEvent(handle, eventName, args);
113 }
114 }
115 }
116 }
117 }
118 }
119
120 inline void QueueEvent(RE::TESObjectREFR* a_target, PassFilterFunc a_callback, Args... a_args)
121 {
122 std::tuple args(VMArg(std::forward<Args>(a_args))...);
123 auto task = GetTaskInterface();
124 assert(task);
125 if (task) {
126 task->AddTask([a_target, a_callback, args, this]() mutable {
127 SendEvent_Tuple(a_target, a_callback, std::move(args), index_sequence_for_tuple<decltype(args)>{});
128 });
129 }
130 }
131
132 private:
133 template <class Tuple, std::size_t... I>
134 inline void SendEvent_Tuple(RE::TESObjectREFR* a_target, PassFilterFunc a_callback, Tuple&& a_tuple, std::index_sequence<I...>)
135 {
136 SendEvent(a_target, a_callback, std::get<I>(std::forward<Tuple>(a_tuple)).Unpack()...);
137 }
138 };
139
140 template <>
142 {
143 private:
145
146 public:
150
151 inline RegistrationMapUnique(const std::string_view& a_eventName) :
152 super(a_eventName)
153 {}
154
156
159
160 inline void SendEvent(const RE::TESObjectREFR* a_target, PassFilterFunc a_callback)
161 {
162 RE::BSFixedString eventName(this->_eventName);
163
165 const auto targetFormID = a_target->GetFormID();
166 if (auto it = this->_regs.find(targetFormID); it != this->_regs.end()) {
167 for (auto& [eventFilter, handles] : it->second) {
168 if (a_callback(eventFilter.first, eventFilter.second)) {
169 for (auto& handle : handles) {
170 auto args = RE::MakeFunctionArguments();
171 vm->SendEvent(handle, eventName, args);
172 }
173 }
174 }
175 }
176 }
177 }
178
179 inline void QueueEvent(RE::TESObjectREFR* a_target, PassFilterFunc a_callback)
180 {
181 auto task = GetTaskInterface();
182 assert(task);
183 task->AddTask([a_target, a_callback, this]() {
184 SendEvent(a_target, std::move(a_callback));
185 });
186 }
187 };
188 };
189
190 template <class Filter>
192 _regs(),
193 _eventName(a_eventName),
194 _lock()
195 {}
196
197 template <class Filter>
199 _regs(),
200 _eventName(a_rhs._eventName),
201 _lock()
202 {
203 a_rhs._lock.lock();
204 _regs = a_rhs._regs;
205 a_rhs._lock.unlock();
206
208 if (auto policy = vm ? vm->GetObjectHandlePolicy() : nullptr) {
209 for (auto& reg : _regs) {
210 for (auto& keyHandles : reg.second) {
211 for (auto& handle : keyHandles.second) {
212 policy->PersistHandle(handle);
213 }
214 }
215 }
216 }
217 }
218
219 template <class Filter>
221 _regs(),
222 _eventName(a_rhs._eventName),
223 _lock()
224 {
225 Locker locker(a_rhs._lock);
226 _regs = std::move(a_rhs._regs);
227 a_rhs._regs.clear();
228 }
229
230 template <class Filter>
232 {
234 if (auto policy = vm ? vm->GetObjectHandlePolicy() : nullptr) {
235 for (auto& reg : _regs) {
236 for (auto& keyHandles : reg.second) {
237 for (auto& handle : keyHandles.second) {
238 policy->ReleaseHandle(handle);
239 }
240 }
241 }
242 }
243 }
244
245 template <class Filter>
247 {
248 if (this == &a_rhs) {
249 return *this;
250 }
251
252 Locker lhsLocker(_lock);
253 Clear();
254
255 {
256 Locker rhsLocker(a_rhs._lock);
257 _regs = a_rhs._regs;
258 _eventName = a_rhs._eventName;
259 }
260
262 if (auto policy = vm ? vm->GetObjectHandlePolicy() : nullptr) {
263 for (auto& reg : _regs) {
264 for (auto& keyHandles : reg.second) {
265 for (auto& handle : keyHandles.second) {
266 policy->PersistHandle(handle);
267 }
268 }
269 }
270 }
271
272 return *this;
273 }
274
275 template <class Filter>
277 {
278 if (this == &a_rhs) {
279 return *this;
280 }
281
282 Locker lhsLocker(_lock);
283 Locker rhsLocker(a_rhs._lock);
284
285 Clear();
286
287 _eventName = a_rhs._eventName;
288
289 _regs = std::move(a_rhs._regs);
290 a_rhs._regs.clear();
291
292 return *this;
293 }
294
295 template <class Filter>
296 bool EventFilterUnique<Filter>::RegistrationMapUniqueBase::Register(RE::TESForm* a_form, const Filter& a_filter, bool a_matchFilter)
297 {
298 assert(a_form);
299
300 const auto reference = a_form->AsReference();
301 const auto formID = reference ? reference->GetFormID() : 0;
302
303 if (formID != 0) {
304 return Register(a_form, formID, { a_filter, a_matchFilter }, static_cast<RE::VMTypeID>(a_form->GetFormType()));
305 }
306
307 return false;
308 }
309
310 template <class Filter>
311 bool EventFilterUnique<Filter>::RegistrationMapUniqueBase::Register(RE::ActiveEffect* a_activeEffect, const Filter& a_filter, bool a_matchFilter)
312 {
313 assert(a_activeEffect);
314
315 const auto target = a_activeEffect->GetTargetActor();
316 const auto formID = target ? target->GetFormID() : 0;
317
318 if (formID != 0) {
319 return Register(a_activeEffect, formID, { a_filter, a_matchFilter }, RE::ActiveEffect::VMTYPEID);
320 }
321
322 return false;
323 }
324
325 template <class Filter>
326 bool EventFilterUnique<Filter>::RegistrationMapUniqueBase::Register(RE::BGSRefAlias* a_alias, const Filter& a_filter, bool a_matchFilter)
327 {
328 assert(a_alias);
329
330 const auto target = a_alias->GetActorReference();
331 const auto formID = target ? target->GetFormID() : 0;
332
333 if (formID != 0) {
334 return Register(a_alias, formID, { a_filter, a_matchFilter }, RE::BGSRefAlias::VMTYPEID);
335 }
336
337 return false;
338 }
339
340 template <class Filter>
341 bool EventFilterUnique<Filter>::RegistrationMapUniqueBase::Unregister(RE::TESForm* a_form, const Filter& a_filter, bool a_matchFilter)
342 {
343 assert(a_form);
344
345 const auto reference = a_form->AsReference();
346 const auto formID = reference ? reference->GetFormID() : 0;
347
348 if (formID != 0) {
349 return Unregister(a_form, formID, { a_filter, a_matchFilter }, static_cast<RE::VMTypeID>(a_form->GetFormType()));
350 }
351
352 return false;
353 }
354
355 template <class Filter>
356 bool EventFilterUnique<Filter>::RegistrationMapUniqueBase::Unregister(RE::ActiveEffect* a_activeEffect, const Filter& a_filter, bool a_matchFilter)
357 {
358 assert(a_activeEffect);
359
360 const auto target = a_activeEffect->GetTargetActor();
361 const auto formID = target ? target->GetFormID() : 0;
362
363 if (formID != 0) {
364 return Unregister(a_activeEffect, formID, { a_filter, a_matchFilter }, RE::ActiveEffect::VMTYPEID);
365 }
366
367 return false;
368 }
369
370 template <class Filter>
371 bool EventFilterUnique<Filter>::RegistrationMapUniqueBase::Unregister(RE::BGSRefAlias* a_alias, const Filter& a_filter, bool a_matchFilter)
372 {
373 assert(a_alias);
374
375 const auto target = a_alias->GetActorReference();
376 const auto formID = target ? target->GetFormID() : 0;
377
378 if (formID != 0) {
379 return Unregister(a_alias, formID, { a_filter, a_matchFilter }, RE::BGSRefAlias::VMTYPEID);
380 }
381
382 return false;
383 }
384
385 template <class Filter>
387 {
388 assert(a_form);
389
390 const auto reference = a_form->AsReference();
391 const auto formID = reference ? reference->GetFormID() : 0;
392
393 if (formID != 0) {
394 UnregisterAll(a_form, formID, static_cast<RE::VMTypeID>(a_form->GetFormType()));
395 }
396 }
397
398 template <class Filter>
400 {
401 assert(a_activeEffect);
402
403 const auto target = a_activeEffect->GetTargetActor();
404 const auto formID = target ? target->GetFormID() : 0;
405
406 if (formID != 0) {
407 UnregisterAll(a_activeEffect, formID, RE::ActiveEffect::VMTYPEID);
408 }
409 }
410
411 template <class Filter>
413 {
414 assert(a_alias);
415
416 const auto target = a_alias->GetActorReference();
417 const auto formID = target ? target->GetFormID() : 0;
418
419 if (formID != 0) {
420 UnregisterAll(a_alias, formID, RE::BGSRefAlias::VMTYPEID);
421 }
422 }
423
424 template <class Filter>
426 {
428 auto policy = vm ? vm->GetObjectHandlePolicy() : nullptr;
429 if (!policy) {
430 log::error("Failed to get handle policy!");
431 return;
432 }
433
434 Locker locker(_lock);
435 for (auto& reg : _regs) {
436 for (auto& keyHandle : reg.second) {
437 if (auto result = keyHandle.second.erase(a_handle); result != 0) {
438 policy->ReleaseHandle(a_handle);
439 }
440 }
441 }
442 }
443
444 template <class Filter>
446 {
448 auto policy = vm ? vm->GetObjectHandlePolicy() : nullptr;
449 if (!policy) {
450 log::error("Failed to get handle policy!");
451 return;
452 }
453
454 Locker locker(_lock);
455 auto it = _regs.find(a_uniqueID);
456 if (it != _regs.end()) {
457 for (auto& keyHandles : it->second) {
458 for (auto& handle : keyHandles.second) {
459 policy->ReleaseHandle(handle);
460 }
461 }
462 _regs.erase(it);
463 }
464 }
465
466 template <class Filter>
468 {
470 auto policy = vm ? vm->GetObjectHandlePolicy() : nullptr;
471 Locker locker(_lock);
472 if (policy) {
473 for (auto& reg : _regs) {
474 for (auto& keyHandle : reg.second) {
475 for (auto& handle : keyHandle.second) {
476 policy->ReleaseHandle(handle);
477 }
478 }
479 }
480 }
481 _regs.clear();
482 }
483
484 template <class Filter>
485 bool EventFilterUnique<Filter>::RegistrationMapUniqueBase::Save(SerializationInterface* a_intfc, std::uint32_t a_type, std::uint32_t a_version)
486 {
487 assert(a_intfc);
488 if (!a_intfc->OpenRecord(a_type, a_version)) {
489 log::error("Failed to open record!");
490 return false;
491 }
492
493 return Save(a_intfc);
494 }
495
496 template <class Filter>
498 {
499 assert(a_intfc);
500 Locker locker(_lock);
501
502 // Reg count
503 const std::size_t numRegs = _regs.size();
504 if (!a_intfc->WriteRecordData(numRegs)) {
505 log::error("Failed to save reg count ({})!", numRegs);
506 return false;
507 }
508 for (auto& reg : _regs) {
509 //FormID
510 if (!a_intfc->WriteRecordData(reg.first)) {
511 log::error("Failed to save handle formID ({:X})", reg.first);
512 return false;
513 }
514 std::size_t numUniqueHandle = reg.second.size();
515 if (!a_intfc->WriteRecordData(numUniqueHandle)) {
516 log::error("Failed to save handle count ({})!", numUniqueHandle);
517 return false;
518 }
519 // UniqueHandle
520 for (auto& [key, handles] : reg.second) {
521 // EventFilter
522 auto [eventFilter, match] = key;
523 if (!eventFilter.Save(a_intfc)) {
524 log::error("Failed to save event filters!");
525 return false;
526 }
527 if (!a_intfc->WriteRecordData(match)) {
528 log::error("Failed to save reg key as bool ({})!", match);
529 return false;
530 }
531 //handle set
532 std::size_t numHandles = handles.size();
533 if (!a_intfc->WriteRecordData(numHandles)) {
534 log::error("Failed to save handle count ({})!", numHandles);
535 return false;
536 }
537 for (auto& handle : handles) {
538 if (!a_intfc->WriteRecordData(handle)) {
539 log::error("Failed to save handle ({})", handle);
540 return false;
541 }
542 }
543 }
544 }
545
546 return true;
547 }
548
549 template <class Filter>
551 {
552 assert(a_intfc);
553 std::size_t numRegs;
554 a_intfc->ReadRecordData(numRegs);
555
556 Locker locker(_lock);
557 _regs.clear();
558
559 //FormID
560 RE::FormID formID;
561 // KeyHandle
562 std::size_t numKeyHandle;
563 // Handle
564 std::size_t numHandles;
565 RE::VMHandle vmHandle;
566
567 for (std::size_t i = 0; i < numRegs; ++i) {
568 a_intfc->ReadRecordData(formID);
569 if (!a_intfc->ResolveFormID(formID, formID)) {
570 log::warn("Failed to resolve target formID ({:X})", formID);
571 continue;
572 }
573 a_intfc->ReadRecordData(numKeyHandle);
574 for (std::size_t j = 0; j < numKeyHandle; ++j) {
575 // filter
576 Filter eventFilter{};
577 if (!eventFilter.Load(a_intfc)) {
578 log::error("Failed to save event filters!");
579 continue;
580 }
581 bool match;
582 a_intfc->ReadRecordData(match);
583 EventFilter curKey = { eventFilter, match };
584 // handles
585 a_intfc->ReadRecordData(numHandles);
586 for (std::size_t k = 0; k < numHandles; ++k) {
587 a_intfc->ReadRecordData(vmHandle);
588 if (a_intfc->ResolveHandle(vmHandle, vmHandle)) {
589 _regs[formID][curKey].insert(vmHandle);
590 }
591 }
592 }
593 }
594
595 return true;
596 }
597
598 template <class Filter>
600 {
601 Clear();
602 }
603
604 template <class Filter>
606 {
607 assert(a_object);
609 auto policy = vm ? vm->GetObjectHandlePolicy() : nullptr;
610 if (!policy) {
611 log::error("Failed to get handle policy!");
612 return false;
613 }
614
615 const auto invalidHandle = policy->EmptyHandle();
616 auto handle = policy->GetHandleForObject(a_typeID, a_object);
617 if (handle == invalidHandle) {
618 log::error("Failed to create handle!");
619 return false;
620 }
621
622 _lock.lock();
623 auto result = _regs[a_formID][a_filter].insert(handle);
624 _lock.unlock();
625
626 if (result.second) {
627 policy->PersistHandle(handle);
628 }
629
630 return result.second;
631 }
632
633 template <class Filter>
635 {
636 assert(a_object);
638 auto policy = vm ? vm->GetObjectHandlePolicy() : nullptr;
639 if (!policy) {
640 log::error("Failed to get handle policy!");
641 return false;
642 }
643
644 const auto invalidHandle = policy->EmptyHandle();
645 const auto handle = policy->GetHandleForObject(a_typeID, a_object);
646 if (handle == invalidHandle) {
647 log::error("Failed to create handle!");
648 return false;
649 }
650
651 Locker locker(_lock);
652 if (auto formIt = _regs.find(a_formID); formIt != _regs.end()) {
653 if (auto keyIt = formIt->second.find(a_filter); keyIt != formIt->second.end()) {
654 if (auto result = keyIt->second.erase(handle); result != 0) {
655 policy->ReleaseHandle(handle);
656 return true;
657 }
658 }
659 }
660
661 return false;
662 }
663
664 template <class Filter>
666 {
667 assert(a_object);
669 auto policy = vm ? vm->GetObjectHandlePolicy() : nullptr;
670 if (!policy) {
671 log::error("Failed to get handle policy!");
672 return;
673 }
674
675 const auto invalidHandle = policy->EmptyHandle();
676 const auto handle = policy->GetHandleForObject(a_typeID, a_object);
677 if (handle == invalidHandle) {
678 log::error("Failed to create handle!");
679 return;
680 }
681
682 Locker locker(_lock);
683 if (auto it = _regs.find(a_formID); it != _regs.end()) {
684 for (auto& keyHandles : it->second) {
685 if (auto result = keyHandles.second.erase(handle); result != 0) {
686 policy->ReleaseHandle(handle);
687 }
688 }
689 }
690 }
691 }
692
693 template <class Filter, class... Args>
695}
Definition ActiveEffect.h:27
static constexpr auto VMTYPEID
Definition ActiveEffect.h:31
Actor * GetTargetActor()
Definition BGSRefAlias.h:15
static auto VMTYPEID
Definition BGSRefAlias.h:18
Actor * GetActorReference() const
static VirtualMachine * GetSingleton()
Definition TESForm.h:35
FormType GetFormType() const noexcept
Definition TESForm.h:288
FormID GetFormID() const noexcept
Definition TESForm.h:287
TESObjectREFR * AsReference()
Definition TESForm.h:269
Definition TESObjectREFR.h:112
void SendEvent(const RE::TESObjectREFR *a_target, PassFilterFunc a_callback, Args... a_args)
Definition RegistrationMapUnique.h:101
void QueueEvent(RE::TESObjectREFR *a_target, PassFilterFunc a_callback, Args... a_args)
Definition RegistrationMapUnique.h:120
RegistrationMapUnique(const RegistrationMapUnique &)=default
RegistrationMapUnique & operator=(const RegistrationMapUnique &)=default
void SendEvent(const RE::TESObjectREFR *a_target, PassFilterFunc a_callback)
Definition RegistrationMapUnique.h:160
RegistrationMapUnique(const std::string_view &a_eventName)
Definition RegistrationMapUnique.h:151
void QueueEvent(RE::TESObjectREFR *a_target, PassFilterFunc a_callback)
Definition RegistrationMapUnique.h:179
RegistrationMapUnique & operator=(RegistrationMapUnique &&)=default
std::recursive_mutex Lock
Definition RegistrationMapUnique.h:61
bool Load(SerializationInterface *a_intfc)
Definition RegistrationMapUnique.h:550
void Clear()
Definition RegistrationMapUnique.h:467
~RegistrationMapUniqueBase()
Definition RegistrationMapUnique.h:231
void Revert(SerializationInterface *)
Definition RegistrationMapUnique.h:599
Lock _lock
Definition RegistrationMapUnique.h:70
std::map< RE::FormID, EventFilterHandleMap > _regs
Definition RegistrationMapUnique.h:68
bool Register(RE::TESForm *a_form, const Filter &a_filter, bool a_matchFilter)
Definition RegistrationMapUnique.h:296
bool Save(SerializationInterface *a_intfc, std::uint32_t a_type, std::uint32_t a_version)
Definition RegistrationMapUnique.h:485
RegistrationMapUniqueBase & operator=(const RegistrationMapUniqueBase &a_rhs)
Definition RegistrationMapUnique.h:246
bool Unregister(RE::TESForm *a_form, const Filter &a_filter, bool a_matchFilter)
Definition RegistrationMapUnique.h:341
void UnregisterAll(const RE::TESForm *a_form)
Definition RegistrationMapUnique.h:386
std::string _eventName
Definition RegistrationMapUnique.h:69
std::lock_guard< Lock > Locker
Definition RegistrationMapUnique.h:62
Definition RegistrationMapUnique.h:74
Definition RegistrationMapUnique.h:24
std::function< bool(const Filter &, bool)> PassFilterFunc
Definition RegistrationMapUnique.h:29
std::map< EventFilter, std::set< RE::VMHandle > > EventFilterHandleMap
Definition RegistrationMapUnique.h:27
std::pair< Filter, bool > EventFilter
Definition RegistrationMapUnique.h:26
Definition RegistrationTraits.h:45
Definition Interfaces.h:71
bool ResolveHandle(RE::VMHandle a_oldHandle, RE::VMHandle &a_newHandle) const
std::uint32_t ReadRecordData(void *a_buf, std::uint32_t a_length) const
bool WriteRecordData(const void *a_buf, std::uint32_t a_length) const
bool ResolveFormID(RE::FormID a_oldFormID, RE::FormID &a_newFormID) const
bool OpenRecord(std::uint32_t a_type, std::uint32_t a_version) const
BSScript::IFunctionArguments * MakeFunctionArguments()
Definition FunctionArguments.h:86
std::uint32_t FormID
Definition BSCoreTypes.h:5
std::uint32_t VMTypeID
Definition BSCoreTypes.h:9
std::uint64_t VMHandle
Definition BSCoreTypes.h:7
Definition API.h:14
typename Impl::EventFilterUnique< Filter >::template RegistrationMapUnique< void, Args... > RegistrationMapUnique
Definition RegistrationMapUnique.h:694
const TaskInterface * GetTaskInterface() noexcept
Definition ActorValueList.h:28
Definition RegistrationTraits.h:40