#ifndef D_SND_UTIL_H #define D_SND_UTIL_H #include "common.h" #include "egg/core/eggDisposer.h" // This setup is only inferred. d/snd uses it all over the place. // This works for dSndPlayerMgr_c, which has a vtable of its own but the Disposer at offset 0. // It also works for the factory at 0x80399c20, which calls a base class ctor, // an inline ctor, and has the Disposer at offset 0x18 template struct SndMgrDisposer : public EGG::Disposer { virtual ~SndMgrDisposer(); static T *create(); static void remove(); }; template SndMgrDisposer::~SndMgrDisposer() { if (this == T::sDisposer) { remove(); } } template T *SndMgrDisposer::create() { if (T::sInstance == nullptr) { T::sInstance = new T(); T::sDisposer = T::sInstance->GetDisposer(); } return T::sInstance; } template void SndMgrDisposer::remove() { T::sInstance = nullptr; T::sDisposer = nullptr; } #define SND_DISPOSER_FORWARD_DECL(class_name) \ class class_name; \ extern template class SndMgrDisposer; #define SND_DISPOSER_DEFINE(class_name) \ template class SndMgrDisposer; \ class_name *class_name::sInstance; \ SndMgrDisposer *class_name::sDisposer; #define SND_DISPOSER_MEMBERS(class_name) \ public: \ SndMgrDisposer *GetDisposer() { \ return &mDisposer; \ } \ \ static class_name *GetInstance() { \ return sInstance; \ } \ \ static void create() { \ SndMgrDisposer::create(); \ } \ \ static class_name *sInstance; \ static SndMgrDisposer *sDisposer; \ \ private: \ SndMgrDisposer mDisposer; #endif