Implement methods to load dta files. (#673)

* Implement methods to load dta files.

* fix style issues

* fix vtables

* fix more style issues

* fix ddtor names

* Remove explicit padding, add annotations, asserts

* Use List template

* trigger CI

* Fix class refactor

* Match code, fix annotations

* Fix

* 98% match

* Fix

---------

Co-authored-by: Christian Semmler <mail@csemmler.com>
This commit is contained in:
Nathan M Gilbert 2024-03-15 20:43:45 -04:00 committed by GitHub
parent 4ddd9e200c
commit d07d7edc81
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 470 additions and 15 deletions

View file

@ -3,6 +3,33 @@
#include "legostate.h"
// SIZE 0x30
struct ModelInfo {
char* m_modelName; // 0x00
MxU8 m_unk0x04; // 0x04
float m_location[3]; // 0x08
float m_direction[3]; // 0x14
float m_up[3]; // 0x20
MxU8 m_unk0x2c; // 0x2c
};
// SIZE 0x30
struct AnimInfo {
char* m_animName; // 0x00
undefined4 m_unk0x04; // 0x04
MxS16 m_unk0x08; // 0x08
MxU8 m_unk0x0a; // 0x0a
MxU8 m_unk0x0b; // 0x0b
MxU8 m_unk0x0c; // 0x0c
MxU8 m_unk0x0d; // 0x0d
MxU32 m_unk0x10[4]; // 0x10
MxU8 m_modelCount; // 0x20
ModelInfo* m_models; // 0x24
MxU8 m_unk0x28; // 0x28
MxU8 m_unk0x29; // 0x29
MxS8 m_unk0x2a[3]; // 0x2a
};
// VTABLE: LEGO1 0x100d8d80
// SIZE 0x1c
class AnimState : public LegoState {
@ -26,6 +53,9 @@ class AnimState : public LegoState {
MxBool SetFlag() override; // vtable+0x18
MxResult VTable0x1c(LegoFile* p_legoFile) override; // vtable+0x1c
void FUN_100651d0(MxU32, AnimInfo*, MxU32&);
void FUN_10065240(MxU32, AnimInfo*, MxU32);
// SYNTHETIC: LEGO1 0x10065130
// AnimState::`scalar deleting destructor'

View file

@ -24,6 +24,7 @@ class Isle : public LegoWorld {
public:
Isle();
~Isle() override;
MxLong Notify(MxParam& p_param) override; // vtable+0x04
// FUNCTION: LEGO1 0x10030910
@ -42,22 +43,25 @@ class Isle : public LegoWorld {
MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18
void ReadyWorld() override; // vtable+50
void Add(MxCore* p_object) override; // vtable+58
// FUNCTION: LEGO1 0x10030900
MxBool VTable0x5c() override { return TRUE; } // vtable+5c
// FUNCTION: LEGO1 0x10033170
void VTable0x60() override {} // vtable+60
MxBool VTable0x64() override; // vtable+64
void Enable(MxBool p_enable) override; // vtable+68
virtual void VTable0x6c(IslePathActor* p_actor); // vtable+6c
inline void SetUnknown13c(MxU32 p_unk0x13c) { m_unk0x13c = p_unk0x13c; }
MxLong StopAction(MxParam& p_param);
MxLong HandleType17Notification(MxParam& p_param);
MxLong HandleType19Notification(MxParam& p_param);
MxLong HandleTransitionEnd();
void FUN_10032620();
inline void SetUnknown13c(MxU32 p_unk0x13c) { m_unk0x13c = p_unk0x13c; }
// SYNTHETIC: LEGO1 0x10030a30
// Isle::`scalar deleting destructor'

View file

@ -1,15 +1,24 @@
#ifndef LEGOANIMATIONMANAGER_H
#define LEGOANIMATIONMANAGER_H
#include "animstate.h"
#include "decomp.h"
#include "legotraninfolist.h"
#include "mxcore.h"
// SIZE 0x18
struct Character {
char* m_name; // 0x00
undefined m_unk0x04[0x10]; // 0x04
MxBool m_active; // 0x14
};
// VTABLE: LEGO1 0x100d8c18
// SIZE 0x500
class LegoAnimationManager : public MxCore {
public:
LegoAnimationManager();
~LegoAnimationManager() override; // vtable+0x00
~LegoAnimationManager() override;
MxLong Notify(MxParam& p_param) override; // vtable+0x04
MxResult Tickle() override; // vtable+0x08
@ -31,8 +40,14 @@ class LegoAnimationManager : public MxCore {
void FUN_1005ef10();
void FUN_1005f0b0();
void FUN_1005f6d0(MxBool);
void FUN_1005f720(MxS32 p_scriptIndex);
MxResult LoadScriptInfo(MxS32 p_scriptIndex);
MxBool FUN_10060140(char* p_name, MxU32& p_index);
MxResult ReadAnimInfo(LegoFile* p_file, AnimInfo* p_info);
MxResult ReadModelInfo(LegoFile* p_file, ModelInfo* p_info);
void FUN_100603c0();
void FUN_10061010(undefined4);
void FUN_100617c0(MxS32, MxU16&, MxU32&);
MxS8 FUN_10062360(char*);
void FUN_10064670(MxBool);
static void configureLegoAnimationManager(MxS32 p_legoAnimationManagerConfig);
@ -43,7 +58,34 @@ class LegoAnimationManager : public MxCore {
private:
void Init();
undefined m_unk0x08[0x4f8]; // 0x08
undefined4 m_unk0x08; // 0x08
MxU16 m_animCount; // 0x0c
MxU16 m_unk0x0e; // 0x0e
MxU32 m_unk0x10; // 0x10
AnimInfo* m_anims; // 0x14
undefined m_unk0x018[8]; // 0x18
LegoTranInfoList* m_tranInfoList; // 0x20
LegoTranInfoList* m_tranInfoList2; // 0x24
undefined4 m_unk0x28[2]; // 0x28
undefined4 m_unk0x30[2]; // 0x30
undefined m_unk0x38; // 0x38
undefined m_unk0x39; // 0x39
undefined m_unk0x3a; // 0x3a
undefined m_unk0x3b[0x3c1]; // 0x3b
undefined4 m_unk0x3fc; // 0x3fc
MxU8 m_unk0x400; // 0x400
undefined m_unk0x401; // 0x401
MxU8 m_unk0x402; // 0x402
undefined m_unk0x403[0x1d]; // 0x403
AnimState* m_animState; // 0x420
undefined4 m_unk0x424; // 0x424
undefined m_unk0x428; // 0x428
undefined m_unk0x429; // 0x429
undefined m_unk0x42a; // 0x42a
undefined m_unk0x42b; // 0x42b
undefined4 m_unk0x42c; // 0x42c
undefined m_unk0x430; // 0x430
undefined m_unk0x431[0xcf]; // 0x431
};
#endif // LEGOANIMATIONMANAGER_H

View file

@ -98,7 +98,6 @@ class LegoOmni : public MxOmni {
inline MxS32 GetIndex() { return m_index; }
inline const char* GetKey() { return m_key; }
private:
MxS32 m_index; // 0x00
char m_key[20]; // 0x04
MxAtomId* m_script; // 0x18
@ -203,6 +202,7 @@ class LegoOmni : public MxOmni {
MxS32 GetScriptIndex(const char* p_key);
static MxS32 GetCurrPathInfo(LegoPathBoundary**, MxS32&);
const char* FindScript(MxU32 p_id);
static void CreateInstance();
static LegoOmni* GetInstance();

View file

@ -0,0 +1,11 @@
#ifndef LEGOTRANINFO_H
#define LEGOTRANINFO_H
#include "decomp.h"
// SIZE 0x78
struct LegoTranInfo { // See FUN_100609f0 for construction
undefined m_unk0x00[0x78]; // 0x00
};
#endif // LEGOTRANINFO_H

View file

@ -0,0 +1,51 @@
#ifndef LEGOTRANINFOLIST_H
#define LEGOTRANINFOLIST_H
#include "legotraninfo.h"
#include "mxlist.h"
#include "mxtypes.h"
// VTABLE: LEGO1 0x100d8ca8
// class MxCollection<LegoTranInfo *>
// VTABLE: LEGO1 0x100d8cc0
// class MxList<LegoTranInfo *>
// VTABLE: LEGO1 0x100d8cd8
// class MxPtrList<LegoTranInfo>
// VTABLE: LEGO1 0x100d8c90
// SIZE 0x18
class LegoTranInfoList : public MxPtrList<LegoTranInfo> {
public:
LegoTranInfoList() : MxPtrList<LegoTranInfo>(FALSE) {}
};
// TEMPLATE: LEGO1 0x1005fdf0
// MxCollection<LegoTranInfo *>::Compare
// TEMPLATE: LEGO1 0x1005fe00
// MxCollection<LegoTranInfo *>::~MxCollection<LegoTranInfo *>
// TEMPLATE: LEGO1 0x1005fe50
// MxCollection<LegoTranInfo *>::Destroy
// TEMPLATE: LEGO1 0x1005fe60
// MxList<LegoTranInfo *>::~MxList<LegoTranInfo *>
// SYNTHETIC: LEGO1 0x1005fef0
// LegoTranInfoList::`scalar deleting destructor'
// TEMPLATE: LEGO1 0x1005ff60
// MxPtrList<LegoTranInfo>::~MxPtrList<LegoTranInfo>
// SYNTHETIC: LEGO1 0x1005ffb0
// MxCollection<LegoTranInfo *>::`scalar deleting destructor'
// SYNTHETIC: LEGO1 0x10060020
// MxList<LegoTranInfo *>::`scalar deleting destructor'
// SYNTHETIC: LEGO1 0x100600d0
// MxPtrList<LegoTranInfo>::`scalar deleting destructor'
#endif // LEGOTRANINFOLIST_H

View file

@ -1,6 +1,8 @@
#include "animstate.h"
DECOMP_SIZE_ASSERT(AnimState, 0x1c);
DECOMP_SIZE_ASSERT(AnimState, 0x1c)
DECOMP_SIZE_ASSERT(ModelInfo, 0x30)
DECOMP_SIZE_ASSERT(AnimInfo, 0x30)
// FUNCTION: LEGO1 0x10064ff0
AnimState::AnimState()
@ -17,6 +19,18 @@ AnimState::~AnimState()
// TODO
}
// STUB: LEGO1 0x100651d0
void AnimState::FUN_100651d0(MxU32, AnimInfo*, MxU32&)
{
// TODO
}
// STUB: LEGO1 0x10065240
void AnimState::FUN_10065240(MxU32, AnimInfo*, MxU32)
{
// TODO
}
// STUB: LEGO1 0x100652d0
MxResult AnimState::VTable0x1c(LegoFile* p_legoFile)
{

View file

@ -1,9 +1,19 @@
#include "legoanimationmanager.h"
#include "legogamestate.h"
#include "legoomni.h"
#include "misc.h"
#include "mxutilities.h"
#include <io.h>
DECOMP_SIZE_ASSERT(LegoAnimationManager, 0x500)
// GLOBAL: LEGO1 0x100f7048
Character g_characters[47]; // TODO: Initialize this
// GLOBAL: LEGO1 0x100f74f8
int g_legoAnimationManagerConfig = 1;
MxS32 g_legoAnimationManagerConfig = 1;
// FUNCTION: LEGO1 0x1005eb50
void LegoAnimationManager::configureLegoAnimationManager(MxS32 p_legoAnimationManagerConfig)
@ -53,8 +63,277 @@ void LegoAnimationManager::FUN_1005f6d0(MxBool)
// TODO
}
// STUB: LEGO1 0x1005f720
void LegoAnimationManager::FUN_1005f720(MxS32 p_scriptIndex)
// FUNCTION: LEGO1 0x1005f720
MxResult LegoAnimationManager::LoadScriptInfo(MxS32 p_scriptIndex)
{
MxResult result = FAILURE;
MxS32 i, j, k;
if (m_unk0x08 != p_scriptIndex) {
if (m_tranInfoList != NULL) {
delete m_tranInfoList;
m_tranInfoList = NULL;
}
if (m_tranInfoList2 != NULL) {
delete m_tranInfoList2;
m_tranInfoList2 = NULL;
}
for (i = 0; i < (MxS32) _countof(m_unk0x28); i++) {
m_unk0x28[i] = 0;
m_unk0x30[i] = 0;
}
m_unk0x38 = 0;
m_unk0x39 = 0;
m_unk0x430 = 0;
m_unk0x42c = 0;
for (j = 0; j < (MxS32) _countof(g_characters); j++) {
g_characters[j].m_active = FALSE;
}
m_animState = (AnimState*) GameState()->GetState("AnimState");
if (m_animState == NULL) {
m_animState = (AnimState*) GameState()->CreateState("AnimState");
}
if (m_unk0x08 == 0) {
m_animState->FUN_10065240(m_animCount, m_anims, m_unk0x3fc);
}
FUN_100603c0();
LegoFile file;
if (p_scriptIndex == -1) {
result = SUCCESS;
goto done;
}
char filename[128];
char path[1024];
sprintf(filename, "lego\\data\\%sinf.dta", Lego()->FindScript(p_scriptIndex));
sprintf(path, "%s", MxOmni::GetHD());
if (path[strlen(path) - 1] != '\\') {
strcat(path, "\\");
}
strcat(path, filename);
if (_access(path, 4)) {
sprintf(path, "%s", MxOmni::GetCD());
if (path[strlen(path) - 1] != '\\') {
strcat(path, "\\");
}
strcat(path, filename);
if (_access(path, 4)) {
goto done;
}
}
if (file.Open(path, LegoFile::c_read) == FAILURE) {
goto done;
}
MxU32 version;
if (file.Read(&version, sizeof(version)) == FAILURE) {
goto done;
}
if (version != 3) {
OmniError("World animation version mismatch", 0);
goto done;
}
if (file.Read(&m_animCount, sizeof(m_animCount)) == FAILURE) {
goto done;
}
m_anims = new AnimInfo[m_animCount];
memset(m_anims, 0, m_animCount * sizeof(*m_anims));
for (j = 0; j < m_animCount; j++) {
if (ReadAnimInfo(&file, &m_anims[j]) == FAILURE) {
goto done;
}
m_anims[j].m_unk0x28 = FUN_10062360(m_anims[j].m_animName + strlen(m_anims[j].m_animName) - 2);
m_anims[j].m_unk0x29 = 0;
for (k = 0; k < 3; k++) {
m_anims[j].m_unk0x2a[k] = -1;
}
if (m_anims[j].m_unk0x08 == -1) {
for (MxS32 l = 0; l < m_anims[j].m_modelCount; l++) {
MxS32 index = FUN_10062360(m_anims[j].m_models[l].m_modelName);
if (index >= 0) {
g_characters[index].m_active = TRUE;
}
}
}
MxS32 count = 0;
for (MxS32 m = 0; m < m_anims[j].m_modelCount; m++) {
MxU32 n;
if (FUN_10060140(m_anims[j].m_models[m].m_modelName, n) && m_anims[j].m_models[m].m_unk0x2c) {
m_anims[j].m_unk0x2a[count++] = n;
if (count > 3) {
break;
}
}
}
}
m_unk0x08 = p_scriptIndex;
m_tranInfoList = new LegoTranInfoList();
m_tranInfoList2 = new LegoTranInfoList();
FUN_100617c0(-1, m_unk0x0e, m_unk0x10);
result = SUCCESS;
m_unk0x402 = 1;
if (m_unk0x42b) {
m_unk0x428 = m_unk0x3a;
m_unk0x429 = m_unk0x400;
m_unk0x42a = 1;
m_unk0x3a = 0;
m_unk0x400 = 0;
m_unk0x402 = 0;
}
if (p_scriptIndex == 0) {
m_animState->FUN_100651d0(m_animCount, m_anims, m_unk0x3fc);
}
}
done:
if (result == FAILURE) {
FUN_100603c0();
}
return result;
}
// STUB: LEGO1 0x10060140
MxBool LegoAnimationManager::FUN_10060140(char* p_name, MxU32& p_index)
{
// TODO
return FALSE;
}
// FUNCTION: LEGO1 0x10060180
MxResult LegoAnimationManager::ReadAnimInfo(LegoFile* p_file, AnimInfo* p_info)
{
MxResult result = FAILURE;
MxU8 length;
MxS32 i, j;
if (p_file->Read(&length, sizeof(length)) == FAILURE) {
goto done;
}
p_info->m_animName = new char[length + 1];
if (p_file->Read(p_info->m_animName, length) == FAILURE) {
goto done;
}
p_info->m_animName[length] = 0;
if (p_file->Read(&p_info->m_unk0x04, sizeof(p_info->m_unk0x04)) == FAILURE) {
goto done;
}
if (p_file->Read(&p_info->m_unk0x08, sizeof(p_info->m_unk0x08)) == FAILURE) {
goto done;
}
if (p_file->Read(&p_info->m_unk0x0a, sizeof(p_info->m_unk0x0a)) == FAILURE) {
goto done;
}
if (p_file->Read(&p_info->m_unk0x0b, sizeof(p_info->m_unk0x0b)) == FAILURE) {
goto done;
}
if (p_file->Read(&p_info->m_unk0x0c, sizeof(p_info->m_unk0x0c)) == FAILURE) {
goto done;
}
if (p_file->Read(&p_info->m_unk0x0d, sizeof(p_info->m_unk0x0d)) == FAILURE) {
goto done;
}
for (i = 0; i < (MxS32) _countof(p_info->m_unk0x10); i++) {
if (p_file->Read(&p_info->m_unk0x10[i], sizeof(*p_info->m_unk0x10)) != SUCCESS) {
goto done;
}
}
if (p_file->Read(&p_info->m_modelCount, sizeof(p_info->m_modelCount)) == FAILURE) {
goto done;
}
p_info->m_models = new ModelInfo[p_info->m_modelCount];
memset(p_info->m_models, 0, p_info->m_modelCount * sizeof(*p_info->m_models));
for (j = 0; j < p_info->m_modelCount; j++) {
if (ReadModelInfo(p_file, &p_info->m_models[j]) == FAILURE) {
goto done;
}
}
result = SUCCESS;
done:
return result;
}
// FUNCTION: LEGO1 0x10060310
MxResult LegoAnimationManager::ReadModelInfo(LegoFile* p_file, ModelInfo* p_info)
{
MxResult result = FAILURE;
MxU8 length;
if (p_file->Read(&length, 1) == FAILURE) {
goto done;
}
p_info->m_modelName = new char[length + 1];
if (p_file->Read(p_info->m_modelName, length) == FAILURE) {
goto done;
}
p_info->m_modelName[length] = 0;
if (p_file->Read(&p_info->m_unk0x04, sizeof(p_info->m_unk0x04)) == FAILURE) {
goto done;
}
if (p_file->Read(p_info->m_location, sizeof(p_info->m_location)) != SUCCESS) {
goto done;
}
if (p_file->Read(p_info->m_direction, sizeof(p_info->m_direction)) != SUCCESS) {
goto done;
}
if (p_file->Read(p_info->m_up, sizeof(p_info->m_up)) != SUCCESS) {
goto done;
}
if (p_file->Read(&p_info->m_unk0x2c, sizeof(p_info->m_unk0x2c)) == FAILURE) {
goto done;
}
result = SUCCESS;
done:
return result;
}
// STUB: LEGO1 0x100603c0
void LegoAnimationManager::FUN_100603c0()
{
// TODO
}
@ -65,11 +344,16 @@ void LegoAnimationManager::FUN_10061010(undefined4)
// TODO
}
// STUB: LEGO1 0x100617c0
void LegoAnimationManager::FUN_100617c0(MxS32, MxU16&, MxU32&)
{
// TODO
}
// STUB: LEGO1 0x100619f0
MxLong LegoAnimationManager::Notify(MxParam& p_param)
{
// TODO
return 0;
}
@ -77,11 +361,18 @@ MxLong LegoAnimationManager::Notify(MxParam& p_param)
MxResult LegoAnimationManager::Tickle()
{
// TODO
return SUCCESS;
}
// STUB: LEGO1 0x10062360
MxS8 LegoAnimationManager::FUN_10062360(char*)
{
// TODO
return 0;
}
// STUB: LEGO1 0x10064670
void LegoAnimationManager::FUN_10064670(MxBool)
{
// TODO
}

View file

@ -577,7 +577,7 @@ void LegoWorld::Enable(MxBool p_enable)
if (m_scriptIndex != -1) {
PlantManager()->FUN_10026360(m_scriptIndex);
AnimationManager()->FUN_1005f720(m_scriptIndex);
AnimationManager()->LoadScriptInfo(m_scriptIndex);
BuildingManager()->FUN_1002fa00();
AnimationManager()->FUN_1005f0b0();
}

View file

@ -54,7 +54,7 @@ LegoWorldPresenter::~LegoWorldPresenter()
if (m_entity) {
MxS32 scriptIndex = ((LegoWorld*) m_entity)->GetScriptIndex();
PlantManager()->FUN_10026360(scriptIndex);
AnimationManager()->FUN_1005f720(scriptIndex);
AnimationManager()->LoadScriptInfo(scriptIndex);
BuildingManager()->FUN_1002fa00();
result = ((LegoWorld*) m_entity)->VTable0x5c();
}

View file

@ -706,6 +706,18 @@ MxS32 LegoOmni::GetCurrPathInfo(LegoPathBoundary** p_path, MxS32& p_value)
return ::CurrentWorld()->GetCurrPathInfo(p_path, p_value);
}
// FUNCTION: LEGO1 0x1005b430
const char* LegoOmni::FindScript(MxU32 p_index)
{
for (MxS32 i = 0; i < 19; i++) {
if (m_scripts[i].m_index == p_index) {
return m_scripts[i].m_key;
}
}
return NULL;
}
// FUNCTION: LEGO1 0x1005b490
MxS32 LegoOmni::GetScriptIndex(const char* p_key)
{