From 4a50a9ff56f9edf3f2848b3439fda64c3c609e43 Mon Sep 17 00:00:00 2001 From: pewpew Date: Sun, 16 Jul 2023 01:43:08 -0500 Subject: [PATCH] MxNotificationManager and MxParam initial work. (#78) * MxNotificationManager initial work. * Add .swp files to .gitignore. * Checkpoint before anything too crazy with param * Cleanup and add MxParam. * Checkpoint for everything except MxNotificationManager::Register. * Add int return type to MxCore::GetId instead of relying on implicit function nonsense. * Add stlcompat.h so this can still be built on modern compilers, fix affected type size asserts. * Switch to Mx types * Add BUILD_COMPAT option to CMake so the project can still be built with modern compilers. * Change vtable14 and vtable18 to Register and Unregister in MxTickleManager. * Remove last unsigned int reference to id type. * Remove MxList, use one inherited class per type. Improves accuracy again. * Address compiler compatibility code review. * Match MxNotificationManager::Register. * Re-enable MxNotificationManager DECOMP_SIZE_ASSERT. --- .gitignore | 1 + CMakeLists.txt | 1 + LEGO1/compat.h | 13 +++ LEGO1/mxcore.h | 7 +- LEGO1/mxnotificationmanager.cpp | 140 ++++++++++++++++++++++++++++++-- LEGO1/mxnotificationmanager.h | 52 +++++++++++- LEGO1/mxparam.cpp | 11 +++ LEGO1/mxparam.h | 33 ++++++++ LEGO1/mxticklemanager.h | 4 +- 9 files changed, 250 insertions(+), 12 deletions(-) create mode 100644 LEGO1/mxparam.cpp create mode 100644 LEGO1/mxparam.h diff --git a/.gitignore b/.gitignore index 14ad2717..402fb660 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ Release/ ISLE.EXE LEGO1.DLL build/ +*.swp diff --git a/CMakeLists.txt b/CMakeLists.txt index eafee9ff..fa4de1e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -135,6 +135,7 @@ add_library(lego1 SHARED LEGO1/mxomnicreateparam.cpp LEGO1/mxomnicreateparambase.cpp LEGO1/mxpalette.cpp + LEGO1/mxparam.cpp LEGO1/mxpresenter.cpp LEGO1/mxscheduler.cpp LEGO1/mxsemaphore.cpp diff --git a/LEGO1/compat.h b/LEGO1/compat.h index 7d76dfd0..6248259b 100644 --- a/LEGO1/compat.h +++ b/LEGO1/compat.h @@ -11,6 +11,19 @@ #define COMPAT_CONST #endif +#define MSVC420_VERSION 1020 + +// STL compatibility. +#if defined(_MSC_VER) && _MSC_VER <= MSVC420_VERSION +#include +#else +#include +#include +using namespace std; +template +using List = list; +#endif + // We use `override` so newer compilers can tell us our vtables are valid, // however this keyword was added in C++11, so we define it as empty for // compatibility with older compilers. diff --git a/LEGO1/mxcore.h b/LEGO1/mxcore.h index 9fb3e689..8ca7c421 100644 --- a/LEGO1/mxcore.h +++ b/LEGO1/mxcore.h @@ -31,8 +31,13 @@ public: return !strcmp(name, MxCore::ClassName()); } + inline MxU32 GetId() + { + return m_id; + } + private: - unsigned int m_id; + MxU32 m_id; }; diff --git a/LEGO1/mxnotificationmanager.cpp b/LEGO1/mxnotificationmanager.cpp index 472c87b5..593572bb 100644 --- a/LEGO1/mxnotificationmanager.cpp +++ b/LEGO1/mxnotificationmanager.cpp @@ -1,15 +1,143 @@ +#include "legoomni.h" +#include "mxautolocker.h" +#include "mxcore.h" #include "mxnotificationmanager.h" +#include "mxparam.h" +#include "mxtypes.h" -// OFFSET: LEGO1 0x100ac450 STUB +#include "compat.h" +#include "decomp.h" + +DECOMP_SIZE_ASSERT(MxNotification, 0x8); +DECOMP_SIZE_ASSERT(MxNotificationManager, 0x40); + +// OFFSET: LEGO1 0x100ac220 +MxNotification::MxNotification(MxCore *p_target, MxParam *p_param) +{ + m_target = p_target; + m_param = p_param->Clone(); +} + +// OFFSET: LEGO1 0x100ac240 +MxNotification::~MxNotification() +{ + delete m_param; +} + +// OFFSET: LEGO1 0x100ac250 +MxNotificationManager::MxNotificationManager() : MxCore(), m_lock(), m_listenerIds() +{ + m_unk2c = 0; + m_queue = NULL; + m_active = TRUE; + m_sendList = NULL; +} + +// OFFSET: LEGO1 0x100ac450 MxNotificationManager::~MxNotificationManager() +{ + MxAutoLocker lock(&m_lock); + Tickle(); + delete m_queue; + m_queue = NULL; + + TickleManager()->Unregister(this); +} + +// OFFSET: LEGO1 0x100ac800 +MxResult MxNotificationManager::Tickle() +{ + m_sendList = new MxNotificationPtrList(); + if (m_sendList == NULL) { + return FAILURE; + } + else { + { + MxAutoLocker lock(&m_lock); + swap(m_queue, m_sendList); + } + + while (m_sendList->size() != 0) { + MxNotification *notif = m_sendList->front(); + m_sendList->pop_front(); + notif->GetTarget()->Notify(*notif->GetParam()); + delete notif; + } + + delete m_sendList; + m_sendList = NULL; + return SUCCESS; + } +} + +// OFFSET: LEGO1 0x100ac600 +MxResult MxNotificationManager::Create(MxS32 p_unk1, MxS32 p_unk2) +{ + MxResult result = SUCCESS; + m_queue = new MxNotificationPtrList(); + + if (m_queue == NULL) { + result = FAILURE; + } + else { + TickleManager()->Register(this, 10); + } + + return result; +} + +// OFFSET: LEGO1 0x100acd20 +void MxNotificationManager::Register(MxCore *p_listener) +{ + MxAutoLocker lock(&m_lock); + + MxIdList::iterator it = find(m_listenerIds.begin(), m_listenerIds.end(), p_listener->GetId()); + if (it != m_listenerIds.end()) + return; + + m_listenerIds.push_back(p_listener->GetId()); +} + +// OFFSET: LEGO1 0x100acdf0 +void MxNotificationManager::Unregister(MxCore *p_listener) +{ + MxAutoLocker lock(&m_lock); + + MxIdList::iterator it = find(m_listenerIds.begin(), m_listenerIds.end(), p_listener->GetId()); + + if (it != m_listenerIds.end()) { + m_listenerIds.erase(it); + FlushPending(p_listener); + } +} + +// OFFSET: LEGO1 0x100ac990 STUB +void MxNotificationManager::FlushPending(MxCore *p_listener) { // TODO } -// OFFSET: LEGO1 0x100ac800 STUB -MxLong MxNotificationManager::Tickle() +// OFFSET: LEGO1 0x100ac6c0 +MxResult MxNotificationManager::Send(MxCore *p_listener, MxParam *p_param) { - // TODO + MxAutoLocker lock(&m_lock); - return 0; -} \ No newline at end of file + if (m_active == FALSE) { + return FAILURE; + } + else { + MxIdList::iterator it = find(m_listenerIds.begin(), m_listenerIds.end(), p_listener->GetId()); + if (it == m_listenerIds.end()) { + return FAILURE; + } + else { + MxNotification *notif = new MxNotification(p_listener, p_param); + if (notif != NULL) { + m_queue->push_back(notif); + return SUCCESS; + } + } + } + + return FAILURE; +} diff --git a/LEGO1/mxnotificationmanager.h b/LEGO1/mxnotificationmanager.h index 86cb4f00..e313510b 100644 --- a/LEGO1/mxnotificationmanager.h +++ b/LEGO1/mxnotificationmanager.h @@ -2,16 +2,62 @@ #define MXNOTIFICATIONMANAGER_H #include "mxcore.h" +#include "mxcriticalsection.h" +#include "mxtypes.h" + +#include "compat.h" + +class MxNotification +{ +public: + MxNotification(MxCore *p_target, MxParam *p_param); + ~MxNotification(); + + inline MxCore *GetTarget() + { + return m_target; + } + + inline MxParam *GetParam() + { + return m_param; + } + +private: + MxCore *m_target; // 0x0 + MxParam *m_param; // 0x4 +}; + +class MxIdList : public List +{}; + +class MxNotificationPtrList : public List +{}; // VTABLE 0x100dc078 class MxNotificationManager : public MxCore { +private: + MxNotificationPtrList *m_queue; // 0x8 + MxNotificationPtrList *m_sendList; // 0xc + MxCriticalSection m_lock; // 0x10 + MxS32 m_unk2c; // 0x2c + MxIdList m_listenerIds; // 0x30 + MxBool m_active; // 0x3c + public: - virtual ~MxNotificationManager(); // vtable+0x0 + MxNotificationManager(); + virtual ~MxNotificationManager(); // vtable+0x0 (scalar deleting destructor) - virtual MxLong Tickle(); // vtable+0x8 + virtual MxResult Tickle(); // vtable+0x8 + // TODO: Where does this method come from? + virtual MxResult Create(MxS32 p_unk1, MxS32 p_unk2); // vtable+0x14 + void Register(MxCore *p_listener); + void Unregister(MxCore *p_listener); + MxResult Send(MxCore *p_listener, MxParam *p_param); - // 0x10: MxCriticalSection +private: + void FlushPending(MxCore *p_listener); }; #endif // MXNOTIFICATIONMANAGER_H diff --git a/LEGO1/mxparam.cpp b/LEGO1/mxparam.cpp new file mode 100644 index 00000000..d7bb36b2 --- /dev/null +++ b/LEGO1/mxparam.cpp @@ -0,0 +1,11 @@ +#include "mxparam.h" + +#include "decomp.h" + +DECOMP_SIZE_ASSERT(MxParam, 0xc); + +// OFFSET: LEGO1 0x10010390 +MxParam* MxParam::Clone() +{ + return new MxParam(m_type, m_sender); +} diff --git a/LEGO1/mxparam.h b/LEGO1/mxparam.h new file mode 100644 index 00000000..c4150ff7 --- /dev/null +++ b/LEGO1/mxparam.h @@ -0,0 +1,33 @@ +#ifndef MXPARAM_H +#define MXPARAM_H + +#include "mxomnicreateparambase.h" +#include "mxtypes.h" + +class MxCore; + +// VTABLE 0x100d56e0 +class MxParam : public MxOmniCreateParamBase +{ +public: + inline MxParam(MxS32 p_type, MxCore *p_sender) : MxOmniCreateParamBase(), m_type(p_type), m_sender(p_sender){} + + virtual ~MxParam(){}; // vtable+0x0 (scalar deleting destructor) + virtual MxParam *Clone(); // vtable+0x4 + + inline MxS32 GetType() const + { + return m_type; + } + + inline MxCore *GetSender() const + { + return m_sender; + } + +private: + MxS32 m_type; // 0x4 + MxCore *m_sender; // 0x8 +}; + +#endif // MXPARAM_H diff --git a/LEGO1/mxticklemanager.h b/LEGO1/mxticklemanager.h index 60f2f14d..3d976d5a 100644 --- a/LEGO1/mxticklemanager.h +++ b/LEGO1/mxticklemanager.h @@ -12,8 +12,8 @@ public: virtual MxLong Tickle(); virtual const char *ClassName() const; virtual MxBool IsA(const char *name) const; - virtual void vtable14(); - virtual void vtable18(); + virtual void Register(MxCore *p_listener, int p_milliseconds); + virtual void Unregister(MxCore *p_listener); virtual void vtable1c(void *v, int p); virtual void vtable20(); };