diff --git a/CMakeLists.txt b/CMakeLists.txt index 2229ea1e..e6678b8a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -150,6 +150,7 @@ add_library(lego1 SHARED LEGO1/mxstring.cpp LEGO1/mxstringvariable.cpp LEGO1/mxthread.cpp + LEGO1/mxticklemanager.cpp LEGO1/mxtimer.cpp LEGO1/mxtransitionmanager.cpp LEGO1/mxunknown100dc6b0.cpp diff --git a/ISLE/isleapp.cpp b/ISLE/isleapp.cpp index a1836e8c..8d175dfa 100644 --- a/ISLE/isleapp.cpp +++ b/ISLE/isleapp.cpp @@ -121,7 +121,7 @@ BOOL IsleApp::SetupLegoOmni() BOOL failure = Lego()->Create(MxOmniCreateParam(mediaPath, (struct HWND__ *) m_windowHandle, m_videoParam, MxOmniCreateFlags())) == FAILURE; if (!failure) { VariableTable()->SetVariable("ACTOR_01", ""); - TickleManager()->vtable1c(VideoManager(), 10); + TickleManager()->SetClientTickleInterval(VideoManager(), 10); result = TRUE; } diff --git a/LEGO1/mxnotificationmanager.cpp b/LEGO1/mxnotificationmanager.cpp index b7d001aa..fe48c7c2 100644 --- a/LEGO1/mxnotificationmanager.cpp +++ b/LEGO1/mxnotificationmanager.cpp @@ -41,7 +41,7 @@ MxNotificationManager::~MxNotificationManager() delete m_queue; m_queue = NULL; - TickleManager()->Unregister(this); + TickleManager()->UnregisterClient(this); } // OFFSET: LEGO1 0x100ac800 @@ -80,7 +80,7 @@ MxResult MxNotificationManager::Create(MxS32 p_unk1, MxS32 p_unk2) result = FAILURE; } else { - TickleManager()->Register(this, 10); + TickleManager()->RegisterClient(this, 10); } return result; diff --git a/LEGO1/mxticklemanager.cpp b/LEGO1/mxticklemanager.cpp new file mode 100644 index 00000000..38cdd37f --- /dev/null +++ b/LEGO1/mxticklemanager.cpp @@ -0,0 +1,113 @@ +#include "mxomni.h" +#include "mxticklemanager.h" +#include "mxtimer.h" +#include "mxtypes.h" + +#include "decomp.h" + +#define TICKLE_MANAGER_FLAG_DESTROY 0x1 + +DECOMP_SIZE_ASSERT(MxTickleClient, 0x10); +DECOMP_SIZE_ASSERT(MxTickleManager, 0x14); + +// OFFSET: LEGO1 0x100bdd10 +MxTickleClient::MxTickleClient(MxCore *p_client, MxTime p_interval) +{ + m_flags = 0; + m_client = p_client; + m_interval = p_interval; + m_lastUpdateTime = -m_interval; +} + +// OFFSET: LEGO1 0x100bdd30 +MxTickleManager::~MxTickleManager() +{ + while (m_clients.size() != 0) { + MxTickleClient *client = m_clients.front(); + m_clients.pop_front(); + delete client; + } +} + +// TODO: Match. +// OFFSET: LEGO1 0x100bdde0 +MxResult MxTickleManager::Tickle() +{ + MxTime time = Timer()->GetTime(); + + MxTickleClientPtrList::iterator it = m_clients.begin(); + + while (it != m_clients.end()) { + MxTickleClient *client = *it; + if ((client->GetFlags() & TICKLE_MANAGER_FLAG_DESTROY) == 0) { + if (client->GetLastUpdateTime() >= time) + client->SetLastUpdateTime(-client->GetTickleInterval()); + + if ((client->GetTickleInterval() + client->GetLastUpdateTime()) < time) { + client->GetClient()->Tickle(); + client->SetLastUpdateTime(time); + } + + it++; + } + else { + m_clients.erase(it++); + delete client; + } + } + + return SUCCESS; +} + +// OFFSET: LEGO1 0x100bde80 +void MxTickleManager::RegisterClient(MxCore *p_client, MxTime p_interval) +{ + MxTime interval = GetClientTickleInterval(p_client); + if (interval == TICKLE_MANAGER_NOT_FOUND) { + MxTickleClient *client = new MxTickleClient(p_client, p_interval); + if (client != NULL) + m_clients.push_back(client); + } +} + +// OFFSET: LEGO1 0x100bdf60 +void MxTickleManager::UnregisterClient(MxCore *p_client) +{ + MxTickleClientPtrList::iterator it = m_clients.begin(); + while (it != m_clients.end()) { + MxTickleClient *client = *it; + if (client->GetClient() == p_client) { + client->SetFlags(client->GetFlags() | TICKLE_MANAGER_FLAG_DESTROY); + return; + } + + it++; + } +} + +// OFFSET: LEGO1 0x100bdfa0 +void MxTickleManager::SetClientTickleInterval(MxCore *p_client, MxTime p_interval) +{ + for (MxTickleClientPtrList::iterator it = m_clients.begin(); it != m_clients.end(); it++) { + MxTickleClient *client = *it; + if ((client->GetClient() == p_client) && ((client->GetFlags() & TICKLE_MANAGER_FLAG_DESTROY) == 0)) { + client->SetTickleInterval(p_interval); + return; + } + } +} + +// OFFSET: LEGO1 0x100be000 +MxTime MxTickleManager::GetClientTickleInterval(MxCore *p_client) +{ + MxTickleClientPtrList::iterator it = m_clients.begin(); + while (it != m_clients.end()) { + MxTickleClient *client = *it; + if ((client->GetClient() == p_client) && ((client->GetFlags() & TICKLE_MANAGER_FLAG_DESTROY) == 0)) + return client->GetTickleInterval(); + + it++; + } + + return TICKLE_MANAGER_NOT_FOUND; +} diff --git a/LEGO1/mxticklemanager.h b/LEGO1/mxticklemanager.h index 3d976d5a..103d3721 100644 --- a/LEGO1/mxticklemanager.h +++ b/LEGO1/mxticklemanager.h @@ -2,20 +2,77 @@ #define MXTICKLEMANAGER_H #include "mxcore.h" +#include "mxtypes.h" + +#include "compat.h" + +class MxTickleClient +{ +public: + MxTickleClient(MxCore *p_client, MxTime p_interval); + + inline MxCore *GetClient() const + { + return m_client; + } + + inline MxTime GetTickleInterval() const + { + return m_interval; + } + + inline MxTime GetLastUpdateTime() const + { + return m_lastUpdateTime; + } + + inline MxU16 GetFlags() const + { + return m_flags; + } + + inline void SetTickleInterval(MxTime p_interval) + { + m_interval = p_interval; + } + + inline void SetLastUpdateTime(MxTime p_lastUpdateTime) + { + m_lastUpdateTime = p_lastUpdateTime; + } + + inline void SetFlags(MxU16 flags) + { + m_flags = flags; + } + +private: + MxCore *m_client; // 0x0 + MxTime m_interval; // 0x4 + MxTime m_lastUpdateTime; // 0x8 + MxU16 m_flags; // 0xc +}; + +class MxTickleClientPtrList : public List +{}; // VTABLE 0x100d86d8 class MxTickleManager : public MxCore { public: - virtual ~MxTickleManager(); + inline MxTickleManager() : MxCore(), m_clients() {} + virtual ~MxTickleManager(); // vtable+0x0 (scalar deleting destructor) - virtual MxLong Tickle(); - virtual const char *ClassName() const; - virtual MxBool IsA(const char *name) const; - 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(); + virtual MxResult Tickle(); // vtable+0x8 + virtual void RegisterClient(MxCore *p_client, MxTime p_interval); // vtable+0x14 + virtual void UnregisterClient(MxCore *p_client); // vtable+0x18 + virtual void SetClientTickleInterval(MxCore *p_client, MxTime p_interval); // vtable+0x1c + virtual MxTime GetClientTickleInterval(MxCore *p_client); // vtable+0x20 + +private: + MxTickleClientPtrList m_clients; // 0x8 }; +#define TICKLE_MANAGER_NOT_FOUND 0x80000000 + #endif // MXTICKLEMANAGER_H diff --git a/LEGO1/mxtypes.h b/LEGO1/mxtypes.h index d17ac09a..1f0aaac7 100644 --- a/LEGO1/mxtypes.h +++ b/LEGO1/mxtypes.h @@ -25,6 +25,8 @@ typedef int MxLong; typedef unsigned int MxULong; #endif +typedef MxS32 MxTime; + typedef MxLong MxResult; const MxResult SUCCESS = 0; const MxResult FAILURE = -1;