mirror of
https://github.com/isledecomp/isle.git
synced 2026-01-24 08:41:16 +00:00
Merge remote-tracking branch 'upstream/master' into impl/legosoundmanager
This commit is contained in:
commit
b49307475c
36
.github/workflows/unittest.yml
vendored
Normal file
36
.github/workflows/unittest.yml
vendored
Normal file
@ -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
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -33,7 +33,7 @@ class MxCore {
|
||||
inline MxU32 GetId() { return m_id; }
|
||||
|
||||
private:
|
||||
MxU32 m_id;
|
||||
MxU32 m_id; // 0x04
|
||||
};
|
||||
|
||||
#endif // MXCORE_H
|
||||
|
||||
@ -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(oldAction);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#include "mxdiskstreamprovider.h"
|
||||
|
||||
#include "mxdsbuffer.h"
|
||||
#include "mxomni.h"
|
||||
#include "mxstreamcontroller.h"
|
||||
#include "mxstring.h"
|
||||
@ -58,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;
|
||||
}
|
||||
}
|
||||
@ -71,7 +71,7 @@ MxResult MxDiskStreamProvider::SetResourceToGet(MxStreamController* p_resource)
|
||||
}
|
||||
|
||||
// STUB: LEGO1 0x100d15e0
|
||||
void MxDiskStreamProvider::VTable0x20(undefined4)
|
||||
void MxDiskStreamProvider::VTable0x20(MxDSAction* p_action)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
@ -87,6 +87,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 +107,7 @@ MxU32 MxDiskStreamProvider::GetFileSize()
|
||||
}
|
||||
|
||||
// FUNCTION: LEGO1 0x100d1ea0
|
||||
MxU32 MxDiskStreamProvider::GetStreamBuffersNum()
|
||||
MxS32 MxDiskStreamProvider::GetStreamBuffersNum()
|
||||
{
|
||||
return m_pFile->GetStreamBuffersNum();
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
#include "mxthread.h"
|
||||
|
||||
class MxDiskStreamProvider;
|
||||
class MxDSStreamingAction;
|
||||
|
||||
// VTABLE: LEGO1 0x100dd130
|
||||
class MxDiskStreamProviderThread : public MxThread {
|
||||
@ -43,13 +44,13 @@ 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 void VTable0x20(undefined4) override; // vtable+0x20
|
||||
virtual MxS32 GetStreamBuffersNum() override; // vtable+0x1c
|
||||
virtual void VTable0x20(MxDSAction* p_action) override; // vtable+0x20
|
||||
virtual MxU32 GetLengthInDWords() override; // vtable+0x24
|
||||
virtual MxU32* GetBufferForDWords() override; // vtable+0x28
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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; }
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -1,42 +1,125 @@
|
||||
#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);
|
||||
|
||||
DeleteChunks();
|
||||
|
||||
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)
|
||||
{
|
||||
// TODO
|
||||
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 0x100b8250
|
||||
// FUNCTION: LEGO1 0x100b8030
|
||||
void MxDSSubscriber::DeleteChunks()
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include "mxcore.h"
|
||||
#include "mxdschunk.h"
|
||||
#include "mxstreamchunk.h"
|
||||
#include "mxstreamchunklist.h"
|
||||
|
||||
class MxStreamController;
|
||||
|
||||
@ -28,13 +29,27 @@ 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 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:
|
||||
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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -54,6 +54,7 @@ class MxList : protected MxCollection<T> {
|
||||
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; }
|
||||
|
||||
@ -92,6 +93,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);
|
||||
@ -193,8 +196,10 @@ inline MxBool MxListCursor<T>::Find(T p_obj)
|
||||
template <class T>
|
||||
inline void MxListCursor<T>::Detach()
|
||||
{
|
||||
m_list->DeleteEntry(m_match);
|
||||
m_match = NULL;
|
||||
if (m_match) {
|
||||
m_list->DeleteEntry(m_match);
|
||||
m_match = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
@ -202,7 +207,8 @@ inline void MxListCursor<T>::Destroy()
|
||||
{
|
||||
if (m_match) {
|
||||
m_list->m_customDestructor(m_match->GetValue());
|
||||
Detach();
|
||||
m_list->DeleteEntry(m_match);
|
||||
m_match = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,6 +235,26 @@ inline MxBool MxListCursor<T>::Current(T& p_obj)
|
||||
return m_match != NULL;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline MxBool MxListCursor<T>::First(T& p_obj)
|
||||
{
|
||||
m_match = m_list->m_first;
|
||||
if (m_match)
|
||||
p_obj = m_match->GetValue();
|
||||
|
||||
return m_match != NULL;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline MxBool MxListCursor<T>::Last(T& p_obj)
|
||||
{
|
||||
m_match = m_list->m_last;
|
||||
if (m_match)
|
||||
p_obj = m_match->GetValue();
|
||||
|
||||
return m_match != NULL;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline MxBool MxListCursor<T>::Advance()
|
||||
{
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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_flags &= 0xfd;
|
||||
this->m_flags &= 0xfb;
|
||||
this->m_elapsedDuration = 0;
|
||||
this->m_flags &= ~Flag_Bit2;
|
||||
this->m_flags &= ~Flag_Bit3;
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
@ -84,12 +85,15 @@ 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());
|
||||
// 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
|
||||
|
||||
@ -23,7 +23,7 @@ MxU32 MxRAMStreamProvider::GetFileSize()
|
||||
}
|
||||
|
||||
// FUNCTION: LEGO1 0x100d0940
|
||||
MxU32 MxRAMStreamProvider::GetStreamBuffersNum()
|
||||
MxS32 MxRAMStreamProvider::GetStreamBuffersNum()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -21,10 +21,10 @@ 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;
|
||||
m_flags &= ~Flag_Bit2;
|
||||
m_flags &= ~Flag_Bit3;
|
||||
}
|
||||
|
||||
// FUNCTION: LEGO1 0x100b3900
|
||||
@ -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()
|
||||
{
|
||||
|
||||
@ -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
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
#include "legoomni.h"
|
||||
#include "mxautolocker.h"
|
||||
#include "mxdsstreamingaction.h"
|
||||
#include "mxnextactiondatastart.h"
|
||||
#include "mxstreamchunk.h"
|
||||
|
||||
@ -21,23 +22,46 @@ MxResult MxStreamController::VTable0x1c(undefined4, undefined4)
|
||||
}
|
||||
|
||||
// FUNCTION: LEGO1 0x100b9420
|
||||
MxResult MxStreamController::VTable0x28()
|
||||
MxDSStreamingAction* MxStreamController::VTable0x28()
|
||||
{
|
||||
return SUCCESS;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// FUNCTION: LEGO1 0x100c0b90
|
||||
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
|
||||
@ -51,6 +75,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)
|
||||
{
|
||||
|
||||
@ -7,16 +7,18 @@
|
||||
#include "mxcriticalsection.h"
|
||||
#include "mxdsaction.h"
|
||||
#include "mxdsobject.h"
|
||||
#include "mxdssubscriber.h"
|
||||
#include "mxstl/stlcompat.h"
|
||||
#include "mxstreamlist.h"
|
||||
#include "mxstreamprovider.h"
|
||||
|
||||
class MxDSStreamingAction;
|
||||
|
||||
// VTABLE: LEGO1 0x100dc968
|
||||
// SIZE 0x64
|
||||
class MxStreamController : public MxCore {
|
||||
public:
|
||||
MxStreamController();
|
||||
|
||||
virtual ~MxStreamController() override; // vtable+0x0
|
||||
|
||||
// FUNCTION: LEGO1 0x100c0f10
|
||||
@ -37,16 +39,18 @@ 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
|
||||
|
||||
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; };
|
||||
@ -55,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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -7,7 +7,18 @@
|
||||
#include "mxstl/stlcompat.h"
|
||||
|
||||
template <class T>
|
||||
class MxStreamList : public list<T> {};
|
||||
class MxStreamList : public list<T> {
|
||||
public:
|
||||
MxBool PopFront(T& p_obj)
|
||||
{
|
||||
if (empty())
|
||||
return FALSE;
|
||||
|
||||
p_obj = front();
|
||||
pop_front();
|
||||
return TRUE;
|
||||
}
|
||||
};
|
||||
|
||||
// SIZE 0xc
|
||||
class MxStreamListMxDSAction : public MxStreamList<MxDSAction*> {
|
||||
|
||||
@ -12,6 +12,6 @@ MxResult MxStreamProvider::SetResourceToGet(MxStreamController* p_resource)
|
||||
}
|
||||
|
||||
// FUNCTION: LEGO1 0x100d07d0
|
||||
void MxStreamProvider::VTable0x20(undefined4)
|
||||
void MxStreamProvider::VTable0x20(MxDSAction* p_action)
|
||||
{
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
#include "mxdsfile.h"
|
||||
|
||||
class MxStreamController;
|
||||
class MxDSAction;
|
||||
|
||||
// VTABLE: LEGO1 0x100dd100
|
||||
// SIZE 0x10
|
||||
@ -27,8 +28,8 @@ 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 void VTable0x20(undefined4); // vtable+0x20
|
||||
virtual MxS32 GetStreamBuffersNum() = 0; // vtable+0x1c
|
||||
virtual void VTable0x20(MxDSAction* p_action); // vtable+0x20
|
||||
virtual MxU32 GetLengthInDWords() = 0; // vtable+0x24
|
||||
virtual MxU32* GetBufferForDWords() = 0; // vtable+0x28
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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)) {
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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] = {}
|
||||
|
||||
@ -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
|
||||
|
||||
32
tools/isledecomp/tests/test_path_resolver_nt.py
Normal file
32
tools/isledecomp/tests/test_path_resolver_nt.py
Normal file
@ -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"
|
||||
69
tools/isledecomp/tests/test_path_resolver_posix.py
Normal file
69
tools/isledecomp/tests/test_path_resolver_posix.py
Normal file
@ -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()
|
||||
@ -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()
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user