Implement Save, Load, DeleteState (#602)

* Implement Save, Load, DeleteState

* WIP

* WIP

* Match LegoGameState::Save

* Spacing

* Match LegoGameState::DeleteState()

* More match

* Match

* Move vars

* Other fixes

* Rename

* Fix error

---------

Co-authored-by: Christian Semmler <mail@csemmler.com>
This commit is contained in:
Nathan M Gilbert 2024-02-27 15:04:17 -05:00 committed by GitHub
parent c0a988b0fe
commit 4d84157888
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 300 additions and 54 deletions

View file

@ -9,6 +9,8 @@ class LegoBackgroundColor : public MxVariable {
public: public:
LegoBackgroundColor(const char* p_key, const char* p_value); LegoBackgroundColor(const char* p_key, const char* p_value);
void SetValue(const char* p_colorString) override; void SetValue(const char* p_colorString) override;
void SetLights(float p_r, float p_g, float p_b);
void SetLights();
private: private:
float m_h; float m_h;

View file

@ -2,6 +2,7 @@
#define LEGOBUILDINGMANAGER_H #define LEGOBUILDINGMANAGER_H
#include "decomp.h" #include "decomp.h"
#include "lego/sources/misc/legostorage.h"
#include "mxcore.h" #include "mxcore.h"
// VTABLE: LEGO1 0x100d6f50 // VTABLE: LEGO1 0x100d6f50
@ -25,6 +26,8 @@ class LegoBuildingManager : public MxCore {
void FUN_1002fa00(); void FUN_1002fa00();
void FUN_1002fb30(); void FUN_1002fb30();
MxResult Save(LegoStorage* p_storage);
MxResult Load(LegoStorage* p_storage);
void FUN_10030590(); void FUN_10030590();
// SYNTHETIC: LEGO1 0x1002f940 // SYNTHETIC: LEGO1 0x1002f940

View file

@ -120,8 +120,9 @@ class LegoGameState {
LegoGameState(); LegoGameState();
~LegoGameState(); ~LegoGameState();
MxResult Load(MxULong);
MxResult Save(MxULong); MxResult Save(MxULong);
MxResult DeleteState();
MxResult Load(MxULong);
void SerializePlayersInfo(MxS16); void SerializePlayersInfo(MxS16);
void SerializeScoreHistory(MxS16 p_flags); void SerializeScoreHistory(MxS16 p_flags);
void SetSavePath(char*); void SetSavePath(char*);
@ -152,7 +153,7 @@ class LegoGameState {
void SetCurrentAct(Act p_currentAct); void SetCurrentAct(Act p_currentAct);
void FindLoadedAct(); void FindLoadedAct();
void SetActor(MxU8 p_actorId); void SetActor(MxU8 p_actorId);
void FUN_10039940(); void ResetROI();
private: private:
void RegisterState(LegoState* p_state); void RegisterState(LegoState* p_state);

View file

@ -2,6 +2,7 @@
#define LEGOPLANTMANAGER_H #define LEGOPLANTMANAGER_H
#include "decomp.h" #include "decomp.h"
#include "lego/sources/misc/legostorage.h"
#include "mxcore.h" #include "mxcore.h"
// VTABLE: LEGO1 0x100d6758 // VTABLE: LEGO1 0x100d6758
@ -22,6 +23,8 @@ class LegoPlantManager : public MxCore {
void FUN_10026360(MxS32 p_scriptIndex); void FUN_10026360(MxS32 p_scriptIndex);
void FUN_100263a0(undefined4 p_und); void FUN_100263a0(undefined4 p_und);
void Save(LegoStorage* p_storage);
MxResult Load(LegoStorage* p_storage);
void FUN_10027120(); void FUN_10027120();
static void SetCustomizeAnimFile(const char* p_value); static void SetCustomizeAnimFile(const char* p_value);

View file

@ -56,6 +56,7 @@ class LegoUnkSaveDataWriter {
LegoUnkSaveDataWriter(); LegoUnkSaveDataWriter();
MxResult WriteSaveData3(LegoStorage* p_storage); MxResult WriteSaveData3(LegoStorage* p_storage);
MxResult ReadSaveData3(LegoStorage* p_storage);
LegoROI* FUN_10083500(const char*, MxBool); LegoROI* FUN_10083500(const char*, MxBool);
static void InitSaveData(); static void InitSaveData();

View file

@ -41,6 +41,7 @@ void FUN_1003ef00(MxBool);
void SetAppCursor(WPARAM p_wparam); void SetAppCursor(WPARAM p_wparam);
MxBool FUN_1003ef60(); MxBool FUN_1003ef60();
MxBool RemoveFromWorld(MxAtomId& p_atomId1, MxS32 p_id1, MxAtomId& p_atomId2, MxS32 p_id2); MxBool RemoveFromWorld(MxAtomId& p_atomId1, MxS32 p_id1, MxAtomId& p_atomId2, MxS32 p_id2);
void SetLightPosition(MxU32);
NamedTexture* ReadNamedTexture(LegoFile* p_file); NamedTexture* ReadNamedTexture(LegoFile* p_file);
void FUN_1003f540(LegoFile* p_file, const char* p_filename); void FUN_1003f540(LegoFile* p_file, const char* p_filename);
void WriteNamedTexture(LegoFile* p_file, NamedTexture* p_texture); void WriteNamedTexture(LegoFile* p_file, NamedTexture* p_texture);

View file

@ -44,6 +44,18 @@ void LegoBuildingManager::FUN_1002fb30()
// TODO // TODO
} }
// STUB: LEGO1 0x1002fb80
MxResult LegoBuildingManager::Save(LegoStorage* p_storage)
{
return SUCCESS;
}
// STUB: LEGO1 0x1002fc10
MxResult LegoBuildingManager::Load(LegoStorage* p_storage)
{
return SUCCESS;
}
// FUNCTION: LEGO1 0x1002ff90 // FUNCTION: LEGO1 0x1002ff90
void LegoBuildingManager::SetCustomizeAnimFile(const char* p_value) void LegoBuildingManager::SetCustomizeAnimFile(const char* p_value)
{ {

View file

@ -66,3 +66,16 @@ void LegoBackgroundColor::SetValue(const char* p_colorString)
delete[] colorStringCopy; delete[] colorStringCopy;
} }
// STUB: LEGO1 0x1003c400
void LegoBackgroundColor::SetLights(float p_r, float p_g, float p_b)
{
}
// FUNCTION: LEGO1 0x1003c4b0
void LegoBackgroundColor::SetLights()
{
float convertedR, convertedG, convertedB;
ConvertHSVToRGB(m_h, m_s, m_v, &convertedR, &convertedG, &convertedB);
SetLights(convertedR, convertedG, convertedB);
}

View file

@ -5,8 +5,10 @@
#include "infocenterstate.h" #include "infocenterstate.h"
#include "islepathactor.h" #include "islepathactor.h"
#include "legoanimationmanager.h" #include "legoanimationmanager.h"
#include "legobuildingmanager.h"
#include "legonavcontroller.h" #include "legonavcontroller.h"
#include "legoomni.h" #include "legoomni.h"
#include "legoplantmanager.h"
#include "legostate.h" #include "legostate.h"
#include "legounksavedatawriter.h" #include "legounksavedatawriter.h"
#include "legoutil.h" #include "legoutil.h"
@ -156,58 +158,219 @@ void LegoGameState::SetActor(MxU8 p_actorId)
SetCurrentActor(newActor); SetCurrentActor(newActor);
} }
// STUB: LEGO1 0x10039940 // FUNCTION: LEGO1 0x10039940
void LegoGameState::FUN_10039940() void LegoGameState::ResetROI()
{ {
// TODO if (m_actorId) {
IslePathActor* actor = CurrentActor();
if (actor) {
LegoROI* roi = actor->GetROI();
if (roi) {
VideoManager()->Get3DManager()->GetLego3DView()->Remove(*roi);
VideoManager()->Get3DManager()->GetLego3DView()->Add(*roi);
}
}
}
} }
// FUNCTION: LEGO1 0x10039980 // FUNCTION: LEGO1 0x10039980
MxResult LegoGameState::Save(MxULong p_slot) MxResult LegoGameState::Save(MxULong p_slot)
{ {
MxResult result;
InfocenterState* infocenterState = (InfocenterState*) GameState()->GetState("InfocenterState"); InfocenterState* infocenterState = (InfocenterState*) GameState()->GetState("InfocenterState");
if (!infocenterState || !infocenterState->HasRegistered()) { if (!infocenterState || !infocenterState->HasRegistered()) {
result = SUCCESS; return SUCCESS;
} }
else {
result = FAILURE;
MxVariableTable* variableTable = VariableTable();
MxString savePath;
GetFileSavePath(&savePath, p_slot);
LegoFile fileStream;
if (fileStream.Open(savePath.GetData(), LegoFile::c_write) != FAILURE) {
MxU32 maybeVersion = 0x1000C;
fileStream.Write(&maybeVersion, 4);
fileStream.Write(&m_unk0x24, 2);
fileStream.Write(&m_currentAct, 2);
fileStream.Write(&m_actorId, 1);
for (MxS32 i = 0; i < sizeof(g_colorSaveData) / sizeof(g_colorSaveData[0]); ++i) { MxResult result = FAILURE;
if (WriteVariable(&fileStream, variableTable, g_colorSaveData[i].m_targetName) == FAILURE) { LegoFile fileStream;
return result; MxVariableTable* variableTable = VariableTable();
} MxS16 count = 0;
} MxU32 i;
MxS32 j;
MxU16 area;
if (WriteVariable(&fileStream, variableTable, "backgroundcolor") != FAILURE) { MxString savePath;
if (WriteVariable(&fileStream, variableTable, "lightposition") != FAILURE) { GetFileSavePath(&savePath, p_slot);
WriteEndOfVariables(&fileStream);
// TODO: Calls down to more aggregate writing functions if (fileStream.Open(savePath.GetData(), LegoFile::c_write) == FAILURE) {
return SUCCESS; goto done;
} }
}
Write(&fileStream, 0x1000c);
Write(&fileStream, m_unk0x24);
Write(&fileStream, (MxU16) m_currentAct);
Write(&fileStream, m_actorId);
for (i = 0; i < _countof(g_colorSaveData); i++) {
if (WriteVariable(&fileStream, variableTable, g_colorSaveData[i].m_targetName) == FAILURE) {
goto done;
} }
} }
if (WriteVariable(&fileStream, variableTable, "backgroundcolor") == FAILURE) {
goto done;
}
if (WriteVariable(&fileStream, variableTable, "lightposition") == FAILURE) {
goto done;
}
WriteEndOfVariables(&fileStream);
UnkSaveDataWriter()->WriteSaveData3(&fileStream);
PlantManager()->Save(&fileStream);
result = BuildingManager()->Save(&fileStream);
for (j = 0; j < m_stateCount; j++) {
if (m_stateArray[j]->VTable0x14()) {
count++;
}
}
Write(&fileStream, count);
for (j = 0; j < m_stateCount; j++) {
if (m_stateArray[j]->VTable0x14()) {
m_stateArray[j]->VTable0x1c(&fileStream);
}
}
area = m_unk0x42c;
Write(&fileStream, (MxU16) area);
SerializeScoreHistory(2);
m_isDirty = FALSE;
done:
return result; return result;
} }
// STUB: LEGO1 0x10039c60 // FUNCTION: LEGO1 0x10039bf0
MxResult LegoGameState::Load(MxULong) MxResult LegoGameState::DeleteState()
{ {
// TODO MxS16 stateCount = m_stateCount;
return 0; LegoState** stateArray = m_stateArray;
m_stateCount = 0;
m_stateArray = NULL;
for (MxS32 count = 0; count < stateCount; count++) {
if (!stateArray[count]->SetFlag() && stateArray[count]->VTable0x14()) {
delete stateArray[count];
}
else {
RegisterState(stateArray[count]);
stateArray[count] = NULL;
}
}
delete[] stateArray;
return SUCCESS;
}
// FUNCTION: LEGO1 0x10039c60
MxResult LegoGameState::Load(MxULong p_slot)
{
MxResult result = FAILURE;
LegoFile fileStream;
MxVariableTable* variableTable = VariableTable();
MxString savePath;
GetFileSavePath(&savePath, p_slot);
if (fileStream.Open(savePath.GetData(), LegoFile::c_read) == FAILURE) {
goto done;
}
MxU32 version, status;
MxS16 count, area, act;
const char* lightPosition;
Read(&fileStream, &version);
if (version != 0x1000c) {
OmniError("Saved game version mismatch", 0);
goto done;
}
Read(&fileStream, &m_unk0x24);
Read(&fileStream, &act);
SetCurrentAct((Act) act);
Read(&fileStream, &m_actorId);
if (m_actorId) {
SetActor(m_actorId);
}
do {
status = ReadVariable(&fileStream, variableTable);
if (status == 1) {
goto done;
}
} while (status != 2);
m_backgroundColor->SetLights();
lightPosition = VariableTable()->GetVariable("lightposition");
if (lightPosition) {
SetLightPosition(atoi(lightPosition));
}
if (UnkSaveDataWriter()->ReadSaveData3(&fileStream) == FAILURE) {
goto done;
}
if (PlantManager()->Load(&fileStream) == FAILURE) {
goto done;
}
if (BuildingManager()->Load(&fileStream) == FAILURE) {
goto done;
}
if (DeleteState() != SUCCESS) {
goto done;
}
char stateName[80];
Read(&fileStream, &count);
if (count) {
for (MxS16 i = 0; i < count; i++) {
MxS16 stateNameLength;
Read(&fileStream, &stateNameLength);
Read(&fileStream, stateName, (MxULong) stateNameLength);
stateName[stateNameLength] = 0;
LegoState* state = GetState(stateName);
if (!state) {
state = CreateState(stateName);
if (!state) {
goto done;
}
}
state->VTable0x1c(&fileStream);
}
}
Read(&fileStream, &area);
if (m_currentAct == 0) {
m_unk0x42c = e_noArea;
}
else {
m_unk0x42c = (Area) area;
}
result = SUCCESS;
m_isDirty = FALSE;
done:
if (result != SUCCESS) {
OmniError("Game state loading was not successful!", 0);
}
return result;
} }
// FUNCTION: LEGO1 0x10039f00 // FUNCTION: LEGO1 0x10039f00

View file

@ -35,6 +35,18 @@ void LegoPlantManager::FUN_100263a0(undefined4 p_und)
// TODO // TODO
} }
// STUB: LEGO1 0x10026720
void LegoPlantManager::Save(LegoStorage* p_storage)
{
// TODO
}
// STUB: LEGO1 0x100267b0
MxResult LegoPlantManager::Load(LegoStorage* p_storage)
{
return SUCCESS;
}
// FUNCTION: LEGO1 0x10026be0 // FUNCTION: LEGO1 0x10026be0
void LegoPlantManager::SetCustomizeAnimFile(const char* p_value) void LegoPlantManager::SetCustomizeAnimFile(const char* p_value)
{ {

View file

@ -90,6 +90,12 @@ MxResult LegoUnkSaveDataWriter::WriteSaveData3(LegoStorage* p_storage)
return result; return result;
} }
// STUB: LEGO1 0x100833f0
MxResult LegoUnkSaveDataWriter::ReadSaveData3(LegoStorage* p_storage)
{
return SUCCESS;
}
// STUB: LEGO1 0x10083500 // STUB: LEGO1 0x10083500
LegoROI* LegoUnkSaveDataWriter::FUN_10083500(const char* p_key, MxBool p_option) LegoROI* LegoUnkSaveDataWriter::FUN_10083500(const char* p_key, MxBool p_option)
{ {

View file

@ -291,6 +291,11 @@ MxBool FUN_1003ef60()
return TRUE; return TRUE;
} }
// STUB: LEGO1 0x1003f0d0
void SetLightPosition(MxU32)
{
}
// STUB: LEGO1 0x1003f3b0 // STUB: LEGO1 0x1003f3b0
NamedTexture* ReadNamedTexture(LegoFile* p_file) NamedTexture* ReadNamedTexture(LegoFile* p_file)
{ {

View file

@ -581,7 +581,7 @@ void LegoWorld::Enable(MxBool p_enable)
AnimationManager()->FUN_1005f0b0(); AnimationManager()->FUN_1005f0b0();
} }
GameState()->FUN_10039940(); GameState()->ResetROI();
SetIsWorldActive(TRUE); SetIsWorldActive(TRUE);
} }
} }

