100% match of many functions in the LegoGameState::Save codepath (#86)

* Only include decomps

* One more function

* Add offset to endOfVariables

* Remove leftover header

* Use undefined where applicable

* Fixes, refactorings

* Fixes

* Fix calling convention

* Added offset comment

---------

Co-authored-by: Christian Semmler <mail@csemmler.com>
This commit is contained in:
Mark Langen 2023-10-12 09:18:24 -07:00 committed by GitHub
parent 49ec7364c2
commit 91c3ed3e70
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 489 additions and 40 deletions

View file

@ -74,6 +74,7 @@ add_library(lego1 SHARED
LEGO1/legolocomotionanimpresenter.cpp LEGO1/legolocomotionanimpresenter.cpp
LEGO1/legomodelpresenter.cpp LEGO1/legomodelpresenter.cpp
LEGO1/legonavcontroller.cpp LEGO1/legonavcontroller.cpp
LEGO1/legoobjectfactory.cpp
LEGO1/legoomni.cpp LEGO1/legoomni.cpp
LEGO1/legopalettepresenter.cpp LEGO1/legopalettepresenter.cpp
LEGO1/legopartpresenter.cpp LEGO1/legopartpresenter.cpp
@ -89,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

@ -1,5 +1,7 @@
#include "infocenterstate.h" #include "infocenterstate.h"
DECOMP_SIZE_ASSERT(InfocenterState, 0x94);
// OFFSET: LEGO1 0x10071600 STUB // OFFSET: LEGO1 0x10071600 STUB
InfocenterState::InfocenterState() InfocenterState::InfocenterState()
{ {

View file

@ -3,6 +3,8 @@
#include "legostate.h" #include "legostate.h"
#include "decomp.h"
// VTABLE 0x100d93a8 // VTABLE 0x100d93a8
// SIZE 0x94 // SIZE 0x94
class InfocenterState : public LegoState class InfocenterState : public LegoState
@ -23,6 +25,40 @@ class InfocenterState : public LegoState
{ {
return !strcmp(name, InfocenterState::ClassName()) || LegoState::IsA(name); return !strcmp(name, InfocenterState::ClassName()) || LegoState::IsA(name);
} }
inline MxU32 GetInfocenterBufferElement(MxS32 p_index) { return m_buffer[p_index]; }
private:
// Members should be renamed with their offsets before use
/*
struct SomeStruct
{
undefined4 unk1;
undefined2 unk2;
undefined2 unk3;
undefined2 unk4;
};
undefined2 unk1;
undefined2 unk2;
undefined4 unk3;
undefined4 padding1;
void *unk4;
undefined2 unk5;
undefined2 unk6;
undefined2 unk7;
undefined2 padding2;
void *unk8;
undefined2 unk9;
undefined2 unk10;
undefined2 unk11;
undefined2 padding3;
SomeStruct unk12[6];
undefined4 unk13;
*/
undefined pad[0x70];
MxU32 m_buffer[7]; // 0x78
}; };
#endif // INFOCENTERSTATE_H #endif // INFOCENTERSTATE_H

View file

@ -1,17 +1,77 @@
#include "legogamestate.h" #include "legogamestate.h"
#include "legoomni.h" #include "legoomni.h"
#include "legostate.h"
#include "infocenterstate.h"
#include "legostream.h"
#include "mxobjectfactory.h"
#include "mxvariabletable.h" #include "mxvariabletable.h"
#include "decomp.h" #include "mxstring.h"
// Based on the highest dword offset (0x42c) referenced in the constructor. // Based on the highest dword offset (0x42c) referenced in the constructor.
// 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)
// GLOBAL OFFSET: LEGO1 0x100f3e40
const char *g_fileExtensionGS = ".GS";
// GLOBAL 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"},
};
// NOTE: This offset = the end of the variables table, the last entry
// in that table is a special entry, the string "END_OF_VARIABLES"
// GLOBAL OFFSET: LEGO1 0x100f3e50
extern const char *s_endOfVariables;
// OFFSET: LEGO1 0x10039550 // OFFSET: LEGO1 0x10039550
LegoGameState::LegoGameState() LegoGameState::LegoGameState()
{ {
// TODO // TODO
m_stateCount = 0;
m_backgroundColor = new LegoBackgroundColor("backgroundcolor", "set 56 54 68"); m_backgroundColor = new LegoBackgroundColor("backgroundcolor", "set 56 54 68");
VariableTable()->SetVariable(m_backgroundColor); VariableTable()->SetVariable(m_backgroundColor);
@ -25,33 +85,93 @@ LegoGameState::LegoGameState()
SerializeScoreHistory(1); SerializeScoreHistory(1);
} }
// OFFSET: LEGO1 0x10039720 // OFFSET: LEGO1 0x10039720 STUB
LegoGameState::~LegoGameState() LegoGameState::~LegoGameState()
{ {
// TODO // TODO
} }
// OFFSET: LEGO1 0x10039c60 // OFFSET: LEGO1 0x10039c60 STUB
MxResult LegoGameState::Load(MxULong) MxResult LegoGameState::Load(MxULong)
{ {
// TODO // TODO
return 0; return 0;
} }
// OFFSET: LEGO1 0x10039980 // OFFSET: LEGO1 0x1003a170
MxResult LegoGameState::Save(MxULong p) void LegoGameState::GetFileSavePath(MxString *p_outPath, MxULong p_slotn)
{ {
// TODO char baseForSlot[2] = "0";
return 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 // OFFSET: LEGO1 0x1003a020
MxResult LegoGameState::WriteEndOfVariables(LegoStream *p_stream)
{
MxU8 len = strlen(s_endOfVariables);
if (p_stream->Write(&len, 1) == SUCCESS)
return p_stream->Write(s_endOfVariables, len);
return FAILURE;
}
// OFFSET: LEGO1 0x10039980
MxResult LegoGameState::Save(MxULong p_slot)
{
MxResult result;
InfocenterState *infocenterState = (InfocenterState *)GameState()->GetState("InfocenterState");
if (!infocenterState || infocenterState->GetInfocenterBufferElement(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 (MxS32 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
return SUCCESS;
}
}
}
}
return result;
}
// OFFSET: LEGO1 0x1003a2e0 STUB
void LegoGameState::SerializePlayersInfo(MxS16 p) void LegoGameState::SerializePlayersInfo(MxS16 p)
{ {
// TODO // TODO
} }
// OFFSET: LEGO1 0x1003cdd0 // OFFSET: LEGO1 0x1003cdd0 STUB
void LegoGameState::SerializeScoreHistory(MxS16 p) void LegoGameState::SerializeScoreHistory(MxS16 p)
{ {
// TODO // TODO
@ -61,16 +181,56 @@ 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
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)
{
MxS32 targetIndex;
for (targetIndex = 0; targetIndex < m_stateCount; ++targetIndex)
if (m_stateArray[targetIndex]->IsA(p_state->ClassName()))
break;
if (targetIndex == m_stateCount) {
LegoState **newBuffer = new LegoState*[m_stateCount + 1];
if (m_stateCount != 0) {
memcpy(newBuffer, m_stateArray, m_stateCount * sizeof(LegoState*));
delete[] m_stateArray;
}
newBuffer[m_stateCount++] = p_state;
m_stateArray = newBuffer;
return;
}
if (m_stateArray[targetIndex])
delete m_stateArray[targetIndex];
m_stateArray[targetIndex] = p_state;
} }

View file

@ -6,6 +6,17 @@
#include "legobackgroundcolor.h" #include "legobackgroundcolor.h"
#include "legofullscreenmovie.h" #include "legofullscreenmovie.h"
class LegoState;
class LegoStream;
class MxVariable;
class MxString;
struct ColorStringStruct
{
const char *m_targetName;
const char *m_colorName;
};
// SIZE 0x430 (at least) // SIZE 0x430 (at least)
class LegoGameState class LegoGameState
{ {
@ -18,13 +29,27 @@ class LegoGameState
__declspec(dllexport) void SerializeScoreHistory(MxS16 p); __declspec(dllexport) void SerializeScoreHistory(MxS16 p);
__declspec(dllexport) void SetSavePath(char *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);
MxResult WriteEndOfVariables(LegoStream *p_stream);
private: private:
char *m_savePath; // 0x0 char *m_savePath; // 0x0
undefined m_unk04[20]; MxS16 m_stateCount;
LegoState **m_stateArray;
MxU8 m_someModeSwitch;
MxU32 m_someEnumState;
undefined4 m_unk0x14;
LegoBackgroundColor *m_backgroundColor; // 0x18 LegoBackgroundColor *m_backgroundColor; // 0x18
LegoBackgroundColor *m_tempBackgroundColor; // 0x1c LegoBackgroundColor *m_tempBackgroundColor; // 0x1c
LegoFullScreenMovie *m_fullScreenMovie; // 0x20 LegoFullScreenMovie *m_fullScreenMovie; // 0x20
undefined m_unk24[1036]; MxU16 m_secondThingWritten;
undefined m_unk24[1032];
}; };
#endif // LEGOGAMESTATE_H #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, 0x1c8);
// OFFSET: LEGO1 0x10006e40
LegoObjectFactory::LegoObjectFactory()
{
#define X(V) this->m_id##V = MxAtomId(#V, LookupMode_Exact);
FOR_LEGOOBJECTFACTORY_OBJECTS(X)
#undef X
}
// OFFSET: LEGO1 0x10009a90
MxCore *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 0x1000fb30 STUB
void LegoObjectFactory::Destroy(void *p_object)
{
// TODO
}

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 0x100d4768
class LegoObjectFactory : public MxObjectFactory
{
public:
LegoObjectFactory();
virtual MxCore *Create(const char *p_name) override; // vtable 0x14
virtual void Destroy(void *p_object) override; // vtable 0x18
private:
#define X(V) MxAtomId m_id##V;
FOR_LEGOOBJECTFACTORY_OBJECTS(X)
#undef X
};
#endif // LEGOOBJECTFACTORY_H

View file

@ -4,6 +4,7 @@
#include "mxdsfile.h" #include "mxdsfile.h"
#include "legogamestate.h" #include "legogamestate.h"
#include "legoutil.h" #include "legoutil.h"
#include "legoobjectfactory.h"
// 0x100f4588 // 0x100f4588
MxAtomId *g_nocdSourceName = NULL; MxAtomId *g_nocdSourceName = NULL;
@ -261,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;
@ -271,11 +272,12 @@ void LegoOmni::Init()
m_transitionManager = NULL; m_transitionManager = NULL;
} }
// OFFSET: LEGO1 0x10058e70 // OFFSET: LEGO1 0x10058e70 STUB
MxResult LegoOmni::Create(COMPAT_CONST MxOmniCreateParam &p) MxResult LegoOmni::Create(COMPAT_CONST MxOmniCreateParam &p)
{ {
// FIXME: Stub
MxOmni::Create(p); MxOmni::Create(p);
m_objectFactory = new LegoObjectFactory();
m_gameState = new LegoGameState(); m_gameState = new LegoGameState();
m_bkgAudioManager = new MxBackgroundAudioManager(); m_bkgAudioManager = new MxBackgroundAudioManager();

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

@ -4,6 +4,14 @@
#include <cstdio> #include <cstdio>
#include <string> #include <string>
#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.
@ -38,7 +46,7 @@ LegoFileStream::~LegoFileStream()
} }
// OFFSET: LEGO1 0x100992c0 // 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) if (m_hFile == NULL)
return FAILURE; return FAILURE;
@ -47,7 +55,7 @@ MxResult LegoFileStream::Read(char* p_buffer, MxU32 p_size)
} }
// OFFSET: LEGO1 0x10099300 // 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) if (m_hFile == NULL)
return FAILURE; return FAILURE;
@ -117,7 +125,7 @@ LegoMemoryStream::LegoMemoryStream(char* p_buffer)
} }
// OFFSET: LEGO1 0x10099160 // 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); memcpy(p_buffer, m_buffer + m_offset, p_size);
m_offset += p_size; m_offset += p_size;
@ -125,7 +133,7 @@ MxResult LegoMemoryStream::Read(char* p_buffer, MxU32 p_size)
} }
// OFFSET: LEGO1 0x10099190 // 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); memcpy(m_buffer + m_offset, p_buffer, p_size);
m_offset += p_size; m_offset += p_size;
@ -146,4 +154,51 @@ MxResult LegoMemoryStream::Seek(MxU32 p_offset)
return SUCCESS; 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) {
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;
}
// 95% match, just some instruction ordering differences on the call to
// MxVariableTable::SetVariable at the end.
// OFFSET: LEGO1 0x1003a080
MxS32 LegoStream::ReadVariable(LegoStream* p_stream, MxVariableTable* p_to)
{
MxS32 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

@ -10,6 +10,8 @@
#define LEGOSTREAM_MODE_READ 1 #define LEGOSTREAM_MODE_READ 1
#define LEGOSTREAM_MODE_WRITE 2 #define LEGOSTREAM_MODE_WRITE 2
class MxVariableTable;
// VTABLE 0x100d7d80 // VTABLE 0x100d7d80
class LegoStream class LegoStream
{ {
@ -17,8 +19,8 @@ class LegoStream
LegoStream() : m_mode(0) {} LegoStream() : m_mode(0) {}
inline virtual ~LegoStream() {}; inline virtual ~LegoStream() {};
virtual MxResult Read(char* p_buffer, MxU32 p_size) = 0; virtual MxResult Read(void* p_buffer, MxU32 p_size) = 0;
virtual MxResult Write(char* 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 Tell(MxU32* p_offset) = 0;
virtual MxResult Seek(MxU32 p_offset) = 0; virtual MxResult Seek(MxU32 p_offset) = 0;
@ -32,6 +34,9 @@ class LegoStream
BinaryBit = 4, BinaryBit = 4,
}; };
static MxResult __stdcall WriteVariable(LegoStream* p_stream, MxVariableTable* p_from, const char* p_variableName);
static MxS32 __stdcall ReadVariable(LegoStream* p_stream, MxVariableTable* p_to);
protected: protected:
MxU8 m_mode; MxU8 m_mode;
}; };
@ -43,8 +48,8 @@ class LegoFileStream : public LegoStream
LegoFileStream(); LegoFileStream();
virtual ~LegoFileStream(); virtual ~LegoFileStream();
MxResult Read(char* p_buffer, MxU32 p_size) override; MxResult Read(void* p_buffer, MxU32 p_size) override;
MxResult Write(char* p_buffer, MxU32 p_size) override; MxResult Write(const void* p_buffer, MxU32 p_size) override;
MxResult Tell(MxU32* p_offset) override; MxResult Tell(MxU32* p_offset) override;
MxResult Seek(MxU32 p_offset) override; MxResult Seek(MxU32 p_offset) override;
@ -61,8 +66,8 @@ class LegoMemoryStream : public LegoStream
LegoMemoryStream(char* p_buffer); LegoMemoryStream(char* p_buffer);
~LegoMemoryStream() {} ~LegoMemoryStream() {}
MxResult Read(char* p_buffer, MxU32 p_size) override; MxResult Read(void* p_buffer, MxU32 p_size) override;
MxResult Write(char* p_buffer, MxU32 p_size) override; MxResult Write(const void* p_buffer, MxU32 p_size) override;
MxResult Tell(MxU32* p_offset) override; MxResult Tell(MxU32* p_offset) override;
MxResult Seek(MxU32 p_offset) override; MxResult Seek(MxU32 p_offset) override;

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

