From 5233b48c596c4ee5be129e03be98734b07f9a2a9 Mon Sep 17 00:00:00 2001
From: Misha <106913236+MishaProductions@users.noreply.github.com>
Date: Sun, 11 Feb 2024 09:03:56 -0500
Subject: [PATCH] Implement LegoModelPresenter::ParseExtra (#557)

* Implement LegoModelPresenter::ParseExtra

* rename function according to leaked source code

* Minor improvement

---------

Co-authored-by: Christian Semmler <mail@csemmler.com>
---
 .../legoomni/include/legomodelpresenter.h     |  4 +-
 .../legoomni/include/legounksavedatawriter.h  |  2 +-
 LEGO1/lego/legoomni/include/legoworld.h       |  1 +
 .../src/common/legounksavedatawriter.cpp      |  2 +-
 .../legoomni/src/video/legomodelpresenter.cpp | 75 +++++++++++++++----
 5 files changed, 64 insertions(+), 20 deletions(-)

diff --git a/LEGO1/lego/legoomni/include/legomodelpresenter.h b/LEGO1/lego/legoomni/include/legomodelpresenter.h
index f84c04e6..db9fc20d 100644
--- a/LEGO1/lego/legoomni/include/legomodelpresenter.h
+++ b/LEGO1/lego/legoomni/include/legomodelpresenter.h
@@ -35,10 +35,10 @@ protected:
 	void Destroy(MxBool p_fromDestructor);
 
 private:
-	AutoROI* m_unk0x64;   // 0x64
+	AutoROI* m_roi;       // 0x64
 	MxBool m_addedToView; // 0x68
 
-	undefined4 LoadModel(MxStreamChunk* p_chunk);
+	MxResult CreateROI(MxStreamChunk* p_chunk);
 };
 
 #endif // LEGOMODELPRESENTER_H
diff --git a/LEGO1/lego/legoomni/include/legounksavedatawriter.h b/LEGO1/lego/legoomni/include/legounksavedatawriter.h
index dd15339a..4915a111 100644
--- a/LEGO1/lego/legoomni/include/legounksavedatawriter.h
+++ b/LEGO1/lego/legoomni/include/legounksavedatawriter.h
@@ -39,7 +39,7 @@ public:
 	LegoUnkSaveDataWriter();
 
 	MxResult WriteSaveData3(LegoStorage* p_stream);
-	AutoROI* FUN_10083500(undefined4, undefined4);
+	AutoROI* FUN_10083500(char*, undefined4);
 	void FUN_100832a0();
 	void FUN_10083db0(LegoROI* p_roi);
 
diff --git a/LEGO1/lego/legoomni/include/legoworld.h b/LEGO1/lego/legoomni/include/legoworld.h
index 28f8a627..e6aecb02 100644
--- a/LEGO1/lego/legoomni/include/legoworld.h
+++ b/LEGO1/lego/legoomni/include/legoworld.h
@@ -68,6 +68,7 @@ public:
 	inline void SetUnknown0xec(undefined4 p_unk0xec) { m_unk0xec = p_unk0xec; }
 	inline undefined4 GetUnknown0xec() { return m_unk0xec; }
 	inline MxCoreSet& GetUnknown0xd0() { return m_set0xd0; }
+	inline list<AutoROI*>& GetUnknownList0xe0() { return m_list0xe0; }
 
 	MxBool PresentersPending();
 	void Remove(MxCore* p_object);
diff --git a/LEGO1/lego/legoomni/src/common/legounksavedatawriter.cpp b/LEGO1/lego/legoomni/src/common/legounksavedatawriter.cpp
index 499a9af7..eb28fb48 100644
--- a/LEGO1/lego/legoomni/src/common/legounksavedatawriter.cpp
+++ b/LEGO1/lego/legoomni/src/common/legounksavedatawriter.cpp
@@ -71,7 +71,7 @@ MxResult LegoUnkSaveDataWriter::WriteSaveData3(LegoStorage* p_stream)
 }
 
 // STUB: LEGO1 0x10083500
