Only include decomps

This commit is contained in:
Mark Langen 2023-07-15 19:06:13 -07:00
parent 67115e32d3
commit 20c7839865
14 changed files with 429 additions and 29 deletions

View File

@ -68,6 +68,7 @@ add_library(lego1 SHARED
LEGO1/legolocomotionanimpresenter.cpp
LEGO1/legomodelpresenter.cpp
LEGO1/legonavcontroller.cpp
LEGO1/legoobjectfactory.cpp
LEGO1/legoomni.cpp
LEGO1/legopalettepresenter.cpp
LEGO1/legopartpresenter.cpp

View File

@ -23,6 +23,38 @@ class InfocenterState : public LegoState
{
return !strcmp(name, InfocenterState::ClassName()) || LegoState::IsA(name);
}
inline MxU32 GetSomething(int p_index) { return m_buffer[p_index]; }
inline void SetSomething(int p_index, MxU32 p_value) { m_buffer[p_index] = p_value; }
private:
// Size: 0xC
struct SomeStruct
{
MxU32 unk1;
MxU16 unk2;
MxU16 unk3;
MxU16 unk4;
MxU16 padding;
};
MxU16 unk1;
MxU16 unk2;
MxU32 unk3;
MxU32 padding1;
void *unk4;
MxU16 unk5;
MxU16 unk6;
MxU16 unk7;
MxU16 padding2;
void *unk8;
MxU16 unk9;
MxU16 unk10;
MxU16 unk11;
MxU16 padding3;
SomeStruct unk12[6];
MxU32 unk13;
MxU32 m_buffer[7];
};
#endif // INFOCENTERSTATE_H

View File