@ -26,9 +26,9 @@ MxObjectFactory::MxObjectFactory()
} }
// OFFSET: LEGO1 0x100b12c0 // OFFSET: LEGO1 0x100b12c0
MxCore *MxObjectFactory::Create(const char *name) MxCore *MxObjectFactory::Create(const char *p_name)
{ {
MxAtomId atom(name, LookupMode_Exact); MxAtomId atom(p_name, LookupMode_Exact);
if (0) { if (0) {
#define X(V) } else if (this->m_id##V == atom) { return new V; #define X(V) } else if (this->m_id##V == atom) { return new V;
@ -40,6 +40,6 @@ MxCore *MxObjectFactory::Create(const char *name)
} }
// OFFSET: LEGO1 0x100b1a30 STUB // OFFSET: LEGO1 0x100b1a30 STUB
void MxObjectFactory::vtable18(void *) { void MxObjectFactory::Destroy(void *p_object) {
// FIXME // FIXME
} }

View file

@ -23,8 +23,22 @@ class MxObjectFactory : public MxCore
{ {
public: public:
MxObjectFactory(); MxObjectFactory();
virtual MxCore *Create(const char *name); // vtable 0x14
virtual void vtable18(void *); // vtable 0x18 // OFFSET: LEGO1 0x10008f70
inline virtual const char *ClassName() const override // vtable+0xc
{
// 0x100f0730
return "MxObjectFactory";
}
// OFFSET: LEGO1 0x10008f80
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
private: private:
#define X(V) MxAtomId m_id##V; #define X(V) MxAtomId m_id##V;
FOR_MXOBJECTFACTORY_OBJECTS(X) FOR_MXOBJECTFACTORY_OBJECTS(X)

View file

@ -93,7 +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(); MxVideoManager *MVideoManager();
MxAtomIdCounterSet *AtomIdCounterSet(); MxAtomIdCounterSet *AtomIdCounterSet();
MxObjectFactory *ObjectFactory();
#endif // MXOMNI_H #endif // MXOMNI_H