diff --git a/CMakeLists.txt b/CMakeLists.txt index d96b0c61..d62c2b2b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -111,6 +111,7 @@ add_library(lego1 SHARED LEGO1/mxdsaction.cpp LEGO1/mxdsactionlist.cpp LEGO1/mxdsanim.cpp + LEGO1/mxdsbuffer.cpp LEGO1/mxdschunk.cpp LEGO1/mxdsevent.cpp LEGO1/mxdsfile.cpp @@ -149,12 +150,14 @@ add_library(lego1 SHARED LEGO1/mxparam.cpp LEGO1/mxpresenter.cpp LEGO1/mxpresenterlist.cpp + LEGO1/mxramstreamcontroller.cpp LEGO1/mxscheduler.cpp LEGO1/mxsemaphore.cpp LEGO1/mxsmkpresenter.cpp LEGO1/mxsoundmanager.cpp LEGO1/mxsoundpresenter.cpp LEGO1/mxstillpresenter.cpp + LEGO1/mxstreamcontroller.cpp LEGO1/mxstreamer.cpp LEGO1/mxstring.cpp LEGO1/mxthread.cpp diff --git a/LEGO1/legoomni.cpp b/LEGO1/legoomni.cpp index 1dd7a561..0c84395e 100644 --- a/LEGO1/legoomni.cpp +++ b/LEGO1/legoomni.cpp @@ -39,10 +39,22 @@ int LegoOmni::GetCurrPathInfo(LegoPathBoundary **,int &) return 0; } -// OFFSET: LEGO1 0x100b6ff0 STUB -void MakeSourceName(char *, const char *) +// OFFSET: LEGO1 0x100b6ff0 +void MakeSourceName(char *p_output, const char *p_input) { - // TODO + const char *cln = strchr(p_input, ':'); + if (cln) { + p_input = cln + 1; + } + + strcpy(p_output, p_input); + + strlwr(p_output); + + char *extLoc = strstr(p_output, ".si"); + if (extLoc) { + *extLoc = 0; + } } // OFFSET: LEGO1 0x100b7050 diff --git a/LEGO1/mxatomid.h b/LEGO1/mxatomid.h index 8efef679..7c89f35f 100644 --- a/LEGO1/mxatomid.h +++ b/LEGO1/mxatomid.h @@ -28,8 +28,11 @@ class MxAtomId { return this->m_internal == other.m_internal; } + void Clear(); + const char *GetInternal() const { return m_internal; } + private: MxAtomIdCounter* GetCounter(const char *, LookupMode); void Destroy(); diff --git a/LEGO1/mxdsbuffer.cpp b/LEGO1/mxdsbuffer.cpp new file mode 100644 index 00000000..686627a4 --- /dev/null +++ b/LEGO1/mxdsbuffer.cpp @@ -0,0 +1,13 @@ +#include "mxdsbuffer.h" + +// OFFSET: LEGO1 0x100c6470 +MxDSBuffer::MxDSBuffer() +{ + // TODO +} + +// OFFSET: LEGO1 0x100c6530 +MxDSBuffer::~MxDSBuffer() +{ + // TODO +} diff --git a/LEGO1/mxdsbuffer.h b/LEGO1/mxdsbuffer.h new file mode 100644 index 00000000..cb962cea --- /dev/null +++ b/LEGO1/mxdsbuffer.h @@ -0,0 +1,20 @@ +#ifndef MXDSBUFFER_H +#define MXDSBUFFER_H + +#include "decomp.h" +#include "mxcore.h" + +// VTABLE 0x100dcca0 +// SIZE 0x34 +class MxDSBuffer : public MxCore +{ +public: + MxDSBuffer(); + virtual ~MxDSBuffer() override; + +private: + undefined m_unk08[0x2C]; + +}; + +#endif // MXDSBUFFER_H diff --git a/LEGO1/mxparam.h b/LEGO1/mxparam.h index c4150ff7..ffbf1530 100644 --- a/LEGO1/mxparam.h +++ b/LEGO1/mxparam.h @@ -1,6 +1,7 @@ #ifndef MXPARAM_H #define MXPARAM_H +#include "compat.h" #include "mxomnicreateparambase.h" #include "mxtypes.h" @@ -12,7 +13,7 @@ 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() override {} // vtable+0x0 (scalar deleting destructor) virtual MxParam *Clone(); // vtable+0x4 inline MxS32 GetType() const @@ -25,7 +26,7 @@ class MxParam : public MxOmniCreateParamBase return m_sender; } -private: +protected: MxS32 m_type; // 0x4 MxCore *m_sender; // 0x8 }; diff --git a/LEGO1/mxramstreamcontroller.cpp b/LEGO1/mxramstreamcontroller.cpp new file mode 100644 index 00000000..a96046a0 --- /dev/null +++ b/LEGO1/mxramstreamcontroller.cpp @@ -0,0 +1,3 @@ +#include "mxramstreamcontroller.h" + +DECOMP_SIZE_ASSERT(MxRAMStreamController, 0x98); diff --git a/LEGO1/mxramstreamcontroller.h b/LEGO1/mxramstreamcontroller.h index 09915cbf..563d9cb6 100644 --- a/LEGO1/mxramstreamcontroller.h +++ b/LEGO1/mxramstreamcontroller.h @@ -1,11 +1,18 @@ #ifndef MXRAMSTREAMCONTROLLER_H #define MXRAMSTREAMCONTROLLER_H +#include "mxdsbuffer.h" #include "mxstreamcontroller.h" // VTABLE 0x100dc728 +// SIZE 0x98 class MxRAMStreamController : public MxStreamController { +public: + inline MxRAMStreamController() {} + +private: + MxDSBuffer m_buffer; }; diff --git a/LEGO1/mxstreamcontroller.cpp b/LEGO1/mxstreamcontroller.cpp new file mode 100644 index 00000000..09f2d95c --- /dev/null +++ b/LEGO1/mxstreamcontroller.cpp @@ -0,0 +1,32 @@ +#include "mxstreamcontroller.h" + +#include "mxautolocker.h" + +// OFFSET: LEGO1 0x100c0b90 STUB +MxStreamController::MxStreamController() +{ + // TODO +} + +// OFFSET: LEGO1 0x100c1290 STUB +MxStreamController::~MxStreamController() +{ + // TODO +} + +// OFFSET: LEGO1 0x100c20d0 STUB +MxBool MxStreamController::FUN_100c20d0(MxDSObject &p_obj) +{ + // TODO + return TRUE; +} + +// OFFSET: LEGO1 0x100c1520 +MxResult MxStreamController::Open(const char *p_filename) +{ + MxAutoLocker locker(&m_criticalSection); + + // TODO + + return SUCCESS; +} diff --git a/LEGO1/mxstreamcontroller.h b/LEGO1/mxstreamcontroller.h index 4ec95e9e..c7e4309e 100644 --- a/LEGO1/mxstreamcontroller.h +++ b/LEGO1/mxstreamcontroller.h @@ -1,13 +1,21 @@ #ifndef MXSTREAMCONTROLLER_H #define MXSTREAMCONTROLLER_H +#include "decomp.h" #include "mxatomid.h" +#include "mxcriticalsection.h" #include "mxcore.h" +#include "mxdsobject.h" // VTABLE 0x100dc968 +// SIZE 0x64 class MxStreamController : public MxCore { public: + MxStreamController(); + + virtual ~MxStreamController() override; // vtable+0x0 + // OFFSET: LEGO1 0x100c0f10 inline virtual const char *ClassName() const override // vtable+0xc { @@ -21,16 +29,15 @@ class MxStreamController : public MxCore return !strcmp(name, MxStreamController::ClassName()) || MxCore::IsA(name); } - int m_unk08; - int m_unk0c; - int m_unk10; - int m_unk14; - int m_unk18; - int m_unk1c; - int m_unk20; + virtual MxResult Open(const char *p_filename); // vtable+0x14 + + MxBool FUN_100c20d0(MxDSObject &p_obj); + + MxCriticalSection m_criticalSection; MxAtomId atom; int m_unk28; int m_unk2c; + undefined m_unk30[0x34]; }; #endif // MXSTREAMCONTROLLER_H diff --git a/LEGO1/mxstreamer.cpp b/LEGO1/mxstreamer.cpp index 12f51f99..2121773e 100644 --- a/LEGO1/mxstreamer.cpp +++ b/LEGO1/mxstreamer.cpp @@ -1,37 +1,166 @@ #include "mxstreamer.h" -// OFFSET: LEGO1 0x100b91d0 STUB -MxStreamer::~MxStreamer() +#include + +#include "legoomni.h" +#include "mxdiskstreamcontroller.h" +#include "mxramstreamcontroller.h" + +DECOMP_SIZE_ASSERT(MxStreamer, 0x2c); + +#define MXSTREAMER_DELETE_NOTIFY 6 + +// OFFSET: LEGO1 0x100b8f00 +MxStreamer::MxStreamer() { - // TODO + NotificationManager()->Register(this); } -// OFFSET: LEGO1 0x100b92c0 STUB -MxStreamController *MxStreamer::Open(const char *name, MxU16 p) +// OFFSET: LEGO1 0x100b9190 +MxResult MxStreamer::Init() +{ + undefined *b = new undefined[m_subclass1.GetSize() * 0x5800]; + m_subclass1.SetBuffer(b); + if (b) { + b = new undefined[m_subclass2.GetSize() * 0x800]; + m_subclass2.SetBuffer(b); + if (b) { + return SUCCESS; + } + } + + return FAILURE; +} + +// OFFSET: LEGO1 0x100b91d0 +MxStreamer::~MxStreamer() +{ + while (!m_openStreams.empty()) { + MxStreamController *c = m_openStreams.front(); + m_openStreams.pop_front(); + delete c; + } + + NotificationManager()->Unregister(this); +} + +// OFFSET: LEGO1 0x100b92c0 +MxStreamController *MxStreamer::Open(const char *p_name, MxU16 p_lookupType) { // TODO + MxStreamController *stream = NULL; + + if (!GetOpenStream(p_name)) { + switch (p_lookupType) { + case e_DiskStream: + stream = new MxDiskStreamController(); + break; + case e_RAMStream: + stream = new MxRAMStreamController(); + break; + } + + if (!stream + || stream->Open(p_name) != SUCCESS + || AddStreamControllerToOpenList(stream) != SUCCESS) { + delete stream; + stream = NULL; + } + } + + return stream; +} + +// OFFSET: LEGO1 0x100b9570 +MxLong MxStreamer::Close(const char *p) +{ + MxDSAction ds; + + ds.SetUnknown24(-2); + + for (list::iterator it = m_openStreams.begin(); it != m_openStreams.end(); it++) { + MxStreamController *c = *it; + + if (!p || !strcmp(p, c->atom.GetInternal())) { + m_openStreams.erase(it); + + if (!c->FUN_100c20d0(ds)) { + MxStreamerNotification notif(MXSTREAMER_DELETE_NOTIFY, NULL, c); + + NotificationManager()->Send(this, ¬if); + } else { + delete c; + } + + return SUCCESS; + } + } + + return FAILURE; +} + +// OFFSET: LEGO1 0x100b9700 +MxParam *MxStreamerNotification::Clone() +{ + return new MxStreamerNotification(m_type, m_sender, m_controller); +} + +// OFFSET: LEGO1 0x100b9870 +MxStreamController *MxStreamer::GetOpenStream(const char *p_name) +{ + for (list::iterator it = m_openStreams.begin(); it != m_openStreams.end(); it++) { + MxStreamController *c = *it; + MxAtomId &atom = c->atom; + if (p_name) { + if (!strcmp(atom.GetInternal(), p_name)) { + return *it; + } + } + } + return NULL; } -// OFFSET: LEGO1 0x100b9570 STUB -MxLong MxStreamer::Close(const char *p) + +// OFFSET: LEGO1 0x100b9930 +MxResult MxStreamer::AddStreamControllerToOpenList(MxStreamController *stream) { - // TODO - return 0; + if (find(m_openStreams.begin(), m_openStreams.end(), stream) == m_openStreams.end()) { + m_openStreams.push_back(stream); + return SUCCESS; + } + + return FAILURE; } -// OFFSET: LEGO1 0x100b9b60 STUB +// OFFSET: LEGO1 0x100b9b60 MxLong MxStreamer::Notify(MxParam &p) { - // TODO + if (p.GetType() == MXSTREAMER_DELETE_NOTIFY) { + MxDSAction ds; + + ds.SetUnknown24(-2); + + MxStreamController *c = static_cast(p).GetController(); + + if (!c->FUN_100c20d0(ds)) { + MxStreamerNotification notif(MXSTREAMER_DELETE_NOTIFY, NULL, c); + NotificationManager()->Send(this, ¬if); + } else { + delete c; + } + } return 0; } -// OFFSET: LEGO1 0x100b9190 STUB -MxResult MxStreamer::VTable0x14() +// No offset, function is always inlined +MxStreamerSubClass1::MxStreamerSubClass1(undefined4 size) { - // TODO - - return MxResult(); + m_buffer = NULL; + m_size = size; + undefined4 *ptr = &m_unk08; + for (int i = 0; i >= 0; i--) { + ptr[i] = 0; + } } diff --git a/LEGO1/mxstreamer.h b/LEGO1/mxstreamer.h index f14ac66d..5ab02cbb 100644 --- a/LEGO1/mxstreamer.h +++ b/LEGO1/mxstreamer.h @@ -1,21 +1,106 @@ #ifndef MXSTREAMER_H #define MXSTREAMER_H +#include + +#include "decomp.h" #include "mxcore.h" +#include "mxparam.h" #include "mxstreamcontroller.h" #include "mxtypes.h" +// NOTE: This feels like some kind of templated class, maybe something from the +// STL. But I haven't figured out what yet (it's definitely not a vector). +class MxStreamerSubClass1 +{ +public: + inline MxStreamerSubClass1(undefined4 size); + + ~MxStreamerSubClass1() { delete [] m_buffer; } + + undefined4 GetSize() { return m_size; } + + void SetBuffer(undefined *p_buf) { m_buffer = p_buf; } + +private: + undefined *m_buffer; + undefined4 m_size; + undefined4 m_unk08; +}; + +class MxStreamerSubClass2 : public MxStreamerSubClass1 +{ +public: + inline MxStreamerSubClass2() : MxStreamerSubClass1(0x40) {} +}; + +class MxStreamerSubClass3 : public MxStreamerSubClass1 +{ +public: + inline MxStreamerSubClass3() : MxStreamerSubClass1(0x80) {} +}; + +class MxStreamerNotification : public MxParam +{ +public: + inline MxStreamerNotification(MxS32 p_type, MxCore *p_sender, MxStreamController *p_ctrlr) : MxParam(p_type, p_sender) + { + m_controller = p_ctrlr; + } + + virtual ~MxStreamerNotification() override {} + + virtual MxParam *Clone() override; + + MxStreamController *GetController() { return m_controller; } + +private: + MxStreamController *m_controller; +}; + // VTABLE 0x100dc710 +// SIZE 0x2c class MxStreamer : public MxCore { public: - virtual ~MxStreamer() override; + enum OpenMode + { + e_DiskStream, + e_RAMStream + }; - __declspec(dllexport) MxStreamController *Open(const char *name, MxU16 p); - __declspec(dllexport) MxLong Close(const char *p); + MxStreamer(); + virtual ~MxStreamer() override; // vtable+0x0 + + __declspec(dllexport) MxStreamController *Open(const char *p_name, MxU16 p_openMode); + __declspec(dllexport) MxLong Close(const char *p_name); virtual MxLong Notify(MxParam &p) override; // vtable+0x4 - virtual MxResult VTable0x14(); // vtable+0x14 + + // OFFSET: LEGO1 0x100b9000 + inline virtual const char *ClassName() const override // vtable+0x0c + { + // 0x1010210c + return "MxStreamer"; + } + + // OFFSET: LEGO1 0x100b9010 + inline virtual MxBool IsA(const char *p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxStreamer::ClassName()) || MxCore::IsA(p_name); + } + + virtual MxResult Init(); // vtable+0x14 + + MxStreamController *GetOpenStream(const char *p_name); + + MxResult AddStreamControllerToOpenList(MxStreamController *p_stream); + +private: + list m_openStreams; // 0x8 + MxStreamerSubClass2 m_subclass1; // 0x14 + MxStreamerSubClass3 m_subclass2; // 0x20 + }; #endif // MXSTREAMER_H