View file

@ -22,16 +22,16 @@ class LegoStorage {
// FUNCTION: LEGO1 0x10045ad0 // FUNCTION: LEGO1 0x10045ad0
virtual ~LegoStorage() {} virtual ~LegoStorage() {}
virtual LegoResult Read(void* p_buffer, LegoU32 p_size) = 0; virtual LegoResult Read(void* p_buffer, LegoU32 p_size) = 0; // vtable+0x04
virtual LegoResult Write(const void* p_buffer, LegoU32 p_size) = 0; virtual LegoResult Write(const void* p_buffer, LegoU32 p_size) = 0; // vtable+0x08
virtual LegoResult GetPosition(LegoU32& p_position) = 0; virtual LegoResult GetPosition(LegoU32& p_position) = 0; // vtable+0x0c
virtual LegoResult SetPosition(LegoU32 p_position) = 0; virtual LegoResult SetPosition(LegoU32 p_position) = 0; // vtable+0x10
// FUNCTION: LEGO1 0x10045ae0 // FUNCTION: LEGO1 0x10045ae0
virtual LegoBool IsWriteMode() { return m_mode == c_write; } virtual LegoBool IsWriteMode() { return m_mode == c_write; } // vtable+0x14
// FUNCTION: LEGO1 0x10045af0 // FUNCTION: LEGO1 0x10045af0
virtual LegoBool IsReadMode() { return m_mode == c_read; } virtual LegoBool IsReadMode() { return m_mode == c_read; } // vtable+0x18
// SYNTHETIC: LEGO1 0x10045b00 // SYNTHETIC: LEGO1 0x10045b00
// LegoStorage::`scalar deleting destructor' // LegoStorage::`scalar deleting destructor'
@ -40,23 +40,35 @@ class LegoStorage {
LegoU8 m_mode; // 0x04 LegoU8 m_mode; // 0x04
}; };
template <class T>
inline void Read(LegoStorage* p_storage, T* p_variable, LegoU32 p_size = sizeof(T))
{
p_storage->Read(p_variable, p_size);
}
template <class T>
inline void Write(LegoStorage* p_storage, T p_variable)
{
p_storage->Write(&p_variable, sizeof(p_variable));
}
// VTABLE: LEGO1 0x100db710 // VTABLE: LEGO1 0x100db710
// SIZE 0x10 // SIZE 0x10
class LegoMemory : public LegoStorage { class LegoMemory : public LegoStorage {
public: public:
LegoMemory(void* p_buffer); LegoMemory(void* p_buffer);
LegoResult Read(void* p_buffer, LegoU32 p_size) override; LegoResult Read(void* p_buffer, LegoU32 p_size) override; // vtable+0x04
LegoResult Write(const void* p_buffer, LegoU32 p_size) override; LegoResult Write(const void* p_buffer, LegoU32 p_size) override; // vtable+0x08
// FUNCTION: LEGO1 0x100994a0 // FUNCTION: LEGO1 0x100994a0
LegoResult GetPosition(LegoU32& p_position) override LegoResult GetPosition(LegoU32& p_position) override // vtable+0x0c
{ {
p_position = m_position; p_position = m_position;
return SUCCESS; return SUCCESS;
} }
// FUNCTION: LEGO1 0x100994b0 // FUNCTION: LEGO1 0x100994b0
LegoResult SetPosition(LegoU32 p_position) override LegoResult SetPosition(LegoU32 p_position) override // vtable+0x10
{ {
m_position = p_position; m_position = p_position;
return SUCCESS; return SUCCESS;
@ -79,10 +91,10 @@ class LegoFile : public LegoStorage {
public: public:
LegoFile(); LegoFile();
~LegoFile() override; ~LegoFile() override;
LegoResult Read(void* p_buffer, LegoU32 p_size) override; LegoResult Read(void* p_buffer, LegoU32 p_size) override; // vtable+0x04
LegoResult Write(const void* p_buffer, LegoU32 p_size) override; LegoResult Write(const void* p_buffer, LegoU32 p_size) override; // vtable+0x08
LegoResult GetPosition(LegoU32& p_position) override; LegoResult GetPosition(LegoU32& p_position) override; // vtable+0x0c
LegoResult SetPosition(LegoU32 p_position) override; LegoResult SetPosition(LegoU32 p_position) override; // vtable+0x10
LegoResult Open(const char* p_name, LegoU32 p_mode); LegoResult Open(const char* p_name, LegoU32 p_mode);
// FUNCTION: LEGO1 0x100343d0 // FUNCTION: LEGO1 0x100343d0

View file

@ -72,7 +72,8 @@ MxBool GetRectIntersection(
); );
void MakeSourceName(char*, const char*); void MakeSourceName(char*, const char*);
void SetOmniUserMessage(void (*)(const char*, int)); void OmniError(const char* p_message, MxS32 p_status);
void SetOmniUserMessage(void (*p_omniUserMessage)(const char*, MxS32));
MxBool ContainsPresenter(MxCompositePresenterList& p_presenterList, MxPresenter* p_presenter); MxBool ContainsPresenter(MxCompositePresenterList& p_presenterList, MxPresenter* p_presenter);
void FUN_100b7220(MxDSAction* p_action, MxU32 p_newFlags, MxBool p_setFlags); void FUN_100b7220(MxDSAction* p_action, MxU32 p_newFlags, MxBool p_setFlags);
MxDSObject* CreateStreamObject(MxDSFile*, MxS16); MxDSObject* CreateStreamObject(MxDSFile*, MxS16);

View file

@ -127,10 +127,21 @@ MxBool ContainsPresenter(MxCompositePresenterList& p_presenterList, MxPresenter*
return FALSE; return FALSE;
} }
// FUNCTION: LEGO1 0x100b7210 // FUNCTION: LEGO1 0x100b71e0
void SetOmniUserMessage(void (*p_userMsg)(const char*, int)) void OmniError(const char* p_message, MxS32 p_status)
{ {
g_omniUserMessage = p_userMsg; if (g_omniUserMessage) {
g_omniUserMessage(p_message, p_status);
}
else if (p_status) {
abort();
}
}
// FUNCTION: LEGO1 0x100b7210
void SetOmniUserMessage(void (*p_omniUserMessage)(const char*, MxS32))
{
g_omniUserMessage = p_omniUserMessage;
} }
// FUNCTION: LEGO1 0x100b7220 // FUNCTION: LEGO1 0x100b7220