-AutoROI* LegoUnkSaveDataWriter::FUN_10083500(undefined4, undefined4)
+AutoROI* LegoUnkSaveDataWriter::FUN_10083500(char*, undefined4)
 {
 	// TODO
 	// involves an STL map with a _Nil node at 0x100fc508
diff --git a/LEGO1/lego/legoomni/src/video/legomodelpresenter.cpp b/LEGO1/lego/legoomni/src/video/legomodelpresenter.cpp
index d5fb18b9..91840b16 100644
--- a/LEGO1/lego/legoomni/src/video/legomodelpresenter.cpp
+++ b/LEGO1/lego/legoomni/src/video/legomodelpresenter.cpp
@@ -1,14 +1,27 @@
 #include "legomodelpresenter.h"
 
+#include "define.h"
 #include "legoentity.h"
 #include "legoentitypresenter.h"
 #include "legoomni.h"
+#include "legounksavedatawriter.h"
 #include "legovideomanager.h"
+#include "legoworld.h"
 #include "mxcompositepresenter.h"
+#include "mxutil.h"
+#include "roi/legoroi.h"
 
 // GLOBAL: LEGO1 0x100f7ae0
 int g_modelPresenterConfig = 1;
 
+// GLOBAL: LEGO1 0x10102054
+// STRING: LEGO1 0x10102018
+char* g_autoCreate = "AUTO_CREATE";
+
+// GLOBAL: LEGO1 0x10102078
+// STRING: LEGO1 0x10101fc4
+char* g_dbCreate = "DB_CREATE";
+
 // FUNCTION: LEGO1 0x1000cca0
 void LegoModelPresenter::Destroy()
 {
@@ -25,7 +38,7 @@ void LegoModelPresenter::configureLegoModelPresenter(MxS32 p_modelPresenterConfi
 void LegoModelPresenter::Destroy(MxBool p_fromDestructor)
 {
 	m_criticalSection.Enter();
-	m_unk0x64 = 0;
+	m_roi = NULL;
 	m_addedToView = FALSE;
 	m_criticalSection.Leave();
 
@@ -35,10 +48,10 @@ void LegoModelPresenter::Destroy(MxBool p_fromDestructor)
 }
 
 // STUB: LEGO1 0x1007f6b0
-undefined4 LegoModelPresenter::LoadModel(MxStreamChunk* p_chunk)
+MxResult LegoModelPresenter::CreateROI(MxStreamChunk* p_chunk)
 {
 	// TODO
-	return 0;
+	return FAILURE;
 }
 
 // FUNCTION: LEGO1 0x10080050
@@ -51,11 +64,9 @@ void LegoModelPresenter::ReadyTickle()
 
 	ParseExtra();
 
-	if (m_unk0x64 != NULL) {
+	if (m_roi != NULL) {
 		if (m_compositePresenter && m_compositePresenter->IsA("LegoEntityPresenter")) {
-			((LegoEntityPresenter*) m_compositePresenter)
-				->GetEntity()
-				->SetROI((LegoROI*) m_unk0x64, m_addedToView, TRUE);
+			((LegoEntityPresenter*) m_compositePresenter)->GetEntity()->SetROI((LegoROI*) m_roi, m_addedToView, TRUE);
 			((LegoEntityPresenter*) m_compositePresenter)
 				->GetEntity()
 				->SetFlags(
@@ -73,17 +84,15 @@ void LegoModelPresenter::ReadyTickle()
 
 		if (chunk != NULL && chunk->GetTime() <= m_action->GetElapsedTime()) {
 			chunk = m_subscriber->NextChunk();
-			undefined4 und = LoadModel(chunk);
+			MxResult result = CreateROI(chunk);
 			m_subscriber->DestroyChunk(chunk);
 
-			if (und == 0) {
-				VideoManager()->Get3DManager()->GetLego3DView()->Add(*m_unk0x64);
-				VideoManager()->Get3DManager()->GetLego3DView()->Moved(*m_unk0x64);
+			if (result == SUCCESS) {
+				VideoManager()->Get3DManager()->GetLego3DView()->Add(*m_roi);
+				VideoManager()->Get3DManager()->GetLego3DView()->Moved(*m_roi);
 
 				if (m_compositePresenter != NULL && m_compositePresenter->IsA("LegoEntityPresenter")) {
-					((LegoEntityPresenter*) m_compositePresenter)
-						->GetEntity()
-						->SetROI((LegoROI*) m_unk0x64, TRUE, TRUE);
+					((LegoEntityPresenter*) m_compositePresenter)->GetEntity()->SetROI((LegoROI*) m_roi, TRUE, TRUE);
 					((LegoEntityPresenter*) m_compositePresenter)
 						->GetEntity()
 						->SetFlags(
@@ -100,8 +109,42 @@ void LegoModelPresenter::ReadyTickle()
 	}
 }
 
-// STUB: LEGO1 0x100801b0
+// FUNCTION: LEGO1 0x100801b0
 void LegoModelPresenter::ParseExtra()
 {
-	// TODO
+	char output[1024];
+
+	MxU16 len = m_action->GetExtraLength();
+	char* extraData = m_action->GetExtraData();
+
+	if (len != 0) {
+		char buffer[1024];
+		output[0] = 0;
+		memcpy(buffer, extraData, len);
+		buffer[len] = 0;
+
+		if (KeyValueStringParse(output, g_autoCreate, buffer) != 0) {
+			char* token = strtok(output, g_parseExtraTokens);
+			if (m_roi == NULL) {
+				m_roi = UnkSaveDataWriter()->FUN_10083500(token, 0);
+				m_addedToView = FALSE;
+			}
+		}
+		else if (KeyValueStringParse(output, g_dbCreate, buffer) != 0 && m_roi == NULL) {
+			LegoWorld* currentWorld = CurrentWorld();
+			list<AutoROI*>& roiList = currentWorld->GetUnknownList0xe0();
+
+			for (list<AutoROI*>::iterator it = roiList.begin(); it != roiList.end(); it++) {
+				if (!strcmpi(((LegoROI*) (*it))->GetUnknown0xe4(), output)) {
+					m_roi = *it;
+					roiList.erase(it);
+
+					m_addedToView = TRUE;
+					VideoManager()->Get3DManager()->GetLego3DView()->Add(*m_roi);
+					VideoManager()->Get3DManager()->GetLego3DView()->Moved(*m_roi);
+					break;
+				}
+			}
+		}
+	}
 }