Fixes, refactorings

This commit is contained in:
Christian Semmler 2023-10-12 11:46:40 -04:00
parent d7835c95c1
commit 9acc23d59f
16 changed files with 259 additions and 261 deletions

View File

@ -90,6 +90,7 @@ add_library(lego1 SHARED
LEGO1/legostream.cpp LEGO1/legostream.cpp
LEGO1/legotexturepresenter.cpp LEGO1/legotexturepresenter.cpp
LEGO1/legoutil.cpp LEGO1/legoutil.cpp
LEGO1/legounksavedatawriter.cpp
LEGO1/legovideomanager.cpp LEGO1/legovideomanager.cpp
LEGO1/legoworld.cpp LEGO1/legoworld.cpp
LEGO1/legoworldpresenter.cpp LEGO1/legoworldpresenter.cpp

View File

@ -26,34 +26,37 @@ class InfocenterState : public LegoState
return !strcmp(name, InfocenterState::ClassName()) || LegoState::IsA(name); return !strcmp(name, InfocenterState::ClassName()) || LegoState::IsA(name);
} }
inline MxU32 GetInfocenterBufferElement(int p_index) { return m_buffer[p_index]; } inline MxU32 GetInfocenterBufferElement(MxS32 p_index) { return m_buffer[p_index]; }
private: private:
// Size: 0xC /*
struct SomeStruct struct SomeStruct
{ {
undefined4 unk1; undefined4 unk1;
undefined2 unk2; undefined2 unk2;
undefined2 unk3; undefined2 unk3;
undefined2 unk4; undefined2 unk4;
}; };
undefined2 unk1; undefined2 unk1;
undefined2 unk2; undefined2 unk2;
undefined4 unk3; undefined4 unk3;
undefined4 padding1; undefined4 padding1;
void *unk4; void *unk4;
undefined2 unk5; undefined2 unk5;
undefined2 unk6; undefined2 unk6;
undefined2 unk7; undefined2 unk7;
undefined2 padding2; undefined2 padding2;
void *unk8; void *unk8;
undefined2 unk9; undefined2 unk9;
undefined2 unk10; undefined2 unk10;
undefined2 unk11; undefined2 unk11;
undefined2 padding3; undefined2 padding3;
SomeStruct unk12[6]; SomeStruct unk12[6];
undefined4 unk13; undefined4 unk13;
*/
undefined pad[0x70];
MxU32 m_buffer[7]; MxU32 m_buffer[7];
}; };

View File

