CommonLibVR
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 args = RE::MakeFunctionArguments(std::forward<Args>(a_args)...);
104  vm->SendEvent(handle, eventName, args);
105  }
106  }
107  }
108  }
109 
110  inline void QueueEvent(Filter a_filter, Args... a_args)
111  {
112  std::tuple args(VMArg(std::forward<Args>(a_args))...);
113  auto task = GetTaskInterface();
114  assert(task);
115  if (task) {
116  task->AddTask([a_filter, args, this]() mutable {
117  SendEvent_Tuple(std::move(a_filter), std::move(args), index_sequence_for_tuple<decltype(args)>{});
118  });
119  }
120  }
121 
122  private:
123  template <class Tuple, std::size_t... I>
124  inline void SendEvent_Tuple(Filter a_filter, Tuple&& a_tuple, std::index_sequence<I...>)
125  {
126  SendEvent(a_filter, std::get<I>(std::forward<Tuple>(a_tuple)).Unpack()...);
127  }
128  };
129 
130  template <>
132  {
133  private:
134  using super = RegistrationMapBase;
135 
136  public:
137  RegistrationMap() = delete;
138  RegistrationMap(const RegistrationMap&) = default;
140 
141  inline RegistrationMap(const std::string_view& a_eventName) :
142  super(a_eventName)
143  {}
144 
145  ~RegistrationMap() = default;
146 
149 
150  inline void SendEvent(Filter a_filter)
151  {
152  RE::BSFixedString eventName(this->_eventName);
153 
155  if (auto it = this->_regs.find(a_filter); it != this->_regs.end()) {
156  for (auto& handle : it->second) {
157  auto args = RE::MakeFunctionArguments();
158  vm->SendEvent(handle, eventName, args);
159  }
160  }
161  }
162  }
163 
164  inline void QueueEvent(Filter a_filter)
165  {
166  auto task = GetTaskInterface();
167  assert(task);
168  task->AddTask([a_filter, this]() {
169  SendEvent(std::move(a_filter));
170  });
171  }
172  };
173  };
174 
175  template <class Filter>
177  _regs(),
178  _eventName(a_eventName),
179  _lock()
180  {}
181 
182  template <class Filter>
184  _regs(),
185  _eventName(a_rhs._eventName),
186  _lock()
187  {
188  a_rhs._lock.lock();
189  _regs = a_rhs._regs;
190  a_rhs._lock.unlock();
191 
193  if (auto policy = vm ? vm->GetObjectHandlePolicy() : nullptr) {
194  for (auto& reg : _regs) {
195  for (auto& handle : reg.second) {
196  policy->PersistHandle(handle);
197  }
198  }
199  }
200  }
201 
202  template <class Filter>
204  _regs(),
205  _eventName(a_rhs._eventName),
206  _lock()
207  {
208  Locker locker(a_rhs._lock);
209  _regs = std::move(a_rhs._regs);
210  a_rhs._regs.clear();
211  }
212 
213  template <class Filter>
215  {
217  if (auto policy = vm ? vm->GetObjectHandlePolicy() : nullptr) {
218  for (auto& reg : _regs) {
219  for (auto& handle : reg.second) {
220  policy->ReleaseHandle(handle);
221  }
222  }
223  }
224  }
225 
226  template <class Filter>
228  {
229  if (this == &a_rhs) {
230  return *this;
231  }
232 
233  Locker lhsLocker(_lock);
234  Clear();
235 
236  {
237  Locker rhsLocker(a_rhs._lock);
238  _regs = a_rhs._regs;
239  _eventName = a_rhs._eventName;
240  }
241 
243  if (auto policy = vm ? vm->GetObjectHandlePolicy() : nullptr) {
244  for (auto& reg : _regs) {
245  for (auto& handle : reg.second) {
246  policy->PersistHandle(handle);
247  }
248  }
249  }
250 
251  return *this;
252  }
253 
254  template <class Filter>
256  {
257  if (this == &a_rhs) {
258  return *this;
259  }
260 
261  Locker lhsLocker(_lock);
262  Locker rhsLocker(a_rhs._lock);
263 
264  Clear();
265 
266  _eventName = a_rhs._eventName;
267 
268  _regs = std::move(a_rhs._regs);
269  a_rhs._regs.clear();
270 
271  return *this;
272  }
273 
274  template <class Filter>
276  {
277  assert(a_form);
278  return Register(a_form, std::move(a_filter), static_cast<RE::VMTypeID>(a_form->GetFormType()));
279  }
280 
281  template <class Filter>
283  {
284  assert(a_alias);
285  return Register(a_alias, std::move(a_filter), a_alias->GetVMTypeID());
286  }
287 
288  template <class Filter>
289  bool EventFilter<Filter>::RegistrationMapBase::Register(const RE::ActiveEffect* a_activeEffect, Filter a_filter)
290  {
291  assert(a_activeEffect);
292  return Register(a_activeEffect, std::move(a_filter), RE::ActiveEffect::VMTYPEID);
293  }
294 
295  template <class Filter>
297  {
298  assert(a_form);
299  return Unregister(a_form, std::move(a_filter), static_cast<RE::VMTypeID>(a_form->GetFormType()));
300  }
301 
302  template <class Filter>
304  {
305  assert(a_alias);
306  return Unregister(a_alias, std::move(a_filter), a_alias->GetVMTypeID());
307  }
308 
309  template <class Filter>
310  bool EventFilter<Filter>::RegistrationMapBase::Unregister(const RE::ActiveEffect* a_activeEffect, Filter a_filter)
311  {
312  assert(a_activeEffect);
313  return Unregister(a_activeEffect, std::move(a_filter), RE::ActiveEffect::VMTYPEID);
314  }
315 
316  template <class Filter>
318  {
319  assert(a_form);
320  UnregisterAll(a_form, static_cast<RE::VMTypeID>(a_form->GetFormType()));
321  }
322 
323  template <class Filter>
325  {
326  assert(a_alias);
327  UnregisterAll(a_alias, a_alias->GetVMTypeID());
328  }
329 
330  template <class Filter>
332  {
333  assert(a_activeEffect);
334  UnregisterAll(a_activeEffect, RE::ActiveEffect::VMTYPEID);
335  }
336 
337  template <class Filter>
339  {
341  auto policy = vm ? vm->GetObjectHandlePolicy() : nullptr;
342  if (!policy) {
343  log::error("Failed to get handle policy!");
344  return;
345  }
346 
347  Locker locker(_lock);
348  for (auto& reg : _regs) {
349  if (auto result = reg.second.erase(a_handle); result != 0) {
350  policy->ReleaseHandle(a_handle);
351  }
352  }
353  }
354 
355  template <class Filter>
357  {
359  auto policy = vm ? vm->GetObjectHandlePolicy() : nullptr;
360  Locker locker(_lock);
361  if (policy) {
362  for (auto& reg : _regs) {
363  for (auto& handle : reg.second) {
364  policy->ReleaseHandle(handle);
365  }
366  }
367  }
368  _regs.clear();
369  }
370 
371  template <class Filter>
372  bool EventFilter<Filter>::RegistrationMapBase::Save(SerializationInterface* a_intfc, std::uint32_t a_type, std::uint32_t a_version)
373  {
374  assert(a_intfc);
375  if (!a_intfc->OpenRecord(a_type, a_version)) {
376  log::error("Failed to open record!");
377  return false;
378  }
379 
380  return Save(a_intfc);
381  }
382 
383  template <class Filter>
385  {
386  if constexpr (std::is_same_v<std::string, Filter>) {
387  std::size_t length = a_filter.length() + 1;
388  if (!a_intfc->WriteRecordData(length) || !a_intfc->WriteRecordData(a_filter.c_str(), static_cast<std::uint32_t>(length))) {
389  return false;
390  }
391  return true;
392  } else {
393  return a_intfc->WriteRecordData(a_filter);
394  }
395  }
396 
397  template <class Filter>
399  {
400  assert(a_intfc);
401  Locker locker(_lock);
402 
403  // Reg count
404  const std::size_t numRegs = _regs.size();
405  if (!a_intfc->WriteRecordData(numRegs)) {
406  log::error("Failed to save reg count ({})!", numRegs);
407  return false;
408  }
409 
410  for (auto& reg : _regs) {
411  // filter
412  if (!SaveFilter(a_intfc, reg.first)) {
413  return false;
414  }
415  // Handle count
416  std::size_t numHandles = reg.second.size();
417  if (!a_intfc->WriteRecordData(numHandles)) {
418  log::error("Failed to save handle count ({})!", numHandles);
419  return false;
420  }
421  // Handle
422  for (auto& handle : reg.second) {
423  if (!a_intfc->WriteRecordData(handle)) {
424  log::error("Failed to save handle ({})", handle);
425  return false;
426  }
427  }
428  }
429 
430  return true;
431  }
432 
433  template <class Filter>
435  {
436  if constexpr (std::is_same_v<std::string, Filter>) {
437  std::size_t length = 0;
438  if (!a_intfc->ReadRecordData(length)) {
439  return false;
440  }
441  a_filter.reserve(length);
442  return a_intfc->ReadRecordData(a_filter.data(), static_cast<std::uint32_t>(length));
443  } else if constexpr (std::is_same_v<RE::FormID, Filter>) {
444  if (!a_intfc->ReadRecordData(a_filter)) {
445  return false;
446  }
447  return a_intfc->ResolveFormID(a_filter, a_filter);
448  } else {
449  return a_intfc->ReadRecordData(a_filter);
450  }
451  }
452 
453  template <class Filter>
455  {
456  assert(a_intfc);
457  std::size_t numRegs;
458  a_intfc->ReadRecordData(numRegs);
459 
460  Locker locker(_lock);
461  _regs.clear();
462 
463  Filter filter{};
464  // Handle count
465  std::size_t numHandles;
466  // Handle
467  RE::VMHandle handle;
468 
469  for (std::size_t i = 0; i < numRegs; ++i) {
470  if (!LoadFilter(a_intfc, filter)) {
471  return false;
472  }
473  a_intfc->ReadRecordData(numHandles);
474  for (std::size_t j = 0; j < numHandles; ++j) {
475  a_intfc->ReadRecordData(handle);
476  if (a_intfc->ResolveHandle(handle, handle)) {
477  _regs[filter].insert(handle);
478  }
479  }
480  }
481 
482  return true;
483  }
484 
485  template <class Filter>
487  {
488  Clear();
489  }
490 
491  template <class Filter>
492  bool EventFilter<Filter>::RegistrationMapBase::Register(const void* a_object, Filter a_filter, RE::VMTypeID a_typeID)
493  {
494  assert(a_object);
496  auto policy = vm ? vm->GetObjectHandlePolicy() : nullptr;
497  if (!policy) {
498  log::error("Failed to get handle policy!");
499  return false;
500  }
501 
502  const auto invalidHandle = policy->EmptyHandle();
503  auto handle = policy->GetHandleForObject(a_typeID, a_object);
504  if (handle == invalidHandle) {
505  log::error("Failed to create handle!");
506  return false;
507  }
508 
509  _lock.lock();
510  auto result = _regs[a_filter].insert(handle);
511  _lock.unlock();
512 
513  if (result.second) {
514  policy->PersistHandle(handle);
515  }
516 
517  return result.second;
518  }
519 
520  template <class Filter>
521  bool EventFilter<Filter>::RegistrationMapBase::Unregister(const void* a_object, Filter a_filter, RE::VMTypeID a_typeID)
522  {
523  assert(a_object);
525  auto policy = vm ? vm->GetObjectHandlePolicy() : nullptr;
526  if (!policy) {
527  log::error("Failed to get handle policy!");
528  return false;
529  }
530 
531  const auto invalidHandle = policy->EmptyHandle();
532  const auto handle = policy->GetHandleForObject(a_typeID, a_object);
533  if (handle == invalidHandle) {
534  log::error("Failed to create handle!");
535  return false;
536  }
537 
538  Locker locker(_lock);
539  if (auto it = _regs.find(a_filter); it != _regs.end()) {
540  if (auto result = it->second.erase(handle); result != 0) {
541  policy->ReleaseHandle(handle);
542  return true;
543  }
544  }
545 
546  return false;
547  }
548 
549  template <class Filter>
551  {
552  assert(a_object);
554  auto policy = vm ? vm->GetObjectHandlePolicy() : nullptr;
555  if (!policy) {
556  log::error("Failed to get handle policy!");
557  return;
558  }
559 
560  const auto invalidHandle = policy->EmptyHandle();
561  const auto handle = policy->GetHandleForObject(a_typeID, a_object);
562  if (handle == invalidHandle) {
563  log::error("Failed to create handle!");
564  return;
565  }
566 
567  Locker locker(_lock);
568  for (auto& reg : _regs) {
569  if (auto result = reg.second.erase(handle); result != 0) {
570  policy->ReleaseHandle(handle);
571  }
572  }
573  }
574  }
575 
576  template <class Filter, class... Args>
578 }
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:40
FormType GetFormType() const noexcept
Definition: TESForm.h:294
Definition: RegistrationMap.h:25
bool Load(SerializationInterface *a_intfc)
Definition: RegistrationMap.h:454
RegistrationMapBase & operator=(const RegistrationMapBase &a_rhs)
Definition: RegistrationMap.h:227
bool LoadFilter(SerializationInterface *a_intfc, Filter &a_filter)
Definition: RegistrationMap.h:434
bool Unregister(const RE::TESForm *a_form, Filter a_filter)
Definition: RegistrationMap.h:296
void Revert(SerializationInterface *)
Definition: RegistrationMap.h:486
~RegistrationMapBase()
Definition: RegistrationMap.h:214
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:275
bool SaveFilter(SerializationInterface *a_intfc, Filter a_filter)
Definition: RegistrationMap.h:384
void Clear()
Definition: RegistrationMap.h:356
std::recursive_mutex Lock
Definition: RegistrationMap.h:53
void UnregisterAll(const RE::TESForm *a_form)
Definition: RegistrationMap.h:317
bool Save(SerializationInterface *a_intfc, std::uint32_t a_type, std::uint32_t a_version)
Definition: RegistrationMap.h:372
RegistrationMap & operator=(const RegistrationMap &)=default
void QueueEvent(Filter a_filter)
Definition: RegistrationMap.h:164
RegistrationMap(const RegistrationMap &)=default
RegistrationMap & operator=(RegistrationMap &&)=default
void SendEvent(Filter a_filter)
Definition: RegistrationMap.h:150
RegistrationMap(const std::string_view &a_eventName)
Definition: RegistrationMap.h:141
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))
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:577
const TaskInterface * GetTaskInterface() noexcept
Definition: EffectArchetypes.h:65
Definition: RegistrationTraits.h:40