Merge branch 'master' into animpresenter-destroy

This commit is contained in:
Christian Semmler 2024-04-25 10:03:38 -04:00
commit d0cf3976ee
33 changed files with 591 additions and 109 deletions

View File

@ -12,10 +12,26 @@ const char* g_strANIMATION = "ANIMATION";
// STRING: LEGO1 0x10102024 // STRING: LEGO1 0x10102024
const char* g_strATTACH_CAMERA = "ATTACH_CAMERA"; const char* g_strATTACH_CAMERA = "ATTACH_CAMERA";
// GLOBAL: LEGO1 0x10102080
// STRING: LEGO1 0x100f4368
const char* g_strFROM_PARENT = "FROM_PARENT";
// GLOBAL: LEGO1 0x10102084
// STRING: LEGO1 0x10101fa4
const char* g_strHIDE_ON_STOP = "HIDE_ON_STOP";
// GLOBAL: LEGO1 0x10102098
// STRING: LEGO1 0x10101f60
const char* g_strMUST_SUCCEED = "MUST_SUCCEED";
// GLOBAL: LEGO1 0x1010209c // GLOBAL: LEGO1 0x1010209c
// STRING: LEGO1 0x10101f58 // STRING: LEGO1 0x10101f58
const char* g_strOBJECT = "OBJECT"; const char* g_strOBJECT = "OBJECT";
// GLOBAL: LEGO1 0x101020a8
// STRING: LEGO1 0x10101f38
const char* g_strPTATCAM = "PTATCAM";
// GLOBAL: LEGO1 0x101020b0 // GLOBAL: LEGO1 0x101020b0
// STRING: LEGO1 0x10101f20 // STRING: LEGO1 0x10101f20
const char* g_strSOUND = "SOUND"; const char* g_strSOUND = "SOUND";
@ -28,6 +44,10 @@ const char* g_strMUTE = "MUTE";
// STRING: LEGO1 0x100f09cc // STRING: LEGO1 0x100f09cc
const char* g_strSPEED = "SPEED"; const char* g_strSPEED = "SPEED";
// GLOBAL: LEGO1 0x101020bc
// STRING: LEGO1 0x10101f10
const char* g_strSUBST = "SUBST";
// GLOBAL: LEGO1 0x101020cc // GLOBAL: LEGO1 0x101020cc
// STRING: LEGO1 0x100f3808 // STRING: LEGO1 0x100f3808
const char* g_strVISIBILITY = "VISIBILITY"; const char* g_strVISIBILITY = "VISIBILITY";

View File

@ -14,5 +14,10 @@ extern const char* g_strSPEED;
extern const char* g_strATTACH_CAMERA; extern const char* g_strATTACH_CAMERA;
extern const char* g_strMUTE; extern const char* g_strMUTE;
extern const char* g_strANIMMAN_ID; extern const char* g_strANIMMAN_ID;
extern const char* g_strFROM_PARENT;
extern const char* g_strHIDE_ON_STOP;
extern const char* g_strMUST_SUCCEED;
extern const char* g_strSUBST;
extern const char* g_strPTATCAM;
#endif // DEFINE_H #endif // DEFINE_H

View File