@ -4,6 +4,7 @@
#include "legostate.h" #include "legostate.h"
#include "infocenterstate.h" #include "infocenterstate.h"
#include "legostream.h" #include "legostream.h"
#include "mxobjectfactory.h"
#include "mxvariabletable.h" #include "mxvariabletable.h"
#include "mxstring.h" #include "mxstring.h"
@ -11,67 +12,10 @@
// There may be other members that come after. // There may be other members that come after.
DECOMP_SIZE_ASSERT(LegoGameState, 0x430) DECOMP_SIZE_ASSERT(LegoGameState, 0x430)
// OFFSET: LEGO1 0x10039550 // GLOBAL OFFSET: LEGO1 0x100f3e40
LegoGameState::LegoGameState()
{
// TODO
m_stateCount = 0;
m_backgroundColor = new LegoBackgroundColor("backgroundcolor", "set 56 54 68");
VariableTable()->SetVariable(m_backgroundColor);
m_tempBackgroundColor = new LegoBackgroundColor("tempBackgroundcolor", "set 56 54 68");
VariableTable()->SetVariable(m_tempBackgroundColor);
m_fullScreenMovie = new LegoFullScreenMovie("fsmovie", "disable");
VariableTable()->SetVariable(m_fullScreenMovie);
VariableTable()->SetVariable("lightposition", "2");
SerializeScoreHistory(1);
}
// OFFSET: LEGO1 0x10039720 STUB
LegoGameState::~LegoGameState()
{
// TODO
}
// OFFSET: LEGO1 0x10039c60 STUB
MxResult LegoGameState::Load(MxULong)
{
// TODO
return 0;
}
// OFFSET: LEGO1 0x100f3e40
const char *g_fileExtensionGS = ".GS"; const char *g_fileExtensionGS = ".GS";
// OFFSET: LEGO1 0x1003a170 // GLOBAL OFFSET: LEGO1 0x100f3e58
void LegoGameState::GetFileSavePath(MxString *p_outPath, MxULong p_slotn)
{
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);
}
struct ColorStringStruct
{
const char *m_targetName;
const char *m_colorName;
};
// OFFSET: LEGO1 0x100f3e58
ColorStringStruct g_colorSaveData[43] = { ColorStringStruct g_colorSaveData[43] = {
{"c_dbbkfny0", "lego red"}, {"c_dbbkfny0", "lego red"},
{"c_dbbkxly0", "lego white"}, {"c_dbbkxly0", "lego white"},
@ -120,145 +64,102 @@ ColorStringStruct g_colorSaveData[43] = {
// NOTE: This offset = the end of the variables table, the last entry // NOTE: This offset = the end of the variables table, the last entry
// in that table is a special entry, the string "END_OF_VARIABLES" // in that table is a special entry, the string "END_OF_VARIABLES"
// OFFSET: LEGO1 0x100f3e50 // GLOBAL OFFSET: LEGO1 0x100f3e50
extern const char *s_endOfVariables; extern const char *s_endOfVariables;
// OFFSET: LEGO1 0x1003a020 // OFFSET: LEGO1 0x10039550
MxResult __stdcall WriteEndOfVariables(LegoStream *p_stream) LegoGameState::LegoGameState()
{ {
unsigned char len = strlen(s_endOfVariables); // TODO
m_stateCount = 0;
m_backgroundColor = new LegoBackgroundColor("backgroundcolor", "set 56 54 68");
VariableTable()->SetVariable(m_backgroundColor);
m_tempBackgroundColor = new LegoBackgroundColor("tempBackgroundcolor", "set 56 54 68");
VariableTable()->SetVariable(m_tempBackgroundColor);
m_fullScreenMovie = new LegoFullScreenMovie("fsmovie", "disable");
VariableTable()->SetVariable(m_fullScreenMovie);
VariableTable()->SetVariable("lightposition", "2");
SerializeScoreHistory(1);
}
// OFFSET: LEGO1 0x10039720 STUB
LegoGameState::~LegoGameState()
{
// TODO
}
// OFFSET: LEGO1 0x10039c60 STUB
MxResult LegoGameState::Load(MxULong)
{
// TODO
return 0;
}
// OFFSET: LEGO1 0x1003a170
void LegoGameState::GetFileSavePath(MxString *p_outPath, MxULong p_slotn)
{
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 0x1003a020
MxResult LegoGameState::WriteEndOfVariables(LegoStream *p_stream)
{
MxU8 len = strlen(s_endOfVariables);
if (p_stream->Write(&len, 1) == SUCCESS) if (p_stream->Write(&len, 1) == SUCCESS)
return p_stream->Write(s_endOfVariables, len); return p_stream->Write(s_endOfVariables, len);
return FAILURE; return FAILURE;
} }
struct LegoSaveDataEntry3 // OFFSET: LEGO1 0x10039980
{
char *m_name;
void *m_pSomething1;
void *m_pSomething2;
int m_savePart1;
int m_savePart2;
MxU8 m_savePart3;
undefined padding1[3];
undefined unk1[24];
MxU8 m_frameOffsetInDwords;
int *m_pFrameData;
MxU8 m_currentFrame;
undefined padding2[3];
undefined unk2[8];
MxU8 m_savePart5;
undefined padding3[3];
undefined unk3[20];
MxU8 m_savePart6;
undefined padding4[3];
undefined unk4[44];
MxU8 m_savePart7;
undefined padding5[3];
undefined unk5[20];
MxU8 m_savePart8;
undefined padding6[3];
undefined unk6[68];
MxU8 m_savePart9;
undefined padding7[3];
undefined unk7[20];
MxU8 m_savePart10;
undefined padding8[3];
};
DECOMP_SIZE_ASSERT(LegoSaveDataEntry3, 0x108);
// OFFSET: LEGO1 0x10104f20
LegoSaveDataEntry3 g_saveData3[66];
// Some Mx singleton which is in 0x8C of LegoOmni
class UnknownWritingSaveData3 {
MxResult WriteSaveData3(LegoStream *p_stream);
};
// Match except for swapped registers
// OFFSET: LEGO1 0x10083310
MxResult UnknownWritingSaveData3::WriteSaveData3(LegoStream *p_stream)
{
MxResult result = FAILURE;
// This should probably be a for loop but I can't figure out how to
// make it match as a for loop.
LegoSaveDataEntry3 *entry = g_saveData3;
const LegoSaveDataEntry3 *end = &g_saveData3[66];
while (true)
{
if (p_stream->Write(&entry->m_savePart1, 4) != SUCCESS)
break;
if (p_stream->Write(&entry->m_savePart2, 4) != SUCCESS)
break;
if (p_stream->Write(&entry->m_savePart3, 1) != SUCCESS)
break;
if (p_stream->Write(&entry->m_currentFrame, 1) != SUCCESS)
break;
if (p_stream->Write(&entry->m_savePart5, 1) != SUCCESS)
break;
if (p_stream->Write(&entry->m_savePart6, 1) != SUCCESS)
break;
if (p_stream->Write(&entry->m_savePart7, 1) != SUCCESS)
break;
if (p_stream->Write(&entry->m_savePart8, 1) != SUCCESS)
break;
if (p_stream->Write(&entry->m_savePart9, 1) != SUCCESS)
break;
if (p_stream->Write(&entry->m_savePart10, 1) != SUCCESS)
break;
if (++entry >= end)
{
result = SUCCESS;
break;
}
}
return result;
}
// OFFSET: LEGO1 0x10039980 STUB
MxResult LegoGameState::Save(MxULong p_slot) MxResult LegoGameState::Save(MxULong p_slot)
{ {
MxResult result; MxResult result;
InfocenterState *infocenterState = (InfocenterState *)GameState()->GetState("InfocenterState"); InfocenterState *infocenterState = (InfocenterState *)GameState()->GetState("InfocenterState");
if (infocenterState == NULL || infocenterState->GetInfocenterBufferElement(0) == 0) if (!infocenterState || infocenterState->GetInfocenterBufferElement(0) == 0)
{
result = SUCCESS; result = SUCCESS;
} else {
else
{
result = FAILURE; result = FAILURE;
MxVariableTable *variableTable = VariableTable(); MxVariableTable *variableTable = VariableTable();
MxString savePath; MxString savePath;
GetFileSavePath(&savePath, p_slot); GetFileSavePath(&savePath, p_slot);
LegoFileStream fileStream; LegoFileStream fileStream;
if (fileStream.Open(savePath.GetData(), LegoStream::WriteBit) != FAILURE) if (fileStream.Open(savePath.GetData(), LegoStream::WriteBit) != FAILURE) {
{
MxU32 maybeVersion = 0x1000C; MxU32 maybeVersion = 0x1000C;
fileStream.Write(&maybeVersion, 4); fileStream.Write(&maybeVersion, 4);
fileStream.Write(&m_secondThingWritten, 2); fileStream.Write(&m_secondThingWritten, 2);
fileStream.Write(&m_someEnumState, 2); fileStream.Write(&m_someEnumState, 2);
fileStream.Write(&m_someModeSwitch, 1); fileStream.Write(&m_someModeSwitch, 1);
for (int i = 0; i < sizeof(g_colorSaveData) / sizeof(g_colorSaveData[0]); ++i) for (MxS32 i = 0; i < sizeof(g_colorSaveData) / sizeof(g_colorSaveData[0]); ++i) {
{
if (LegoStream::WriteVariable(&fileStream, variableTable, g_colorSaveData[i].m_targetName) == FAILURE) if (LegoStream::WriteVariable(&fileStream, variableTable, g_colorSaveData[i].m_targetName) == FAILURE)
return result; return result;
} }
if (LegoStream::WriteVariable(&fileStream, variableTable, "backgroundcolor") != FAILURE) if (LegoStream::WriteVariable(&fileStream, variableTable, "backgroundcolor") != FAILURE) {
{ if (LegoStream::WriteVariable(&fileStream, variableTable, "lightposition") != FAILURE) {
if (LegoStream::WriteVariable(&fileStream, variableTable, "lightposition") != FAILURE)
{
WriteEndOfVariables(&fileStream); WriteEndOfVariables(&fileStream);
// TODO: Calls down to more aggregate writing functions // TODO: Calls down to more aggregate writing functions
return SUCCESS; return SUCCESS;
} }
} }
} }
} }
return result; return result;
@ -280,30 +181,22 @@ void LegoGameState::SerializeScoreHistory(MxS16 p)
void LegoGameState::SetSavePath(char *p_savePath) void LegoGameState::SetSavePath(char *p_savePath)
{ {
if (m_savePath != NULL) if (m_savePath != NULL)
{
delete[] m_savePath; delete[] m_savePath;
}
if (p_savePath) if (p_savePath) {
{
m_savePath = new char[strlen(p_savePath) + 1]; m_savePath = new char[strlen(p_savePath) + 1];
strcpy(m_savePath, p_savePath); strcpy(m_savePath, p_savePath);
} }
else else
{
m_savePath = NULL; m_savePath = NULL;
}
} }
// OFFSET: LEGO1 0x1003bbb0 // OFFSET: LEGO1 0x1003bbb0
LegoState *LegoGameState::GetState(char *p_stateName) LegoState *LegoGameState::GetState(char *p_stateName)
{ {
for (MxS32 i = 0; i < m_stateCount; ++i) for (MxS32 i = 0; i < m_stateCount; ++i)
{
if (m_stateArray[i]->IsA(p_stateName)) if (m_stateArray[i]->IsA(p_stateName))
{
return m_stateArray[i]; return m_stateArray[i];
}
}
return NULL; return NULL;
} }
@ -319,27 +212,25 @@ LegoState *LegoGameState::CreateState(char *p_stateName)
// OFFSET: LEGO1 0x1003bc30 // OFFSET: LEGO1 0x1003bc30
void LegoGameState::RegisterState(LegoState *p_state) void LegoGameState::RegisterState(LegoState *p_state)
{ {
int targetIndex; MxS32 targetIndex;
for (targetIndex = 0; targetIndex < m_stateCount; ++targetIndex) for (targetIndex = 0; targetIndex < m_stateCount; ++targetIndex)
{
if (m_stateArray[targetIndex]->IsA(p_state->ClassName())) if (m_stateArray[targetIndex]->IsA(p_state->ClassName()))
break; break;
}
if (targetIndex == m_stateCount) if (targetIndex == m_stateCount) {
{ LegoState **newBuffer = new LegoState*[m_stateCount + 1];
LegoState **newBuffer = (LegoState**)malloc(m_stateCount * 4 + 4);
if (m_stateCount != 0) if (m_stateCount != 0) {
{
memcpy(newBuffer, m_stateArray, m_stateCount * sizeof(LegoState*)); memcpy(newBuffer, m_stateArray, m_stateCount * sizeof(LegoState*));
free(m_stateArray); delete[] m_stateArray;
} }
newBuffer[m_stateCount++] = p_state; newBuffer[m_stateCount++] = p_state;
m_stateArray = newBuffer; m_stateArray = newBuffer;
return; return;
} }
if (m_stateArray[targetIndex] != NULL)
{ if (m_stateArray[targetIndex])
delete m_stateArray[targetIndex]; delete m_stateArray[targetIndex];
}
m_stateArray[targetIndex] = p_state; m_stateArray[targetIndex] = p_state;
} }

View File

@ -7,9 +7,16 @@
#include "legofullscreenmovie.h" #include "legofullscreenmovie.h"
class LegoState; class LegoState;
class LegoStream;
class MxVariable; class MxVariable;
class MxString; class MxString;
struct ColorStringStruct
{
const char *m_targetName;
const char *m_colorName;
};
// SIZE 0x430 (at least) // SIZE 0x430 (at least)
class LegoGameState class LegoGameState
{ {
@ -29,6 +36,7 @@ class LegoGameState
private: private:
void RegisterState(LegoState *p_state); void RegisterState(LegoState *p_state);
MxResult WriteEndOfVariables(LegoStream *p_stream);
private: private:
char *m_savePath; // 0x0 char *m_savePath; // 0x0
@ -41,7 +49,7 @@ class LegoGameState
LegoBackgroundColor *m_tempBackgroundColor; // 0x1c LegoBackgroundColor *m_tempBackgroundColor; // 0x1c
LegoFullScreenMovie *m_fullScreenMovie; // 0x20 LegoFullScreenMovie *m_fullScreenMovie; // 0x20
MxU16 m_secondThingWritten; MxU16 m_secondThingWritten;
undefined m_unk24[1036]; undefined m_unk24[1032];
}; };
#endif // LEGOGAMESTATE_H #endif // LEGOGAMESTATE_H

View File

@ -1,13 +1,12 @@
#include "legoobjectfactory.h" #include "legoobjectfactory.h"
#include "infocenterstate.h" #include "infocenterstate.h"
#include "decomp.h" #include "decomp.h"
// TODO: Uncomment once we have all the relevant types ready // TODO: Uncomment once we have all the relevant types ready
// DECOMP_SIZE_ASSERT(LegoObjectFactory, 0x1c4); // DECOMP_SIZE_ASSERT(LegoObjectFactory, 0x1c8);
// OFFSET: LEGO1 0x100b0d80 // OFFSET: LEGO1 0x10006e40
LegoObjectFactory::LegoObjectFactory() LegoObjectFactory::LegoObjectFactory()
{ {
#define X(V) this->m_id##V = MxAtomId(#V, LookupMode_Exact); #define X(V) this->m_id##V = MxAtomId(#V, LookupMode_Exact);
@ -15,8 +14,8 @@ LegoObjectFactory::LegoObjectFactory()
#undef X #undef X
} }
// OFFSET: LEGO1 0x100b12c0 // OFFSET: LEGO1 0x10009a90
void *LegoObjectFactory::Create(const char *p_name) MxCore *LegoObjectFactory::Create(const char *p_name)
{ {
MxAtomId atom(p_name, LookupMode_Exact); MxAtomId atom(p_name, LookupMode_Exact);
@ -29,7 +28,8 @@ void *LegoObjectFactory::Create(const char *p_name)
} }
} }
// OFFSET: LEGO1 0x100b1a30 STUB // OFFSET: LEGO1 0x1000fb30 STUB
void LegoObjectFactory::Destroy(void *p_object) { void LegoObjectFactory::Destroy(void *p_object)
// FIXME {
// TODO
} }

View File

@ -6,13 +6,13 @@
#define FOR_LEGOOBJECTFACTORY_OBJECTS(X) \ #define FOR_LEGOOBJECTFACTORY_OBJECTS(X) \
X(InfocenterState) X(InfocenterState)
// VTABLE 0x100dc220 // VTABLE 0x100d4768
class LegoObjectFactory : public MxObjectFactory class LegoObjectFactory : public MxObjectFactory
{ {
public: public:
LegoObjectFactory(); LegoObjectFactory();
virtual void *Create(const char *p_name); // vtable 0x14 virtual MxCore *Create(const char *p_name) override; // vtable 0x14
virtual void Destroy(void *p_object); // vtable 0x18 virtual void Destroy(void *p_object) override; // vtable 0x18
private: private:
#define X(V) MxAtomId m_id##V; #define X(V) MxAtomId m_id##V;
FOR_LEGOOBJECTFACTORY_OBJECTS(X) FOR_LEGOOBJECTFACTORY_OBJECTS(X)

View File

@ -262,7 +262,7 @@ void LegoOmni::Init()
m_currentWorld = NULL; m_currentWorld = NULL;
m_unk80 = FALSE; m_unk80 = FALSE;
m_isle = NULL; m_isle = NULL;
m_unk8c = 0; m_unkLegoSaveDataWriter = NULL;
m_plantManager = NULL; m_plantManager = NULL;
m_gameState = NULL; m_gameState = NULL;
m_animationManager = NULL; m_animationManager = NULL;

View File

@ -16,6 +16,7 @@ class LegoPathBoundary;
class LegoPlantManager; class LegoPlantManager;
class LegoROI; class LegoROI;
class LegoSoundManager; class LegoSoundManager;
class LegoUnkSaveDataWriter;
class LegoVideoManager; class LegoVideoManager;
class LegoWorld; class LegoWorld;
class MxAtomId; class MxAtomId;
@ -77,8 +78,8 @@ class LegoOmni : public MxOmni
LegoWorld *GetCurrentWorld() { return m_currentWorld; } LegoWorld *GetCurrentWorld() { return m_currentWorld; }
private: private:
int m_unk68; undefined4 m_unk68;
int m_unk6c; undefined4 m_unk6c;
LegoInputManager *m_inputMgr; // 0x70 LegoInputManager *m_inputMgr; // 0x70
undefined4 m_unk74; undefined4 m_unk74;
undefined4 m_unk78; undefined4 m_unk78;
@ -86,7 +87,7 @@ class LegoOmni : public MxOmni
MxBool m_unk80; MxBool m_unk80;
LegoNavController *m_navController; // 0x84 LegoNavController *m_navController; // 0x84
Isle* m_isle; // 0x88 Isle* m_isle; // 0x88
undefined4 m_unk8c; LegoUnkSaveDataWriter* m_unkLegoSaveDataWriter;
LegoPlantManager* m_plantManager; // 0x90 LegoPlantManager* m_plantManager; // 0x90
LegoAnimationManager* m_animationManager; LegoAnimationManager* m_animationManager;
LegoBuildingManager* m_buildingManager; // 0x98 LegoBuildingManager* m_buildingManager; // 0x98

View File

@ -6,6 +6,12 @@
#include "mxvariabletable.h" #include "mxvariabletable.h"
// 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.
// GLOBAL OFFSET: LEGO1 0x100f3e50
const char *s_endOfVariables = "END_OF_VARIABLES";
// Very likely but not certain sizes. // Very likely but not certain sizes.
// The classes are only used on the stack in functions we have not 100% matched // The classes are only used on the stack in functions we have not 100% matched
// yet, we can confirm the size once we have. // yet, we can confirm the size once we have.
@ -153,13 +159,11 @@ MxResult LegoStream::WriteVariable(LegoStream* p_stream, MxVariableTable* p_from
{ {
MxResult result = FAILURE; MxResult result = FAILURE;
const char *variableValue = p_from->GetVariable(p_variableName); const char *variableValue = p_from->GetVariable(p_variableName);
if (variableValue != NULL)
{ if (variableValue) {
MxU8 length = strlen(p_variableName); MxU8 length = strlen(p_variableName);
if (p_stream->Write((char*)&length, 1) == SUCCESS) if (p_stream->Write((char*)&length, 1) == SUCCESS) {
{ if (p_stream->Write(p_variableName, length) == SUCCESS) {
if (p_stream->Write(p_variableName, length) == SUCCESS)
{
length = strlen(variableValue); length = strlen(variableValue);
if (p_stream->Write((char*)&length, 1) == SUCCESS) if (p_stream->Write((char*)&length, 1) == SUCCESS)
result = p_stream->Write((char *)variableValue, length); result = p_stream->Write((char *)variableValue, length);
@ -169,37 +173,25 @@ MxResult LegoStream::WriteVariable(LegoStream* p_stream, MxVariableTable* p_from
return result; 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 // 95% match, just some instruction ordering differences on the call to
// MxVariableTable::SetVariable at the end. // MxVariableTable::SetVariable at the end.
// OFFSET: LEGO1 0x1003a080 // OFFSET: LEGO1 0x1003a080
int LegoStream::ReadVariable(LegoStream* p_stream, MxVariableTable* p_to) MxS32 LegoStream::ReadVariable(LegoStream* p_stream, MxVariableTable* p_to)
{ {
int result = 1; MxS32 result = 1;
MxU8 length; MxU8 length;
if (p_stream->Read((char*)&length, 1) == SUCCESS)
{ if (p_stream->Read((char*)&length, 1) == SUCCESS) {
char nameBuffer[256]; char nameBuffer[256];
if (p_stream->Read(nameBuffer, length) == SUCCESS) if (p_stream->Read(nameBuffer, length) == SUCCESS) {
{
nameBuffer[length] = '\0'; nameBuffer[length] = '\0';
if (strcmp(nameBuffer, s_endOfVariables) == 0) if (strcmp(nameBuffer, s_endOfVariables) == 0)
{
// 2 -> "This was the last entry, done reading." // 2 -> "This was the last entry, done reading."
result = 2; result = 2;
} else {
else if (p_stream->Read((char*)&length, 1) == SUCCESS) {
{
if (p_stream->Read((char*)&length, 1) == SUCCESS)
{
char valueBuffer[256]; char valueBuffer[256];
if (p_stream->Read(valueBuffer, length) == SUCCESS) if (p_stream->Read(valueBuffer, length) == SUCCESS) {
{
result = 0; result = 0;
valueBuffer[length] = '\0'; valueBuffer[length] = '\0';
p_to->SetVariable(nameBuffer, valueBuffer); p_to->SetVariable(nameBuffer, valueBuffer);

View File

@ -34,8 +34,8 @@ class LegoStream
BinaryBit = 4, BinaryBit = 4,
}; };
static MxResult __stdcall WriteVariable(LegoStream* p_stream, MxVariableTable* p_from, const char* p_variableName); static MxResult WriteVariable(LegoStream* p_stream, MxVariableTable* p_from, const char* p_variableName);
static int __stdcall ReadVariable(LegoStream* p_stream, MxVariableTable* p_to); static MxS32 ReadVariable(LegoStream* p_stream, MxVariableTable* p_to);
protected: protected:
MxU8 m_mode; MxU8 m_mode;

View File

@ -0,0 +1,48 @@
#include "legounksavedatawriter.h"
#include "legogamestate.h"
#include "legostream.h"
DECOMP_SIZE_ASSERT(LegoSaveDataEntry3, 0x108);
// GLOBAL OFFSET: LEGO1 0x10104f20
LegoSaveDataEntry3 g_saveData3[66];
// OFFSET: LEGO1 0x10083310
MxResult LegoUnkSaveDataWriter::WriteSaveData3(LegoStream *p_stream)
{
MxResult result = FAILURE;
// This should probably be a for loop but I can't figure out how to
// make it match as a for loop.
LegoSaveDataEntry3 *entry = g_saveData3;
const LegoSaveDataEntry3 *end = &g_saveData3[66];
while (TRUE) {
if (p_stream->Write(&entry->m_savePart1, 4) != SUCCESS)
break;
if (p_stream->Write(&entry->m_savePart2, 4) != SUCCESS)
break;
if (p_stream->Write(&entry->m_savePart3, 1) != SUCCESS)
break;
if (p_stream->Write(&entry->m_currentFrame, 1) != SUCCESS)
break;
if (p_stream->Write(&entry->m_savePart5, 1) != SUCCESS)
break;
if (p_stream->Write(&entry->m_savePart6, 1) != SUCCESS)
break;
if (p_stream->Write(&entry->m_savePart7, 1) != SUCCESS)
break;
if (p_stream->Write(&entry->m_savePart8, 1) != SUCCESS)
break;
if (p_stream->Write(&entry->m_savePart9, 1) != SUCCESS)
break;
if (p_stream->Write(&entry->m_savePart10, 1) != SUCCESS)
break;
if (++entry >= end) {
result = SUCCESS;
break;
}
}
return result;
}

View File

@ -0,0 +1,40 @@
#ifndef LEGOUNKSAVEDATAWRITER_H
#define LEGOUNKSAVEDATAWRITER_H
#include "mxtypes.h"
#include "decomp.h"
class LegoStream;
struct LegoSaveDataEntry3
{
char *m_name;
void *m_unk0x04;
void *m_unk0x08;
MxS32 m_savePart1;
MxS32 m_savePart2;
MxU8 m_savePart3;
undefined4 m_unk0x18[6];
MxU8 m_frameOffsetInDwords; // 0x30
MxS32 *m_pFrameData;
MxU8 m_currentFrame;
undefined4 m_unk0x3c[2];
MxU8 m_savePart5; // 0x44
undefined4 m_unk0x48[5];
MxU8 m_savePart6; // 0x5c
undefined4 m_unk0x60[11];
MxU8 m_savePart7; // 0x8c
undefined4 m_unk0x90[5];
MxU8 m_savePart8; // 0xa4
undefined4 m_unk0xa8[17];
MxU8 m_savePart9; // 0xec
undefined4 m_unk0xf0[5];
MxU8 m_savePart10; // 0x104
};
class LegoUnkSaveDataWriter
{
MxResult WriteSaveData3(LegoStream *p_stream);
};
#endif // LEGOUNKSAVEDATAWRITER_H

View File

@ -15,7 +15,7 @@ MxAtomId::MxAtomId(const char *p_str, LookupMode p_mode)
counter->Inc(); counter->Inc();
} }
// OFFSET: LEGO1 0x100acfd0 STUB // OFFSET: LEGO1 0x100acfd0
MxAtomId::~MxAtomId() MxAtomId::~MxAtomId()
{ {
Destroy(); Destroy();

View File

@ -26,7 +26,7 @@ MxObjectFactory::MxObjectFactory()
} }
// OFFSET: LEGO1 0x100b12c0 // OFFSET: LEGO1 0x100b12c0
void *MxObjectFactory::Create(const char *p_name) MxCore *MxObjectFactory::Create(const char *p_name)
{ {
MxAtomId atom(p_name, LookupMode_Exact); MxAtomId atom(p_name, LookupMode_Exact);

View File

@ -23,7 +23,21 @@ class MxObjectFactory : public MxCore
{ {
public: public:
MxObjectFactory(); MxObjectFactory();
virtual void *Create(const char *p_name); // vtable 0x14
// OFFSET: LEGO1 0x1008f70
inline virtual const char *ClassName() const override // vtable+0xc
{
// 0x100f0730
return "MxObjectFactory";
}
// OFFSET: LEGO1 0x1008f80
inline virtual MxBool IsA(const char *name) const override // vtable+0x10
{
return !strcmp(name, MxObjectFactory::ClassName()) || MxCore::IsA(name);
}
virtual MxCore *Create(const char *p_name); // vtable 0x14
virtual void Destroy(void *p_object); // vtable 0x18 virtual void Destroy(void *p_object); // vtable 0x18
private: private:
#define X(V) MxAtomId m_id##V; #define X(V) MxAtomId m_id##V;

View File

@ -93,9 +93,9 @@ __declspec(dllexport) MxVariableTable * VariableTable();
__declspec(dllexport) MxMusicManager * MusicManager(); __declspec(dllexport) MxMusicManager * MusicManager();
__declspec(dllexport) MxEventManager * EventManager(); __declspec(dllexport) MxEventManager * EventManager();
__declspec(dllexport) MxNotificationManager * NotificationManager(); __declspec(dllexport) MxNotificationManager * NotificationManager();
MxVideoManager * MVideoManager();
MxAtomIdCounterSet* AtomIdCounterSet();
MxVideoManager *MVideoManager();
MxAtomIdCounterSet *AtomIdCounterSet();
MxObjectFactory *ObjectFactory(); MxObjectFactory *ObjectFactory();
#endif // MXOMNI_H #endif // MXOMNI_H