@ -1,39 +1,192 @@
#include "legogamestate.h"
#include "legoomni.h"
#include "legostate.h"
#include "infocenterstate.h"
#include "mxstring.h"
#include "legostream.h"
#include "mxomni.h"
// OFFSET: LEGO1 0x10039550
// OFFSET: LEGO1 0x10039550 STUB
LegoGameState::LegoGameState()
{
// TODO
m_stateCount = 0;
}
// OFFSET: LEGO1 0x10039720
// OFFSET: LEGO1 0x10039720 STUB
LegoGameState::~LegoGameState()
{
// TODO
}
// OFFSET: LEGO1 0x10039c60
// OFFSET: LEGO1 0x10039c60 STUB
MxResult LegoGameState::Load(MxULong)
{
// TODO
return 0;
}
// OFFSET: LEGO1 0x10039980
MxResult LegoGameState::Save(MxULong p)
// OFFSET: LEGO1 0x100f3e40
const char *g_fileExtensionGS = ".GS";
// OFFSET: LEGO1 0x1003a170
void LegoGameState::GetFileSavePath(MxString *p_outPath, MxULong p_slotn)
{
// TODO
return 0;
char baseForSlot[2] = "0";
char path[1024] = "";
// Save path base
if (m_savePath != NULL)
strcpy(path, m_savePath);
// Slot: "G0", "G1", ...
strcat(path, "G");
baseForSlot[0] += p_slotn;
strcat(path, baseForSlot);
// Extension: ".GS"
strcat(path, g_fileExtensionGS);
*p_outPath = &MxString(path);
}
// OFFSET: LEGO1 0x1003a2e0
struct ColorStringStruct
{
const char *m_targetName;
const char *m_colorName;
};
// OFFSET: LEGO1 0x100f3e58
ColorStringStruct g_colorSaveData[43] = {
{"c_dbbkfny0", "lego red"},
{"c_dbbkxly0", "lego white"},
{"c_chbasey0", "lego black"},
{"c_chbacky0", "lego black"},
{"c_chdishy0", "lego white"},
{"c_chhorny0", "lego black"},
{"c_chljety1", "lego black"},
{"c_chrjety1", "lego black"},
{"c_chmidly0", "lego black"},
{"c_chmotry0", "lego blue"},
{"c_chsidly0", "lego black"},
{"c_chsidry0", "lego black"},
{"c_chstuty0", "lego black"},
{"c_chtaily0", "lego black"},
{"c_chwindy1", "lego black"},
{"c_dbfbrdy0", "lego red"},
{"c_dbflagy0", "lego yellow"},
{"c_dbfrfny4", "lego red"},
{"c_dbfrxly0", "lego white"},
{"c_dbhndly0", "lego white"},
{"c_dbltbry0", "lego white"},
{"c_jsdashy0", "lego white"},
{"c_jsexhy0", "lego black"},
{"c_jsfrnty5", "lego black"},
{"c_jshndly0", "lego red"},
{"c_jslsidy0", "lego black"},
{"c_jsrsidy0", "lego black"},
{"c_jsskiby0", "lego red"},
{"c_jswnshy5", "lego white"},
{"c_rcbacky6", "lego green"},
{"c_rcedgey0", "lego green"},
{"c_rcfrmey0", "lego red"},
{"c_rcfrnty6", "lego green"},
{"c_rcmotry0", "lego white"},
{"c_rcsidey0", "lego green"},
{"c_rcstery0", "lego white"},
{"c_rcstrpy0", "lego yellow"},
{"c_rctailya", "lego white"},
{"c_rcwhl1y0", "lego white"},
{"c_rcwhl2y0", "lego white"},
{"c_jsbasey0", "lego white"},
{"c_chblady0", "lego black"},
{"c_chseaty0", "lego white"},
};
// Move this into the appropriate header
extern const char *s_endOfVariables;
// OFFSET: LEGO1 0x1003a020
MxResult __stdcall WriteEndOfVariables(LegoStream *p_stream)
{
unsigned char len = strlen(s_endOfVariables);
if (p_stream->Write(&len, 1) == SUCCESS)
return p_stream->Write(s_endOfVariables, len);
return FAILURE;
}
struct SaveData3
{
};
DECOMP_SIZE_ASSERT(SaveData3, 0x108);
MxResult WriteSaveData3(void* p_unusedThis, LegoStream* p_stream)
{
MxResult result = FAILURE;
return result;
}
// TODO: Not decomp accurate, but trying to work towards writing a functional
// save file.
// OFFSET: LEGO1 0x10039980 STUB
MxResult LegoGameState::Save(MxULong p_slot)
{
MxResult result;
InfocenterState *infocenterState = (InfocenterState *)GameState()->GetState("InfocenterState");
if (infocenterState == NULL || infocenterState->GetSomething(0) == 0)
{
result = SUCCESS;
}
else
{
result = FAILURE;
MxVariableTable *variableTable = VariableTable();
MxString savePath;
GetFileSavePath(&savePath, p_slot);
LegoFileStream fileStream;
if (fileStream.Open(savePath.GetData(), LegoStream::WriteBit) != FAILURE)
{
MxU32 maybeVersion = 0x1000C;
fileStream.Write(&maybeVersion, 4);
fileStream.Write(&m_secondThingWritten, 2);
fileStream.Write(&m_someEnumState, 2);
fileStream.Write(&m_someModeSwitch, 1);
for (int i = 0; i < sizeof(g_colorSaveData) / sizeof(g_colorSaveData[0]); ++i)
{
if (LegoStream::WriteVariable(&fileStream, variableTable, g_colorSaveData[i].m_targetName) == FAILURE)
return result;
}
if (LegoStream::WriteVariable(&fileStream, variableTable, "backgroundcolor") != FAILURE)
{
if (LegoStream::WriteVariable(&fileStream, variableTable, "lightposition") != FAILURE)
{
WriteEndOfVariables(&fileStream);
// TODO: Calls down to more aggregate writing functions
printf("Debug|Saved as much as implemented so far.\n");
return SUCCESS;
}
}
}
}
return result;
}
// OFFSET: LEGO1 0x1003a2e0 STUB
void LegoGameState::SerializePlayersInfo(MxS16 p)
{
// TODO
}
// OFFSET: LEGO1 0x1003cdd0
// OFFSET: LEGO1 0x1003cdd0 STUB
void LegoGameState::SerializeScoreHistory(MxS16 p)
{
// TODO
@ -56,3 +209,53 @@ void LegoGameState::SetSavePath(char *p_savePath)
m_savePath = NULL;
}
}
// OFFSET: LEGO1 0x1003bbb0
LegoState *LegoGameState::GetState(char *p_stateName)
{
for (MxS32 i = 0; i < m_stateCount; ++i)
{
if (m_stateArray[i]->IsA(p_stateName))
{
return m_stateArray[i];
}
}
return NULL;
}
// OFFSET: LEGO1 0x1003bc00
LegoState *LegoGameState::CreateState(char *p_stateName)
{
LegoState* newState = (LegoState*)ObjectFactory()->Create(p_stateName);
RegisterState(newState);
return newState;
}
// OFFSET: LEGO1 0x1003bc30
void LegoGameState::RegisterState(LegoState *p_state)
{
int targetIndex;
for (targetIndex = 0; targetIndex < m_stateCount; ++targetIndex)
{
if (m_stateArray[targetIndex]->IsA(p_state->ClassName()))
break;
}
if (targetIndex == m_stateCount)
{
LegoState **newBuffer = (LegoState**)malloc(m_stateCount * 4 + 4);
if (m_stateCount != 0)
{
memcpy(newBuffer, m_stateArray, m_stateCount * sizeof(LegoState*));
free(m_stateArray);
}
newBuffer[m_stateCount++] = p_state;
m_stateArray = newBuffer;
return;
}
if (m_stateArray[targetIndex] != NULL)
{
delete m_stateArray[targetIndex];
}
m_stateArray[targetIndex] = p_state;
}

