CommonLibSSE (powerof3)
RegistrationMap.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include "RE/A/ActiveEffect.h"
4 #include "RE/B/BGSBaseAlias.h"
5 #include "RE/B/BSFixedString.h"
8 #include "RE/T/TESForm.h"
9 #include "RE/T/TypeTraits.h"
10 #include "RE/V/VirtualMachine.h"
11 
12 #include "SKSE/API.h"
14 #include "SKSE/Interfaces.h"
15 
16 namespace SKSE
17 {
18  namespace Impl
19  {
20  template <class Filter>
22  {
23  public:
25  {
26  public:
27  RegistrationMapBase() = delete;
28  RegistrationMapBase(const std::string_view& a_eventName);
32 
35 
36  bool Register(const RE::TESForm* a_form, Filter a_filter);
37  bool Register(const RE::BGSBaseAlias* a_alias, Filter a_filter);
38  bool Register(const RE::ActiveEffect* a_activeEffect, Filter a_filter);
39  bool Unregister(const RE::TESForm* a_form, Filter a_filter);
40  bool Unregister(const RE::BGSBaseAlias* a_alias, Filter a_filter);
41  bool Unregister(const RE::ActiveEffect* a_activeEffect, Filter a_filter);
42  void UnregisterAll(const RE::TESForm* a_form);
43  void UnregisterAll(const RE::BGSBaseAlias* a_alias);
44  void UnregisterAll(const RE::ActiveEffect* a_activeEffect);
45  void UnregisterAll(RE::VMHandle a_handle);
46  void Clear();
47  bool Save(SerializationInterface* a_intfc, std::uint32_t a_type, std::uint32_t a_version);
48  bool Save(SerializationInterface* a_intfc);
49  bool Load(SerializationInterface* a_intfc);
51 
52  protected:
53  using Lock = std::recursive_mutex;
54  using Locker = std::lock_guard<Lock>;
55 
56  bool Register(const void* a_object, Filter a_filter, RE::VMTypeID a_typeID);
57  bool Unregister(const void* a_object, Filter a_filter, RE::VMTypeID a_typeID);
58  void UnregisterAll(const void* a_object, RE::VMTypeID a_typeID);
59 
60  bool SaveFilter(SerializationInterface* a_intfc, Filter a_filter);
61  bool LoadFilter(SerializationInterface* a_intfc, Filter& a_filter);
62 
63  std::map<Filter, std::set<RE::VMHandle>> _regs;
65  mutable Lock _lock;
66  };
67 
68  template <class Enable, class... Args>
70 
71  template <class... Args>
73  std::enable_if_t<
74  std::conjunction_v<
75  RE::BSScript::is_return_convertible<Args>...>>,
76  Args...> :
77  public RegistrationMapBase
78  {
79  private:
80  using super = RegistrationMapBase;
81 
82  public:
83  RegistrationMap() = delete;
84  RegistrationMap(const RegistrationMap&) = default;
86 
87  inline RegistrationMap(const std::string_view& a_eventName) :
88  super(a_eventName)
89  {}
90 
91  ~RegistrationMap() = default;
92 
95 
96  inline void SendEvent(Filter a_filter, Args... a_args)
97  {
98  RE::BSFixedString eventName(this->_eventName);
99 
101  if (auto it = this->_regs.find(a_filter); it != this->_regs.end()) {
102  for (auto& handle : it->second) {
103  auto copy = std::make_tuple(a_args...);
104  std::apply([&](auto&&... a_copy) {
105  auto args = RE::MakeFunctionArguments(std::forward<Args>(a_copy)...);
106  vm->SendEvent(handle, eventName, args);
107  },
108  copy);
109  }
110  }
111  }
112  }
113 
114  inline void QueueEvent(Filter a_filter, Args... a_args)
115  {
116  std::tuple args(VMArg(std::forward<Args>(a_args))...);
117  auto task = GetTaskInterface();
118  assert(task);
119  if (task) {
120  task->AddTask([a_filter, args, this]() mutable {
121  SendEvent_Tuple(std::move(a_filter), std::move(args), index_sequence_for_tuple<decltype(args)>{});
122  });
123  }
124  }
125 
126  private:
127  template <class Tuple, std::size_t... I>
128  inline void SendEvent_Tuple(Filter a_filter, Tuple&& a_tuple, std::index_sequence<I...>)
129  {
130  SendEvent(a_filter, std::get<I>(std::forward<Tuple>(a_tuple)).Unpack()...);
131  }
132  };
133 
134  template <>
136  {
137  private:
138  using super = RegistrationMapBase;
139 
140  public:
141  RegistrationMap() = delete;
142  RegistrationMap(const RegistrationMap&) = default;
144 
145  inline RegistrationMap(const std::string_view& a_eventName) :
146  super(a_eventName)
147  {}
148 
149  ~RegistrationMap() = default;
150 
153 
154  inline void SendEvent(Filter a_filter)
155  {
156  RE::BSFixedString eventName(this->_eventName);
157 
159  if (auto it = this->_regs.find(a_filter); it != this->_regs.end()) {
160  for (auto& handle : it->second) {
161  auto args = RE::MakeFunctionArguments();
162  vm->SendEvent(handle, eventName, args);
163  }
164  }
165  }
166  }
167 
168  inline void QueueEvent(Filter a_filter)
169  {
170  auto task = GetTaskInterface();
171  assert(task);
172  task->AddTask([a_filter, this]() {
173  SendEvent(std::move(a_filter));
174  });
175  }
176  };
177  };
178 
179  template <class Filter>
181  _regs(),
182  _eventName(a_eventName),
183  _lock()
184  {}
185 
186  template <class Filter>
188  _regs(),
189  _eventName(a_rhs._eventName),
190  _lock()
191  {
192  a_rhs._lock.lock();
193  _regs = a_rhs._regs;
194  a_rhs._lock.unlock();
195 
197  if (auto policy = vm ? vm->GetObjectHandlePolicy() : nullptr) {
198  for (auto& reg : _regs) {
199  for (auto& handle : reg.second) {
200  policy->PersistHandle(handle);
201  }
202  }
203  }
204  }
205 
206  template <class Filter>
208  _regs(),
209  _eventName(a_rhs._eventName),
210  _lock()
211  {
212  Locker locker(a_rhs._lock);
213  _regs = std::move(a_rhs._regs);
214  a_rhs._regs.clear();
215  }
216 
217  template <class Filter>
219  {
221  if (auto policy = vm ? vm->GetObjectHandlePolicy() : nullptr) {
222  for (auto& reg : _regs) {
223  for (auto& handle : reg.second) {
224  policy->ReleaseHandle(handle);
225  }
226  }
227  }
228  }
229 
230  template <class Filter>
232  {
233  if (this == &a_rhs) {
234  return *this;
235  }
236 
237  Locker lhsLocker(_lock);
238  Clear();
239 
240  {
241  Locker rhsLocker(a_rhs._lock);
242  _regs = a_rhs._regs;
243  _eventName = a_rhs._eventName;
244  }
245 
247  if (auto policy = vm ? vm->GetObjectHandlePolicy() : nullptr) {
248  for (auto& reg : _regs) {
249  for (auto& handle : reg.second) {
250  policy->PersistHandle(handle);
251  }
252  }
253  }
254 
255  return *this;
256  }
257 
258  template <class Filter>
260  {
261  if (this == &a_rhs) {
262  return *this;
263  }
264 
265  Locker lhsLocker(_lock);
266  Locker rhsLocker(a_rhs._lock);
267 
268  Clear();
269 
270  _eventName = a_rhs._eventName;
271 
272  _regs = std::move(a_rhs._regs);
273  a_rhs._regs.clear();
274 
275  return *this;
276  }
277 
278  template <class Filter>
280  {
281  assert(a_form);
282  return Register(a_form, std::move(a_filter), static_cast<RE::VMTypeID>(a_form->GetFormType()));
283  }
284 
285  template <class Filter>
287  {
288  assert(a_alias);
289  return Register(a_alias, std::move(a_filter), a_alias->GetVMTypeID());
290  }
291 
292  template <class Filter>
293  bool EventFilter<Filter>::RegistrationMapBase::Register(const RE::ActiveEffect* a_activeEffect, Filter a_filter)
294  {
295  assert(a_activeEffect);
296  return Register(a_activeEffect, std::move(a_filter), RE::ActiveEffect::VMTYPEID);
297  }
298 
299  template <class Filter>
301  {
302  assert(a_form);
303  return Unregister(a_form, std::move(a_filter), static_cast<RE::VMTypeID>(a_form->GetFormType()));
304  }
305 
306  template <class Filter>
308  {
309  assert(a_alias);
310  return Unregister(a_alias, std::move(a_filter), a_alias->GetVMTypeID());
311  }
312 
313  template <class Filter>
314  bool EventFilter<Filter>::RegistrationMapBase::Unregister(const RE::ActiveEffect* a_activeEffect, Filter a_filter)
315  {
316  assert(a_activeEffect);
317  return Unregister(a_activeEffect, std::move(a_filter), RE::ActiveEffect::VMTYPEID);
318  }
319 
320  template <class Filter>
322  {
323  assert(a_form);
324  UnregisterAll(a_form, static_cast<RE::VMTypeID>(a_form->GetFormType()));
325  }
326 
327  template <class Filter>
329  {
330  assert(a_alias);
331  UnregisterAll(a_alias, a_alias->GetVMTypeID());
332  }
333 
334  template <class Filter>
336  {
337  assert(a_activeEffect);
338  UnregisterAll(a_activeEffect, RE::ActiveEffect::VMTYPEID);
339  }
340 
341  template <class Filter>
343  {
345  auto policy = vm ? vm->GetObjectHandlePolicy() : nullptr;
346  if (!policy) {
347  log::error("Failed to get handle policy!");
348  return;
349  }
350 
351  Locker locker(_lock);
352  for (auto& reg : _regs) {
353  if (auto result = reg.second.erase(a_handle); result != 0) {
354  policy->ReleaseHandle(a_handle);
355  }
356  }
357  }
358 
359  template <class Filter>
361  {
363  auto policy = vm ? vm->GetObjectHandlePolicy() : nullptr;
364  Locker locker(_lock);
365  if (policy) {
366  for (auto& reg : _regs) {
367  for (auto& handle : reg.second) {
368  policy->ReleaseHandle(handle);
369  }
370  }
371  }
372  _regs.clear();
373  }
374 
375  template <class Filter>
376  bool EventFilter<Filter>::RegistrationMapBase::Save(SerializationInterface* a_intfc, std::uint32_t a_type, std::uint32_t a_version)
377  {
378  assert(a_intfc);
379  if (!a_intfc->OpenRecord(a_type, a_version)) {
380  log::error("Failed to open record!");
381  return false;
382  }
383 
384  return Save(a_intfc);
385  }
386 
387  template <class Filter>
389  {
390  if constexpr (std::is_same_v<std::string, Filter>) {
391  std::size_t length = a_filter.length() + 1;
392  if (!a_intfc->WriteRecordData(length) || !a_intfc->WriteRecordData(a_filter.c_str(), static_cast<std::uint32_t>(length))) {
393  return false;
394  }
395  return true;
396  } else {
397  return a_intfc->WriteRecordData(a_filter);
398  }
399  }
400 
401  template <class Filter>
403  {
404  assert(a_intfc);
405  Locker locker(_lock);
406 
407  // Reg count
408  const std::size_t numRegs = _regs.size();
409  if (!a_intfc->WriteRecordData(numRegs)) {
410  log::error("Failed to save reg count ({})!", numRegs);
411  return false;
412  }
413 
414  for (auto& reg : _regs) {
415  // filter
416  if (!SaveFilter(a_intfc, reg.first)) {
417  return false;
418  }
419  // Handle count
420  std::size_t numHandles = reg.second.size();
421  if (!a_intfc->WriteRecordData(numHandles)) {
422  log::error("Failed to save handle count ({})!", numHandles);
423  return false;
424  }
425  // Handle
426  for (auto& handle : reg.second) {
427  if (!a_intfc->WriteRecordData(handle)) {
428  log::error("Failed to save handle ({})", handle);
429  return false;
430  }
431  }
432  }
433 
434  return true;
435  }
436 
437  template <class Filter>
439  {
440  if constexpr (std::is_same_v<std::string, Filter>) {
441  std::size_t length = 0;
442  if (!a_intfc->ReadRecordData(length)) {
443  return false;
444  }
445  a_filter.reserve(length);
446  return a_intfc->ReadRecordData(a_filter.data(), static_cast<std::uint32_t>(length));
447  } else if constexpr (std::is_same_v<RE::FormID, Filter>) {
448  if (!a_intfc->ReadRecordData(a_filter)) {
449  return false;
450  }
451  return a_intfc->ResolveFormID(a_filter, a_filter);
452  } else {
453  return a_intfc->ReadRecordData(a_filter);
454  }
455  }
456 
457  template <class Filter>
459  {
460  assert(a_intfc);
461  std::size_t numRegs;
462  a_intfc->ReadRecordData(numRegs);
463 
464  Locker locker(_lock);
465  _regs.clear();
466 
467  Filter filter{};
468  // Handle count
469  std::size_t numHandles;
470  // Handle
471  RE::VMHandle handle;
472 
473  for (std::size_t i = 0; i < numRegs; ++i) {
474  if (!LoadFilter(a_intfc, filter)) {
475  return false;
476  }
477  a_intfc->ReadRecordData(numHandles);
478  for (std::size_t j = 0; j < numHandles; ++j) {
479  a_intfc->ReadRecordData(handle);
480  if (a_intfc->ResolveHandle(handle, handle)) {
481  _regs[filter].insert(handle);
482  }
483  }
484  }
485 
486  return true;
487  }
488 
489  template <class Filter>
491  {
492  Clear();
493  }
494 
495  template <class Filter>
496  bool EventFilter<Filter>::RegistrationMapBase::Register(const void* a_object, Filter a_filter, RE::VMTypeID a_typeID)
497  {
498  assert(a_object);
500  auto policy = vm ? vm->GetObjectHandlePolicy() : nullptr;
501  if (!policy) {
502  log::error("Failed to get handle policy!");
503  return false;
504  }
505 
506  const auto invalidHandle = policy->EmptyHandle();
507  auto handle = policy->GetHandleForObject(a_typeID, a_object);
508  if (handle == invalidHandle) {
509  log::error("Failed to create handle!");
510  return false;
511  }
512 
513  _lock.lock();
514  auto result = _regs[a_filter].insert(handle);
515  _lock.unlock();
516 
517  if (result.second) {
518  policy->PersistHandle(handle);
519  }
520 
521  return result.second;
522  }
523 
524  template <class Filter>
525  bool EventFilter<Filter>::RegistrationMapBase::Unregister(const void* a_object, Filter a_filter, RE::VMTypeID a_typeID)
526  {
527  assert(a_object);
529  auto policy = vm ? vm->GetObjectHandlePolicy() : nullptr;
530  if (!policy) {
531  log::error("Failed to get handle policy!");
532  return false;
533  }
534 
535  const auto invalidHandle = policy->EmptyHandle();
536  const auto handle = policy->GetHandleForObject(a_typeID, a_object);
537  if (handle == invalidHandle) {
538  log::error("Failed to create handle!");
539  return false;
540  }
541 
542  Locker locker(_lock);
543  if (auto it = _regs.find(a_filter); it != _regs.end()) {
544  if (auto result = it->second.erase(handle); result != 0) {
545  policy->ReleaseHandle(handle);
546  return true;
547  }
548  }
549 
550  return false;
551  }
552 
553  template <class Filter>
555  {
556  assert(a_object);
558  auto policy = vm ? vm->GetObjectHandlePolicy() : nullptr;
559  if (!policy) {
560  log::error("Failed to get handle policy!");
561  return;
562  }
563 
564  const auto invalidHandle = policy->EmptyHandle();
565  const auto handle = policy->GetHandleForObject(a_typeID, a_object);
566  if (handle == invalidHandle) {
567  log::error("Failed to create handle!");
568  return;
569  }
570 
571  Locker locker(_lock);
572  for (auto& reg : _regs) {
573  if (auto result = reg.second.erase(handle); result != 0) {
574  policy->ReleaseHandle(handle);
575  }
576  }
577  }
578  }
579 
580  template <class Filter, class... Args>
582 }
Definition: ActiveEffect.h:27
static constexpr auto VMTYPEID
Definition: ActiveEffect.h:31
Definition: BGSBaseAlias.h:12
VMTypeID GetVMTypeID() const
static VirtualMachine * GetSingleton()
Definition: TESForm.h:36
FormType GetFormType() const noexcept
Definition: TESForm.h:290
Definition: RegistrationMap.h:25
bool Load(SerializationInterface *a_intfc)
Definition: RegistrationMap.h:458
RegistrationMapBase & operator=(const RegistrationMapBase &a_rhs)
Definition: RegistrationMap.h:231
bool LoadFilter(SerializationInterface *a_intfc, Filter &a_filter)
Definition: RegistrationMap.h:438
bool Unregister(const RE::TESForm *a_form, Filter a_filter)
Definition: RegistrationMap.h:300
void Revert(SerializationInterface *)
Definition: RegistrationMap.h:490
~RegistrationMapBase()
Definition: RegistrationMap.h:218
std::string _eventName
Definition: RegistrationMap.h:64
std::lock_guard< Lock > Locker
Definition: RegistrationMap.h:54
Lock _lock
Definition: RegistrationMap.h:65
std::map< Filter, std::set< RE::VMHandle > > _regs
Definition: RegistrationMap.h:63
bool Register(const RE::TESForm *a_form, Filter a_filter)
Definition: RegistrationMap.h:279
bool SaveFilter(SerializationInterface *a_intfc, Filter a_filter)
Definition: RegistrationMap.h:388
void Clear()
Definition: RegistrationMap.h:360
std::recursive_mutex Lock
Definition: RegistrationMap.h:53
void UnregisterAll(const RE::TESForm *a_form)
Definition: RegistrationMap.h:321
bool Save(SerializationInterface *a_intfc, std::uint32_t a_type, std::uint32_t a_version)
Definition: RegistrationMap.h:376
RegistrationMap & operator=(const RegistrationMap &)=default
void QueueEvent(Filter a_filter)
Definition: RegistrationMap.h:168
RegistrationMap(const RegistrationMap &)=default
RegistrationMap & operator=(RegistrationMap &&)=default
void SendEvent(Filter a_filter)
Definition: RegistrationMap.h:154
RegistrationMap(const std::string_view &a_eventName)
Definition: RegistrationMap.h:145
Definition: RegistrationMap.h:69
Definition: RegistrationMap.h:22
Definition: Interfaces.h:82
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
constexpr REL::ID Save(static_cast< std::uint64_t >(34818))
auto make_tuple(T1 &&a_first, T2 &&a_second)
Definition: BSTTuple.h:187
std::uint32_t VMTypeID
Definition: BSCoreTypes.h:9
std::uint64_t VMHandle
Definition: BSCoreTypes.h:7
BSScript::IFunctionArguments * MakeFunctionArguments(Args &&... a_args)
Definition: FunctionArguments.h:80
VMArg(T &&) -> VMArg< T >
string(const CharT(&)[N]) -> string< CharT, N - 1 >
Definition: API.h:14
typename Impl::EventFilter< Filter >::template RegistrationMap< void, Args... > RegistrationMap
Definition: RegistrationMap.h:581
const TaskInterface * GetTaskInterface() noexcept
Definition: EffectArchetypes.h:65
Definition: RegistrationTraits.h:40