@ -8,6 +8,9 @@
#include "legotraninfolist.h" #include "legotraninfolist.h"
#include "mxcore.h" #include "mxcore.h"
class LegoAnimPresenter;
class LegoROIList;
// SIZE 0x18 // SIZE 0x18
struct Character { struct Character {
char* m_name; // 0x00 char* m_name; // 0x00
@ -92,6 +95,8 @@ class LegoAnimationManager : public MxCore {
void FUN_10062770(); void FUN_10062770();
void FUN_100627d0(MxBool); void FUN_100627d0(MxBool);
void FUN_100629b0(MxU32, MxBool); void FUN_100629b0(MxU32, MxBool);
void FUN_10063270(LegoROIList*, LegoAnimPresenter*);
void FUN_10063780(LegoROIList*);
void FUN_10064670(MxBool); void FUN_10064670(MxBool);
void FUN_10064740(MxBool); void FUN_10064740(MxBool);

View File

@ -10,11 +10,16 @@
class LegoWorld; class LegoWorld;
class LegoAnimClass; class LegoAnimClass;
class LegoAnimActor; class LegoAnimActor;
class LegoPathBoundary;
struct LegoAnimStructComparator { struct LegoAnimStructComparator {
MxBool operator()(const char* const& p_a, const char* const& p_b) const { return strcmp(p_a, p_b) < 0; } MxBool operator()(const char* const& p_a, const char* const& p_b) const { return strcmp(p_a, p_b) < 0; }
}; };
struct LegoAnimSubstComparator {
MxBool operator()(const char* const& p_a, const char* const& p_b) const { return strcmp(p_a, p_b) < 0; }
};
// SIZE 0x08 // SIZE 0x08
struct LegoAnimStruct { struct LegoAnimStruct {
LegoROI* m_roi; // 0x00 LegoROI* m_roi; // 0x00
@ -22,14 +27,15 @@ struct LegoAnimStruct {
}; };
typedef map<const char*, LegoAnimStruct, LegoAnimStructComparator> LegoAnimPresenterMap; typedef map<const char*, LegoAnimStruct, LegoAnimStructComparator> LegoAnimPresenterMap;
typedef map<const char*, const char*, LegoAnimSubstComparator> LegoAnimSubstMap;
// VTABLE: LEGO1 0x100d90c8 // VTABLE: LEGO1 0x100d90c8
// SIZE 0xbc // SIZE 0xbc
class LegoAnimPresenter : public MxVideoPresenter { class LegoAnimPresenter : public MxVideoPresenter {
public: public:
enum { enum {
c_bit1 = 0x01, c_hideOnStop = 0x01,
c_bit2 = 0x02 c_mustSucceed = 0x02
}; };
LegoAnimPresenter(); LegoAnimPresenter();
@ -62,7 +68,7 @@ class LegoAnimPresenter : public MxVideoPresenter {
virtual void VTable0x8c(); // vtable+0x8c virtual void VTable0x8c(); // vtable+0x8c
virtual void VTable0x90(); // vtable+0x90 virtual void VTable0x90(); // vtable+0x90
virtual MxResult VTable0x94(Vector3&, Vector3&, float, float, Vector3&); // vtable+0x94 virtual MxResult VTable0x94(Vector3&, Vector3&, float, float, Vector3&); // vtable+0x94
virtual void VTable0x98(); // vtable+0x98 virtual MxResult VTable0x98(LegoPathBoundary* p_boundary); // vtable+0x98
// FUNCTION: LEGO1 0x1000c990 // FUNCTION: LEGO1 0x1000c990
virtual LegoROI** GetROIMap(MxU32& p_roiMapSize) virtual LegoROI** GetROIMap(MxU32& p_roiMapSize)
@ -71,16 +77,14 @@ class LegoAnimPresenter : public MxVideoPresenter {
return m_roiMap; return m_roiMap;
} // vtable+0x9c } // vtable+0x9c
virtual void VTable0xa0(Matrix4*); // vtable+0xa0 virtual void VTable0xa0(Matrix4& p_matrix); // vtable+0xa0
MxResult FUN_1006afc0(MxMatrix*&, undefined4); MxResult FUN_1006afc0(MxMatrix*& p_matrix, float p_und);
MxResult FUN_1006b140(LegoROI* p_roi); MxResult FUN_1006b140(LegoROI* p_roi);
void FUN_1006d680(LegoAnimActor* p_actor, MxFloat p_value); const char* GetActionObjectName();
inline LegoAnim* GetAnimation() { return m_anim; } inline LegoAnim* GetAnimation() { return m_anim; }
const char* GetActionObjectName();
protected: protected:
void Init(); void Init();
void Destroy(MxBool p_fromDestructor); void Destroy(MxBool p_fromDestructor);
@ -98,36 +102,52 @@ class LegoAnimPresenter : public MxVideoPresenter {
LegoBool FUN_1006aba0(); LegoBool FUN_1006aba0();
MxBool FUN_1006abb0(LegoTreeNode* p_node, LegoROI* p_roi); MxBool FUN_1006abb0(LegoTreeNode* p_node, LegoROI* p_roi);
void FUN_1006ac90(); void FUN_1006ac90();
void FUN_1006b900(LegoAnim* p_anim, MxLong p_time, Matrix4* p_matrix);
void FUN_1006b9a0(LegoAnim* p_anim, MxLong p_time, Matrix4* p_matrix); void FUN_1006b9a0(LegoAnim* p_anim, MxLong p_time, Matrix4* p_matrix);
void FUN_1006c8a0(MxBool p_bool); void FUN_1006c8a0(MxBool p_bool);
LegoAnim* m_anim; // 0x64 LegoAnim* m_anim; // 0x64
LegoROI** m_roiMap; // 0x68 LegoROI** m_roiMap; // 0x68
MxU32 m_roiMapSize; // 0x6c MxU32 m_roiMapSize; // 0x6c
LegoROIList* m_unk0x70; // 0x70 LegoROIList* m_unk0x70; // 0x70
LegoROIList* m_unk0x74; // 0x74 LegoROIList* m_unk0x74; // 0x74
MxMatrix* m_unk0x78; // 0x78 MxMatrix* m_unk0x78; // 0x78
MxU32 m_flags; // 0x7c MxU32 m_flags; // 0x7c
LegoWorld* m_currentWorld; // 0x80 LegoWorld* m_currentWorld; // 0x80
MxAtomId m_animAtom; // 0x84 MxAtomId m_worldAtom; // 0x84
undefined4 m_unk0x88; // 0x88 MxS32 m_worldId; // 0x88
LegoROI** m_unk0x8c; // 0x8c LegoROI** m_unk0x8c; // 0x8c
char** m_unk0x90; // 0x90 char** m_unk0x90; // 0x90
MxU8 m_unk0x94; // 0x94 MxU8 m_unk0x94; // 0x94
undefined m_unk0x95; // 0x95 undefined m_unk0x95; // 0x95
MxBool m_unk0x96; // 0x96 MxBool m_unk0x96; // 0x96
undefined m_unk0x97; // 0x97 undefined m_unk0x97; // 0x97
undefined4 m_unk0x98; // 0x98 LegoAnimSubstMap* m_substMap; // 0x98
MxS16 m_unk0x9c; // 0x9c MxS16 m_unk0x9c; // 0x9c
undefined4* m_unk0xa0; // 0xa0 undefined4* m_unk0xa0; // 0xa0
undefined4 m_unk0xa4; // 0xa4 undefined4 m_unk0xa4; // 0xa4
Mx3DPointFloat m_unk0xa8; // 0xa8 Mx3DPointFloat m_unk0xa8; // 0xa8
}; };
// clang-format off // clang-format off
// SYNTHETIC: LEGO1 0x10068650 // SYNTHETIC: LEGO1 0x10068650
// LegoAnimPresenter::`scalar deleting destructor' // LegoAnimPresenter::`scalar deleting destructor'
// TEMPLATE: LEGO1 0x100689c0
// map<char const *,char const *,LegoAnimSubstComparator,allocator<char const *> >::~map<char const *,char const *,LegoAnimSubstComparator,allocator<char const *> >
// TEMPLATE: LEGO1 0x10068a10
// _Tree<char const *,pair<char const * const,char const *>,map<char const *,char const *,LegoAnimSubstComparator,allocator<char const *> >::_Kfn,LegoAnimSubstComparator,allocator<char const *> >::~_Tree<char const *,pair<char const * const,char const *>,map
// TEMPLATE: LEGO1 0x10068ae0
// _Tree<char const *,pair<char const * const,char const *>,map<char const *,char const *,LegoAnimSubstComparator,allocator<char const *> >::_Kfn,LegoAnimSubstComparator,allocator<char const *> >::iterator::_Inc
// TEMPLATE: LEGO1 0x10068b20
// _Tree<char const *,pair<char const * const,char const *>,map<char const *,char const *,LegoAnimSubstComparator,allocator<char const *> >::_Kfn,LegoAnimSubstComparator,allocator<char const *> >::erase
// TEMPLATE: LEGO1 0x10068f70
// _Tree<char const *,pair<char const * const,char const *>,map<char const *,char const *,LegoAnimSubstComparator,allocator<char const *> >::_Kfn,LegoAnimSubstComparator,allocator<char const *> >::_Erase
// TEMPLATE: LEGO1 0x10069d80 // TEMPLATE: LEGO1 0x10069d80
// _Tree<char const *,pair<char const * const,LegoAnimStruct>,map<char const *,LegoAnimStruct,LegoAnimStructComparator,allocator<LegoAnimStruct> >::_Kfn,LegoAnimStructComparator,allocator<LegoAnimStruct> >::~_Tree<char const *,pair<char const * const,LegoAni // _Tree<char const *,pair<char const * const,LegoAnimStruct>,map<char const *,LegoAnimStruct,LegoAnimStructComparator,allocator<LegoAnimStruct> >::_Kfn,LegoAnimStructComparator,allocator<LegoAnimStruct> >::~_Tree<char const *,pair<char const * const,LegoAni
@ -152,6 +172,21 @@ class LegoAnimPresenter : public MxVideoPresenter {
// TEMPLATE: LEGO1 0x1006a7a0 // TEMPLATE: LEGO1 0x1006a7a0
// _Tree<char const *,pair<char const * const,LegoAnimStruct>,map<char const *,LegoAnimStruct,LegoAnimStructComparator,allocator<LegoAnimStruct> >::_Kfn,LegoAnimStructComparator,allocator<LegoAnimStruct> >::_Insert // _Tree<char const *,pair<char const * const,LegoAnimStruct>,map<char const *,LegoAnimStruct,LegoAnimStructComparator,allocator<LegoAnimStruct> >::_Kfn,LegoAnimStructComparator,allocator<LegoAnimStruct> >::_Insert
// TEMPLATE: LEGO1 0x1006c1b0
// _Tree<char const *,pair<char const * const,char const *>,map<char const *,char const *,LegoAnimSubstComparator,allocator<char const *> >::_Kfn,LegoAnimSubstComparator,allocator<char const *> >::iterator::_Dec
// TEMPLATE: LEGO1 0x1006c200
// _Tree<char const *,pair<char const * const,char const *>,map<char const *,char const *,LegoAnimSubstComparator,allocator<char const *> >::_Kfn,LegoAnimSubstComparator,allocator<char const *> >::_Insert
// TEMPLATE: LEGO1 0x1006c4b0
// list<char *,allocator<char *> >::~list<char *,allocator<char *> >
// TEMPLATE: LEGO1 0x1006c520
// List<char *>::~List<char *>
// GLOBAL: LEGO1 0x100f7680
// _Tree<char const *,pair<char const * const,char const *>,map<char const *,char const *,LegoAnimSubstComparator,allocator<char const *> >::_Kfn,LegoAnimSubstComparator,allocator<char const *> >::_Nil
// GLOBAL: LEGO1 0x100f7688 // GLOBAL: LEGO1 0x100f7688
// _Tree<char const *,pair<char const * const,LegoAnimStruct>,map<char const *,LegoAnimStruct,LegoAnimStructComparator,allocator<LegoAnimStruct> >::_Kfn,LegoAnimStructComparator,allocator<LegoAnimStruct> >::_Nil // _Tree<char const *,pair<char const * const,LegoAnimStruct>,map<char const *,LegoAnimStruct,LegoAnimStructComparator,allocator<LegoAnimStruct> >::_Kfn,LegoAnimStructComparator,allocator<LegoAnimStruct> >::_Nil
// clang-format on // clang-format on

View File

@ -2,7 +2,6 @@
#define LEGOEXTRAACTOR_H #define LEGOEXTRAACTOR_H
#include "legoanimactor.h" #include "legoanimactor.h"
#include "legoanimpresenter.h"
// VTABLE: LEGO1 0x100d6c00 LegoAnimActor // VTABLE: LEGO1 0x100d6c00 LegoAnimActor
// VTABLE: LEGO1 0x100d6c10 LegoPathActor // VTABLE: LEGO1 0x100d6c10 LegoPathActor

View File

@ -35,6 +35,8 @@ class LegoLocomotionAnimPresenter : public LegoLoopingAnimPresenter {
// SYNTHETIC: LEGO1 0x1006cfe0 // SYNTHETIC: LEGO1 0x1006cfe0
// LegoLocomotionAnimPresenter::`scalar deleting destructor' // LegoLocomotionAnimPresenter::`scalar deleting destructor'
void FUN_1006d680(LegoAnimActor* p_actor, MxFloat p_value);
inline void DecrementUnknown0xd4() inline void DecrementUnknown0xd4()
{ {
if (m_unk0xd4) { if (m_unk0xd4) {

View File

@ -3,11 +3,11 @@
#include "geom/legounkown100db7f4.h" #include "geom/legounkown100db7f4.h"
#include "legoactor.h" #include "legoactor.h"
#include "legopathboundary.h"
#include "misc/legounknown.h" #include "misc/legounknown.h"
#include "mxtypes.h" #include "mxtypes.h"
#include "realtime/matrix.h" #include "realtime/matrix.h"
class LegoPathBoundary;
class LegoPathController; class LegoPathController;
// VTABLE: LEGO1 0x100d6e28 // VTABLE: LEGO1 0x100d6e28

View File

@ -5,6 +5,7 @@
#include "legopathactor.h" #include "legopathactor.h"
#include "mxcore.h" #include "mxcore.h"
class LegoAnimPresenter;
class LegoPathBoundary; class LegoPathBoundary;
class LegoWorld; class LegoWorld;
@ -41,6 +42,8 @@ class LegoPathController : public MxCore {
virtual void Destroy(); // vtable+0x18 virtual void Destroy(); // vtable+0x18
undefined4 FUN_10046770(LegoPathActor* p_actor); undefined4 FUN_10046770(LegoPathActor* p_actor);
void FUN_100468f0(LegoAnimPresenter* p_presenter);
void FUN_10046930(LegoAnimPresenter* p_presenter);
MxResult FUN_10046b30(LegoPathBoundary** p_path, MxS32& p_value); MxResult FUN_10046b30(LegoPathBoundary** p_path, MxS32& p_value);
void Enable(MxBool p_enable); void Enable(MxBool p_enable);
void FUN_10046bb0(LegoWorld* p_world); void FUN_10046bb0(LegoWorld* p_world);

View File

@ -12,12 +12,14 @@
// class MxList<LegoPhoneme *> // class MxList<LegoPhoneme *>
// VTABLE: LEGO1 0x100d9d00 // VTABLE: LEGO1 0x100d9d00
// VTABLE: BETA10 0x101bef58
// SIZE 0x18 // SIZE 0x18
class LegoPhonemeList : public MxList<LegoPhoneme*> { class LegoPhonemeList : public MxList<LegoPhoneme*> {
public: public:
LegoPhonemeList() { SetDestroy(Destroy); } LegoPhonemeList() { SetDestroy(Destroy); }
// FUNCTION: LEGO1 0x1007b210 // FUNCTION: LEGO1 0x1007b210
// FUNCTION: BETA10 0x100d8340
MxS8 Compare(LegoPhoneme* p_a, LegoPhoneme* p_b) override MxS8 Compare(LegoPhoneme* p_a, LegoPhoneme* p_b) override
{ {
MxString a(p_a->GetName()); MxString a(p_a->GetName());

View File

@ -75,6 +75,7 @@ class LegoWorld : public LegoEntity {
); );
void FUN_1001fc80(IslePathActor* p_actor); void FUN_1001fc80(IslePathActor* p_actor);
void FUN_1001fda0(LegoAnimPresenter* p_presenter); void FUN_1001fda0(LegoAnimPresenter* p_presenter);
void FUN_1001fe90(LegoAnimPresenter* p_presenter);
void AddPath(LegoPathController* p_controller); void AddPath(LegoPathController* p_controller);
MxResult GetCurrPathInfo(LegoPathBoundary** p_path, MxS32& p_value); MxResult GetCurrPathInfo(LegoPathBoundary** p_path, MxS32& p_value);
MxCore* Find(const char* p_class, const char* p_name); MxCore* Find(const char* p_class, const char* p_name);

View File

@ -2,6 +2,7 @@
#include "legoanimationmanager.h" #include "legoanimationmanager.h"
#include "legonavcontroller.h" #include "legonavcontroller.h"
#include "legopathboundary.h"
#include "legoutils.h" #include "legoutils.h"
#include "misc.h" #include "misc.h"
#include "mxnotificationparam.h" #include "mxnotificationparam.h"

View File

@ -621,6 +621,18 @@ void LegoAnimationManager::FUN_100629b0(MxU32, MxBool)
// TODO // TODO
} }
// STUB: LEGO1 0x10063270
void LegoAnimationManager::FUN_10063270(LegoROIList*, LegoAnimPresenter*)
{
// TODO
}
// STUB: LEGO1 0x10063780
void LegoAnimationManager::FUN_10063780(LegoROIList*)
{
// TODO
}
// STUB: LEGO1 0x10064670 // STUB: LEGO1 0x10064670
void LegoAnimationManager::FUN_10064670(MxBool) void LegoAnimationManager::FUN_10064670(MxBool)
{ {

View File

@ -4,6 +4,7 @@
#include "define.h" #include "define.h"
#include "islepathactor.h" #include "islepathactor.h"
#include "legoanimationmanager.h" #include "legoanimationmanager.h"
#include "legoanimpresenter.h"
#include "legotraninfo.h" #include "legotraninfo.h"
#include "legovideomanager.h" #include "legovideomanager.h"
#include "legoworld.h" #include "legoworld.h"
@ -149,7 +150,7 @@ void LegoAnimMMPresenter::ReadyTickle()
} }
if (m_tranInfo != NULL && m_tranInfo->m_unk0x0c != NULL) { if (m_tranInfo != NULL && m_tranInfo->m_unk0x0c != NULL) {
m_presenter->VTable0xa0(m_tranInfo->m_unk0x0c); m_presenter->VTable0xa0(*m_tranInfo->m_unk0x0c);
} }
if (m_presenter != NULL) { if (m_presenter != NULL) {

View File

@ -2,6 +2,7 @@
#include "act1state.h" #include "act1state.h"
#include "islepathactor.h" #include "islepathactor.h"
#include "legoanimpresenter.h"
#include "legogamestate.h" #include "legogamestate.h"
#include "legoinputmanager.h" #include "legoinputmanager.h"
#include "legonamedtexture.h" #include "legonamedtexture.h"

View File

@ -68,12 +68,13 @@ const char* g_nick = "Nick";
const char* g_laura = "Laura"; const char* g_laura = "Laura";
// FUNCTION: LEGO1 0x10037d00 // FUNCTION: LEGO1 0x10037d00
// FUNCTION: BETA10 0x100d5620
void VisibilityVariable::SetValue(const char* p_value) void VisibilityVariable::SetValue(const char* p_value)
{ {
MxVariable::SetValue(p_value); MxVariable::SetValue(p_value);
if (p_value) { if (p_value) {
char* instruction = strtok(m_value.GetDataPtr(), g_delimiter2); char* instruction = strtok(m_value.GetData(), g_delimiter2);
char* name = strtok(NULL, g_delimiter2); char* name = strtok(NULL, g_delimiter2);
MxBool show; MxBool show;

View File

@ -299,10 +299,28 @@ void LegoWorld::FUN_1001fc80(IslePathActor* p_actor)
} }
} }
// STUB: LEGO1 0x1001fda0 // FUNCTION: LEGO1 0x1001fda0
// FUNCTION: BETA10 0x100da621
void LegoWorld::FUN_1001fda0(LegoAnimPresenter* p_presenter) void LegoWorld::FUN_1001fda0(LegoAnimPresenter* p_presenter)
{ {
// TODO LegoPathControllerListCursor cursor(&m_list0x68);
LegoPathController* controller;
while (cursor.Next(controller)) {
controller->FUN_100468f0(p_presenter);
}
}
// FUNCTION: LEGO1 0x1001fe90
// FUNCTION: BETA10 0x100da6b5
void LegoWorld::FUN_1001fe90(LegoAnimPresenter* p_presenter)
{
LegoPathControllerListCursor cursor(&m_list0x68);
LegoPathController* controller;
while (cursor.Next(controller)) {
controller->FUN_10046930(p_presenter);
}
} }
// FUNCTION: LEGO1 0x1001ff80 // FUNCTION: LEGO1 0x1001ff80

View File

@ -1,7 +1,8 @@
#include "legoanimactor.h" #include "legoanimactor.h"
#include "define.h" #include "define.h"
#include "legoanimpresenter.h" #include "legolocomotionanimpresenter.h"
#include "legopathboundary.h"
#include "legoworld.h" #include "legoworld.h"
#include "misc.h" #include "misc.h"
#include "mxutilities.h" #include "mxutilities.h"
@ -200,7 +201,8 @@ void LegoAnimActor::ParseAction(char* p_extra)
char* token = strtok(value, g_parseExtraTokens); char* token = strtok(value, g_parseExtraTokens);
while (token) { while (token) {
LegoAnimPresenter* presenter = (LegoAnimPresenter*) world->Find("LegoAnimPresenter", token); LegoLocomotionAnimPresenter* presenter =
(LegoLocomotionAnimPresenter*) world->Find("LegoAnimPresenter", token);
if (presenter != NULL) { if (presenter != NULL) {
token = strtok(NULL, g_parseExtraTokens); token = strtok(NULL, g_parseExtraTokens);

View File

@ -1,5 +1,7 @@
#include "legoextraactor.h" #include "legoextraactor.h"
#include "legolocomotionanimpresenter.h"
#include "legopathboundary.h"
#include "legosoundmanager.h" #include "legosoundmanager.h"
#include "misc.h" #include "misc.h"
#include "mxmisc.h" #include "mxmisc.h"
@ -11,10 +13,10 @@ DECOMP_SIZE_ASSERT(LegoExtraActor, 0x1dc)
LegoWorld* g_unk0x100f31d0 = NULL; LegoWorld* g_unk0x100f31d0 = NULL;
// GLOBAL: LEGO1 0x100f31d4 // GLOBAL: LEGO1 0x100f31d4
LegoAnimPresenter* m_assAnimP = NULL; LegoLocomotionAnimPresenter* m_assAnimP = NULL;
// GLOBAL: LEGO1 0x100f31d8 // GLOBAL: LEGO1 0x100f31d8
LegoAnimPresenter* m_disAnimP = NULL; LegoLocomotionAnimPresenter* m_disAnimP = NULL;
// GLOBAL: LEGO1 0x100f31dc // GLOBAL: LEGO1 0x100f31dc
MxS32 g_unk0x100f31dc = 0; MxS32 g_unk0x100f31dc = 0;
@ -156,8 +158,8 @@ inline void LegoExtraActor::FUN_1002ad8a()
if (g_unk0x100f31d0 != w) { if (g_unk0x100f31d0 != w) {
g_unk0x100f31d0 = w; g_unk0x100f31d0 = w;
m_assAnimP = (LegoAnimPresenter*) w->Find("LegoAnimPresenter", "BNsAss01"); m_assAnimP = (LegoLocomotionAnimPresenter*) w->Find("LegoAnimPresenter", "BNsAss01");
m_disAnimP = (LegoAnimPresenter*) w->Find("LegoAnimPresenter", "BNsDis01"); m_disAnimP = (LegoLocomotionAnimPresenter*) w->Find("LegoAnimPresenter", "BNsDis01");
} }
if (!m_assAnim) { if (!m_assAnim) {

View File

@ -1,6 +1,7 @@
#include "legopathactor.h" #include "legopathactor.h"
#include "legonavcontroller.h" #include "legonavcontroller.h"
#include "legopathboundary.h"
#include "legosoundmanager.h" #include "legosoundmanager.h"
#include "misc.h" #include "misc.h"
#include "mxmisc.h" #include "mxmisc.h"

View File

@ -33,6 +33,18 @@ undefined4 LegoPathController::FUN_10046770(LegoPathActor* p_actor)
return 0; return 0;
} }
// STUB: LEGO1 0x100468f0
// FUNCTION: BETA10 0x100b72f7
void LegoPathController::FUN_100468f0(LegoAnimPresenter* p_presenter)
{
}
// STUB: LEGO1 0x10046930
// FUNCTION: BETA10 0x100b737b
void LegoPathController::FUN_10046930(LegoAnimPresenter* p_presenter)
{
}
// STUB: LEGO1 0x10046b30 // STUB: LEGO1 0x10046b30
MxResult LegoPathController::FUN_10046b30(LegoPathBoundary** p_path, MxS32& p_value) MxResult LegoPathController::FUN_10046b30(LegoPathBoundary** p_path, MxS32& p_value)
{ {

View File

@ -1,7 +1,10 @@
#include "legoanimpresenter.h" #include "legoanimpresenter.h"
#include "define.h"
#include "legoanimationmanager.h"
#include "legoanimmmpresenter.h" #include "legoanimmmpresenter.h"
#include "legocharactermanager.h" #include "legocharactermanager.h"
#include "legopathboundary.h"
#include "legovideomanager.h" #include "legovideomanager.h"
#include "legoworld.h" #include "legoworld.h"
#include "misc.h" #include "misc.h"
@ -13,6 +16,7 @@
#include "mxstreamchunk.h" #include "mxstreamchunk.h"
#include "mxtimer.h" #include "mxtimer.h"
#include "mxtype18notificationparam.h" #include "mxtype18notificationparam.h"
#include "mxutilities.h"
#include "mxvideomanager.h" #include "mxvideomanager.h"
#include "realtime/realtime.h" #include "realtime/realtime.h"
@ -44,9 +48,9 @@ void LegoAnimPresenter::Init()
m_unk0xa4 = 0; m_unk0xa4 = 0;
m_currentWorld = NULL; m_currentWorld = NULL;
m_unk0x95 = 0; m_unk0x95 = 0;
m_unk0x88 = -1; m_worldId = -1;
m_unk0x98 = 0; m_substMap = NULL;
m_animAtom.Clear(); m_worldAtom.Clear();
m_unk0x9c = 0; m_unk0x9c = 0;
m_unk0x8c = NULL; m_unk0x8c = NULL;
m_unk0x90 = NULL; m_unk0x90 = NULL;
@ -505,10 +509,15 @@ void LegoAnimPresenter::FUN_1006aa60()
// TODO // TODO
} }
// STUB: LEGO1 0x1006ab70 // FUNCTION: LEGO1 0x1006ab70
void LegoAnimPresenter::FUN_1006ab70() void LegoAnimPresenter::FUN_1006ab70()
{ {
// TODO if (m_unk0x96) {
AnimationManager()->FUN_10063270(m_unk0x74, this);
}
else {
AnimationManager()->FUN_10063780(m_unk0x74);
}
} }
// FUNCTION: LEGO1 0x1006aba0 // FUNCTION: LEGO1 0x1006aba0
@ -627,11 +636,32 @@ void LegoAnimPresenter::PutFrame()
} }
} }
// STUB: LEGO1 0x1006afc0 // FUNCTION: LEGO1 0x1006afc0
// FUNCTION: BETA10 0x1005059a // FUNCTION: BETA10 0x1005059a
MxResult LegoAnimPresenter::FUN_1006afc0(MxMatrix*&, undefined4) MxResult LegoAnimPresenter::FUN_1006afc0(MxMatrix*& p_matrix, float p_und)
{ {
// TODO MxU32 length = m_roiMapSize + 1;
p_matrix = new MxMatrix[length];
MxS32 i;
for (i = 1; i < length; i++) {
if (m_roiMap[i] != NULL) {
p_matrix[i] = m_roiMap[i]->GetLocal2World();
}
}
FUN_1006b900(m_anim, p_und, m_unk0x78);
for (i = 1; i < length; i++) {
MxMatrix mat;
if (m_roiMap[i] != NULL) {
mat = p_matrix[i];
p_matrix[i] = m_roiMap[i]->GetLocal2World();
m_roiMap[i]->FUN_100a58f0(mat);
}
}
return SUCCESS; return SUCCESS;
} }
@ -674,7 +704,7 @@ void LegoAnimPresenter::StartingTickle()
FUN_100692b0(); FUN_100692b0();
FUN_100695c0(); FUN_100695c0();
if (m_flags & c_bit2 && !FUN_1006aba0()) { if (m_flags & c_mustSucceed && !FUN_1006aba0()) {
goto done; goto done;
} }
@ -770,6 +800,31 @@ const char* LegoAnimPresenter::GetActionObjectName()
return m_action->GetObjectName(); return m_action->GetObjectName();
} }
// FUNCTION: LEGO1 0x1006b900
// FUNCTION: BETA10 0x100510d8
void LegoAnimPresenter::FUN_1006b900(LegoAnim* p_anim, MxLong p_time, Matrix4* p_matrix)
{
LegoTreeNode* root = p_anim->GetRoot();
MxMatrix mat;
LegoAnimNodeData* data = (LegoAnimNodeData*) root->GetData();
if (p_matrix != NULL) {
mat = *p_matrix;
}
else {
LegoROI* roi = m_roiMap[data->GetUnknown0x20()];
if (roi != NULL) {
mat = roi->GetLocal2World();
}
else {
mat.SetIdentity();
}
}
LegoROI::FUN_100a8fd0(root, mat, p_time, m_roiMap);
}
// FUNCTION: LEGO1 0x1006b9a0 // FUNCTION: LEGO1 0x1006b9a0
void LegoAnimPresenter::FUN_1006b9a0(LegoAnim* p_anim, MxLong p_time, Matrix4* p_matrix) void LegoAnimPresenter::FUN_1006b9a0(LegoAnim* p_anim, MxLong p_time, Matrix4* p_matrix)
{ {
@ -803,16 +858,117 @@ void LegoAnimPresenter::FUN_1006b9a0(LegoAnim* p_anim, MxLong p_time, Matrix4* p
LegoROI::FUN_100a8e80(root, mat, p_time, m_roiMap); LegoROI::FUN_100a8e80(root, mat, p_time, m_roiMap);
} }
// STUB: LEGO1 0x1006bac0 // FUNCTION: LEGO1 0x1006bac0
// FUNCTION: BETA10 0x100512e1
void LegoAnimPresenter::ParseExtra() void LegoAnimPresenter::ParseExtra()
{ {
// TODO MxU16 extraLength;
char* extraData;
m_action->GetExtra(extraLength, extraData);
if (extraLength & MAXWORD) {
char extraCopy[256];
memcpy(extraCopy, extraData, extraLength & MAXWORD);
extraCopy[extraLength & MAXWORD] = '\0';
char output[256];
if (KeyValueStringParse(NULL, g_strFROM_PARENT, extraCopy) && m_compositePresenter != NULL) {
m_compositePresenter->GetAction()->GetExtra(extraLength, extraData);
if (extraLength & MAXWORD) {
memcpy(extraCopy, extraData, extraLength & MAXWORD);
extraCopy[extraLength & MAXWORD] = '\0';
}
}
if (KeyValueStringParse(output, g_strHIDE_ON_STOP, extraCopy)) {
m_flags |= c_hideOnStop;
}
if (KeyValueStringParse(output, g_strMUST_SUCCEED, extraCopy)) {
m_flags |= c_mustSucceed;
}
if (KeyValueStringParse(output, g_strSUBST, extraCopy)) {
m_substMap = new LegoAnimSubstMap();
char* substToken = output;
char *key, *value;
while ((key = strtok(substToken, g_parseExtraTokens))) {
substToken = NULL;
if ((value = strtok(NULL, g_parseExtraTokens))) {
char* keyCopy = new char[strlen(key) + 1];
strcpy(keyCopy, key);
char* valueCopy = new char[strlen(value) + 1];
strcpy(valueCopy, value);
(*m_substMap)[keyCopy] = valueCopy;
}
}
}
if (KeyValueStringParse(output, g_strWORLD, extraCopy)) {
char* token = strtok(output, g_parseExtraTokens);
m_worldAtom = MxAtomId(token, e_lowerCase2);
token = strtok(NULL, g_parseExtraTokens);
m_worldId = atoi(token);
}
if (KeyValueStringParse(output, g_strPTATCAM, extraCopy)) {
list<char*> tmp;
if (m_unk0x90 != NULL) {
for (MxS32 i = 0; i < m_unk0x94; i++) {
if (m_unk0x90[i] != NULL) {
// (modernization) critical bug: wrong free
delete[] m_unk0x90;
}
}
delete[] m_unk0x90;
m_unk0x90 = NULL;
}
if (m_unk0x8c != NULL) {
delete[] m_unk0x8c;
m_unk0x8c = NULL;
}
char* token = strtok(output, g_parseExtraTokens);
while (token != NULL) {
char* valueCopy = new char[strlen(token) + 1];
strcpy(valueCopy, token);
tmp.push_back(valueCopy);
token = strtok(NULL, g_parseExtraTokens);
}
m_unk0x94 = tmp.size();
if (m_unk0x94 != 0) {
m_unk0x8c = new LegoROI*[m_unk0x94];
m_unk0x90 = new char*[m_unk0x94];
memset(m_unk0x8c, 0, sizeof(*m_unk0x8c) * m_unk0x94);
memset(m_unk0x90, 0, sizeof(*m_unk0x90) * m_unk0x94);
MxS32 i = 0;
for (list<char*>::iterator it = tmp.begin(); it != tmp.end(); it++, i++) {
m_unk0x90[i] = *it;
}
}
}
}
} }
// STUB: LEGO1 0x1006c570 // FUNCTION: LEGO1 0x1006c570
void LegoAnimPresenter::VTable0xa0(Matrix4*) // FUNCTION: BETA10 0x10051ab3
void LegoAnimPresenter::VTable0xa0(Matrix4& p_matrix)
{ {
// TODO if (m_unk0x78 != NULL) {
delete m_unk0x78;
}
m_unk0x78 = new MxMatrix(p_matrix);
} }
// FUNCTION: LEGO1 0x1006c620 // FUNCTION: LEGO1 0x1006c620
@ -844,7 +1000,7 @@ void LegoAnimPresenter::EndAction()
FUN_1006b9a0(m_anim, m_anim->GetDuration(), m_unk0x78); FUN_1006b9a0(m_anim, m_anim->GetDuration(), m_unk0x78);
} }
if (m_roiMapSize != 0 && m_roiMap != NULL && m_roiMap[1] != NULL && m_flags & c_bit1) { if (m_roiMapSize != 0 && m_roiMap != NULL && m_roiMap[1] != NULL && m_flags & c_hideOnStop) {
for (MxS16 i = 1; i <= m_roiMapSize; i++) { for (MxS16 i = 1; i <= m_roiMapSize; i++) {
if (m_roiMap[i] != NULL) { if (m_roiMap[i] != NULL) {
m_roiMap[i]->SetVisibility(FALSE); m_roiMap[i]->SetVisibility(FALSE);
@ -864,6 +1020,7 @@ void LegoAnimPresenter::EndAction()
} }
// FUNCTION: LEGO1 0x1006c7d0 // FUNCTION: LEGO1 0x1006c7d0
// FUNCTION: BETA10 0x10051e07
void LegoAnimPresenter::VTable0x8c() void LegoAnimPresenter::VTable0x8c()
{ {
if (m_unk0x78) { if (m_unk0x78) {
@ -874,7 +1031,7 @@ void LegoAnimPresenter::VTable0x8c()
} }
if (m_currentWorld == NULL) { if (m_currentWorld == NULL) {
m_currentWorld = m_unk0x88 != -1 ? FindWorld(m_animAtom, m_unk0x88) : CurrentWorld(); m_currentWorld = m_worldId != -1 ? FindWorld(m_worldAtom, m_worldId) : CurrentWorld();
} }
if (m_currentWorld) { if (m_currentWorld) {
@ -885,10 +1042,19 @@ void LegoAnimPresenter::VTable0x8c()
} }
} }
// STUB: LEGO1 0x1006c860 // FUNCTION: LEGO1 0x1006c860
// FUNCTION: BETA10 0x10051f45
void LegoAnimPresenter::VTable0x90() void LegoAnimPresenter::VTable0x90()
{ {
// TODO if (m_currentWorld != NULL) {
m_currentWorld->FUN_1001fe90(this);
if (m_compositePresenter != NULL && m_compositePresenter->IsA("LegoAnimMMPresenter")) {
return;
}
m_currentWorld->Remove(this);
}
} }
// FUNCTION: LEGO1 0x1006c8a0 // FUNCTION: LEGO1 0x1006c8a0
@ -917,14 +1083,17 @@ MxResult LegoAnimPresenter::VTable0x94(Vector3&, Vector3&, float, float, Vector3
return SUCCESS; return SUCCESS;
} }
// STUB: LEGO1 0x1006ca50 // FUNCTION: LEGO1 0x1006ca50
void LegoAnimPresenter::VTable0x98() // FUNCTION: BETA10 0x100521d0
MxResult LegoAnimPresenter::VTable0x98(LegoPathBoundary* p_boundary)
{ {
// TODO for (MxU32 i = 1; i <= m_roiMapSize; i++) {
} LegoEntity* entity = m_roiMap[i]->GetEntity();
// STUB: LEGO1 0x1006d680 if (entity != NULL) {
void LegoAnimPresenter::FUN_1006d680(LegoAnimActor* p_actor, MxFloat p_value) p_boundary->AddActor((LegoPathActor*) entity);
{ }
// TODO }
return SUCCESS;
} }

View File

@ -113,3 +113,9 @@ void LegoLocomotionAnimPresenter::EndAction()
MxVideoPresenter::EndAction(); MxVideoPresenter::EndAction();
} }
} }
// STUB: LEGO1 0x1006d680
void LegoLocomotionAnimPresenter::FUN_1006d680(LegoAnimActor* p_actor, MxFloat p_value)
{
// TODO
}

View File

@ -405,14 +405,14 @@ LegoResult LegoROI::FUN_100a8da0(LegoTreeNode* p_node, const Matrix4& p_matrix,
} }
// FUNCTION: LEGO1 0x100a8e80 // FUNCTION: LEGO1 0x100a8e80
void LegoROI::FUN_100a8e80(LegoTreeNode* p_node, Matrix4& p_matrix, LegoTime p_time, LegoROI** p_rois) void LegoROI::FUN_100a8e80(LegoTreeNode* p_node, Matrix4& p_matrix, LegoTime p_time, LegoROI** p_roiMap)
{ {
MxMatrix mat; MxMatrix mat;
LegoAnimNodeData* data = (LegoAnimNodeData*) p_node->GetData(); LegoAnimNodeData* data = (LegoAnimNodeData*) p_node->GetData();
FUN_100a8cb0(data, p_time, mat); FUN_100a8cb0(data, p_time, mat);
LegoROI* roi = p_rois[data->GetUnknown0x20()]; LegoROI* roi = p_roiMap[data->GetUnknown0x20()];
if (roi != NULL) { if (roi != NULL) {
roi->m_local2world.Product(mat, p_matrix); roi->m_local2world.Product(mat, p_matrix);
roi->VTable0x1c(); roi->VTable0x1c();
@ -421,7 +421,7 @@ void LegoROI::FUN_100a8e80(LegoTreeNode* p_node, Matrix4& p_matrix, LegoTime p_t
roi->SetVisibility(und); roi->SetVisibility(und);
for (LegoU32 i = 0; i < p_node->GetNumChildren(); i++) { for (LegoU32 i = 0; i < p_node->GetNumChildren(); i++) {
FUN_100a8e80(p_node->GetChild(i), roi->m_local2world, p_time, p_rois); FUN_100a8e80(p_node->GetChild(i), roi->m_local2world, p_time, p_roiMap);
} }
} }
else { else {
@ -429,7 +429,34 @@ void LegoROI::FUN_100a8e80(LegoTreeNode* p_node, Matrix4& p_matrix, LegoTime p_t
local2world.Product(mat, p_matrix); local2world.Product(mat, p_matrix);
for (LegoU32 i = 0; i < p_node->GetNumChildren(); i++) { for (LegoU32 i = 0; i < p_node->GetNumChildren(); i++) {
FUN_100a8e80(p_node->GetChild(i), local2world, p_time, p_rois); FUN_100a8e80(p_node->GetChild(i), local2world, p_time, p_roiMap);
}
}
}
// FUNCTION: LEGO1 0x100a8fd0
// FUNCTION: BETA10 0x1018ac81
void LegoROI::FUN_100a8fd0(LegoTreeNode* p_node, Matrix4& p_matrix, LegoTime p_time, LegoROI** p_roiMap)
{
MxMatrix mat;
LegoAnimNodeData* data = (LegoAnimNodeData*) p_node->GetData();
FUN_100a8cb0(data, p_time, mat);
LegoROI* roi = p_roiMap[data->GetUnknown0x20()];
if (roi != NULL) {
roi->m_local2world.Product(mat, p_matrix);
for (LegoU32 i = 0; i < p_node->GetNumChildren(); i++) {
FUN_100a8fd0(p_node->GetChild(i), roi->m_local2world, p_time, p_roiMap);
}
}
else {
MxMatrix local2world;
local2world.Product(mat, p_matrix);
for (LegoU32 i = 0; i < p_node->GetNumChildren(); i++) {
FUN_100a8fd0(p_node->GetChild(i), local2world, p_time, p_roiMap);
} }
} }
} }

View File

@ -32,7 +32,8 @@ class LegoROI : public ViewROI {
); );
LegoROI* FindChildROI(const LegoChar* p_name, LegoROI* p_roi); LegoROI* FindChildROI(const LegoChar* p_name, LegoROI* p_roi);
LegoResult FUN_100a8da0(LegoTreeNode* p_node, const Matrix4& p_matrix, LegoTime p_time, LegoROI* p_roi); LegoResult FUN_100a8da0(LegoTreeNode* p_node, const Matrix4& p_matrix, LegoTime p_time, LegoROI* p_roi);
static void FUN_100a8e80(LegoTreeNode* p_node, Matrix4& p_matrix, LegoTime p_time, LegoROI** p_rois); static void FUN_100a8e80(LegoTreeNode* p_node, Matrix4& p_matrix, LegoTime p_time, LegoROI** p_roiMap);
static void FUN_100a8fd0(LegoTreeNode* p_node, Matrix4& p_matrix, LegoTime p_time, LegoROI** p_roiMap);
LegoResult SetFrame(LegoAnim* p_anim, LegoTime p_time); LegoResult SetFrame(LegoAnim* p_anim, LegoTime p_time);
LegoResult FUN_100a9170(LegoFloat p_red, LegoFloat p_green, LegoFloat p_blue, LegoFloat p_alpha); LegoResult FUN_100a9170(LegoFloat p_red, LegoFloat p_green, LegoFloat p_blue, LegoFloat p_alpha);
LegoResult FUN_100a9210(LegoTextureInfo* p_textureInfo); LegoResult FUN_100a9210(LegoTextureInfo* p_textureInfo);

View File

@ -58,7 +58,7 @@ MxResult ModelDbPart::Read(FILE* p_file)
return FAILURE; return FAILURE;
} }
// Critical bug: buffer overrun // (modernization) critical bug: buffer overrun
if (fread(buff, len, 1, p_file) != 1) { if (fread(buff, len, 1, p_file) != 1) {
return FAILURE; return FAILURE;
} }

View File

@ -7,6 +7,7 @@
// SIZE 0x48 // SIZE 0x48
class MxMatrix : public Matrix4 { class MxMatrix : public Matrix4 {
public: public:
// FUNCTION: LEGO1 0x1006b120
inline MxMatrix() : Matrix4(m_elements) {} inline MxMatrix() : Matrix4(m_elements) {}
// FUNCTION: LEGO1 0x10032770 // FUNCTION: LEGO1 0x10032770
@ -26,7 +27,7 @@ class MxMatrix : public Matrix4 {
virtual void operator=(const MxMatrix& p_matrix) { Equals(p_matrix); } // vtable+0x48 virtual void operator=(const MxMatrix& p_matrix) { Equals(p_matrix); } // vtable+0x48
private: private:
float m_elements[4][4]; float m_elements[4][4]; // 0x08
}; };
#endif // MXMATRIX_H #endif // MXMATRIX_H

View File

@ -4,28 +4,42 @@
#include "mxcore.h" #include "mxcore.h"
// VTABLE: LEGO1 0x100dc110 // VTABLE: LEGO1 0x100dc110
// VTABLE: BETA10 0x101c1be0
// SIZE 0x10 // SIZE 0x10
class MxString : public MxCore { class MxString : public MxCore {
public: public:
MxString(const MxString& p_str);
~MxString() override;
const MxString& operator=(const char* p_data);
MxString(); MxString();
MxString(const char*); MxString(const MxString& p_str);
MxString(const char* p_str);
MxString(const char* p_str, MxU16 p_maxlen);
~MxString() override;
void Reverse();
void ToUpperCase(); void ToUpperCase();
void ToLowerCase(); void ToLowerCase();
MxString& operator=(const MxString& p_str); MxString& operator=(const MxString& p_str);
MxString operator+(const char* p_str); const MxString& operator=(const char* p_str);
MxString operator+(const MxString& p_str) const;
MxString operator+(const char* p_str) const;
MxString& operator+=(const char* p_str); MxString& operator+=(const char* p_str);
inline MxS8 Compare(const MxString& p_str) const { return strcmp(m_data, p_str.m_data); } static void CharSwap(char* p_a, char* p_b);
inline MxBool Equal(const MxString& p_str) const { return strcmp(m_data, p_str.m_data) == 0; }
inline const char* GetData() const { return m_data; } // FUNCTION: BETA10 0x10017c50
inline char* GetDataPtr() const { return m_data; } inline char* GetData() const { return m_data; }
// FUNCTION: BETA10 0x10067630
inline const MxU16 GetLength() const { return m_length; } inline const MxU16 GetLength() const { return m_length; }
// FUNCTION: BETA10 0x100d8a30
inline MxBool Equal(const MxString& p_str) const { return strcmp(m_data, p_str.m_data) == 0; }
// FUNCTION: BETA10 0x1012a810
inline MxS8 Compare(const MxString& p_str) const { return strcmp(m_data, p_str.m_data); }
// SYNTHETIC: LEGO1 0x100ae280 // SYNTHETIC: LEGO1 0x100ae280
// SYNTHETIC: BETA10 0x1012c9d0
// MxString::`scalar deleting destructor' // MxString::`scalar deleting destructor'
private: private:

View File

@ -8,6 +8,7 @@
DECOMP_SIZE_ASSERT(MxString, 0x10) DECOMP_SIZE_ASSERT(MxString, 0x10)
// FUNCTION: LEGO1 0x100ae200 // FUNCTION: LEGO1 0x100ae200
// FUNCTION: BETA10 0x1012c110
MxString::MxString() MxString::MxString()
{ {
// Set string to one char in length and set that char to null terminator // Set string to one char in length and set that char to null terminator
@ -17,6 +18,7 @@ MxString::MxString()
} }
// FUNCTION: LEGO1 0x100ae2a0 // FUNCTION: LEGO1 0x100ae2a0
// FUNCTION: BETA10 0x1012c1a1
MxString::MxString(const MxString& p_str) MxString::MxString(const MxString& p_str)
{ {
this->m_length = p_str.m_length; this->m_length = p_str.m_length;
@ -25,6 +27,7 @@ MxString::MxString(const MxString& p_str)
} }
// FUNCTION: LEGO1 0x100ae350 // FUNCTION: LEGO1 0x100ae350
// FUNCTION: BETA10 0x1012c24f
MxString::MxString(const char* p_str) MxString::MxString(const char* p_str)
{ {
if (p_str) { if (p_str) {
@ -39,25 +42,65 @@ MxString::MxString(const char* p_str)
} }
} }
// FUNCTION: BETA10 0x1012c330
MxString::MxString(const char* p_str, MxU16 p_maxlen)
{
if (p_str) {
if (strlen(p_str) <= p_maxlen) {
this->m_length = strlen(p_str);
}
else {
this->m_length = p_maxlen;
}
// Basically strncpy
this->m_data = new char[this->m_length + 1];
memcpy(this->m_data, p_str, this->m_length);
this->m_data[this->m_length] = '\0';
}
else {
this->m_data = new char[1];
this->m_data[0] = 0;
this->m_length = 0;
}
}
// FUNCTION: LEGO1 0x100ae420 // FUNCTION: LEGO1 0x100ae420
// FUNCTION: BETA10 0x1012c45b
MxString::~MxString() MxString::~MxString()
{ {
delete[] this->m_data; delete[] this->m_data;
} }
// FUNCTION: BETA10 0x1012c4de
void MxString::Reverse()
{
char* start = this->m_data;
char* end = this->m_data + this->m_length - 1;
while (start < end) {
CharSwap(start, end);
start++;
end--;
}
}
// FUNCTION: LEGO1 0x100ae490 // FUNCTION: LEGO1 0x100ae490
// FUNCTION: BETA10 0x1012c537
void MxString::ToUpperCase() void MxString::ToUpperCase()
{ {
strupr(this->m_data); strupr(this->m_data);
} }
// FUNCTION: LEGO1 0x100ae4a0 // FUNCTION: LEGO1 0x100ae4a0
// FUNCTION: BETA10 0x1012c55c
void MxString::ToLowerCase() void MxString::ToLowerCase()
{ {
strlwr(this->m_data); strlwr(this->m_data);
} }
// FUNCTION: LEGO1 0x100ae4b0 // FUNCTION: LEGO1 0x100ae4b0
// FUNCTION: BETA10 0x1012c581
MxString& MxString::operator=(const MxString& p_str) MxString& MxString::operator=(const MxString& p_str)
{ {
if (this->m_data != p_str.m_data) { if (this->m_data != p_str.m_data) {
@ -71,22 +114,39 @@ MxString& MxString::operator=(const MxString& p_str)
} }
// FUNCTION: LEGO1 0x100ae510 // FUNCTION: LEGO1 0x100ae510
const MxString& MxString::operator=(const char* p_data) // FUNCTION: BETA10 0x1012c606
const MxString& MxString::operator=(const char* p_str)
{ {
if (this->m_data != p_data) { if (this->m_data != p_str) {
delete[] this->m_data; delete[] this->m_data;
this->m_length = strlen(p_data); this->m_length = strlen(p_str);
this->m_data = new char[this->m_length + 1]; this->m_data = new char[this->m_length + 1];
strcpy(this->m_data, p_data); strcpy(this->m_data, p_str);
} }
return *this; return *this;
} }
// FUNCTION: BETA10 0x1012c68a
MxString MxString::operator+(const MxString& p_str) const
{
MxString tmp;
delete[] tmp.m_data;
tmp.m_length = p_str.m_length + this->m_length;
tmp.m_data = new char[tmp.m_length + 1];
strcpy(tmp.m_data, this->m_data);
strcpy(tmp.m_data + this->m_length, p_str.m_data);
return MxString(tmp);
}
// Return type is intentionally just MxString, not MxString&. // Return type is intentionally just MxString, not MxString&.
// This forces MSVC to add $ReturnUdt$ to the stack for 100% match. // This forces MSVC to add $ReturnUdt$ to the stack for 100% match.
// FUNCTION: LEGO1 0x100ae580 // FUNCTION: LEGO1 0x100ae580
MxString MxString::operator+(const char* p_str) // FUNCTION: BETA10 0x1012c78d
MxString MxString::operator+(const char* p_str) const
{ {
// MxString constructor allocates 1 byte for m_data, so free that first // MxString constructor allocates 1 byte for m_data, so free that first
MxString tmp; MxString tmp;
@ -102,6 +162,7 @@ MxString MxString::operator+(const char* p_str)
} }
// FUNCTION: LEGO1 0x100ae690 // FUNCTION: LEGO1 0x100ae690
// FUNCTION: BETA10 0x1012c92f
MxString& MxString::operator+=(const char* p_str) MxString& MxString::operator+=(const char* p_str)
{ {
int newlen = this->m_length + strlen(p_str); int newlen = this->m_length + strlen(p_str);
@ -111,8 +172,16 @@ MxString& MxString::operator+=(const char* p_str)
strcpy(tmp + this->m_length, p_str); strcpy(tmp + this->m_length, p_str);
delete[] this->m_data; delete[] this->m_data;
this->m_length = newlen;
this->m_data = tmp; this->m_data = tmp;
this->m_length = newlen;
return *this; return *this;
} }
// FUNCTION: BETA10 0x1012ca10
void MxString::CharSwap(char* p_a, char* p_b)
{
char t = *p_a;
*p_a = *p_b;
*p_b = t;
}

View File

@ -56,7 +56,7 @@ class ParseAsm:
def __init__( def __init__(
self, self,
relocate_lookup: Optional[Callable[[int], bool]] = None, relocate_lookup: Optional[Callable[[int], bool]] = None,
name_lookup: Optional[Callable[[int], str]] = None, name_lookup: Optional[Callable[[int, bool], str]] = None,
bin_lookup: Optional[Callable[[int, int], Optional[bytes]]] = None, bin_lookup: Optional[Callable[[int, int], Optional[bytes]]] = None,
) -> None: ) -> None:
self.relocate_lookup = relocate_lookup self.relocate_lookup = relocate_lookup
@ -86,13 +86,15 @@ def float_replace(self, addr: int, data_size: int) -> Optional[str]:
return None return None
def lookup(self, addr: int, use_cache: bool = True) -> Optional[str]: def lookup(
self, addr: int, use_cache: bool = True, exact: bool = False
) -> Optional[str]:
"""Return a replacement name for this address if we find one.""" """Return a replacement name for this address if we find one."""
if use_cache and (cached := self.replacements.get(addr, None)) is not None: if use_cache and (cached := self.replacements.get(addr, None)) is not None:
return cached return cached
if callable(self.name_lookup): if callable(self.name_lookup):
if (name := self.name_lookup(addr)) is not None: if (name := self.name_lookup(addr, exact)) is not None:
if use_cache: if use_cache:
self.replacements[addr] = name self.replacements[addr] = name
@ -210,7 +212,7 @@ def sanitize(self, inst: DisasmLiteInst) -> Tuple[str, str]:
# If we have a name for this address, use it. If not, # If we have a name for this address, use it. If not,
# do not create a new placeholder. We will instead # do not create a new placeholder. We will instead
# fall through to generic jump handling below. # fall through to generic jump handling below.
potential_name = self.lookup(op_str_address) potential_name = self.lookup(op_str_address, exact=True)
if potential_name is not None: if potential_name is not None:
return (inst.mnemonic, potential_name) return (inst.mnemonic, potential_name)

View File

@ -2,6 +2,7 @@
import logging import logging
import difflib import difflib
import struct import struct
import uuid
from dataclasses import dataclass from dataclasses import dataclass
from typing import Callable, Iterable, List, Optional from typing import Callable, Iterable, List, Optional
from isledecomp.bin import Bin as IsleBin, InvalidVirtualAddressError from isledecomp.bin import Bin as IsleBin, InvalidVirtualAddressError
@ -71,6 +72,9 @@ def __init__(
self.recomp_bin = recomp_bin self.recomp_bin = recomp_bin
self.pdb_file = pdb_file self.pdb_file = pdb_file
self.code_dir = code_dir self.code_dir = code_dir
# Controls whether we dump the asm output to a file
self.debug: bool = False
self.runid: str = uuid.uuid4().hex[:8]
self._lines_db = LinesDb(code_dir) self._lines_db = LinesDb(code_dir)
self._db = CompareDb() self._db = CompareDb()
@ -452,6 +456,16 @@ def _find_vtordisp(self):
) )
self._db.set_function_pair(orig_addr, recomp_addr) self._db.set_function_pair(orig_addr, recomp_addr)
def _dump_asm(self, orig_combined, recomp_combined):
"""Append the provided assembly output to the debug files"""
with open(f"orig-{self.runid}.txt", "a", encoding="utf-8") as f:
for addr, line in orig_combined:
f.write(f"{addr}: {line}\n")
with open(f"recomp-{self.runid}.txt", "a", encoding="utf-8") as f:
for addr, line in recomp_combined:
f.write(f"{addr}: {line}\n")
def _compare_function(self, match: MatchInfo) -> DiffReport: def _compare_function(self, match: MatchInfo) -> DiffReport:
# Detect when the recomp function size would cause us to read # Detect when the recomp function size would cause us to read
# enough bytes from the original function that we cross into # enough bytes from the original function that we cross into
@ -478,19 +492,33 @@ def _compare_function(self, match: MatchInfo) -> DiffReport:
except IndexError: except IndexError:
pass pass
def orig_lookup(addr: int) -> Optional[str]: def orig_lookup(addr: int, exact: bool) -> Optional[str]:
m = self._db.get_by_orig(addr) m = self._db.get_by_orig(addr, exact)
if m is None: if m is None:
return None return None
return m.match_name() if m.orig_addr == addr:
return m.match_name()
def recomp_lookup(addr: int) -> Optional[str]: offset = addr - m.orig_addr
m = self._db.get_by_recomp(addr) if m.compare_type != SymbolType.DATA or offset >= m.size:
return None
return m.offset_name(offset)
def recomp_lookup(addr: int, exact: bool) -> Optional[str]:
m = self._db.get_by_recomp(addr, exact)
if m is None: if m is None:
return None return None
return m.match_name() if m.recomp_addr == addr:
return m.match_name()
offset = addr - m.recomp_addr
if m.compare_type != SymbolType.DATA or offset >= m.size:
return None
return m.offset_name(offset)
orig_should_replace = create_reloc_lookup(self.orig_bin) orig_should_replace = create_reloc_lookup(self.orig_bin)
recomp_should_replace = create_reloc_lookup(self.recomp_bin) recomp_should_replace = create_reloc_lookup(self.recomp_bin)
@ -512,6 +540,9 @@ def recomp_lookup(addr: int) -> Optional[str]:
orig_combined = orig_parse.parse_asm(orig_raw, match.orig_addr) orig_combined = orig_parse.parse_asm(orig_raw, match.orig_addr)
recomp_combined = recomp_parse.parse_asm(recomp_raw, match.recomp_addr) recomp_combined = recomp_parse.parse_asm(recomp_raw, match.recomp_addr)
if self.debug:
self._dump_asm(orig_combined, recomp_combined)
# Detach addresses from asm lines for the text diff. # Detach addresses from asm lines for the text diff.
orig_asm = [x[1] for x in orig_combined] orig_asm = [x[1] for x in orig_combined]
recomp_asm = [x[1] for x in recomp_combined] recomp_asm = [x[1] for x in recomp_combined]

View File

@ -53,7 +53,7 @@ def __init__(
self.name = name self.name = name
self.size = size self.size = size
def match_name(self) -> str: def match_name(self) -> Optional[str]:
"""Combination of the name and compare type. """Combination of the name and compare type.
Intended for name substitution in the diff. If there is a diff, Intended for name substitution in the diff. If there is a diff,
it will be more obvious what this symbol indicates.""" it will be more obvious what this symbol indicates."""
@ -64,6 +64,12 @@ def match_name(self) -> str:
name = repr(self.name) if ctype == "STRING" else self.name name = repr(self.name) if ctype == "STRING" else self.name
return f"{name} ({ctype})" return f"{name} ({ctype})"
def offset_name(self, ofs: int) -> Optional[str]:
if self.name is None:
return None
return f"{self.name}+{ofs} (OFFSET)"
def matchinfo_factory(_, row): def matchinfo_factory(_, row):
return MatchInfo(*row) return MatchInfo(*row)
@ -135,7 +141,32 @@ def get_one_match(self, addr: int) -> Optional[MatchInfo]:
cur.row_factory = matchinfo_factory cur.row_factory = matchinfo_factory
return cur.fetchone() return cur.fetchone()
def get_by_orig(self, addr: int) -> Optional[MatchInfo]: def _get_closest_orig(self, addr: int) -> Optional[int]:
value = self._db.execute(
"""SELECT max(orig_addr) FROM `symbols`
WHERE ? >= orig_addr
LIMIT 1
""",
(addr,),
).fetchone()
return value[0] if value is not None else None
def _get_closest_recomp(self, addr: int) -> Optional[int]:
value = self._db.execute(
"""SELECT max(recomp_addr) FROM `symbols`
WHERE ? >= recomp_addr
LIMIT 1
""",
(addr,),
).fetchone()
return value[0] if value is not None else None
def get_by_orig(self, addr: int, exact: bool = True) -> Optional[MatchInfo]:
if not exact and not self._orig_used(addr):
addr = self._get_closest_orig(addr)
if addr is None:
return None
cur = self._db.execute( cur = self._db.execute(
"""SELECT * FROM `match_info` """SELECT * FROM `match_info`
WHERE orig_addr = ? WHERE orig_addr = ?
@ -145,7 +176,12 @@ def get_by_orig(self, addr: int) -> Optional[MatchInfo]:
cur.row_factory = matchinfo_factory cur.row_factory = matchinfo_factory
return cur.fetchone() return cur.fetchone()
def get_by_recomp(self, addr: int) -> Optional[MatchInfo]: def get_by_recomp(self, addr: int, exact: bool = True) -> Optional[MatchInfo]:
if not exact and not self._recomp_used(addr):
addr = self._get_closest_recomp(addr)
if addr is None:
return None
cur = self._db.execute( cur = self._db.execute(
"""SELECT * FROM `match_info` """SELECT * FROM `match_info`
WHERE recomp_addr = ? WHERE recomp_addr = ?

View File

@ -113,7 +113,7 @@ def relocate_lookup(addr: int) -> bool:
def test_name_replace(start, end): def test_name_replace(start, end):
"""Make sure the name lookup function is called if present""" """Make sure the name lookup function is called if present"""
def substitute(_: int) -> str: def substitute(_: int, __: bool) -> str:
return "_substitute_" return "_substitute_"
p = ParseAsm(name_lookup=substitute) p = ParseAsm(name_lookup=substitute)
@ -137,7 +137,7 @@ def test_replacement_numbering():
"""If we can use the name lookup for the first address but not the second, """If we can use the name lookup for the first address but not the second,
the second replacement should be <OFFSET2> not <OFFSET1>.""" the second replacement should be <OFFSET2> not <OFFSET1>."""
def substitute_1234(addr: int) -> Optional[str]: def substitute_1234(addr: int, _: bool) -> Optional[str]:
return "_substitute_" if addr == 0x1234 else None return "_substitute_" if addr == 0x1234 else None
p = ParseAsm(name_lookup=substitute_1234) p = ParseAsm(name_lookup=substitute_1234)
@ -171,7 +171,7 @@ def test_jump_to_function():
assume this is the case for all jumps. Only replace the jump with a name assume this is the case for all jumps. Only replace the jump with a name
if we can find it using our lookup.""" if we can find it using our lookup."""
def substitute_1234(addr: int) -> Optional[str]: def substitute_1234(addr: int, _: bool) -> Optional[str]:
return "_substitute_" if addr == 0x1234 else None return "_substitute_" if addr == 0x1234 else None
p = ParseAsm(name_lookup=substitute_1234) p = ParseAsm(name_lookup=substitute_1234)
@ -212,7 +212,7 @@ def test_float_variable():
"""If there is a variable at the address referenced by a float instruction, """If there is a variable at the address referenced by a float instruction,
use the name instead of calling into the float replacement handler.""" use the name instead of calling into the float replacement handler."""
def name_lookup(addr: int) -> Optional[str]: def name_lookup(addr: int, _: bool) -> Optional[str]:
return "g_myFloatVariable" if addr == 0x1234 else None return "g_myFloatVariable" if addr == 0x1234 else None
p = ParseAsm(name_lookup=name_lookup) p = ParseAsm(name_lookup=name_lookup)
@ -234,7 +234,7 @@ def relocate_lookup(addr: int) -> bool:
return addr in (0x1234, 0x5555) return addr in (0x1234, 0x5555)
# Only 0x5555 is a "known" address # Only 0x5555 is a "known" address
def name_lookup(addr: int) -> Optional[str]: def name_lookup(addr: int, _: bool) -> Optional[str]:
return "hello" if addr == 0x5555 else None return "hello" if addr == 0x5555 else None
p = ParseAsm(relocate_lookup=relocate_lookup, name_lookup=name_lookup) p = ParseAsm(relocate_lookup=relocate_lookup, name_lookup=name_lookup)
@ -263,7 +263,7 @@ def test_absolute_indirect():
we have it, but there are some circumstances where we want to replace we have it, but there are some circumstances where we want to replace
with the pointer's name (i.e. an import function).""" with the pointer's name (i.e. an import function)."""
def name_lookup(addr: int) -> Optional[str]: def name_lookup(addr: int, _: bool) -> Optional[str]:
return { return {
0x1234: "Hello", 0x1234: "Hello",
0x4321: "xyz", 0x4321: "xyz",

View File

@ -241,6 +241,9 @@ def main():
isle_compare = IsleCompare(origfile, recompfile, args.pdb, args.decomp_dir) isle_compare = IsleCompare(origfile, recompfile, args.pdb, args.decomp_dir)
if args.loglevel == logging.DEBUG:
isle_compare.debug = True
print() print()
### Compare one or none. ### Compare one or none.