View File

@ -3,6 +3,10 @@
#include "mxtypes.h"
class LegoState;
class MxVariable;
class MxString;
class LegoGameState
{
public:
@ -14,8 +18,27 @@ class LegoGameState
__declspec(dllexport) void SerializeScoreHistory(MxS16 p);
__declspec(dllexport) void SetSavePath(char *p);
LegoState *GetState(char *p_stateName);
LegoState *CreateState(char *p_stateName);
void GetFileSavePath(MxString *p_outPath, MxULong p_slotn);
private:
void RegisterState(LegoState *p_state);
private:
char *m_savePath;
MxS16 m_stateCount;
MxU16 padding1;
LegoState **m_stateArray;
MxU8 m_someModeSwitch;
MxU8 padding2[3];
MxU32 m_someEnumState;
MxU32 unk1;
MxVariable *m_backgroundColor;
MxVariable *m_tempBackgroundColor;
MxVariable *m_fsMovieVariable;
MxU16 m_secondThingWritten;
};
#endif // LEGOGAMESTATE_H

View File

@ -0,0 +1,35 @@
#include "legoobjectfactory.h"
#include "infocenterstate.h"
#include "decomp.h"
// TODO: Uncomment once we have all the relevant types ready
// DECOMP_SIZE_ASSERT(LegoObjectFactory, 0x1c4);
// OFFSET: LEGO1 0x100b0d80
LegoObjectFactory::LegoObjectFactory()
{
#define X(V) this->m_id##V = MxAtomId(#V, LookupMode_Exact);
FOR_LEGOOBJECTFACTORY_OBJECTS(X)
#undef X
}
// OFFSET: LEGO1 0x100b12c0
void *LegoObjectFactory::Create(const char *p_name)
{
MxAtomId atom(p_name, LookupMode_Exact);
if (0) {
#define X(V) } else if (this->m_id##V == atom) { return new V;
FOR_LEGOOBJECTFACTORY_OBJECTS(X)
#undef X
} else {
return MxObjectFactory::Create(p_name);
}
}
// OFFSET: LEGO1 0x100b1a30 STUB
void LegoObjectFactory::Destroy(void *p_object) {
// FIXME
}

22
LEGO1/legoobjectfactory.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef LEGOOBJECTFACTORY_H
#define LEGOOBJECTFACTORY_H
#include "mxobjectfactory.h"
#define FOR_LEGOOBJECTFACTORY_OBJECTS(X) \
X(InfocenterState)
// VTABLE 0x100dc220
class LegoObjectFactory : public MxObjectFactory
{
public:
LegoObjectFactory();
virtual void *Create(const char *p_name); // vtable 0x14
virtual void Destroy(void *p_object); // vtable 0x18
private:
#define X(V) MxAtomId m_id##V;
FOR_LEGOOBJECTFACTORY_OBJECTS(X)
#undef X
};
#endif // LEGOOBJECTFACTORY_H

View File

@ -1,4 +1,5 @@
#include "legoomni.h"
#include "legoobjectfactory.h"
// 0x100f4588
char *g_nocdSourceName = NULL;
@ -175,10 +176,13 @@ void LegoOmni::Init()
// FIXME: Stub
}
// OFFSET: LEGO1 0x10058e70
// OFFSET: LEGO1 0x10058e70 STUB
MxResult LegoOmni::Create(COMPAT_CONST MxOmniCreateParam &p)
{
// FIXME: Stub
MxOmni::Create(p);
m_objectFactory = new LegoObjectFactory();
m_gameState = new LegoGameState();
return SUCCESS;
}

View File

