From c0acf11f9bc0da5c8adf3e0f6eb1d5412e7c4072 Mon Sep 17 00:00:00 2001 From: Nathan M Gilbert Date: Sun, 28 Jan 2024 11:45:49 -0500 Subject: [PATCH] Implement/Match LegoTree (#485) * Implement/Match LegoTree * Fix vtable * Fixes --------- Co-authored-by: Christian Semmler --- CMakeLists.txt | 1 + .../lego/legoomni/include/legoanimpresenter.h | 28 +---- .../legoomni/src/video/legoanimpresenter.cpp | 46 ++------ LEGO1/lego/sources/misc/legotree.cpp | 110 ++++++++++++++++++ LEGO1/lego/sources/misc/legotree.h | 77 ++++++++++++ 5 files changed, 204 insertions(+), 58 deletions(-) create mode 100644 LEGO1/lego/sources/misc/legotree.cpp create mode 100644 LEGO1/lego/sources/misc/legotree.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 388c4777..03353834 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -106,6 +106,7 @@ add_library(misc STATIC LEGO1/lego/sources/misc/legoimage.cpp LEGO1/lego/sources/misc/legostorage.cpp LEGO1/lego/sources/misc/legotexture.cpp + LEGO1/lego/sources/misc/legotree.cpp ) register_lego1_target(misc) set_property(TARGET misc PROPERTY ARCHIVE_OUTPUT_NAME "misc$<$:d>") diff --git a/LEGO1/lego/legoomni/include/legoanimpresenter.h b/LEGO1/lego/legoomni/include/legoanimpresenter.h index 2ca9c910..594c13ca 100644 --- a/LEGO1/lego/legoomni/include/legoanimpresenter.h +++ b/LEGO1/lego/legoomni/include/legoanimpresenter.h @@ -2,6 +2,7 @@ #define LEGOANIMPRESENTER_H #include "lego/sources/misc/legostorage.h" +#include "lego/sources/misc/legotree.h" #include "mxgeometry/mxgeometry3d.h" #include "mxvideopresenter.h" @@ -75,37 +76,20 @@ class LegoAnimPresenter : public MxVideoPresenter { // SYNTHETIC: LEGO1 0x10068650 // LegoAnimPresenter::`scalar deleting destructor' -// VTABLE: LEGO1 0x100db768 -// SIZE 0x08 -class LegoAnimClassBase { -public: - LegoAnimClassBase(); - virtual ~LegoAnimClassBase(); - - virtual void VTable0x4(); // vtable+0x04 - virtual void VTable0x8(); // vtable+0x08 - virtual void VTable0xc(); // vtable+0x0c - - undefined4 m_unk0x4; // 0x04 -}; - -// SYNTHETIC: LEGO1 0x10099de0 -// LegoAnimClassBase::`scalar deleting destructor' - // VTABLE: LEGO1 0x100db8d8 // SIZE 0x18 -class LegoAnimClass : public LegoAnimClassBase { +class LegoAnimClass : public LegoTree { public: LegoAnimClass(); virtual ~LegoAnimClass() override; - virtual void VTable0x8() override; // vtable+0x08 - virtual void VTable0xc() override; // vtable+0x0c - virtual MxResult VTable0x10(LegoMemory* p_stream, MxS32); // vtable+0x10 + virtual LegoResult Write(LegoStorage* p_storage) override; // vtable+0x08 + virtual LegoTreeNodeData* CreateData() override; // vtable+0x0c + virtual MxResult VTable0x10(LegoMemory* p_stream, MxS32); // vtable+0x10 inline MxLong GetUnknown0x8() { return m_unk0x8; } - // private: +private: MxLong m_unk0x8; // 0x08 undefined4 m_unk0xc; // 0x0c undefined4 m_unk0x10; // 0x10 diff --git a/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp b/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp index 6da994ec..be04b444 100644 --- a/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp +++ b/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp @@ -8,7 +8,6 @@ #include "mxvideomanager.h" DECOMP_SIZE_ASSERT(LegoAnimPresenter, 0xc0) -DECOMP_SIZE_ASSERT(LegoAnimClassBase, 0x08) DECOMP_SIZE_ASSERT(LegoAnimClass, 0x18) // FUNCTION: LEGO1 0x10068420 @@ -140,12 +139,7 @@ void LegoAnimPresenter::StreamingTickle() m_subscriber->DestroyChunk(chunk); } - if (m_unk0x95 == 0) { - if (m_unk0x64->m_unk0x8 + m_action->GetStartTime() < m_action->GetElapsedTime()) { - m_unk0x95 = 1; - } - } - else { + if (m_unk0x95) { ProgressTickleState(e_done); if (m_compositePresenter) { if (m_compositePresenter->IsA("LegoAnimMMPresenter")) { @@ -153,6 +147,11 @@ void LegoAnimPresenter::StreamingTickle() } } } + else { + if (m_action->GetElapsedTime() > m_unk0x64->GetUnknown0x8() + m_action->GetStartTime()) { + m_unk0x95 = 1; + } + } } // STUB: LEGO1 0x1006b8c0 @@ -200,33 +199,6 @@ void LegoAnimPresenter::EndAction() MxVideoPresenter::EndAction(); } -// FUNCTION: LEGO1 0x10099dd0 -LegoAnimClassBase::LegoAnimClassBase() -{ - m_unk0x4 = 0; -} - -// STUB: LEGO1 0x10099e00 -LegoAnimClassBase::~LegoAnimClassBase() -{ - // TODO -} - -// STUB: LEGO1 0x10099e20 -void LegoAnimClassBase::VTable0x4() -{ -} - -// STUB: LEGO1 0x10099e40 -void LegoAnimClassBase::VTable0x8() -{ -} - -// STUB: LEGO1 0x10099f70 -void LegoAnimClassBase::VTable0xc() -{ -} - // FUNCTION: LEGO1 0x100a0b30 LegoAnimClass::LegoAnimClass() { @@ -249,13 +221,15 @@ MxResult LegoAnimClass::VTable0x10(LegoMemory* p_stream, MxS32) } // STUB: LEGO1 0x100a0e30 -void LegoAnimClass::VTable0x8() +LegoResult LegoAnimClass::Write(LegoStorage* p_storage) { // TODO + return SUCCESS; } // STUB: LEGO1 0x100a1040 -void LegoAnimClass::VTable0xc() +LegoTreeNodeData* LegoAnimClass::CreateData() { // TODO + return NULL; } diff --git a/LEGO1/lego/sources/misc/legotree.cpp b/LEGO1/lego/sources/misc/legotree.cpp new file mode 100644 index 00000000..e7f24513 --- /dev/null +++ b/LEGO1/lego/sources/misc/legotree.cpp @@ -0,0 +1,110 @@ +#include "legotree.h" + +#include "decomp.h" +#include "legostorage.h" + +DECOMP_SIZE_ASSERT(LegoTreeNodeData, 0x04) +DECOMP_SIZE_ASSERT(LegoTreeNode, 0x010) +DECOMP_SIZE_ASSERT(LegoTree, 0x08) + +// FUNCTION: LEGO1 0x10099d60 +LegoTreeNode::LegoTreeNode() +{ + m_data = NULL; + m_numChildren = 0; + m_children = NULL; +} + +// FUNCTION: LEGO1 0x10099da0 +LegoTreeNode::~LegoTreeNode() +{ + if (m_data) { + delete m_data; + } + if (m_children) { + delete[] m_children; + } +} + +// FUNCTION: LEGO1 0x10099dd0 +LegoTree::LegoTree() +{ + m_root = NULL; +} + +// FUNCTION: LEGO1 0x10099e00 +LegoTree::~LegoTree() +{ + if (m_root) { + Delete(m_root); + } +} + +// FUNCTION: LEGO1 0x10099e20 +LegoResult LegoTree::Read(LegoStorage* p_storage) +{ + return Read(p_storage, m_root); +} + +// FUNCTION: LEGO1 0x10099e40 +LegoResult LegoTree::Write(LegoStorage* p_storage) +{ + return Write(p_storage, m_root); +} + +// FUNCTION: LEGO1 0x10099e60 +LegoResult LegoTree::Read(LegoStorage* p_storage, LegoTreeNode*& p_node) +{ + LegoResult result; + p_node = new LegoTreeNode(); + p_node->SetData(CreateData()); + if ((result = p_node->GetData()->Read(p_storage)) != SUCCESS) { + return result; + } + LegoU32 numChildren; + if ((result = p_storage->Read(&numChildren, sizeof(numChildren))) != SUCCESS) { + return result; + } + if (numChildren) { + p_node->SetChildren(new LegoTreeNode*[numChildren]); + for (LegoU32 i = 0; i < numChildren; i++) { + LegoTreeNode* node; + if ((result = Read(p_storage, node)) != SUCCESS) { + return result; + } + p_node->SetNumChildren(p_node->GetNumChildren() + 1); + p_node->SetChild(i, node); + } + } + return SUCCESS; +} + +// FUNCTION: LEGO1 0x1009a020 +LegoResult LegoTree::Write(LegoStorage* p_storage, LegoTreeNode* p_node) +{ + LegoResult result; + if (p_node->GetData()) { + if ((result = p_node->GetData()->Write(p_storage)) != SUCCESS) { + return result; + } + } + LegoU32 numChildren = p_node->GetNumChildren(); + if ((result = p_storage->Write(&numChildren, sizeof(numChildren))) != SUCCESS) { + return result; + } + for (LegoU32 i = 0; i < p_node->GetNumChildren(); i++) { + if ((result = Write(p_storage, p_node->GetChild(i))) != SUCCESS) { + return result; + } + } + return SUCCESS; +} + +// FUNCTION: LEGO1 0x1009a0a0 +void LegoTree::Delete(LegoTreeNode* p_node) +{ + for (LegoU32 i = 0; i < p_node->GetNumChildren(); i++) { + Delete(p_node->GetChild(i)); + } + delete p_node; +} diff --git a/LEGO1/lego/sources/misc/legotree.h b/LEGO1/lego/sources/misc/legotree.h new file mode 100644 index 00000000..185c178f --- /dev/null +++ b/LEGO1/lego/sources/misc/legotree.h @@ -0,0 +1,77 @@ +#ifndef __LEGOTREE_H +#define __LEGOTREE_H + +#ifdef _DEBUG +#include +#endif +#include "legotypes.h" + +class LegoStorage; + +// VTABLE: LEGO1 0x100db778 +// SIZE 0x4 +class LegoTreeNodeData { +public: + LegoTreeNodeData() {} + virtual ~LegoTreeNodeData() {} + + // FUNCTION: LEGO1 0x10099fe0 + virtual LegoResult Read(LegoStorage* p_storage) { return SUCCESS; } // vtable+0x4 + + // FUNCTION: LEGO1 0x10099ff0 + virtual LegoResult Write(LegoStorage* p_storage) { return SUCCESS; } // vtable+0x8 + + // SYNTHETIC: LEGO1 0x1009a000 + // LegoTreeNodeData::`scalar deleting destructor' +}; + +// VTABLE: LEGO1 0x100db764 +// SIZE 0x10 +class LegoTreeNode { +public: + LegoTreeNode(); + virtual ~LegoTreeNode(); + LegoTreeNodeData* GetData() { return m_data; } + void SetData(LegoTreeNodeData* p_data) { m_data = p_data; } + LegoU32 GetNumChildren() { return m_numChildren; } + void SetNumChildren(LegoU32 p_numChildren) { m_numChildren = p_numChildren; } + LegoTreeNode* GetChild(LegoU32 p_i) { return m_children[p_i]; } + void SetChild(LegoU32 p_i, LegoTreeNode* p_child) { m_children[p_i] = p_child; } + LegoTreeNode** GetChildren() { return m_children; } + void SetChildren(LegoTreeNode** p_children) { m_children = p_children; } + + // SYNTHETIC: LEGO1 0x10099d80 + // LegoTreeNode::`scalar deleting destructor' + +protected: + LegoTreeNodeData* m_data; // 0x4 + LegoU32 m_numChildren; // 0x8 + LegoTreeNode** m_children; // 0xc +}; + +// VTABLE: LEGO1 0x100db768 +// SIZE 0x8 +class LegoTree { +public: + LegoTree(); + virtual ~LegoTree(); + LegoTreeNode* GetRoot() { return m_root; } + void SetRoot(LegoTreeNode* p_root) { m_root = p_root; } + virtual LegoResult Read(LegoStorage* p_storage); // vtable+0x4 + virtual LegoResult Write(LegoStorage* p_storage); // vtable+0x8 + + // SYNTHETIC: LEGO1 0x10099de0 + // LegoTree::`scalar deleting destructor' + +protected: + LegoResult Read(LegoStorage* p_storage, LegoTreeNode*& p_node); + LegoResult Write(LegoStorage* p_storage, LegoTreeNode* p_node); + void Delete(LegoTreeNode* p_node); + + // FUNCTION: LEGO1 0x10099f70 + virtual LegoTreeNodeData* CreateData() { return new LegoTreeNodeData(); } // vtable+0xc + + LegoTreeNode* m_root; // 0x4 +}; + +#endif // __LEGOTREE_H