From e22ad6031caf955c9b494c4d0f3470531d38f197 Mon Sep 17 00:00:00 2001 From: Misha <106913236+MishaProductions@users.noreply.github.com> Date: Fri, 22 Dec 2023 14:03:55 -0500 Subject: [PATCH 01/13] More MxDiskStreamController functions (#350) * push code * remove accidently commited code * Update mxstreamcontroller.cpp * implement MxDiskStreamController::VTable0x30 * implement MxDiskStreamController::VTable0x28 * Update mxdiskstreamcontroller.cpp * FUN_100c7d10 & FUN_100c8360 * fix format * Match MxDiskStreamController::FUN_100c7980 * Improve match of MxDiskStreamController::VTable0x28 * Match MxDiskStreamController::FUN_100c7d10 * Minor style fix --------- Co-authored-by: Christian Semmler --- LEGO1/mxdiskstreamcontroller.cpp | 193 +++++++++++++++++++++++++++++-- LEGO1/mxdiskstreamcontroller.h | 10 +- LEGO1/mxdiskstreamprovider.cpp | 10 +- LEGO1/mxdiskstreamprovider.h | 5 +- LEGO1/mxdsbuffer.cpp | 6 +- LEGO1/mxdsbuffer.h | 8 +- LEGO1/mxdsstreamingaction.h | 3 + LEGO1/mxramstreamcontroller.cpp | 2 +- LEGO1/mxramstreamprovider.cpp | 2 +- LEGO1/mxramstreamprovider.h | 2 +- LEGO1/mxstreamcontroller.cpp | 5 +- LEGO1/mxstreamcontroller.h | 4 +- LEGO1/mxstreamlist.h | 12 ++ LEGO1/mxstreamprovider.h | 2 +- 14 files changed, 243 insertions(+), 21 deletions(-) diff --git a/LEGO1/mxdiskstreamcontroller.cpp b/LEGO1/mxdiskstreamcontroller.cpp index 489d1b74..9bb8fdf6 100644 --- a/LEGO1/mxdiskstreamcontroller.cpp +++ b/LEGO1/mxdiskstreamcontroller.cpp @@ -58,18 +58,134 @@ MxResult MxDiskStreamController::VTable0x34(undefined4) return FAILURE; } -// STUB: LEGO1 0x100c7ac0 -MxResult MxDiskStreamController::VTable0x28() +// FUNCTION: LEGO1 0x100c7980 +void MxDiskStreamController::FUN_100c7980() { - // TODO - return FAILURE; + MxDSBuffer* buffer; + MxDSStreamingAction* action = NULL; + + { + MxAutoLocker lock(&this->m_criticalSection); + + if (m_unk0x3c.size() && m_unk0x8c < m_provider->GetStreamBuffersNum()) { + buffer = new MxDSBuffer(); + + if (buffer->AllocateBuffer(m_provider->GetFileSize(), MxDSBufferType_Chunk) != SUCCESS) { + if (buffer) + delete buffer; + return; + } + + action = VTable0x28(); + if (!action) { + if (buffer) + delete buffer; + return; + } + + action->SetUnknowna0(buffer); + m_unk0x8c++; + } + } + + if (action) { + ((MxDiskStreamProvider*) m_provider)->FUN_100d1780(action); + } } -// STUB: LEGO1 0x100c7c00 +// FUNCTION: LEGO1 0x100c7ac0 +MxDSStreamingAction* MxDiskStreamController::VTable0x28() +{ + MxAutoLocker lock(&this->m_criticalSection); + MxDSAction* oldAction; + MxDSStreamingAction* result = NULL; + MxU32 filesize = m_provider->GetFileSize(); + + if (m_unk0x3c.PopFront(oldAction)) { + result = new MxDSStreamingAction((MxDSStreamingAction&) *oldAction); + if (result) { + MxU32 offset = result->GetBufferOffset() + filesize; + ((MxDSStreamingAction*) oldAction)->SetUnknown94(offset); + ((MxDSStreamingAction*) oldAction)->SetBufferOffset(offset); + m_unk0x3c.push_back(result); + } + } + + return result; +} + +// FUNCTION: LEGO1 0x100c7c00 MxResult MxDiskStreamController::VTable0x30(MxDSAction* p_action) +{ + MxAutoLocker lock(&this->m_criticalSection); + MxResult result = MxStreamController::VTable0x30(p_action); + + MxDSStreamingAction* item; + while (TRUE) { + item = (MxDSStreamingAction*) m_list0x90.Find(p_action, TRUE); + if (item == NULL) { + break; + } + FUN_100c7cb0(item); + } + + while (TRUE) { + item = (MxDSStreamingAction*) m_list0x64.Find(p_action, TRUE); + if (item == NULL) { + break; + } + FUN_100c7cb0(item); + } + + return result; +} + +// FUNCTION: LEGO1 0x100c7cb0 +void MxDiskStreamController::FUN_100c7cb0(MxDSStreamingAction* p_action) +{ + if (p_action->GetUnknowna0()) { + FUN_100c7ce0(p_action->GetUnknowna0()); + } + p_action->SetUnknowna0(NULL); + delete p_action; +} + +// FUNCTION: LEGO1 0x100c7ce0 +void MxDiskStreamController::FUN_100c7ce0(MxDSBuffer* p_buffer) +{ + switch (p_buffer->GetMode()) { + case MxDSBufferType_Chunk: + m_unk0x8c--; + case MxDSBufferType_Allocate: + case MxDSBufferType_Unknown: + delete p_buffer; + break; + } +} + +// FUNCTION: LEGO1 0x100c7d10 +MxResult MxDiskStreamController::FUN_100c7d10() +{ + MxAutoLocker lock(&this->m_criticalSection); + MxDSStreamingAction* action = FUN_100c7db0(); + + if (!action) + return FAILURE; + + if (FUN_100c8360(action) != SUCCESS) { + VTable0x24(action); + FUN_100c7cb0(action); + return FAILURE; + } + + return SUCCESS; +} + +// STUB: LEGO1 0x100c7db0 +MxDSStreamingAction* MxDiskStreamController::FUN_100c7db0() { // TODO - return FAILURE; + return NULL; } // FUNCTION: LEGO1 0x100c7f40 @@ -115,6 +231,37 @@ MxResult MxDiskStreamController::VTable0x24(MxDSAction* p_action) return FAILURE; } +// FUNCTION: LEGO1 0x100c8360 +MxResult MxDiskStreamController::FUN_100c8360(MxDSStreamingAction* p_action) +{ + MxAutoLocker lock(&this->m_criticalSection); + MxDSBuffer* buffer = p_action->GetUnknowna0(); + MxDSStreamingAction* action2 = (MxDSStreamingAction*) m_list0x90.Find(p_action, TRUE); + buffer->FUN_100c6f80(p_action->GetUnknown94() - p_action->GetBufferOffset()); + buffer->FUN_100c67b0(this, p_action, &action2); + + if (buffer->GetRefCount()) { + p_action->SetUnknowna0(NULL); + InsertToList74(buffer); + } + + if (action2) { + if (action2->GetUnknowna0() == NULL) { + FUN_100c7cb0(action2); + } + else { + if (action2->GetObjectId() == -1) { + action2->SetObjectId(p_action->GetObjectId()); + } + + m_list0x90.push_back(action2); + } + } + + FUN_100c7cb0(p_action); + return SUCCESS; +} + // FUNCTION: LEGO1 0x100c84a0 void MxDiskStreamController::InsertToList74(MxDSBuffer* p_buffer) { @@ -122,9 +269,39 @@ void MxDiskStreamController::InsertToList74(MxDSBuffer* p_buffer) m_list0x74.push_back(p_buffer); } -// STUB: LEGO1 0x100c8640 -MxResult MxDiskStreamController::Tickle() +// STUB: LEGO1 0x100c8540 +void MxDiskStreamController::FUN_100c8540() { // TODO +} + +// FUNCTION: LEGO1 0x100c8640 +MxResult MxDiskStreamController::Tickle() +{ + if (m_unk0xc4) { + FUN_100c7d10(); + } + + FUN_100c8540(); + FUN_100c8720(); + + if (m_unk0x70) { + FUN_100c7980(); + } + return SUCCESS; } + +// FUNCTION: LEGO1 0x100c8720 +void MxDiskStreamController::FUN_100c8720() +{ + MxAutoLocker lock(&this->m_critical9c); + + MxDSStreamingAction* action; + while (m_list0xb8.size() != 0) { + action = (MxDSStreamingAction*) m_list0xb8.front(); + m_list0xb8.pop_front(); + + FUN_100c7cb0(action); + } +} diff --git a/LEGO1/mxdiskstreamcontroller.h b/LEGO1/mxdiskstreamcontroller.h index 373e29a1..1d1cf7d5 100644 --- a/LEGO1/mxdiskstreamcontroller.h +++ b/LEGO1/mxdiskstreamcontroller.h @@ -22,7 +22,7 @@ class MxDiskStreamController : public MxStreamController { virtual MxResult VTable0x18(undefined4, undefined4) override; // vtable+0x18 virtual MxResult VTable0x20(MxDSAction* p_action) override; // vtable+0x20 virtual MxResult VTable0x24(MxDSAction* p_action) override; // vtable+0x24 - virtual MxResult VTable0x28() override; // vtable+0x28 + virtual MxDSStreamingAction* VTable0x28() override; // vtable+0x28 virtual MxResult VTable0x30(MxDSAction* p_action) override; // vtable+0x30 virtual MxResult VTable0x34(undefined4); // vtable+0x34 @@ -50,8 +50,16 @@ class MxDiskStreamController : public MxStreamController { MxStreamListMxDSAction m_list0xb8; // 0xb8 undefined m_unk0xc4; // 0xc4 + void FUN_100c7cb0(MxDSStreamingAction* p_action); + void FUN_100c7ce0(MxDSBuffer* p_buffer); + MxResult FUN_100c7d10(); + void FUN_100c7980(); + MxDSStreamingAction* FUN_100c7db0(); void FUN_100c7f40(MxDSStreamingAction* p_streamingaction); + MxResult FUN_100c8360(MxDSStreamingAction* p_action); void InsertToList74(MxDSBuffer* p_buffer); + void FUN_100c8540(); + void FUN_100c8720(); }; // TEMPLATE: LEGO1 0x100c7330 diff --git a/LEGO1/mxdiskstreamprovider.cpp b/LEGO1/mxdiskstreamprovider.cpp index e4f8c2a1..dfdf8158 100644 --- a/LEGO1/mxdiskstreamprovider.cpp +++ b/LEGO1/mxdiskstreamprovider.cpp @@ -1,5 +1,6 @@ #include "mxdiskstreamprovider.h" +#include "mxdsbuffer.h" #include "mxomni.h" #include "mxstreamcontroller.h" #include "mxstring.h" @@ -87,6 +88,13 @@ MxResult MxDiskStreamProvider::WaitForWorkToComplete() return SUCCESS; } +// STUB: LEGO1 0x100d1780 +MxResult MxDiskStreamProvider::FUN_100d1780(MxDSStreamingAction* p_action) +{ + // TODO + return FAILURE; +} + // STUB: LEGO1 0x100d18f0 void MxDiskStreamProvider::PerformWork() { @@ -100,7 +108,7 @@ MxU32 MxDiskStreamProvider::GetFileSize() } // FUNCTION: LEGO1 0x100d1ea0 -MxU32 MxDiskStreamProvider::GetStreamBuffersNum() +MxS32 MxDiskStreamProvider::GetStreamBuffersNum() { return m_pFile->GetStreamBuffersNum(); } diff --git a/LEGO1/mxdiskstreamprovider.h b/LEGO1/mxdiskstreamprovider.h index 20b78f81..b5a2e9ff 100644 --- a/LEGO1/mxdiskstreamprovider.h +++ b/LEGO1/mxdiskstreamprovider.h @@ -10,6 +10,7 @@ #include "mxthread.h" class MxDiskStreamProvider; +class MxDSStreamingAction; // VTABLE: LEGO1 0x100dd130 class MxDiskStreamProviderThread : public MxThread { @@ -43,12 +44,12 @@ class MxDiskStreamProvider : public MxStreamProvider { } MxResult WaitForWorkToComplete(); - + MxResult FUN_100d1780(MxDSStreamingAction* p_action); void PerformWork(); virtual MxResult SetResourceToGet(MxStreamController* p_resource) override; // vtable+0x14 virtual MxU32 GetFileSize() override; // vtable+0x18 - virtual MxU32 GetStreamBuffersNum() override; // vtable+0x1c + virtual MxS32 GetStreamBuffersNum() override; // vtable+0x1c virtual void VTable0x20(undefined4) override; // vtable+0x20 virtual MxU32 GetLengthInDWords() override; // vtable+0x24 virtual MxU32* GetBufferForDWords() override; // vtable+0x28 diff --git a/LEGO1/mxdsbuffer.cpp b/LEGO1/mxdsbuffer.cpp index 501cefd6..634afc6e 100644 --- a/LEGO1/mxdsbuffer.cpp +++ b/LEGO1/mxdsbuffer.cpp @@ -123,7 +123,11 @@ MxResult MxDSBuffer::SetBufferPointer(MxU32* p_buffer, MxU32 p_size) } // STUB: LEGO1 0x100c67b0 -MxResult MxDSBuffer::FUN_100c67b0(MxStreamController* p_controller, MxDSAction* p_action, undefined4*) +MxResult MxDSBuffer::FUN_100c67b0( + MxStreamController* p_controller, + MxDSAction* p_action, + MxDSStreamingAction** p_streamingAction +) { // TODO STUB return FAILURE; diff --git a/LEGO1/mxdsbuffer.h b/LEGO1/mxdsbuffer.h index af9b466f..d8532a55 100644 --- a/LEGO1/mxdsbuffer.h +++ b/LEGO1/mxdsbuffer.h @@ -33,7 +33,11 @@ class MxDSBuffer : public MxCore { MxResult AllocateBuffer(MxU32 p_bufferSize, MxDSBufferType p_mode); MxResult SetBufferPointer(MxU32* p_buffer, MxU32 p_size); - MxResult FUN_100c67b0(MxStreamController* p_controller, MxDSAction* p_action, undefined4*); + MxResult FUN_100c67b0( + MxStreamController* p_controller, + MxDSAction* p_action, + MxDSStreamingAction** p_streamingAction + ); MxResult CreateObject( MxStreamController* p_controller, MxU32* p_data, @@ -55,6 +59,8 @@ class MxDSBuffer : public MxCore { inline MxU8* GetBuffer() { return m_pBuffer; } inline MxU32 GetWriteOffset() { return m_writeOffset; } + inline MxU16 GetRefCount() { return m_refcount; } + inline MxDSBufferType GetMode() { return m_mode; } private: MxU8* m_pBuffer; // 0x08 diff --git a/LEGO1/mxdsstreamingaction.h b/LEGO1/mxdsstreamingaction.h index 49c2d74f..5b764c8f 100644 --- a/LEGO1/mxdsstreamingaction.h +++ b/LEGO1/mxdsstreamingaction.h @@ -35,7 +35,10 @@ class MxDSStreamingAction : public MxDSAction { inline MxDSBuffer* GetUnknowna0() { return m_unk0xa0; } inline MxDSBuffer* GetUnknowna4() { return m_unk0xa4; } inline MxDSAction* GetInternalAction() { return m_internalAction; } + inline MxU32 GetBufferOffset() { return m_bufferOffset; } + inline void SetUnknown94(MxU32 p_unk0x94) { m_unk0x94 = p_unk0x94; } inline void SetUnknowna0(MxDSBuffer* p_unk0xa0) { m_unk0xa0 = p_unk0xa0; } + inline void SetBufferOffset(MxU32 p_bufferOffset) { m_bufferOffset = p_bufferOffset; } private: MxU32 m_unk0x94; diff --git a/LEGO1/mxramstreamcontroller.cpp b/LEGO1/mxramstreamcontroller.cpp index 24c5a79d..930ca4ce 100644 --- a/LEGO1/mxramstreamcontroller.cpp +++ b/LEGO1/mxramstreamcontroller.cpp @@ -84,7 +84,7 @@ MxResult MxRAMStreamController::DeserializeObject(MxDSStreamingAction& p_action) { MxAutoLocker locker(&m_criticalSection); MxResult result; - undefined4 value = 0; + MxDSStreamingAction* value = NULL; do { m_buffer.FUN_100c6f80(p_action.GetUnknown94()); result = m_buffer.FUN_100c67b0(this, &p_action, &value); diff --git a/LEGO1/mxramstreamprovider.cpp b/LEGO1/mxramstreamprovider.cpp index 016bcc8d..9c52c20e 100644 --- a/LEGO1/mxramstreamprovider.cpp +++ b/LEGO1/mxramstreamprovider.cpp @@ -23,7 +23,7 @@ MxU32 MxRAMStreamProvider::GetFileSize() } // FUNCTION: LEGO1 0x100d0940 -MxU32 MxRAMStreamProvider::GetStreamBuffersNum() +MxS32 MxRAMStreamProvider::GetStreamBuffersNum() { return 1; } diff --git a/LEGO1/mxramstreamprovider.h b/LEGO1/mxramstreamprovider.h index 70402a8f..112f6b71 100644 --- a/LEGO1/mxramstreamprovider.h +++ b/LEGO1/mxramstreamprovider.h @@ -24,7 +24,7 @@ class MxRAMStreamProvider : public MxStreamProvider { virtual MxResult SetResourceToGet(MxStreamController* p_resource) override; // vtable+0x14 virtual MxU32 GetFileSize() override; // vtable+0x18 - virtual MxU32 GetStreamBuffersNum() override; // vtable+0x1c + virtual MxS32 GetStreamBuffersNum() override; // vtable+0x1c virtual MxU32 GetLengthInDWords() override; // vtable+0x24 virtual MxU32* GetBufferForDWords() override; // vtable+0x28 diff --git a/LEGO1/mxstreamcontroller.cpp b/LEGO1/mxstreamcontroller.cpp index e882898b..c6aa8996 100644 --- a/LEGO1/mxstreamcontroller.cpp +++ b/LEGO1/mxstreamcontroller.cpp @@ -2,6 +2,7 @@ #include "legoomni.h" #include "mxautolocker.h" +#include "mxdsstreamingaction.h" #include "mxnextactiondatastart.h" #include "mxstreamchunk.h" @@ -21,9 +22,9 @@ MxResult MxStreamController::VTable0x1c(undefined4, undefined4) } // FUNCTION: LEGO1 0x100b9420 -MxResult MxStreamController::VTable0x28() +MxDSStreamingAction* MxStreamController::VTable0x28() { - return SUCCESS; + return NULL; } // FUNCTION: LEGO1 0x100c0b90 diff --git a/LEGO1/mxstreamcontroller.h b/LEGO1/mxstreamcontroller.h index 50259226..468782b1 100644 --- a/LEGO1/mxstreamcontroller.h +++ b/LEGO1/mxstreamcontroller.h @@ -11,6 +11,8 @@ #include "mxstreamlist.h" #include "mxstreamprovider.h" +class MxDSStreamingAction; + // VTABLE: LEGO1 0x100dc968 // SIZE 0x64 class MxStreamController : public MxCore { @@ -37,7 +39,7 @@ class MxStreamController : public MxCore { virtual MxResult VTable0x1c(undefined4, undefined4); // vtable+0x1c virtual MxResult VTable0x20(MxDSAction* p_action); // vtable+0x20 virtual MxResult VTable0x24(MxDSAction* p_action); // vtable+0x24 - virtual MxResult VTable0x28(); // vtable+0x28 + virtual MxDSStreamingAction* VTable0x28(); // vtable+0x28 virtual MxResult VTable0x2c(MxDSAction* p_action, MxU32 p_bufferval); // vtable+0x2c virtual MxResult VTable0x30(MxDSAction* p_action); // vtable+0x30 diff --git a/LEGO1/mxstreamlist.h b/LEGO1/mxstreamlist.h index 2a9e7351..abe48779 100644 --- a/LEGO1/mxstreamlist.h +++ b/LEGO1/mxstreamlist.h @@ -13,6 +13,18 @@ class MxStreamList : public list {}; class MxStreamListMxDSAction : public MxStreamList { public: MxDSAction* Find(MxDSAction* p_action, MxBool p_delete); + + // Could move this to MxStreamList + MxBool PopFront(MxDSAction*& p_obj) + { + if (!empty()) { + p_obj = front(); + pop_front(); + return TRUE; + } + + return FALSE; + } }; // SIZE 0xc diff --git a/LEGO1/mxstreamprovider.h b/LEGO1/mxstreamprovider.h index d32d2ab4..66f75be2 100644 --- a/LEGO1/mxstreamprovider.h +++ b/LEGO1/mxstreamprovider.h @@ -27,7 +27,7 @@ class MxStreamProvider : public MxCore { virtual MxResult SetResourceToGet(MxStreamController* p_resource); // vtable+0x14 virtual MxU32 GetFileSize() = 0; // vtable+0x18 - virtual MxU32 GetStreamBuffersNum() = 0; // vtable+0x1c + virtual MxS32 GetStreamBuffersNum() = 0; // vtable+0x1c virtual void VTable0x20(undefined4); // vtable+0x20 virtual MxU32 GetLengthInDWords() = 0; // vtable+0x24 virtual MxU32* GetBufferForDWords() = 0; // vtable+0x28 From cdc7b43db2f943d605cb4450a6464330c7e2a4a1 Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Fri, 22 Dec 2023 14:05:42 -0500 Subject: [PATCH 02/13] Implement/match MxLoopingSmkPresenter (#351) * Implement/match MxLoopingSmkPresenter * Rename variable * Rename variable --- LEGO1/mxdsmediaaction.h | 1 + LEGO1/mxlist.h | 22 +++++++ LEGO1/mxloopingsmkpresenter.cpp | 107 +++++++++++++++++++++++++++++++- LEGO1/mxloopingsmkpresenter.h | 12 +++- LEGO1/mxsmkpresenter.cpp | 22 ++++--- LEGO1/mxsmkpresenter.h | 6 +- 6 files changed, 156 insertions(+), 14 deletions(-) diff --git a/LEGO1/mxdsmediaaction.h b/LEGO1/mxdsmediaaction.h index 6cddd8c1..72fcf036 100644 --- a/LEGO1/mxdsmediaaction.h +++ b/LEGO1/mxdsmediaaction.h @@ -33,6 +33,7 @@ class MxDSMediaAction : public MxDSAction { void CopyMediaSrcPath(const char* p_mediaSrcPath); + inline MxS32 GetFramesPerSecond() const { return this->m_framesPerSecond; } inline MxS32 GetMediaFormat() const { return this->m_mediaFormat; } inline MxS32 GetPaletteManagement() const { return this->m_paletteManagement; } inline MxLong GetSustainTime() const { return this->m_sustainTime; } diff --git a/LEGO1/mxlist.h b/LEGO1/mxlist.h index afdeadf4..11afe695 100644 --- a/LEGO1/mxlist.h +++ b/LEGO1/mxlist.h @@ -92,6 +92,8 @@ class MxListCursor : public MxCore { void Destroy(); MxBool Next(T& p_obj); MxBool Current(T& p_obj); + MxBool First(T& p_obj); + MxBool Last(T& p_obj); MxBool Advance(); MxBool HasMatch() { return m_match != NULL; } void SetValue(T p_obj); @@ -229,6 +231,26 @@ inline MxBool MxListCursor::Current(T& p_obj) return m_match != NULL; } +template +inline MxBool MxListCursor::First(T& p_obj) +{ + m_match = m_list->m_first; + if (m_match) + p_obj = m_match->GetValue(); + + return m_match != NULL; +} + +template +inline MxBool MxListCursor::Last(T& p_obj) +{ + m_match = m_list->m_last; + if (m_match) + p_obj = m_match->GetValue(); + + return m_match != NULL; +} + template inline MxBool MxListCursor::Advance() { diff --git a/LEGO1/mxloopingsmkpresenter.cpp b/LEGO1/mxloopingsmkpresenter.cpp index 26cf3d43..7f9a5851 100644 --- a/LEGO1/mxloopingsmkpresenter.cpp +++ b/LEGO1/mxloopingsmkpresenter.cpp @@ -1,6 +1,7 @@ #include "mxloopingsmkpresenter.h" -#include "decomp.h" +#include "mxautolocker.h" +#include "mxdsmediaaction.h" DECOMP_SIZE_ASSERT(MxLoopingSmkPresenter, 0x724); @@ -19,12 +20,112 @@ MxLoopingSmkPresenter::~MxLoopingSmkPresenter() // FUNCTION: LEGO1 0x100b49b0 void MxLoopingSmkPresenter::Init() { - this->m_unk0x720 = 0; + this->m_elapsedDuration = 0; this->m_flags &= 0xfd; this->m_flags &= 0xfb; } -// STUB: LEGO1 0x100b49d0 +// FUNCTION: LEGO1 0x100b49d0 void MxLoopingSmkPresenter::Destroy(MxBool p_fromDestructor) { + m_criticalSection.Enter(); + Init(); + m_criticalSection.Leave(); + + if (!p_fromDestructor) + MxSmkPresenter::Destroy(); +} + +// FUNCTION: LEGO1 0x100b4a00 +void MxLoopingSmkPresenter::VTable0x88() +{ + if (m_mxSmack.m_smackTag.Frames == m_currentFrame) { + m_currentFrame = 0; + // TODO: struct incorrect, Palette at wrong offset? + memset(&m_mxSmack.m_smackTag.Palette[4], 0, sizeof(m_mxSmack.m_smackTag.Palette)); + } +} + +// FUNCTION: LEGO1 0x100b4a30 +void MxLoopingSmkPresenter::NextFrame() +{ + MxStreamChunk* chunk = NextChunk(); + + if (chunk->GetFlags() & MxStreamChunk::Flag_Bit2) { + m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState; + m_currentTickleState = TickleState_Repeating; + } + else { + LoadFrame(chunk); + AppendChunk(chunk); + m_elapsedDuration += 1000 / ((MxDSMediaAction*) m_action)->GetFramesPerSecond(); + } + + m_subscriber->FUN_100b8390(chunk); +} + +// FUNCTION: LEGO1 0x100b4a90 +void MxLoopingSmkPresenter::VTable0x8c() +{ + if (m_action->GetDuration() < m_elapsedDuration) { + m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState; + m_currentTickleState = TickleState_unk5; + } + else { + MxStreamChunk* chunk; + m_cursor->Current(chunk); + LoadFrame(chunk); + m_elapsedDuration += 1000 / ((MxDSMediaAction*) m_action)->GetFramesPerSecond(); + } +} + +// FUNCTION: LEGO1 0x100b4b00 +void MxLoopingSmkPresenter::RepeatingTickle() +{ + for (MxS16 i = 0; i < m_unk0x5c; i++) { + if (!m_cursor->HasMatch()) { + MxStreamChunk* chunk; + MxStreamChunkListCursor cursor(m_chunks); + + cursor.Last(chunk); + MxLong time = chunk->GetTime(); + + cursor.First(chunk); + + time -= chunk->GetTime(); + time += 1000 / ((MxDSMediaAction*) m_action)->GetFramesPerSecond(); + + cursor.Reset(); + while (cursor.Next(chunk)) + chunk->SetTime(chunk->GetTime() + time); + + m_cursor->Advance(); + } + + MxStreamChunk* chunk; + m_cursor->Current(chunk); + + if (m_action->GetElapsedTime() < chunk->GetTime()) + break; + + VTable0x8c(); + + m_cursor->Next(chunk); + + if (m_currentTickleState != TickleState_Repeating) + break; + } +} + +// FUNCTION: LEGO1 0x100b4cd0 +MxResult MxLoopingSmkPresenter::AddToManager() +{ + MxAutoLocker lock(&m_criticalSection); + return MxSmkPresenter::AddToManager(); +} + +// FUNCTION: LEGO1 0x100b4d40 +void MxLoopingSmkPresenter::Destroy() +{ + Destroy(FALSE); } diff --git a/LEGO1/mxloopingsmkpresenter.h b/LEGO1/mxloopingsmkpresenter.h index b2eba1ca..2f20676e 100644 --- a/LEGO1/mxloopingsmkpresenter.h +++ b/LEGO1/mxloopingsmkpresenter.h @@ -18,11 +18,21 @@ class MxLoopingSmkPresenter : public MxSmkPresenter { return "MxLoopingSmkPresenter"; } + virtual void RepeatingTickle() override; // vtable+0x24 + virtual MxResult AddToManager() override; // vtable+0x34 + virtual void Destroy() override; // vtable+0x38 + virtual void NextFrame() override; // vtable+0x64 + virtual void VTable0x88() override; // vtable+0x88 + virtual void VTable0x8c(); // vtable+0x8c + private: void Init(); void Destroy(MxBool p_fromDestructor); - undefined4 m_unk0x720; + MxLong m_elapsedDuration; // 0x720 }; +// SYNTHETIC: LEGO1 0x100b4930 +// MxLoopingSmkPresenter::`scalar deleting destructor' + #endif // MXLOOPINGSMKPRESENTER_H diff --git a/LEGO1/mxsmkpresenter.cpp b/LEGO1/mxsmkpresenter.cpp index 442e59a7..709151c3 100644 --- a/LEGO1/mxsmkpresenter.cpp +++ b/LEGO1/mxsmkpresenter.cpp @@ -21,7 +21,7 @@ MxSmkPresenter::~MxSmkPresenter() // FUNCTION: LEGO1 0x100b38d0 void MxSmkPresenter::Init() { - m_unk0x71c = 0; + m_currentFrame = 0; memset(&m_mxSmack, 0, sizeof(m_mxSmack)); m_flags &= 0xfd; m_flags &= 0xfb; @@ -65,8 +65,8 @@ void MxSmkPresenter::LoadFrame(MxStreamChunk* p_chunk) MxU8* bitmapData = m_bitmap->GetBitmapData(); MxU8* chunkData = p_chunk->GetData(); - MxBool paletteChanged = m_mxSmack.m_frameTypes[m_unk0x71c] & 1; - m_unk0x71c++; + MxBool paletteChanged = m_mxSmack.m_frameTypes[m_currentFrame] & 1; + m_currentFrame++; VTable0x88(); MxRectList list(TRUE); @@ -90,13 +90,13 @@ void MxSmkPresenter::LoadFrame(MxStreamChunk* p_chunk) void MxSmkPresenter::VTable0x88() { if ((m_mxSmack.m_smackTag.SmackerType & 1) != 0) { - MxU32 und = (m_unk0x71c % m_mxSmack.m_smackTag.Frames); - if (1 < m_unk0x71c && und == 1) - m_unk0x71c = 1; + MxU32 und = (m_currentFrame % m_mxSmack.m_smackTag.Frames); + if (1 < m_currentFrame && und == 1) + m_currentFrame = 1; } else { - if (m_mxSmack.m_smackTag.Frames == m_unk0x71c) { - m_unk0x71c = 0; + if (m_mxSmack.m_smackTag.Frames == m_currentFrame) { + m_currentFrame = 0; // TODO: struct incorrect, Palette at wrong offset? memset(&m_mxSmack.m_smackTag.Palette[4], 0, sizeof(m_mxSmack.m_smackTag.Palette)); } @@ -111,6 +111,12 @@ void MxSmkPresenter::RealizePalette() delete palette; } +// FUNCTION: LEGO1 0x100b42f0 +MxResult MxSmkPresenter::AddToManager() +{ + return MxVideoPresenter::AddToManager(); +} + // FUNCTION: LEGO1 0x100b4300 void MxSmkPresenter::Destroy() { diff --git a/LEGO1/mxsmkpresenter.h b/LEGO1/mxsmkpresenter.h index c70894d7..95b6a201 100644 --- a/LEGO1/mxsmkpresenter.h +++ b/LEGO1/mxsmkpresenter.h @@ -25,6 +25,7 @@ class MxSmkPresenter : public MxVideoPresenter { return !strcmp(p_name, MxSmkPresenter::ClassName()) || MxVideoPresenter::IsA(p_name); } + virtual MxResult AddToManager() override; // vtable+0x34 virtual void Destroy() override; // vtable+0x38 virtual void LoadHeader(MxStreamChunk* p_chunk) override; // vtable+0x5c virtual void CreateBitmap() override; // vtable+0x60 @@ -36,8 +37,9 @@ class MxSmkPresenter : public MxVideoPresenter { void Init(); void Destroy(MxBool p_fromDestructor); - MxSmack m_mxSmack; // 0x64 - undefined4 m_unk0x71c; // 0x71c +protected: + MxSmack m_mxSmack; // 0x64 + MxU32 m_currentFrame; // 0x71c }; #endif // MXSMKPRESENTER_H From 2686643d20bd59c8d6d735788c53fb8831dedd4b Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Fri, 22 Dec 2023 13:57:23 -0500 Subject: [PATCH 03/13] Replace magic values with proper flag clearing --- LEGO1/mxflcpresenter.cpp | 4 ++-- LEGO1/mxloopingflcpresenter.cpp | 4 ++-- LEGO1/mxloopingsmkpresenter.cpp | 4 ++-- LEGO1/mxsmkpresenter.cpp | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/LEGO1/mxflcpresenter.cpp b/LEGO1/mxflcpresenter.cpp index 8c49505d..76cc7efe 100644 --- a/LEGO1/mxflcpresenter.cpp +++ b/LEGO1/mxflcpresenter.cpp @@ -12,8 +12,8 @@ DECOMP_SIZE_ASSERT(MxFlcPresenter, 0x68); MxFlcPresenter::MxFlcPresenter() { this->m_flicHeader = NULL; - this->m_flags &= 0xfd; - this->m_flags &= 0xfb; + this->m_flags &= ~Flag_Bit2; + this->m_flags &= ~Flag_Bit3; } // FUNCTION: LEGO1 0x100b3420 diff --git a/LEGO1/mxloopingflcpresenter.cpp b/LEGO1/mxloopingflcpresenter.cpp index 4a8b3ff1..cb4fd40b 100644 --- a/LEGO1/mxloopingflcpresenter.cpp +++ b/LEGO1/mxloopingflcpresenter.cpp @@ -20,8 +20,8 @@ MxLoopingFlcPresenter::~MxLoopingFlcPresenter() void MxLoopingFlcPresenter::Init() { this->m_unk0x68 = 0; - this->m_flags &= 0xfd; - this->m_flags &= 0xfb; + this->m_flags &= ~Flag_Bit2; + this->m_flags &= ~Flag_Bit3; } // STUB: LEGO1 0x100b4432 diff --git a/LEGO1/mxloopingsmkpresenter.cpp b/LEGO1/mxloopingsmkpresenter.cpp index 7f9a5851..b000c835 100644 --- a/LEGO1/mxloopingsmkpresenter.cpp +++ b/LEGO1/mxloopingsmkpresenter.cpp @@ -21,8 +21,8 @@ MxLoopingSmkPresenter::~MxLoopingSmkPresenter() void MxLoopingSmkPresenter::Init() { this->m_elapsedDuration = 0; - this->m_flags &= 0xfd; - this->m_flags &= 0xfb; + this->m_flags &= ~Flag_Bit2; + this->m_flags &= ~Flag_Bit3; } // FUNCTION: LEGO1 0x100b49d0 diff --git a/LEGO1/mxsmkpresenter.cpp b/LEGO1/mxsmkpresenter.cpp index 709151c3..17985fdd 100644 --- a/LEGO1/mxsmkpresenter.cpp +++ b/LEGO1/mxsmkpresenter.cpp @@ -23,8 +23,8 @@ void MxSmkPresenter::Init() { m_currentFrame = 0; memset(&m_mxSmack, 0, sizeof(m_mxSmack)); - m_flags &= 0xfd; - m_flags &= 0xfb; + m_flags &= ~Flag_Bit2; + m_flags &= ~Flag_Bit3; } // FUNCTION: LEGO1 0x100b3900 From f75bbf478efd340d3eebe66c3c9bc000c3cac786 Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Fri, 22 Dec 2023 14:10:20 -0500 Subject: [PATCH 04/13] Replace more magic values --- LEGO1/mxvideopresenter.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/LEGO1/mxvideopresenter.cpp b/LEGO1/mxvideopresenter.cpp index 259d8651..b1beb08e 100644 --- a/LEGO1/mxvideopresenter.cpp +++ b/LEGO1/mxvideopresenter.cpp @@ -188,16 +188,16 @@ void MxVideoPresenter::Init() m_unk0x5c = 1; m_unk0x58 = NULL; m_unk0x60 = -1; - m_flags = m_flags & 0xfe; + m_flags &= ~Flag_Bit1; if (MVideoManager() != NULL) { MVideoManager(); - m_flags = m_flags | 2; - m_flags = m_flags & 0xfb; + m_flags |= Flag_Bit2; + m_flags &= ~Flag_Bit3; } - m_flags = m_flags & 0xf7; - m_flags = m_flags & 0xef; + m_flags &= ~Flag_Bit4; + m_flags &= ~Flag_Bit5; } // FUNCTION: LEGO1 0x100b27b0 @@ -209,8 +209,8 @@ void MxVideoPresenter::Destroy(MxBool p_fromDestructor) if (m_unk0x58) { m_unk0x58->Release(); m_unk0x58 = NULL; - m_flags = m_flags & 0xfd; - m_flags = m_flags & 0xfb; + m_flags &= ~Flag_Bit2; + m_flags &= ~Flag_Bit3; } if (MVideoManager() && (m_alpha || m_bitmap)) { From b2c730e1df48e2b1fa0b7813b5170cfd65994b0f Mon Sep 17 00:00:00 2001 From: MS Date: Sat, 23 Dec 2023 08:05:07 -0500 Subject: [PATCH 05/13] Refactor WinePathConverter into PathResolver (#353) * Refactor WinePathConverter into PathResolver * Run pytest in CI --- .github/workflows/unittest.yml | 36 +++++++ tools/isledecomp/isledecomp/dir.py | 98 +++++++++++++------ tools/isledecomp/isledecomp/syminfo.py | 13 ++- .../tests/test_parser_statechange.py | 3 +- .../isledecomp/tests/test_path_resolver_nt.py | 32 ++++++ .../tests/test_path_resolver_posix.py | 69 +++++++++++++ tools/reccmp/reccmp.py | 8 +- 7 files changed, 215 insertions(+), 44 deletions(-) create mode 100644 .github/workflows/unittest.yml create mode 100644 tools/isledecomp/tests/test_path_resolver_nt.py create mode 100644 tools/isledecomp/tests/test_path_resolver_posix.py diff --git a/.github/workflows/unittest.yml b/.github/workflows/unittest.yml new file mode 100644 index 00000000..06446888 --- /dev/null +++ b/.github/workflows/unittest.yml @@ -0,0 +1,36 @@ +name: Unit Tests + +on: [push, pull_request] + +jobs: + pytest-win: + runs-on: windows-latest + + steps: + - uses: actions/checkout@v3 + + - name: Install python libraries + shell: bash + run: | + pip install pytest -r tools/requirements.txt + + - name: Run python unit tests (Windows) + shell: bash + run: | + pytest tools/isledecomp + + pytest-ubuntu: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Install python libraries + shell: bash + run: | + pip install pytest -r tools/requirements.txt + + - name: Run python unit tests (Ubuntu) + shell: bash + run: | + pytest tools/isledecomp diff --git a/tools/isledecomp/isledecomp/dir.py b/tools/isledecomp/isledecomp/dir.py index 3ee95a87..ca7e3fd5 100644 --- a/tools/isledecomp/isledecomp/dir.py +++ b/tools/isledecomp/isledecomp/dir.py @@ -1,43 +1,83 @@ import os import subprocess import sys +import pathlib from typing import Iterator -class WinePathConverter: - def __init__(self, unix_cwd): - self.unix_cwd = unix_cwd - self.win_cwd = self._call_winepath_unix2win(self.unix_cwd) +def winepath_win_to_unix(path: str) -> str: + return subprocess.check_output(["winepath", path], text=True).strip() - def get_wine_path(self, unix_fn: str) -> str: - if unix_fn.startswith("./"): - return self.win_cwd + "\\" + unix_fn[2:].replace("/", "\\") - if unix_fn.startswith(self.unix_cwd): - return ( - self.win_cwd - + "\\" - + unix_fn.removeprefix(self.unix_cwd).replace("/", "\\").lstrip("\\") + +def winepath_unix_to_win(path: str) -> str: + return subprocess.check_output(["winepath", "-w", path], text=True).strip() + + +class PathResolver: + """Intended to resolve Windows/Wine paths used in the PDB (cvdump) output + into a "canonical" format to be matched against code file paths from os.walk. + MSVC may include files from the parent dir using `..`. We eliminate those and create + an absolute path so that information about the same file under different names + will be combined into the same record. (i.e. line_no/addr pairs from LINES section.) + """ + + def __init__(self, basedir) -> None: + """basedir is the root path of the code directory in the format for your OS. + We will convert it to a PureWindowsPath to be platform-independent + and match that to the paths from the PDB.""" + + # Memoize the converted paths. We will need to do this for each path + # in the PDB, for each function in that file. (i.e. lots of repeated work) + self._memo = {} + + # Convert basedir to an absolute path if it is not already. + # If it is not absolute, we cannot do the path swap on unix. + self._realdir = pathlib.Path(basedir).resolve() + + self._is_unix = os.name != "nt" + if self._is_unix: + self._basedir = pathlib.PureWindowsPath( + winepath_unix_to_win(str(self._realdir)) ) - return self._call_winepath_unix2win(unix_fn) + else: + self._basedir = self._realdir - def get_unix_path(self, win_fn: str) -> str: - if win_fn.startswith(".\\") or win_fn.startswith("./"): - return self.unix_cwd + "/" + win_fn[2:].replace("\\", "/") - if win_fn.startswith(self.win_cwd): - return ( - self.unix_cwd - + "/" - + win_fn.removeprefix(self.win_cwd).replace("\\", "/") - ) - return self._call_winepath_win2unix(win_fn) + def _memo_wrapper(self, path_str: str) -> str: + """Wrapper so we can memoize from the public caller method""" + path = pathlib.PureWindowsPath(path_str) + if not path.is_absolute(): + # pathlib syntactic sugar for path concat + path = self._basedir / path - @staticmethod - def _call_winepath_unix2win(fn: str) -> str: - return subprocess.check_output(["winepath", "-w", fn], text=True).strip() + if self._is_unix: + # If the given path is relative to the basedir, deconstruct the path + # and swap in our unix path to avoid an expensive call to winepath. + try: + # Will raise ValueError if we are not relative to the base. + section = path.relative_to(self._basedir) + # Should combine to pathlib.PosixPath + mockpath = (self._realdir / section).resolve() + if mockpath.is_file(): + return str(mockpath) + except ValueError: + pass - @staticmethod - def _call_winepath_win2unix(fn: str) -> str: - return subprocess.check_output(["winepath", fn], text=True).strip() + # We are not relative to the basedir, or our path swap attempt + # did not point at an actual file. Either way, we are forced + # to call winepath using our original path. + return winepath_win_to_unix(str(path)) + + # We must be on Windows. Convert back to WindowsPath. + # The resolve() call will eliminate intermediate backdir references. + return str(pathlib.Path(path).resolve()) + + def resolve_cvdump(self, path_str: str) -> str: + """path_str is in Windows/Wine path format. + We will return a path in the format for the host OS.""" + if path_str not in self._memo: + self._memo[path_str] = self._memo_wrapper(path_str) + + return self._memo[path_str] def is_file_cpp(filename: str) -> bool: diff --git a/tools/isledecomp/isledecomp/syminfo.py b/tools/isledecomp/isledecomp/syminfo.py index 3e98c118..e7ab0df4 100644 --- a/tools/isledecomp/isledecomp/syminfo.py +++ b/tools/isledecomp/isledecomp/syminfo.py @@ -1,6 +1,7 @@ import os import subprocess from isledecomp.lib import lib_path_join +from isledecomp.dir import PathResolver, winepath_unix_to_win class RecompiledInfo: @@ -16,14 +17,15 @@ class SymInfo: lines = {} names = {} - def __init__(self, pdb, sym_recompfile, sym_logger, sym_wine_path_converter=None): + def __init__(self, pdb, sym_recompfile, sym_logger, base_dir): self.logger = sym_logger + path_resolver = PathResolver(base_dir) call = [lib_path_join("cvdump.exe"), "-l", "-s"] - if sym_wine_path_converter: + if os.name != "nt": # Run cvdump through wine and convert path to Windows-friendly wine path call.insert(0, "wine") - call.append(sym_wine_path_converter.get_wine_path(pdb)) + call.append(winepath_unix_to_win(pdb)) else: call.append(pdb) @@ -70,10 +72,7 @@ def __init__(self, pdb, sym_recompfile, sym_logger, sym_wine_path_converter=None and not line.startswith(" ") ): sourcepath = line.split()[0] - - if sym_wine_path_converter: - # Convert filename to Unix path for file compare - sourcepath = sym_wine_path_converter.get_unix_path(sourcepath) + sourcepath = path_resolver.resolve_cvdump(sourcepath) if sourcepath not in self.lines: self.lines[sourcepath] = {} diff --git a/tools/isledecomp/tests/test_parser_statechange.py b/tools/isledecomp/tests/test_parser_statechange.py index 714de579..8d18d547 100644 --- a/tools/isledecomp/tests/test_parser_statechange.py +++ b/tools/isledecomp/tests/test_parser_statechange.py @@ -1,3 +1,4 @@ +from typing import Optional import pytest from isledecomp.parser.parser import ( ReaderState as _rs, @@ -70,7 +71,7 @@ "state, marker_type, new_state, expected_error", state_change_marker_cases ) def test_state_change_by_marker( - state: _rs, marker_type: str, new_state: _rs, expected_error: None | _pe + state: _rs, marker_type: str, new_state: _rs, expected_error: Optional[_pe] ): p = DecompParser() p.state = state diff --git a/tools/isledecomp/tests/test_path_resolver_nt.py b/tools/isledecomp/tests/test_path_resolver_nt.py new file mode 100644 index 00000000..93ddfd17 --- /dev/null +++ b/tools/isledecomp/tests/test_path_resolver_nt.py @@ -0,0 +1,32 @@ +from os import name as os_name +import pytest +from isledecomp.dir import PathResolver + + +if os_name != "nt": + pytest.skip(reason="Skip Windows-only tests", allow_module_level=True) + + +@pytest.fixture(name="resolver") +def fixture_resolver_win(): + yield PathResolver("C:\\isle") + + +def test_identity(resolver): + assert resolver.resolve_cvdump("C:\\isle\\test.h") == "C:\\isle\\test.h" + + +def test_outside_basedir(resolver): + assert resolver.resolve_cvdump("C:\\lego\\test.h") == "C:\\lego\\test.h" + + +def test_relative(resolver): + assert resolver.resolve_cvdump(".\\test.h") == "C:\\isle\\test.h" + assert resolver.resolve_cvdump("..\\test.h") == "C:\\test.h" + + +def test_intermediate_relative(resolver): + """These paths may not register as `relative` paths, but we want to + produce a single absolute path for each.""" + assert resolver.resolve_cvdump("C:\\isle\\test\\..\\test.h") == "C:\\isle\\test.h" + assert resolver.resolve_cvdump(".\\subdir\\..\\test.h") == "C:\\isle\\test.h" diff --git a/tools/isledecomp/tests/test_path_resolver_posix.py b/tools/isledecomp/tests/test_path_resolver_posix.py new file mode 100644 index 00000000..af0c89e5 --- /dev/null +++ b/tools/isledecomp/tests/test_path_resolver_posix.py @@ -0,0 +1,69 @@ +from os import name as os_name +from unittest.mock import patch +import pytest +from isledecomp.dir import PathResolver + + +if os_name == "nt": + pytest.skip(reason="Skip Posix-only tests", allow_module_level=True) + + +@pytest.fixture(name="resolver") +def fixture_resolver_posix(): + # Skip the call to winepath by using a patch, although this is not strictly necessary. + with patch("isledecomp.dir.winepath_unix_to_win", return_value="Z:\\usr\\isle"): + yield PathResolver("/usr/isle") + + +@patch("isledecomp.dir.winepath_win_to_unix") +def test_identity(winepath_mock, resolver): + """Test with an absolute Wine path where a path swap is possible.""" + # In this and upcoming tests, patch is_file so we always assume there is + # a file at the given unix path. We want to test the conversion logic only. + with patch("pathlib.Path.is_file", return_value=True): + assert resolver.resolve_cvdump("Z:\\usr\\isle\\test.h") == "/usr/isle/test.h" + winepath_mock.assert_not_called() + + # Without the patch, this should call the winepath_mock, but we have + # memoized the value from the previous run. + assert resolver.resolve_cvdump("Z:\\usr\\isle\\test.h") == "/usr/isle/test.h" + winepath_mock.assert_not_called() + + +@patch("isledecomp.dir.winepath_win_to_unix") +def test_file_does_not_exist(winepath_mock, resolver): + """These test files (probably) don't exist, so we always assume + the path swap failed and defer to winepath.""" + resolver.resolve_cvdump("Z:\\usr\\isle\\test.h") + winepath_mock.assert_called_once_with("Z:\\usr\\isle\\test.h") + + +@patch("isledecomp.dir.winepath_win_to_unix") +def test_outside_basedir(winepath_mock, resolver): + """Test an absolute path where we cannot do a path swap.""" + with patch("pathlib.Path.is_file", return_value=True): + resolver.resolve_cvdump("Z:\\lego\\test.h") + winepath_mock.assert_called_once_with("Z:\\lego\\test.h") + + +@patch("isledecomp.dir.winepath_win_to_unix") +def test_relative(winepath_mock, resolver): + """Test relative paths inside and outside of the base dir.""" + with patch("pathlib.Path.is_file", return_value=True): + assert resolver.resolve_cvdump("./test.h") == "/usr/isle/test.h" + + # This works because we will resolve "/usr/isle/test/../test.h" + assert resolver.resolve_cvdump("../test.h") == "/usr/test.h" + winepath_mock.assert_not_called() + + +@patch("isledecomp.dir.winepath_win_to_unix") +def test_intermediate_relative(winepath_mock, resolver): + """We can resolve intermediate backdirs if they are relative to the basedir.""" + with patch("pathlib.Path.is_file", return_value=True): + assert ( + resolver.resolve_cvdump("Z:\\usr\\isle\\test\\..\\test.h") + == "/usr/isle/test.h" + ) + assert resolver.resolve_cvdump(".\\subdir\\..\\test.h") == "/usr/isle/test.h" + winepath_mock.assert_not_called() diff --git a/tools/reccmp/reccmp.py b/tools/reccmp/reccmp.py index cbfafcdd..913154f5 100755 --- a/tools/reccmp/reccmp.py +++ b/tools/reccmp/reccmp.py @@ -16,7 +16,6 @@ print_diff, SymInfo, walk_source_dir, - WinePathConverter, ) from capstone import Cs, CS_ARCH_X86, CS_MODE_32 @@ -295,13 +294,8 @@ def main(): svg = args.svg - wine_path_converter = None - if os.name != "nt": - wine_path_converter = WinePathConverter(source) with Bin(original, logger) as origfile, Bin(recomp, logger) as recompfile: - syminfo = SymInfo( - syms, recompfile, logger, sym_wine_path_converter=wine_path_converter - ) + syminfo = SymInfo(syms, recompfile, logger, source) print() From 9eefc82c8ce1ba38af32ba89f999167c1526d08a Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Sat, 23 Dec 2023 08:40:39 -0500 Subject: [PATCH 06/13] Bootstrap MxDSSubscriber (#352) * Bootstrap MxDSSubscriber * Fix offset comment --- LEGO1/mxdssubscriber.cpp | 51 +++++++++++++++++++++++++++++++----- LEGO1/mxdssubscriber.h | 18 +++++++++++-- LEGO1/mxmediapresenter.cpp | 2 +- LEGO1/mxstreamcontroller.cpp | 12 +++++++++ LEGO1/mxstreamcontroller.h | 8 +++--- 5 files changed, 78 insertions(+), 13 deletions(-) diff --git a/LEGO1/mxdssubscriber.cpp b/LEGO1/mxdssubscriber.cpp index b7a6d50b..49d145f0 100644 --- a/LEGO1/mxdssubscriber.cpp +++ b/LEGO1/mxdssubscriber.cpp @@ -1,24 +1,61 @@ #include "mxdssubscriber.h" +#include "mxstreamcontroller.h" + DECOMP_SIZE_ASSERT(MxDSSubscriber, 0x4c); -// STUB: LEGO1 0x100b7bb0 +// FUNCTION: LEGO1 0x100b7bb0 MxDSSubscriber::MxDSSubscriber() { - // TODO + m_unk0x48 = -1; + m_objectId = -1; + m_unk0x20 = NULL; + m_unk0x3c = NULL; } -// STUB: LEGO1 0x100b7e00 +// FUNCTION: LEGO1 0x100b7e00 MxDSSubscriber::~MxDSSubscriber() { - // TODO + if (m_controller) + m_controller->FUN_100c1620(this); + + FUN_100b8030(); + + if (m_unk0x20) + delete m_unk0x20; + m_unk0x20 = NULL; + + if (m_unk0x3c) + delete m_unk0x3c; + m_unk0x3c = NULL; } -// STUB: LEGO1 0x100b7ed0 -MxResult MxDSSubscriber::FUN_100b7ed0(MxStreamController*, MxU32, MxS16) +// FUNCTION: LEGO1 0x100b7ed0 +MxResult MxDSSubscriber::Create(MxStreamController* p_controller, MxU32 p_objectId, MxS16 p_unk0x48) +{ + m_objectId = p_objectId; + m_unk0x48 = p_unk0x48; + + if (!p_controller) + return FAILURE; + m_controller = p_controller; + + m_unk0x20 = new MxStreamChunkListCursor(&m_unk0x08); + if (!m_unk0x20) + return FAILURE; + + m_unk0x3c = new MxStreamChunkListCursor(&m_unk0x24); + if (!m_unk0x3c) + return FAILURE; + + m_controller->FUN_100c15d0(this); + return SUCCESS; +} + +// STUB: LEGO1 0x100b8030 +void MxDSSubscriber::FUN_100b8030() { // TODO - return SUCCESS; } // STUB: LEGO1 0x100b8250 diff --git a/LEGO1/mxdssubscriber.h b/LEGO1/mxdssubscriber.h index 2cba7416..748acb84 100644 --- a/LEGO1/mxdssubscriber.h +++ b/LEGO1/mxdssubscriber.h @@ -5,6 +5,7 @@ #include "mxcore.h" #include "mxdschunk.h" #include "mxstreamchunk.h" +#include "mxstreamchunklist.h" class MxStreamController; @@ -28,13 +29,26 @@ class MxDSSubscriber : public MxCore { return !strcmp(p_name, MxDSSubscriber::ClassName()) || MxCore::IsA(p_name); } - MxResult FUN_100b7ed0(MxStreamController*, MxU32, MxS16); + MxResult Create(MxStreamController* p_controller, MxU32 p_objectId, MxS16 p_unk0x48); + void FUN_100b8030(); MxStreamChunk* FUN_100b8250(); MxStreamChunk* FUN_100b8360(); void FUN_100b8390(MxStreamChunk*); private: - undefined m_pad[0x44]; // 0x8 + MxStreamChunkList m_unk0x08; // 0x08 + MxStreamChunkListCursor* m_unk0x20; // 0x20 + MxStreamChunkList m_unk0x24; // 0x24 + MxStreamChunkListCursor* m_unk0x3c; // 0x3c + MxStreamController* m_controller; // 0x40 + MxU32 m_objectId; // 0x44 + MxS16 m_unk0x48; // 0x48 }; +// SYNTHETIC: LEGO1 0x100b7de0 +// MxDSSubscriber::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x100b7d00 +// MxStreamChunkList::~MxStreamChunkList + #endif // MXDSSUBSCRIBER_H diff --git a/LEGO1/mxmediapresenter.cpp b/LEGO1/mxmediapresenter.cpp index 9a13adf5..b3eb2274 100644 --- a/LEGO1/mxmediapresenter.cpp +++ b/LEGO1/mxmediapresenter.cpp @@ -124,7 +124,7 @@ MxResult MxMediaPresenter::StartAction(MxStreamController* p_controller, MxDSAct m_subscriber = new MxDSSubscriber; if (!m_subscriber || - m_subscriber->FUN_100b7ed0(p_controller, p_action->GetObjectId(), p_action->GetUnknown24()) != SUCCESS) + m_subscriber->Create(p_controller, p_action->GetObjectId(), p_action->GetUnknown24()) != SUCCESS) goto done; } diff --git a/LEGO1/mxstreamcontroller.cpp b/LEGO1/mxstreamcontroller.cpp index c6aa8996..f97a7e76 100644 --- a/LEGO1/mxstreamcontroller.cpp +++ b/LEGO1/mxstreamcontroller.cpp @@ -52,6 +52,18 @@ MxResult MxStreamController::Open(const char* p_filename) return SUCCESS; } +// STUB: LEGO1 0x100c15d0 +void MxStreamController::FUN_100c15d0(MxDSSubscriber* p_subscriber) +{ + // TODO +} + +// STUB: LEGO1 0x100c1620 +void MxStreamController::FUN_100c1620(MxDSSubscriber* p_subscriber) +{ + // TODO +} + // FUNCTION: LEGO1 0x100c1690 MxResult MxStreamController::VTable0x20(MxDSAction* p_action) { diff --git a/LEGO1/mxstreamcontroller.h b/LEGO1/mxstreamcontroller.h index 468782b1..ce204aa4 100644 --- a/LEGO1/mxstreamcontroller.h +++ b/LEGO1/mxstreamcontroller.h @@ -7,6 +7,7 @@ #include "mxcriticalsection.h" #include "mxdsaction.h" #include "mxdsobject.h" +#include "mxdssubscriber.h" #include "mxstl/stlcompat.h" #include "mxstreamlist.h" #include "mxstreamprovider.h" @@ -18,7 +19,6 @@ class MxDSStreamingAction; class MxStreamController : public MxCore { public: MxStreamController(); - virtual ~MxStreamController() override; // vtable+0x0 // FUNCTION: LEGO1 0x100c0f10 @@ -43,12 +43,14 @@ class MxStreamController : public MxCore { virtual MxResult VTable0x2c(MxDSAction* p_action, MxU32 p_bufferval); // vtable+0x2c virtual MxResult VTable0x30(MxDSAction* p_action); // vtable+0x30 + void FUN_100c15d0(MxDSSubscriber* p_subscriber); + void FUN_100c1620(MxDSSubscriber* p_subscriber); MxResult FUN_100c1800(MxDSAction* p_action, MxU32 p_val); - MxBool FUN_100c20d0(MxDSObject& p_obj); MxResult FUN_100c1a00(MxDSAction* p_action, MxU32 p_bufferval); MxPresenter* FUN_100c1e70(MxDSAction& p_action); - MxResult InsertActionToList54(MxDSAction* p_action); MxResult FUN_100c1f00(MxDSAction* p_action); + MxBool FUN_100c20d0(MxDSObject& p_obj); + MxResult InsertActionToList54(MxDSAction* p_action); inline MxAtomId& GetAtom() { return m_atom; }; inline MxStreamListMxDSAction& GetUnk0x54() { return m_unk0x54; }; From 439173f1d59928e2e21d70b99cd36b9f82829c9e Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Sat, 23 Dec 2023 10:42:30 -0500 Subject: [PATCH 07/13] Implement/match rest of MxDSSubscriber (#354) * Implement/match rest of MxDSSubscriber * Fix MxRAMStreamController::VTable0x20 match * Match MxRAMStreamController::DeserializeObject --- LEGO1/mxcore.h | 2 +- LEGO1/mxdssubscriber.cpp | 72 +++++++++++++++++++++++++++------ LEGO1/mxdssubscriber.h | 5 ++- LEGO1/mxlist.h | 10 +++-- LEGO1/mxramstreamcontroller.cpp | 8 +++- 5 files changed, 76 insertions(+), 21 deletions(-) diff --git a/LEGO1/mxcore.h b/LEGO1/mxcore.h index 2933973e..5792eaf2 100644 --- a/LEGO1/mxcore.h +++ b/LEGO1/mxcore.h @@ -33,7 +33,7 @@ class MxCore { inline MxU32 GetId() { return m_id; } private: - MxU32 m_id; + MxU32 m_id; // 0x04 }; #endif // MXCORE_H diff --git a/LEGO1/mxdssubscriber.cpp b/LEGO1/mxdssubscriber.cpp index 49d145f0..b4fa97a0 100644 --- a/LEGO1/mxdssubscriber.cpp +++ b/LEGO1/mxdssubscriber.cpp @@ -19,7 +19,7 @@ MxDSSubscriber::~MxDSSubscriber() if (m_controller) m_controller->FUN_100c1620(this); - FUN_100b8030(); + DeleteChunks(); if (m_unk0x20) delete m_unk0x20; @@ -52,28 +52,74 @@ MxResult MxDSSubscriber::Create(MxStreamController* p_controller, MxU32 p_object return SUCCESS; } -// STUB: LEGO1 0x100b8030 -void MxDSSubscriber::FUN_100b8030() +// FUNCTION: LEGO1 0x100b8030 +void MxDSSubscriber::DeleteChunks() { - // TODO + if (m_controller) { + MxStreamChunk* chunk = NULL; + + while (m_unk0x20->First(chunk)) { + m_unk0x20->Detach(); + delete chunk; + } + + while (m_unk0x3c->First(chunk)) { + m_unk0x3c->Detach(); + delete chunk; + } + } } -// STUB: LEGO1 0x100b8250 +// FUNCTION: LEGO1 0x100b8150 +MxResult MxDSSubscriber::AddChunk(MxStreamChunk* p_chunk, MxBool p_append) +{ + if (m_unk0x20) { + if (p_append) + m_unk0x08.Append(p_chunk); + else + m_unk0x08.Prepend(p_chunk); + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100b8250 MxStreamChunk* MxDSSubscriber::FUN_100b8250() { - // TODO - return NULL; + MxStreamChunk* chunk = NULL; + + if (m_unk0x20) + m_unk0x20->First(chunk); + + if (chunk) { + m_unk0x20->Detach(); + m_unk0x24.Append(chunk); + } + + return chunk; } -// STUB: LEGO1 0x100b8360 +// FUNCTION: LEGO1 0x100b8360 MxStreamChunk* MxDSSubscriber::FUN_100b8360() { - // TODO - return NULL; + MxStreamChunk* chunk = NULL; + + if (m_unk0x20) + m_unk0x20->First(chunk); + + return chunk; } -// STUB: LEGO1 0x100b8390 -void MxDSSubscriber::FUN_100b8390(MxStreamChunk*) +// FUNCTION: LEGO1 0x100b8390 +void MxDSSubscriber::FUN_100b8390(MxStreamChunk* p_chunk) { - // TODO + if (p_chunk) { + if (m_unk0x3c->Find(p_chunk)) { + m_unk0x3c->Detach(); + if (p_chunk) + delete p_chunk; + } + else if ((p_chunk->GetFlags() & MxStreamChunk::Flag_Bit1) != 0 && p_chunk) + delete p_chunk; + } } diff --git a/LEGO1/mxdssubscriber.h b/LEGO1/mxdssubscriber.h index 748acb84..35961f54 100644 --- a/LEGO1/mxdssubscriber.h +++ b/LEGO1/mxdssubscriber.h @@ -30,10 +30,11 @@ class MxDSSubscriber : public MxCore { } MxResult Create(MxStreamController* p_controller, MxU32 p_objectId, MxS16 p_unk0x48); - void FUN_100b8030(); + void DeleteChunks(); + MxResult AddChunk(MxStreamChunk* p_chunk, MxBool p_append); MxStreamChunk* FUN_100b8250(); MxStreamChunk* FUN_100b8360(); - void FUN_100b8390(MxStreamChunk*); + void FUN_100b8390(MxStreamChunk* p_chunk); private: MxStreamChunkList m_unk0x08; // 0x08 diff --git a/LEGO1/mxlist.h b/LEGO1/mxlist.h index 11afe695..8a5f3e0e 100644 --- a/LEGO1/mxlist.h +++ b/LEGO1/mxlist.h @@ -54,6 +54,7 @@ class MxList : protected MxCollection { virtual ~MxList() override; void Append(T p_obj) { InsertEntry(p_obj, this->m_last, NULL); }; + void Prepend(T p_obj) { InsertEntry(p_obj, NULL, this->m_first); }; void DeleteAll(MxBool p_destroy = TRUE); MxU32 GetCount() { return this->m_count; } @@ -195,8 +196,10 @@ inline MxBool MxListCursor::Find(T p_obj) template inline void MxListCursor::Detach() { - m_list->DeleteEntry(m_match); - m_match = NULL; + if (m_match) { + m_list->DeleteEntry(m_match); + m_match = NULL; + } } template @@ -204,7 +207,8 @@ inline void MxListCursor::Destroy() { if (m_match) { m_list->m_customDestructor(m_match->GetValue()); - Detach(); + m_list->DeleteEntry(m_match); + m_match = NULL; } } diff --git a/LEGO1/mxramstreamcontroller.cpp b/LEGO1/mxramstreamcontroller.cpp index 930ca4ce..0a5e29cd 100644 --- a/LEGO1/mxramstreamcontroller.cpp +++ b/LEGO1/mxramstreamcontroller.cpp @@ -40,8 +40,9 @@ MxResult MxRAMStreamController::Open(const char* p_filename) MxResult MxRAMStreamController::VTable0x20(MxDSAction* p_action) { MxAutoLocker locker(&m_criticalSection); - MxS16 unk0x24 = 0; + MxS32 unk0x24 = 0; MxResult result = FAILURE; + if (p_action->GetUnknown24() == -1) { p_action->SetUnknown24(-3); MxDSAction* action = m_unk0x54.Find(p_action, FALSE); @@ -85,11 +86,14 @@ MxResult MxRAMStreamController::DeserializeObject(MxDSStreamingAction& p_action) MxAutoLocker locker(&m_criticalSection); MxResult result; MxDSStreamingAction* value = NULL; + do { m_buffer.FUN_100c6f80(p_action.GetUnknown94()); + // Probably not MxResult, see below result = m_buffer.FUN_100c67b0(this, &p_action, &value); } while (m_unk0x3c.Find(&p_action, FALSE) != NULL); - return result; + + return result == SUCCESS ? SUCCESS : FAILURE; } // STUB: LEGO1 0x100d0d80 From 24a3a8f3fd2cbfd0a2efbfdc819645387228094d Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Sat, 23 Dec 2023 14:19:32 -0500 Subject: [PATCH 08/13] Fix match of MxDiskStreamController::VTable0x28 --- LEGO1/mxdiskstreamcontroller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LEGO1/mxdiskstreamcontroller.cpp b/LEGO1/mxdiskstreamcontroller.cpp index 9bb8fdf6..71ebc827 100644 --- a/LEGO1/mxdiskstreamcontroller.cpp +++ b/LEGO1/mxdiskstreamcontroller.cpp @@ -107,7 +107,7 @@ MxDSStreamingAction* MxDiskStreamController::VTable0x28() MxU32 offset = result->GetBufferOffset() + filesize; ((MxDSStreamingAction*) oldAction)->SetUnknown94(offset); ((MxDSStreamingAction*) oldAction)->SetBufferOffset(offset); - m_unk0x3c.push_back(result); + m_unk0x3c.push_back(oldAction); } } From bbe5d6f8106dec9b6f0c5b5b5d064e45b27004c4 Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Sun, 24 Dec 2023 08:52:26 -0500 Subject: [PATCH 09/13] Add MxStreamController::~MxStreamController (#355) --- LEGO1/mxdiskstreamprovider.cpp | 2 +- LEGO1/mxdiskstreamprovider.h | 2 +- LEGO1/mxstreamcontroller.cpp | 29 ++++++++++++++++++++++++++--- LEGO1/mxstreamcontroller.h | 2 +- LEGO1/mxstreamlist.h | 25 ++++++++++++------------- LEGO1/mxstreamprovider.cpp | 2 +- LEGO1/mxstreamprovider.h | 3 ++- 7 files changed, 44 insertions(+), 21 deletions(-) diff --git a/LEGO1/mxdiskstreamprovider.cpp b/LEGO1/mxdiskstreamprovider.cpp index dfdf8158..e55287fd 100644 --- a/LEGO1/mxdiskstreamprovider.cpp +++ b/LEGO1/mxdiskstreamprovider.cpp @@ -72,7 +72,7 @@ MxResult MxDiskStreamProvider::SetResourceToGet(MxStreamController* p_resource) } // STUB: LEGO1 0x100d15e0 -void MxDiskStreamProvider::VTable0x20(undefined4) +void MxDiskStreamProvider::VTable0x20(MxDSAction* p_action) { // TODO } diff --git a/LEGO1/mxdiskstreamprovider.h b/LEGO1/mxdiskstreamprovider.h index b5a2e9ff..55d4f0f2 100644 --- a/LEGO1/mxdiskstreamprovider.h +++ b/LEGO1/mxdiskstreamprovider.h @@ -50,7 +50,7 @@ class MxDiskStreamProvider : public MxStreamProvider { virtual MxResult SetResourceToGet(MxStreamController* p_resource) override; // vtable+0x14 virtual MxU32 GetFileSize() override; // vtable+0x18 virtual MxS32 GetStreamBuffersNum() override; // vtable+0x1c - virtual void VTable0x20(undefined4) override; // vtable+0x20 + virtual void VTable0x20(MxDSAction* p_action) override; // vtable+0x20 virtual MxU32 GetLengthInDWords() override; // vtable+0x24 virtual MxU32* GetBufferForDWords() override; // vtable+0x28 diff --git a/LEGO1/mxstreamcontroller.cpp b/LEGO1/mxstreamcontroller.cpp index f97a7e76..ed681b8c 100644 --- a/LEGO1/mxstreamcontroller.cpp +++ b/LEGO1/mxstreamcontroller.cpp @@ -31,14 +31,37 @@ MxDSStreamingAction* MxStreamController::VTable0x28() MxStreamController::MxStreamController() { m_provider = NULL; - m_unk0x2c = 0; // TODO: probably also NULL + m_unk0x2c = NULL; m_action0x60 = NULL; } -// STUB: LEGO1 0x100c1290 +// FUNCTION: LEGO1 0x100c1290 MxStreamController::~MxStreamController() { - // TODO + MxAutoLocker lock(&m_criticalSection); + + MxDSSubscriber* subscriber; + while (m_subscriberList.PopFront(subscriber)) + delete subscriber; + + MxDSAction* action; + while (m_unk0x3c.PopFront(action)) + delete action; + + if (m_provider) { + MxStreamProvider* provider = m_provider; + m_provider = NULL; + provider->VTable0x20(&MxDSAction()); + delete provider; + } + + if (m_unk0x2c) { + delete m_unk0x2c; + m_unk0x2c = NULL; + } + + while (m_unk0x54.PopFront(action)) + delete action; } // FUNCTION: LEGO1 0x100c1520 diff --git a/LEGO1/mxstreamcontroller.h b/LEGO1/mxstreamcontroller.h index ce204aa4..d3310338 100644 --- a/LEGO1/mxstreamcontroller.h +++ b/LEGO1/mxstreamcontroller.h @@ -59,7 +59,7 @@ class MxStreamController : public MxCore { MxCriticalSection m_criticalSection; // 0x8 MxAtomId m_atom; // 0x24 MxStreamProvider* m_provider; // 0x28 - undefined4 m_unk0x2c; // 0x2c + undefined4* m_unk0x2c; // 0x2c MxStreamListMxDSSubscriber m_subscriberList; // 0x30 MxStreamListMxDSAction m_unk0x3c; // 0x3c MxStreamListMxNextActionDataStart m_nextActionList; // 0x48 diff --git a/LEGO1/mxstreamlist.h b/LEGO1/mxstreamlist.h index abe48779..9b65c53d 100644 --- a/LEGO1/mxstreamlist.h +++ b/LEGO1/mxstreamlist.h @@ -7,24 +7,23 @@ #include "mxstl/stlcompat.h" template -class MxStreamList : public list {}; +class MxStreamList : public list { +public: + MxBool PopFront(T& p_obj) + { + if (empty()) + return FALSE; + + p_obj = front(); + pop_front(); + return TRUE; + } +}; // SIZE 0xc class MxStreamListMxDSAction : public MxStreamList { public: MxDSAction* Find(MxDSAction* p_action, MxBool p_delete); - - // Could move this to MxStreamList - MxBool PopFront(MxDSAction*& p_obj) - { - if (!empty()) { - p_obj = front(); - pop_front(); - return TRUE; - } - - return FALSE; - } }; // SIZE 0xc diff --git a/LEGO1/mxstreamprovider.cpp b/LEGO1/mxstreamprovider.cpp index 9d77121b..740b2c65 100644 --- a/LEGO1/mxstreamprovider.cpp +++ b/LEGO1/mxstreamprovider.cpp @@ -12,6 +12,6 @@ MxResult MxStreamProvider::SetResourceToGet(MxStreamController* p_resource) } // FUNCTION: LEGO1 0x100d07d0 -void MxStreamProvider::VTable0x20(undefined4) +void MxStreamProvider::VTable0x20(MxDSAction* p_action) { } diff --git a/LEGO1/mxstreamprovider.h b/LEGO1/mxstreamprovider.h index 66f75be2..ecbe9ab4 100644 --- a/LEGO1/mxstreamprovider.h +++ b/LEGO1/mxstreamprovider.h @@ -6,6 +6,7 @@ #include "mxdsfile.h" class MxStreamController; +class MxDSAction; // VTABLE: LEGO1 0x100dd100 // SIZE 0x10 @@ -28,7 +29,7 @@ class MxStreamProvider : public MxCore { virtual MxResult SetResourceToGet(MxStreamController* p_resource); // vtable+0x14 virtual MxU32 GetFileSize() = 0; // vtable+0x18 virtual MxS32 GetStreamBuffersNum() = 0; // vtable+0x1c - virtual void VTable0x20(undefined4); // vtable+0x20 + virtual void VTable0x20(MxDSAction* p_action); // vtable+0x20 virtual MxU32 GetLengthInDWords() = 0; // vtable+0x24 virtual MxU32* GetBufferForDWords() = 0; // vtable+0x28 From 848a92735fd77a8d00050cb1aff9093697ce2ba6 Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Sun, 24 Dec 2023 09:14:47 -0500 Subject: [PATCH 10/13] Match MxStreamer::Open --- LEGO1/mxstreamer.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/LEGO1/mxstreamer.cpp b/LEGO1/mxstreamer.cpp index b4357d87..c35a4e8f 100644 --- a/LEGO1/mxstreamer.cpp +++ b/LEGO1/mxstreamer.cpp @@ -46,7 +46,6 @@ MxStreamer::~MxStreamer() // FUNCTION: LEGO1 0x100b92c0 MxStreamController* MxStreamer::Open(const char* p_name, MxU16 p_lookupType) { - // TODO MxStreamController* stream = NULL; if (!GetOpenStream(p_name)) { @@ -59,7 +58,7 @@ MxStreamController* MxStreamer::Open(const char* p_name, MxU16 p_lookupType) break; } - if (!stream || stream->Open(p_name) != SUCCESS || AddStreamControllerToOpenList(stream) != SUCCESS) { + if (stream && (stream->Open(p_name) != SUCCESS || AddStreamControllerToOpenList(stream) != SUCCESS)) { delete stream; stream = NULL; } From 43efcc5253d9f4ae1e160053fb1e9992a03f0ece Mon Sep 17 00:00:00 2001 From: Joshua Peisach Date: Sun, 24 Dec 2023 09:16:07 -0500 Subject: [PATCH 11/13] jukebox ctor (#356) * jukebox ctor * naming conventions * Fixes --------- Co-authored-by: Christian Semmler --- LEGO1/jukebox.cpp | 11 +++++++++-- LEGO1/jukebox.h | 6 ++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/LEGO1/jukebox.cpp b/LEGO1/jukebox.cpp index b13b1f82..d5ded948 100644 --- a/LEGO1/jukebox.cpp +++ b/LEGO1/jukebox.cpp @@ -1,7 +1,14 @@ #include "jukebox.h" -// STUB: LEGO1 0x1005d660 +#include "mxnotificationmanager.h" +#include "mxomni.h" + +DECOMP_SIZE_ASSERT(JukeBox, 0x104) + +// FUNCTION: LEGO1 0x1005d660 JukeBox::JukeBox() { - // TODO + m_unk0x100 = 0; + m_unk0xfc = 0; + NotificationManager()->Register(this); } diff --git a/LEGO1/jukebox.h b/LEGO1/jukebox.h index 1f04bac3..63b04520 100644 --- a/LEGO1/jukebox.h +++ b/LEGO1/jukebox.h @@ -1,6 +1,7 @@ #ifndef JUKEBOX_H #define JUKEBOX_H +#include "decomp.h" #include "legoworld.h" // VTABLE: LEGO1 0x100d8958 @@ -21,6 +22,11 @@ class JukeBox : public LegoWorld { { return !strcmp(p_name, JukeBox::ClassName()) || LegoWorld::IsA(p_name); } + +private: + undefined m_unk0xf8[4]; // 0xf8 + undefined4 m_unk0xfc; // 0xfc + undefined2 m_unk0x100; // 0x100 }; #endif // JUKEBOX_H From d23b4db2ffd7555df5cdea27e87a6dfdcfa06bf4 Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Sun, 24 Dec 2023 10:01:23 -0500 Subject: [PATCH 12/13] Match MxDiskStreamProvider::SetResourceToGet --- LEGO1/mxdiskstreamprovider.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/LEGO1/mxdiskstreamprovider.cpp b/LEGO1/mxdiskstreamprovider.cpp index e55287fd..a8d15984 100644 --- a/LEGO1/mxdiskstreamprovider.cpp +++ b/LEGO1/mxdiskstreamprovider.cpp @@ -59,10 +59,9 @@ MxResult MxDiskStreamProvider::SetResourceToGet(MxStreamController* p_resource) } m_remainingWork = 1; - MxResult success = m_busySemaphore.Init(0, 100); - m_thread.StartWithTarget(this); + m_busySemaphore.Init(0, 100); - if (success == SUCCESS && p_resource != NULL) { + if (m_thread.StartWithTarget(this) == SUCCESS && p_resource != NULL) { result = SUCCESS; } } From 84056c6ea2142e260ee3dfaabddb90cba5e5c658 Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Sun, 24 Dec 2023 11:48:40 -0500 Subject: [PATCH 13/13] Improve MxTickleManager::Tickle code gneeration --- LEGO1/mxticklemanager.cpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/LEGO1/mxticklemanager.cpp b/LEGO1/mxticklemanager.cpp index 28a6c141..29f8428c 100644 --- a/LEGO1/mxticklemanager.cpp +++ b/LEGO1/mxticklemanager.cpp @@ -29,30 +29,29 @@ MxTickleManager::~MxTickleManager() } } -// TODO: Match. // FUNCTION: LEGO1 0x100bdde0 MxResult MxTickleManager::Tickle() { MxTime time = Timer()->GetTime(); - MxTickleClientPtrList::iterator it = m_clients.begin(); - - while (it != m_clients.end()) { + for (MxTickleClientPtrList::iterator it = m_clients.begin(); it != m_clients.end();) { MxTickleClient* client = *it; - if ((client->GetFlags() & TICKLE_MANAGER_FLAG_DESTROY) == 0) { - if (client->GetLastUpdateTime() >= time) + + // TODO: Match. + if ((MxU8) client->GetFlags() & TICKLE_MANAGER_FLAG_DESTROY) { + m_clients.erase(it++); + delete client; + } + else { + it++; + + 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; } }