@ -4,6 +4,8 @@
#include <cstdio>
#include <string>
#include "mxvariabletable.h"
// Very likely but not certain sizes.
// The classes are only used on the stack in functions we have not 100% matched
// yet, we can confirm the size once we have.
@ -38,7 +40,7 @@ LegoFileStream::~LegoFileStream()
}
// OFFSET: LEGO1 0x100992c0
MxResult LegoFileStream::Read(char* p_buffer, MxU32 p_size)
MxResult LegoFileStream::Read(void* p_buffer, MxU32 p_size)
{
if (m_hFile == NULL)
return FAILURE;
@ -47,7 +49,7 @@ MxResult LegoFileStream::Read(char* p_buffer, MxU32 p_size)
}
// OFFSET: LEGO1 0x10099300
MxResult LegoFileStream::Write(char* p_buffer, MxU32 p_size)
MxResult LegoFileStream::Write(const void* p_buffer, MxU32 p_size)
{
if (m_hFile == NULL)
return FAILURE;
@ -117,7 +119,7 @@ LegoMemoryStream::LegoMemoryStream(char* p_buffer)
}
// OFFSET: LEGO1 0x10099160
MxResult LegoMemoryStream::Read(char* p_buffer, MxU32 p_size)
MxResult LegoMemoryStream::Read(void* p_buffer, MxU32 p_size)
{
memcpy(p_buffer, m_buffer + m_offset, p_size);
m_offset += p_size;
@ -125,7 +127,7 @@ MxResult LegoMemoryStream::Read(char* p_buffer, MxU32 p_size)
}
// OFFSET: LEGO1 0x10099190
MxResult LegoMemoryStream::Write(char* p_buffer, MxU32 p_size)
MxResult LegoMemoryStream::Write(const void* p_buffer, MxU32 p_size)
{
memcpy(m_buffer + m_offset, p_buffer, p_size);
m_offset += p_size;
@ -146,4 +148,65 @@ MxResult LegoMemoryStream::Seek(MxU32 p_offset)
return SUCCESS;
}
// OFFSET: LEGO1 0x10039f70
MxResult LegoStream::WriteVariable(LegoStream* p_stream, MxVariableTable* p_from, const char* p_variableName)
{
MxResult result = FAILURE;
const char *variableValue = p_from->GetVariable(p_variableName);
if (variableValue != NULL)
{
MxU8 length = strlen(p_variableName);
if (p_stream->Write((char*)&length, 1) == SUCCESS)
{
if (p_stream->Write(p_variableName, length) == SUCCESS)
{
length = strlen(variableValue);
if (p_stream->Write((char*)&length, 1) == SUCCESS)
result = p_stream->Write((char *)variableValue, length);
}
}
}
return result;
}
// This is a pointer to the end of the global variable name table, which has
// the text "END_OF_VARIABLES" in it.
// TODO: make s_endOfVariables reference the actual end of the variable array.
// OFFSET: LEGO1 0x100f3e50
const char *s_endOfVariables = "END_OF_VARIABLES";
// 95% match, just some instruction ordering differences on the call to
// MxVariableTable::SetVariable at the end.
// OFFSET: LEGO1 0x1003a080
int LegoStream::ReadVariable(LegoStream* p_stream, MxVariableTable* p_to)
{
int result = 1;
MxU8 length;
if (p_stream->Read((char*)&length, 1) == SUCCESS)
{
char nameBuffer[256];
if (p_stream->Read(nameBuffer, length) == SUCCESS)
{
nameBuffer[length] = '\0';
if (strcmp(nameBuffer, s_endOfVariables) == 0)
{
// 2 -> "This was the last entry, done reading."
result = 2;
}
else
{
if (p_stream->Read((char*)&length, 1) == SUCCESS)
{
char valueBuffer[256];
if (p_stream->Read(valueBuffer, length) == SUCCESS)
{
result = 0;
valueBuffer[length] = '\0';
p_to->SetVariable(nameBuffer, valueBuffer);
}
}
}
}
}
return result;
}

View File

@ -9,6 +9,8 @@
#define LEGOSTREAM_MODE_READ 1
#define LEGOSTREAM_MODE_WRITE 2
class MxVariableTable;
// VTABLE 0x100d7d80
class LegoStream
{
@ -16,8 +18,8 @@ class LegoStream
LegoStream() : m_mode(0) {}
inline virtual ~LegoStream() {};
virtual MxResult Read(char* p_buffer, MxU32 p_size) = 0;
virtual MxResult Write(char* p_buffer, MxU32 p_size) = 0;
virtual MxResult Read(void* p_buffer, MxU32 p_size) = 0;
virtual MxResult Write(const void* p_buffer, MxU32 p_size) = 0;
virtual MxResult Tell(MxU32* p_offset) = 0;
virtual MxResult Seek(MxU32 p_offset) = 0;
@ -31,6 +33,9 @@ class LegoStream
BinaryBit = 4,
};
static MxResult __stdcall WriteVariable(LegoStream* p_stream, MxVariableTable* p_from, const char* p_variableName);
static int __stdcall ReadVariable(LegoStream* p_stream, MxVariableTable* p_to);
protected:
MxU8 m_mode;
};
@ -42,8 +47,8 @@ class LegoFileStream : public LegoStream
LegoFileStream();
virtual ~LegoFileStream();
MxResult Read(char* p_buffer, MxU32 p_size) override;
MxResult Write(char* p_buffer, MxU32 p_size) override;
MxResult Read(void* p_buffer, MxU32 p_size) override;
MxResult Write(const void* p_buffer, MxU32 p_size) override;
MxResult Tell(MxU32* p_offset) override;
MxResult Seek(MxU32 p_offset) override;
@ -60,8 +65,8 @@ class LegoMemoryStream : public LegoStream
LegoMemoryStream(char* p_buffer);
~LegoMemoryStream() {}
MxResult Read(char* p_buffer, MxU32 p_size) override;
MxResult Write(char* p_buffer, MxU32 p_size) override;
MxResult Read(void* p_buffer, MxU32 p_size) override;
MxResult Write(const void* p_buffer, MxU32 p_size) override;
MxResult Tell(MxU32* p_offset) override;
MxResult Seek(MxU32 p_offset) override;

View File

@ -1,18 +1,18 @@
#include "mxatomid.h"
// OFFSET: LEGO1 0x100acf90
// OFFSET: LEGO1 0x100acf90 STUB
MxAtomId::MxAtomId(const char *, LookupMode)
{
// TODO
}
// OFFSET: LEGO1 0x100acfd0
// OFFSET: LEGO1 0x100acfd0 STUB
MxAtomId::~MxAtomId()
{
// TODO
}
// OFFSET: LEGO1 0x100ad1c0
// OFFSET: LEGO1 0x100ad1c0 STUB
MxAtomId &MxAtomId::operator=(const MxAtomId &id)
{
// TODO

View File

@ -1,5 +1,7 @@
#include "mxobjectfactory.h"
#include <stdio.h>
#include "mxpresenter.h"
#include "mxcompositepresenter.h"
#include "mxvideopresenter.h"
@ -26,9 +28,9 @@ MxObjectFactory::MxObjectFactory()
}
// OFFSET: LEGO1 0x100b12c0
MxCore *MxObjectFactory::Create(const char *name)
void *MxObjectFactory::Create(const char *p_name)
{
MxAtomId atom(name, LookupMode_Exact);
MxAtomId atom(p_name, LookupMode_Exact);
if (0) {
#define X(V) } else if (this->m_id##V == atom) { return new V;
@ -40,6 +42,6 @@ MxCore *MxObjectFactory::Create(const char *name)
}
// OFFSET: LEGO1 0x100b1a30 STUB
void MxObjectFactory::vtable18(void *) {
void MxObjectFactory::Destroy(void *p_object) {
// FIXME
}

View File

@ -23,8 +23,8 @@ class MxObjectFactory : public MxCore
{
public:
MxObjectFactory();
virtual MxCore *Create(const char *name); // vtable 0x14
virtual void vtable18(void *); // vtable 0x18
virtual void *Create(const char *p_name); // vtable 0x14
virtual void Destroy(void *p_object); // vtable 0x18
private:
#define X(V) MxAtomId m_id##V;
FOR_MXOBJECTFACTORY_OBJECTS(X)

View File

@ -104,6 +104,14 @@ void MxOmni::SetInstance(MxOmni *instance)
// OFFSET: LEGO1 0x100af0c0
MxResult MxOmni::Create(MxOmniCreateParam &p)
{
if (p.CreateFlags().CreateObjectFactory())
{
MxObjectFactory *factory = new MxObjectFactory();
this->m_objectFactory = factory;
if (factory == NULL)
return FAILURE;
}
if (p.CreateFlags().CreateTimer())
{
MxTimer *timer = new MxTimer();

View File

@ -78,4 +78,6 @@ __declspec(dllexport) MxMusicManager * MusicManager();
__declspec(dllexport) MxEventManager * EventManager();
__declspec(dllexport) MxNotificationManager * NotificationManager();
MxObjectFactory *ObjectFactory();
#endif // MXOMNI_H