mirror of
https://github.com/isledecomp/isle.git
synced 2026-01-29 03:01:15 +00:00
Merge remote-tracking branch 'upstream/master' into vtable/legoanimpresenter
This commit is contained in:
commit
67775e10ea
@ -99,7 +99,7 @@ add_library(lego1 SHARED
|
|||||||
LEGO1/lego/legoomni/src/isle/jukebox.cpp
|
LEGO1/lego/legoomni/src/isle/jukebox.cpp
|
||||||
LEGO1/lego/legoomni/src/isle/jukeboxentity.cpp
|
LEGO1/lego/legoomni/src/isle/jukeboxentity.cpp
|
||||||
LEGO1/lego/legoomni/src/isle/jukeboxstate.cpp
|
LEGO1/lego/legoomni/src/isle/jukeboxstate.cpp
|
||||||
LEGO1/lego/legoomni/src/isle/motorcycle.cpp
|
LEGO1/lego/legoomni/src/isle/motocycle.cpp
|
||||||
LEGO1/lego/legoomni/src/isle/radio.cpp
|
LEGO1/lego/legoomni/src/isle/radio.cpp
|
||||||
LEGO1/lego/legoomni/src/isle/radiostate.cpp
|
LEGO1/lego/legoomni/src/isle/radiostate.cpp
|
||||||
LEGO1/lego/legoomni/src/isle/skateboard.cpp
|
LEGO1/lego/legoomni/src/isle/skateboard.cpp
|
||||||
|
|||||||
@ -614,8 +614,8 @@ MxResult IsleApp::SetupWindow(HINSTANCE hInstance, LPSTR lpCmdLine)
|
|||||||
LegoAnimationManager::configureLegoAnimationManager(m_islandQuality);
|
LegoAnimationManager::configureLegoAnimationManager(m_islandQuality);
|
||||||
if (LegoOmni::GetInstance()) {
|
if (LegoOmni::GetInstance()) {
|
||||||
if (LegoOmni::GetInstance()->GetInputManager()) {
|
if (LegoOmni::GetInstance()->GetInputManager()) {
|
||||||
LegoOmni::GetInstance()->GetInputManager()->m_useJoystick = m_useJoystick;
|
LegoOmni::GetInstance()->GetInputManager()->SetUseJoystick(m_useJoystick);
|
||||||
LegoOmni::GetInstance()->GetInputManager()->m_joystickIndex = m_joystickIndex;
|
LegoOmni::GetInstance()->GetInputManager()->SetJoystickIndex(m_joystickIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (m_fullScreen) {
|
if (m_fullScreen) {
|
||||||
|
|||||||
@ -10,20 +10,20 @@ MxS32 g_mxcoreCount[101] = {0, -6643, -5643, -5058, -4643, -4321, -4058, -38
|
|||||||
-358, -340, -321, -304, -286, -268, -251, -234, -217, -200, -184, -168, -152,
|
-358, -340, -321, -304, -286, -268, -251, -234, -217, -200, -184, -168, -152,
|
||||||
-136, -120, -104, -89, -74, -58, -43, -29, -14, 0};
|
-136, -120, -104, -89, -74, -58, -43, -29, -14, 0};
|
||||||
|
|
||||||
// GLOBAL: LEGO1 0x10101eac
|
// GLOBAL: LEGO1 0x10102048
|
||||||
const char* g_parseExtraTokens = ":;";
|
const char* g_strACTION = "ACTION";
|
||||||
|
|
||||||
// GLOBAL: LEGO1 0x10101edc
|
// GLOBAL: LEGO1 0x1010209c
|
||||||
const char* g_strWORLD = "WORLD";
|
|
||||||
|
|
||||||
// GLOBAL: LEGO1 0x10101f20
|
|
||||||
const char* g_strSOUND = "SOUND";
|
|
||||||
|
|
||||||
// GLOBAL: LEGO1 0x10101f58
|
|
||||||
const char* g_strOBJECT = "OBJECT";
|
const char* g_strOBJECT = "OBJECT";
|
||||||
|
|
||||||
// GLOBAL: LEGO1 0x10102040
|
// GLOBAL: LEGO1 0x101020b0
|
||||||
const char* g_strACTION = "ACTION";
|
const char* g_strSOUND = "SOUND";
|
||||||
|
|
||||||
// GLOBAL: LEGO1 0x101020cc
|
// GLOBAL: LEGO1 0x101020cc
|
||||||
const char* g_strVISIBILITY = "VISIBILITY";
|
const char* g_strVISIBILITY = "VISIBILITY";
|
||||||
|
|
||||||
|
// GLOBAL: LEGO1 0x101020d0
|
||||||
|
const char* g_strWORLD = "WORLD";
|
||||||
|
|
||||||
|
// GLOBAL: LEGO1 0x101020e4
|
||||||
|
const char* g_parseExtraTokens = ":;";
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
#ifndef ELEVATORBOTTOM_H
|
#ifndef ELEVATORBOTTOM_H
|
||||||
#define ELEVATORBOTTOM_H
|
#define ELEVATORBOTTOM_H
|
||||||
|
|
||||||
|
#include "decomp.h"
|
||||||
#include "legoworld.h"
|
#include "legoworld.h"
|
||||||
|
|
||||||
// VTABLE: LEGO1 0x100d5f20
|
// VTABLE: LEGO1 0x100d5f20
|
||||||
|
// SIZE: 0xfc (from inlined ctor at 0x1000a8aa)
|
||||||
class ElevatorBottom : public LegoWorld {
|
class ElevatorBottom : public LegoWorld {
|
||||||
public:
|
public:
|
||||||
ElevatorBottom();
|
ElevatorBottom();
|
||||||
@ -23,6 +25,9 @@ class ElevatorBottom : public LegoWorld {
|
|||||||
{
|
{
|
||||||
return !strcmp(p_name, ElevatorBottom::ClassName()) || LegoWorld::IsA(p_name);
|
return !strcmp(p_name, ElevatorBottom::ClassName()) || LegoWorld::IsA(p_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
undefined4 m_unk0xf8; // 0xf8
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ELEVATORBOTTOM_H
|
#endif // ELEVATORBOTTOM_H
|
||||||
|
|||||||
@ -12,7 +12,7 @@ class JukeBoxEntity;
|
|||||||
class Helicopter;
|
class Helicopter;
|
||||||
class Bike;
|
class Bike;
|
||||||
class DuneBuggy;
|
class DuneBuggy;
|
||||||
class Motorcycle;
|
class Motocycle;
|
||||||
class SkateBoard;
|
class SkateBoard;
|
||||||
class RaceCar;
|
class RaceCar;
|
||||||
class Jetski;
|
class Jetski;
|
||||||
@ -69,7 +69,7 @@ class Isle : public LegoWorld {
|
|||||||
Helicopter* m_helicopter; // 0x110
|
Helicopter* m_helicopter; // 0x110
|
||||||
Bike* m_bike; // 0x114
|
Bike* m_bike; // 0x114
|
||||||
DuneBuggy* m_dunebuggy; // 0x118
|
DuneBuggy* m_dunebuggy; // 0x118
|
||||||
Motorcycle* m_motorcycle; // 0x11c
|
Motocycle* m_motocycle; // 0x11c
|
||||||
SkateBoard* m_skateboard; // 0x120
|
SkateBoard* m_skateboard; // 0x120
|
||||||
RaceCar* m_racecar; // 0x124
|
RaceCar* m_racecar; // 0x124
|
||||||
Jetski* m_jetski; // 0x128
|
Jetski* m_jetski; // 0x128
|
||||||
|
|||||||
@ -20,4 +20,10 @@ class IsleActor : public LegoActor {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x1000e940
|
||||||
|
// IsleActor::~IsleActor
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x1000e990
|
||||||
|
// IsleActor::`scalar deleting destructor'
|
||||||
|
|
||||||
#endif // ISLEACTOR_H
|
#endif // ISLEACTOR_H
|
||||||
|
|||||||
@ -13,6 +13,8 @@
|
|||||||
class IslePathActor : public LegoPathActor {
|
class IslePathActor : public LegoPathActor {
|
||||||
public:
|
public:
|
||||||
IslePathActor();
|
IslePathActor();
|
||||||
|
|
||||||
|
// FUNCTION: LEGO1 0x10002e10
|
||||||
inline virtual ~IslePathActor() override { IslePathActor::Destroy(TRUE); } // vtable+0x0
|
inline virtual ~IslePathActor() override { IslePathActor::Destroy(TRUE); } // vtable+0x0
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x10002ea0
|
// FUNCTION: LEGO1 0x10002ea0
|
||||||
@ -29,6 +31,7 @@ class IslePathActor : public LegoPathActor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18
|
virtual MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18
|
||||||
|
virtual void Destroy(MxBool p_fromDestructor) override; // vtable+0x1c
|
||||||
// FUNCTION: LEGO1 0x10002e70
|
// FUNCTION: LEGO1 0x10002e70
|
||||||
virtual MxU32 VTable0xcc() { return 0; } // vtable+0xcc
|
virtual MxU32 VTable0xcc() { return 0; } // vtable+0xcc
|
||||||
// FUNCTION: LEGO1 0x10002df0
|
// FUNCTION: LEGO1 0x10002df0
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
class LegoActor : public LegoEntity {
|
class LegoActor : public LegoEntity {
|
||||||
public:
|
public:
|
||||||
LegoActor();
|
LegoActor();
|
||||||
|
virtual ~LegoActor() override;
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x1002d210
|
// FUNCTION: LEGO1 0x1002d210
|
||||||
inline virtual const char* ClassName() const override // vtable+0x0c
|
inline virtual const char* ClassName() const override // vtable+0x0c
|
||||||
@ -43,4 +44,7 @@ class LegoActor : public LegoEntity {
|
|||||||
MxU8 m_unk0x74; // 0x74
|
MxU8 m_unk0x74; // 0x74
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x1002d300
|
||||||
|
// LegoActor::`scalar deleting destructor'
|
||||||
|
|
||||||
#endif // LEGOACTOR_H
|
#endif // LEGOACTOR_H
|
||||||
|
|||||||
@ -92,4 +92,7 @@ class LegoAnimClass {
|
|||||||
undefined4 m_unk0x14;
|
undefined4 m_unk0x14;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x10068650
|
||||||
|
// LegoAnimPresenter::`scalar deleting destructor'
|
||||||
|
|
||||||
#endif // LEGOANIMPRESENTER_H
|
#endif // LEGOANIMPRESENTER_H
|
||||||
|
|||||||
@ -26,20 +26,20 @@ class LegoEntityPresenter : public MxCompositePresenter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void ReadyTickle() override; // vtable+0x18
|
virtual void ReadyTickle() override; // vtable+0x18
|
||||||
virtual void RepeatingTickle(); // vtable+0x24
|
virtual void RepeatingTickle() override; // vtable+0x24
|
||||||
virtual void ParseExtra(); // vtable+0x30
|
virtual void ParseExtra() override; // vtable+0x30
|
||||||
virtual void Destroy() override; // vtable+0x38
|
virtual void Destroy() override; // vtable+0x38
|
||||||
virtual MxResult StartAction(MxStreamController* p_controller, MxDSAction* p_action) override; // vtable+0x3c
|
virtual MxResult StartAction(MxStreamController* p_controller, MxDSAction* p_action) override; // vtable+0x3c
|
||||||
virtual void Init(); // vtable+0x68
|
virtual void Init(); // vtable+0x68
|
||||||
virtual undefined4 SetBackend(LegoEntity* p_unk0x4c); // vtable+0x6c
|
virtual undefined4 SetEntity(LegoEntity* p_entity); // vtable+0x6c
|
||||||
|
|
||||||
void SetBackendLocation(Mx3DPointFloat& p_location, Mx3DPointFloat& p_direction, Mx3DPointFloat& p_up);
|
void SetEntityLocation(Mx3DPointFloat& p_location, Mx3DPointFloat& p_direction, Mx3DPointFloat& p_up);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Destroy(MxBool p_fromDestructor);
|
void Destroy(MxBool p_fromDestructor);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
LegoEntity* m_objectBackend; // 0x4c
|
LegoEntity* m_entity; // 0x4c
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // LEGOENTITYPRESENTER_H
|
#endif // LEGOENTITYPRESENTER_H
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
// VTABLE: LEGO1 0x100d6aa0
|
// VTABLE: LEGO1 0x100d6aa0
|
||||||
|
// SIZE 0x20
|
||||||
class LegoEventNotificationParam : public MxNotificationParam {
|
class LegoEventNotificationParam : public MxNotificationParam {
|
||||||
public:
|
public:
|
||||||
inline LegoEventNotificationParam() : MxNotificationParam(PARAM_NONE, NULL) {}
|
inline LegoEventNotificationParam() : MxNotificationParam(PARAM_NONE, NULL) {}
|
||||||
@ -22,7 +23,6 @@ class LegoEventNotificationParam : public MxNotificationParam {
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~LegoEventNotificationParam() override {} // vtable+0x0 (scalar deleting destructor)
|
|
||||||
inline MxU8 GetKey() const { return m_key; }
|
inline MxU8 GetKey() const { return m_key; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -33,4 +33,10 @@ class LegoEventNotificationParam : public MxNotificationParam {
|
|||||||
MxU32 m_unk0x1c; // 0x1c
|
MxU32 m_unk0x1c; // 0x1c
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x10028770
|
||||||
|
// LegoEventNotificationParam::`scalar deleting destructor'
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x100287e0
|
||||||
|
// LegoEventNotificationParam::~LegoEventNotificationParam
|
||||||
|
|
||||||
#endif // LEGOEVENTNOTIFICATIONPARAM_H
|
#endif // LEGOEVENTNOTIFICATIONPARAM_H
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
class LegoHideAnimPresenter : public LegoLoopingAnimPresenter {
|
class LegoHideAnimPresenter : public LegoLoopingAnimPresenter {
|
||||||
public:
|
public:
|
||||||
LegoHideAnimPresenter();
|
LegoHideAnimPresenter();
|
||||||
|
virtual ~LegoHideAnimPresenter() override;
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x1006d880
|
// FUNCTION: LEGO1 0x1006d880
|
||||||
inline const char* ClassName() const override // vtable+0xc
|
inline const char* ClassName() const override // vtable+0xc
|
||||||
@ -26,4 +27,7 @@ class LegoHideAnimPresenter : public LegoLoopingAnimPresenter {
|
|||||||
void Init();
|
void Init();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x1006d9d0
|
||||||
|
// LegoHideAnimPresenter::`scalar deleting destructor'
|
||||||
|
|
||||||
#endif // LEGOHIDEANIMPRESENTER_H
|
#endif // LEGOHIDEANIMPRESENTER_H
|
||||||
|
|||||||
@ -53,6 +53,8 @@ class LegoInputManager : public MxPresenter {
|
|||||||
|
|
||||||
inline void SetUnknown88(MxBool p_unk0x88) { m_unk0x88 = p_unk0x88; }
|
inline void SetUnknown88(MxBool p_unk0x88) { m_unk0x88 = p_unk0x88; }
|
||||||
inline void SetUnknown336(MxBool p_unk0x336) { m_unk0x336 = p_unk0x336; }
|
inline void SetUnknown336(MxBool p_unk0x336) { m_unk0x336 = p_unk0x336; }
|
||||||
|
inline void SetUseJoystick(MxBool p_useJoystick) { m_useJoystick = p_useJoystick; }
|
||||||
|
inline void SetJoystickIndex(MxS32 p_joystickIndex) { m_joystickIndex = p_joystickIndex; }
|
||||||
|
|
||||||
inline LegoControlManager* GetControlManager() { return m_controlManager; }
|
inline LegoControlManager* GetControlManager() { return m_controlManager; }
|
||||||
inline LegoWorld* GetWorld() { return m_world; }
|
inline LegoWorld* GetWorld() { return m_world; }
|
||||||
@ -61,7 +63,7 @@ class LegoInputManager : public MxPresenter {
|
|||||||
void ProcessEvents();
|
void ProcessEvents();
|
||||||
MxBool ProcessOneEvent(LegoEventNotificationParam& p_param);
|
MxBool ProcessOneEvent(LegoEventNotificationParam& p_param);
|
||||||
|
|
||||||
// private:
|
private:
|
||||||
MxCriticalSection m_criticalSection;
|
MxCriticalSection m_criticalSection;
|
||||||
MxList<undefined4>* m_unk0x5c; // list or hash table
|
MxList<undefined4>* m_unk0x5c; // list or hash table
|
||||||
LegoCameraController* m_camera;
|
LegoCameraController* m_camera;
|
||||||
@ -94,6 +96,9 @@ class LegoInputManager : public MxPresenter {
|
|||||||
// TEMPLATE: LEGO1 0x1005bb80
|
// TEMPLATE: LEGO1 0x1005bb80
|
||||||
// MxCollection<LegoEventNotificationParam>::Compare
|
// MxCollection<LegoEventNotificationParam>::Compare
|
||||||
|
|
||||||
|
// TEMPLATE: LEGO1 0x1005bbe0
|
||||||
|
// MxCollection<LegoEventNotificationParam>::~MxCollection<LegoEventNotificationParam>
|
||||||
|
|
||||||
// TEMPLATE: LEGO1 0x1005bc30
|
// TEMPLATE: LEGO1 0x1005bc30
|
||||||
// MxCollection<LegoEventNotificationParam>::Destroy
|
// MxCollection<LegoEventNotificationParam>::Destroy
|
||||||
|
|
||||||
@ -109,6 +114,9 @@ class LegoInputManager : public MxPresenter {
|
|||||||
// SYNTHETIC: LEGO1 0x1005beb0
|
// SYNTHETIC: LEGO1 0x1005beb0
|
||||||
// LegoEventQueue::`scalar deleting destructor'
|
// LegoEventQueue::`scalar deleting destructor'
|
||||||
|
|
||||||
|
// TEMPLATE: LEGO1 0x1005bf20
|
||||||
|
// MxQueue<LegoEventNotificationParam>::~MxQueue<LegoEventNotificationParam>
|
||||||
|
|
||||||
// SYNTHETIC: LEGO1 0x1005bf70
|
// SYNTHETIC: LEGO1 0x1005bf70
|
||||||
// MxQueue<LegoEventNotificationParam>::`scalar deleting destructor'
|
// MxQueue<LegoEventNotificationParam>::`scalar deleting destructor'
|
||||||
|
|
||||||
|
|||||||
@ -21,4 +21,10 @@ class LegoLoopingAnimPresenter : public LegoAnimPresenter {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x1006d000
|
||||||
|
// LegoLoopingAnimPresenter::~LegoLoopingAnimPresenter
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x1000f440
|
||||||
|
// LegoLoopingAnimPresenter::`scalar deleting destructor'
|
||||||
|
|
||||||
#endif // LEGOLOOPINGANIMPRESENTER_H
|
#endif // LEGOLOOPINGANIMPRESENTER_H
|
||||||
|
|||||||
@ -7,7 +7,30 @@
|
|||||||
// SIZE 0x94 (from 0x1000a163)
|
// SIZE 0x94 (from 0x1000a163)
|
||||||
class LegoMeterPresenter : public MxStillPresenter {
|
class LegoMeterPresenter : public MxStillPresenter {
|
||||||
public:
|
public:
|
||||||
|
LegoMeterPresenter();
|
||||||
|
virtual ~LegoMeterPresenter() override;
|
||||||
|
|
||||||
// MxStillPresenter's `::ClassName` and `::IsA` are used.
|
// MxStillPresenter's `::ClassName` and `::IsA` are used.
|
||||||
|
|
||||||
|
virtual void StreamingTickle() override; // vtable+0x20
|
||||||
|
virtual void RepeatingTickle() override; // vtable+0x24
|
||||||
|
virtual void ParseExtra() override; // vtable+0x30
|
||||||
|
|
||||||
|
private:
|
||||||
|
void FUN_10043a50();
|
||||||
|
|
||||||
|
MxU8* m_unk0x6c; // 0x6c
|
||||||
|
MxU16 m_type; // 0x70
|
||||||
|
MxString m_variable; // 0x74
|
||||||
|
MxFloat m_unk0x84; // 0x84
|
||||||
|
MxU16 m_unk0x88; // 0x88
|
||||||
|
MxU16 m_unk0x8a; // 0x8a
|
||||||
|
MxU16 m_unk0x8c; // 0x8c
|
||||||
|
MxU16 m_unk0x8e; // 0x8e
|
||||||
|
MxU16 m_layout; // 0x90
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x10043760
|
||||||
|
// LegoMeterPresenter::`scalar deleting destructor'
|
||||||
|
|
||||||
#endif // LEGOMETERPRESENTER_H
|
#endif // LEGOMETERPRESENTER_H
|
||||||
|
|||||||
@ -70,7 +70,7 @@
|
|||||||
X(RaceCar) \
|
X(RaceCar) \
|
||||||
X(Jetski) \
|
X(Jetski) \
|
||||||
X(Bike) \
|
X(Bike) \
|
||||||
X(Motorcycle) \
|
X(Motocycle) \
|
||||||
X(Ambulance) \
|
X(Ambulance) \
|
||||||
X(AmbulanceMissionState) \
|
X(AmbulanceMissionState) \
|
||||||
X(TowTrack) \
|
X(TowTrack) \
|
||||||
|
|||||||
@ -18,7 +18,8 @@ class MxVariableTable;
|
|||||||
class LegoStream {
|
class LegoStream {
|
||||||
public:
|
public:
|
||||||
LegoStream() : m_mode(0) {}
|
LegoStream() : m_mode(0) {}
|
||||||
inline virtual ~LegoStream(){};
|
// FUNCTION: LEGO1 0x10045ad0
|
||||||
|
inline virtual ~LegoStream() {}
|
||||||
|
|
||||||
virtual MxResult Read(void* p_buffer, MxU32 p_size) = 0;
|
virtual MxResult Read(void* p_buffer, MxU32 p_size) = 0;
|
||||||
virtual MxResult Write(const void* p_buffer, MxU32 p_size) = 0;
|
virtual MxResult Write(const void* p_buffer, MxU32 p_size) = 0;
|
||||||
@ -41,11 +42,14 @@ class LegoStream {
|
|||||||
MxU8 m_mode;
|
MxU8 m_mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x10045b00
|
||||||
|
// LegoStream::`scalar deleting destructor'
|
||||||
|
|
||||||
// VTABLE: LEGO1 0x100db730
|
// VTABLE: LEGO1 0x100db730
|
||||||
class LegoFileStream : public LegoStream {
|
class LegoFileStream : public LegoStream {
|
||||||
public:
|
public:
|
||||||
LegoFileStream();
|
LegoFileStream();
|
||||||
virtual ~LegoFileStream();
|
virtual ~LegoFileStream() override;
|
||||||
|
|
||||||
MxResult Read(void* p_buffer, MxU32 p_size) override;
|
MxResult Read(void* p_buffer, MxU32 p_size) override;
|
||||||
MxResult Write(const void* p_buffer, MxU32 p_size) override;
|
MxResult Write(const void* p_buffer, MxU32 p_size) override;
|
||||||
@ -60,11 +64,13 @@ class LegoFileStream : public LegoStream {
|
|||||||
FILE* m_hFile;
|
FILE* m_hFile;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x10099230
|
||||||
|
// LegoFileStream::`scalar deleting destructor'
|
||||||
|
|
||||||
// VTABLE: LEGO1 0x100db710
|
// VTABLE: LEGO1 0x100db710
|
||||||
class LegoMemoryStream : public LegoStream {
|
class LegoMemoryStream : public LegoStream {
|
||||||
public:
|
public:
|
||||||
LegoMemoryStream(char* p_buffer);
|
LegoMemoryStream(char* p_buffer);
|
||||||
~LegoMemoryStream() {}
|
|
||||||
|
|
||||||
MxResult Read(void* p_buffer, MxU32 p_size) override;
|
MxResult Read(void* p_buffer, MxU32 p_size) override;
|
||||||
MxResult Write(const void* p_buffer, MxU32 p_size) override;
|
MxResult Write(const void* p_buffer, MxU32 p_size) override;
|
||||||
@ -76,4 +82,10 @@ class LegoMemoryStream : public LegoStream {
|
|||||||
MxU32 m_offset;
|
MxU32 m_offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x10045a80
|
||||||
|
// LegoMemoryStream::~LegoMemoryStream
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x100990f0
|
||||||
|
// LegoMemoryStream::`scalar deleting destructor'
|
||||||
|
|
||||||
#endif // LEGOSTREAM_H
|
#endif // LEGOSTREAM_H
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
#include "decomp.h"
|
#include "decomp.h"
|
||||||
#include "mxstring.h"
|
#include "mxstring.h"
|
||||||
|
|
||||||
|
// VTABLE: LEGO1 0x100d7c88
|
||||||
class LegoUnknown100d7c88 {
|
class LegoUnknown100d7c88 {
|
||||||
public:
|
public:
|
||||||
~LegoUnknown100d7c88();
|
~LegoUnknown100d7c88();
|
||||||
|
|||||||
@ -27,9 +27,15 @@ class LegoUnknown100d9d00 : public MxList<LegoUnknown100d7c88*> {
|
|||||||
// TEMPLATE: LEGO1 0x1007b300
|
// TEMPLATE: LEGO1 0x1007b300
|
||||||
// MxCollection<LegoUnknown100d7c88 *>::Compare
|
// MxCollection<LegoUnknown100d7c88 *>::Compare
|
||||||
|
|
||||||
|
// TEMPLATE: LEGO1 0x1007b310
|
||||||
|
// MxCollection<LegoUnknown100d7c88 *>::~MxCollection<LegoUnknown100d7c88 *>
|
||||||
|
|
||||||
// TEMPLATE: LEGO1 0x1007b360
|
// TEMPLATE: LEGO1 0x1007b360
|
||||||
// MxCollection<LegoUnknown100d7c88 *>::Destroy
|
// MxCollection<LegoUnknown100d7c88 *>::Destroy
|
||||||
|
|
||||||
|
// TEMPLATE: LEGO1 0x1007b370
|
||||||
|
// MxList<LegoUnknown100d7c88 *>::~MxList<LegoUnknown100d7c88 *>
|
||||||
|
|
||||||
// SYNTHETIC: LEGO1 0x1007b400
|
// SYNTHETIC: LEGO1 0x1007b400
|
||||||
// LegoUnknown100d9d00::`scalar deleting destructor'
|
// LegoUnknown100d9d00::`scalar deleting destructor'
|
||||||
|
|
||||||
|
|||||||
@ -1,14 +1,14 @@
|
|||||||
#ifndef MOTORCYCLE_H
|
#ifndef MOTOCYCLE_H
|
||||||
#define MOTORCYCLE_H
|
#define MOTOCYCLE_H
|
||||||
|
|
||||||
#include "decomp.h"
|
#include "decomp.h"
|
||||||
#include "islepathactor.h"
|
#include "islepathactor.h"
|
||||||
|
|
||||||
// VTABLE: LEGO1 0x100d7090
|
// VTABLE: LEGO1 0x100d7090
|
||||||
// SIZE 0x16c
|
// SIZE 0x16c
|
||||||
class Motorcycle : public IslePathActor {
|
class Motocycle : public IslePathActor {
|
||||||
public:
|
public:
|
||||||
Motorcycle();
|
Motocycle();
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x10035840
|
// FUNCTION: LEGO1 0x10035840
|
||||||
inline virtual const char* ClassName() const override // vtable+0x0c
|
inline virtual const char* ClassName() const override // vtable+0x0c
|
||||||
@ -20,7 +20,7 @@ class Motorcycle : public IslePathActor {
|
|||||||
// FUNCTION: LEGO1 0x10035850
|
// FUNCTION: LEGO1 0x10035850
|
||||||
inline virtual MxBool IsA(const char* p_name) const override // vtable+0x10
|
inline virtual MxBool IsA(const char* p_name) const override // vtable+0x10
|
||||||
{
|
{
|
||||||
return !strcmp(p_name, Motorcycle::ClassName()) || IslePathActor::IsA(p_name);
|
return !strcmp(p_name, Motocycle::ClassName()) || IslePathActor::IsA(p_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -29,4 +29,4 @@ class Motorcycle : public IslePathActor {
|
|||||||
undefined m_unk0x168[4];
|
undefined m_unk0x168[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MOTORCYCLE_H
|
#endif // MOTOCYCLE_H
|
||||||
@ -6,6 +6,7 @@ DECOMP_SIZE_ASSERT(GifMap, 0x08);
|
|||||||
DECOMP_SIZE_ASSERT(GifManagerBase, 0x14);
|
DECOMP_SIZE_ASSERT(GifManagerBase, 0x14);
|
||||||
DECOMP_SIZE_ASSERT(GifManager, 0x30);
|
DECOMP_SIZE_ASSERT(GifManager, 0x30);
|
||||||
|
|
||||||
|
// GLOBAL: LEGO1 0x100f0100
|
||||||
GifMapEntry* g_unk0x100f0100;
|
GifMapEntry* g_unk0x100f0100;
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x10001cc0
|
// FUNCTION: LEGO1 0x10001cc0
|
||||||
|
|||||||
@ -7,8 +7,13 @@
|
|||||||
|
|
||||||
DECOMP_SIZE_ASSERT(LegoBackgroundColor, 0x30)
|
DECOMP_SIZE_ASSERT(LegoBackgroundColor, 0x30)
|
||||||
|
|
||||||
|
// GLOBAL: LEGO1 0x100f3fb0
|
||||||
const char* g_delimiter = "\t";
|
const char* g_delimiter = "\t";
|
||||||
|
|
||||||
|
// GLOBAL: LEGO1 0x100f3fb4
|
||||||
const char* g_set = "set";
|
const char* g_set = "set";
|
||||||
|
|
||||||
|
// GLOBAL: LEGO1 0x100f3fb8
|
||||||
const char* g_reset = "reset";
|
const char* g_reset = "reset";
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x1003bfb0
|
// FUNCTION: LEGO1 0x1003bfb0
|
||||||
|
|||||||
@ -7,10 +7,10 @@
|
|||||||
|
|
||||||
DECOMP_SIZE_ASSERT(LegoFullScreenMovie, 0x24)
|
DECOMP_SIZE_ASSERT(LegoFullScreenMovie, 0x24)
|
||||||
|
|
||||||
// GLOBAL: LEGO1 0x100f3be8
|
// GLOBAL: LEGO1 0x100f3fbc
|
||||||
const char* g_strEnable = "enable";
|
const char* g_strEnable = "enable";
|
||||||
|
|
||||||
// GLOBAL: LEGO1 0x100f3bf4
|
// GLOBAL: LEGO1 0x100f3fc0
|
||||||
const char* g_strDisable = "disable";
|
const char* g_strDisable = "disable";
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x1003c500
|
// FUNCTION: LEGO1 0x1003c500
|
||||||
|
|||||||
@ -19,15 +19,15 @@
|
|||||||
// There may be other members that come after.
|
// There may be other members that come after.
|
||||||
DECOMP_SIZE_ASSERT(LegoGameState, 0x430)
|
DECOMP_SIZE_ASSERT(LegoGameState, 0x430)
|
||||||
|
|
||||||
// GLOBAL: LEGO1 0x100f3e24
|
|
||||||
const char* g_historyGSI = "History.gsi";
|
|
||||||
|
|
||||||
// GLOBAL: LEGO1 0x100f3e30
|
|
||||||
const char* g_playersGSI = "Players.gsi";
|
|
||||||
|
|
||||||
// GLOBAL: LEGO1 0x100f3e40
|
// GLOBAL: LEGO1 0x100f3e40
|
||||||
const char* g_fileExtensionGS = ".GS";
|
const char* g_fileExtensionGS = ".GS";
|
||||||
|
|
||||||
|
// GLOBAL: LEGO1 0x100f3e44
|
||||||
|
const char* g_playersGSI = "Players.gsi";
|
||||||
|
|
||||||
|
// GLOBAL: LEGO1 0x100f3e48
|
||||||
|
const char* g_historyGSI = "History.gsi";
|
||||||
|
|
||||||
// GLOBAL: LEGO1 0x100f3e58
|
// GLOBAL: LEGO1 0x100f3e58
|
||||||
ColorStringStruct g_colorSaveData[43] = {
|
ColorStringStruct g_colorSaveData[43] = {
|
||||||
{"c_dbbkfny0", "lego red"}, {"c_dbbkxly0", "lego white"}, {"c_chbasey0", "lego black"},
|
{"c_dbbkfny0", "lego red"}, {"c_dbbkxly0", "lego white"}, {"c_chbasey0", "lego black"},
|
||||||
@ -168,7 +168,7 @@ void LegoGameState::GetFileSavePath(MxString* p_outPath, MxULong p_slotn)
|
|||||||
strcpy(path, m_savePath);
|
strcpy(path, m_savePath);
|
||||||
|
|
||||||
// Slot: "G0", "G1", ...
|
// Slot: "G0", "G1", ...
|
||||||
strcat(path, "G");
|
strcat(path, "\\G");
|
||||||
baseForSlot[0] += p_slotn;
|
baseForSlot[0] += p_slotn;
|
||||||
strcat(path, baseForSlot);
|
strcat(path, baseForSlot);
|
||||||
|
|
||||||
|
|||||||
@ -68,7 +68,7 @@
|
|||||||
#include "doors.h"
|
#include "doors.h"
|
||||||
#include "jetski.h"
|
#include "jetski.h"
|
||||||
#include "legoanimmmpresenter.h"
|
#include "legoanimmmpresenter.h"
|
||||||
#include "motorcycle.h"
|
#include "motocycle.h"
|
||||||
#include "racecar.h"
|
#include "racecar.h"
|
||||||
#include "towtrack.h"
|
#include "towtrack.h"
|
||||||
#include "towtrackmissionstate.h"
|
#include "towtrackmissionstate.h"
|
||||||
|
|||||||
@ -16,13 +16,13 @@ MxCompositeMediaPresenter::MxCompositeMediaPresenter()
|
|||||||
{
|
{
|
||||||
m_unk0x4c = 0;
|
m_unk0x4c = 0;
|
||||||
m_unk0x4e = FALSE;
|
m_unk0x4e = FALSE;
|
||||||
VideoManager()->AddPresenter(*this);
|
VideoManager()->RegisterPresenter(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x10074020
|
// FUNCTION: LEGO1 0x10074020
|
||||||
MxCompositeMediaPresenter::~MxCompositeMediaPresenter()
|
MxCompositeMediaPresenter::~MxCompositeMediaPresenter()
|
||||||
{
|
{
|
||||||
VideoManager()->RemovePresenter(*this);
|
VideoManager()->UnregisterPresenter(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x10074090
|
// FUNCTION: LEGO1 0x10074090
|
||||||
@ -58,9 +58,9 @@ MxResult MxCompositeMediaPresenter::StartAction(MxStreamController* p_controller
|
|||||||
presenter->SetTickleState(TickleState_Idle);
|
presenter->SetTickleState(TickleState_Idle);
|
||||||
|
|
||||||
if (presenter->IsA("MxVideoPresenter"))
|
if (presenter->IsA("MxVideoPresenter"))
|
||||||
VideoManager()->RemovePresenter(*presenter);
|
VideoManager()->UnregisterPresenter(*presenter);
|
||||||
else if (presenter->IsA("MxAudioPresenter"))
|
else if (presenter->IsA("MxAudioPresenter"))
|
||||||
SoundManager()->RemovePresenter(*presenter);
|
SoundManager()->UnregisterPresenter(*presenter);
|
||||||
|
|
||||||
success = TRUE;
|
success = TRUE;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,3 +11,9 @@ LegoActor::LegoActor()
|
|||||||
m_unk0x10 = 0;
|
m_unk0x10 = 0;
|
||||||
m_unk0x74 = 0;
|
m_unk0x74 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// STUB: LEGO1 0x1002d320
|
||||||
|
LegoActor::~LegoActor()
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|||||||
@ -7,10 +7,10 @@
|
|||||||
void LegoActorPresenter::ReadyTickle()
|
void LegoActorPresenter::ReadyTickle()
|
||||||
{
|
{
|
||||||
if (GetCurrentWorld()) {
|
if (GetCurrentWorld()) {
|
||||||
m_objectBackend = (LegoEntity*) CreateEntityBackend("LegoActor");
|
m_entity = (LegoEntity*) CreateEntity("LegoActor");
|
||||||
if (m_objectBackend) {
|
if (m_entity) {
|
||||||
SetBackendLocation(m_action->GetLocation(), m_action->GetDirection(), m_action->GetUp());
|
SetEntityLocation(m_action->GetLocation(), m_action->GetDirection(), m_action->GetUp());
|
||||||
m_objectBackend->Create(*m_action);
|
m_entity->Create(*m_action);
|
||||||
}
|
}
|
||||||
ProgressTickleState(TickleState_Starting);
|
ProgressTickleState(TickleState_Starting);
|
||||||
}
|
}
|
||||||
@ -19,7 +19,7 @@ void LegoActorPresenter::ReadyTickle()
|
|||||||
// FUNCTION: LEGO1 0x10076c90
|
// FUNCTION: LEGO1 0x10076c90
|
||||||
void LegoActorPresenter::StartingTickle()
|
void LegoActorPresenter::StartingTickle()
|
||||||
{
|
{
|
||||||
if (m_objectBackend->GetROI()) {
|
if (m_entity->GetROI()) {
|
||||||
ProgressTickleState(TickleState_Streaming);
|
ProgressTickleState(TickleState_Streaming);
|
||||||
ParseExtra();
|
ParseExtra();
|
||||||
}
|
}
|
||||||
@ -34,6 +34,6 @@ void LegoActorPresenter::ParseExtra()
|
|||||||
memcpy(buffer, extraData, m_action->GetExtraLength());
|
memcpy(buffer, extraData, m_action->GetExtraLength());
|
||||||
buffer[m_action->GetExtraLength()] = 0;
|
buffer[m_action->GetExtraLength()] = 0;
|
||||||
|
|
||||||
m_objectBackend->ParseAction(buffer);
|
m_entity->ParseAction(buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -46,7 +46,7 @@ MxResult LegoEntity::Create(MxDSAction& p_dsAction)
|
|||||||
{
|
{
|
||||||
m_mxEntityId = p_dsAction.GetObjectId();
|
m_mxEntityId = p_dsAction.GetObjectId();
|
||||||
m_atom = p_dsAction.GetAtomId();
|
m_atom = p_dsAction.GetAtomId();
|
||||||
Init();
|
SetWorld();
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,7 @@ LegoEntityPresenter::LegoEntityPresenter()
|
|||||||
// FUNCTION: LEGO1 0x100535c0
|
// FUNCTION: LEGO1 0x100535c0
|
||||||
void LegoEntityPresenter::Init()
|
void LegoEntityPresenter::Init()
|
||||||
{
|
{
|
||||||
m_objectBackend = 0;
|
m_entity = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100535d0
|
// FUNCTION: LEGO1 0x100535d0
|
||||||
@ -25,9 +25,9 @@ LegoEntityPresenter::~LegoEntityPresenter()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x10053630
|
// FUNCTION: LEGO1 0x10053630
|
||||||
undefined4 LegoEntityPresenter::SetBackend(LegoEntity* p_backend)
|
undefined4 LegoEntityPresenter::SetEntity(LegoEntity* p_entity)
|
||||||
{
|
{
|
||||||
m_objectBackend = p_backend;
|
m_entity = p_entity;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ undefined4 LegoEntityPresenter::SetBackend(LegoEntity* p_backend)
|
|||||||
void LegoEntityPresenter::Destroy(MxBool p_fromDestructor)
|
void LegoEntityPresenter::Destroy(MxBool p_fromDestructor)
|
||||||
{
|
{
|
||||||
if (VideoManager()) {
|
if (VideoManager()) {
|
||||||
VideoManager()->RemovePresenter(*this);
|
VideoManager()->UnregisterPresenter(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Init();
|
Init();
|
||||||
@ -53,7 +53,7 @@ MxResult LegoEntityPresenter::StartAction(MxStreamController* p_controller, MxDS
|
|||||||
MxResult result = MxCompositePresenter::StartAction(p_controller, p_action);
|
MxResult result = MxCompositePresenter::StartAction(p_controller, p_action);
|
||||||
|
|
||||||
if (VideoManager()) {
|
if (VideoManager()) {
|
||||||
VideoManager()->AddPresenter(*this);
|
VideoManager()->RegisterPresenter(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -63,10 +63,10 @@ MxResult LegoEntityPresenter::StartAction(MxStreamController* p_controller, MxDS
|
|||||||
void LegoEntityPresenter::ReadyTickle()
|
void LegoEntityPresenter::ReadyTickle()
|
||||||
{
|
{
|
||||||
if (GetCurrentWorld()) {
|
if (GetCurrentWorld()) {
|
||||||
m_objectBackend = (LegoEntity*) MxPresenter::CreateEntityBackend("LegoEntity");
|
m_entity = (LegoEntity*) MxPresenter::CreateEntity("LegoEntity");
|
||||||
if (m_objectBackend) {
|
if (m_entity) {
|
||||||
m_objectBackend->Create(*m_action);
|
m_entity->Create(*m_action);
|
||||||
m_objectBackend->SetLocation(m_action->GetLocation(), m_action->GetDirection(), m_action->GetUp(), TRUE);
|
m_entity->SetLocation(m_action->GetLocation(), m_action->GetDirection(), m_action->GetUp(), TRUE);
|
||||||
ParseExtra();
|
ParseExtra();
|
||||||
}
|
}
|
||||||
ProgressTickleState(TickleState_Starting);
|
ProgressTickleState(TickleState_Starting);
|
||||||
@ -82,14 +82,14 @@ void LegoEntityPresenter::RepeatingTickle()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x10053730
|
// FUNCTION: LEGO1 0x10053730
|
||||||
void LegoEntityPresenter::SetBackendLocation(
|
void LegoEntityPresenter::SetEntityLocation(
|
||||||
Mx3DPointFloat& p_location,
|
Mx3DPointFloat& p_location,
|
||||||
Mx3DPointFloat& p_direction,
|
Mx3DPointFloat& p_direction,
|
||||||
Mx3DPointFloat& p_up
|
Mx3DPointFloat& p_up
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (m_objectBackend) {
|
if (m_entity) {
|
||||||
m_objectBackend->SetLocation(p_location, p_direction, p_up, TRUE);
|
m_entity->SetLocation(p_location, p_direction, p_up, TRUE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,6 +103,6 @@ void LegoEntityPresenter::ParseExtra()
|
|||||||
data[len] = 0;
|
data[len] = 0;
|
||||||
|
|
||||||
len &= MAXWORD;
|
len &= MAXWORD;
|
||||||
m_objectBackend->ParseAction(data);
|
m_entity->ParseAction(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,26 +35,26 @@ LegoWorldPresenter::LegoWorldPresenter()
|
|||||||
LegoWorldPresenter::~LegoWorldPresenter()
|
LegoWorldPresenter::~LegoWorldPresenter()
|
||||||
{
|
{
|
||||||
MxBool result = FALSE;
|
MxBool result = FALSE;
|
||||||
if (m_objectBackend) {
|
if (m_entity) {
|
||||||
undefined4 world = ((LegoWorld*) m_objectBackend)->GetUnknown0xec();
|
undefined4 world = ((LegoWorld*) m_entity)->GetUnknown0xec();
|
||||||
PlantManager()->FUN_10026360(world);
|
PlantManager()->FUN_10026360(world);
|
||||||
AnimationManager()->FUN_1005f720(world);
|
AnimationManager()->FUN_1005f720(world);
|
||||||
BuildingManager()->FUN_1002fa00();
|
BuildingManager()->FUN_1002fa00();
|
||||||
result = ((LegoWorld*) m_objectBackend)->VTable0x5c();
|
result = ((LegoWorld*) m_entity)->VTable0x5c();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result == FALSE) {
|
if (result == FALSE) {
|
||||||
FUN_10015820(0, 7);
|
FUN_10015820(0, 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_objectBackend) {
|
if (m_entity) {
|
||||||
#ifdef COMPAT_MODE
|
#ifdef COMPAT_MODE
|
||||||
{
|
{
|
||||||
MxNotificationParam param(c_notificationNewPresenter, NULL);
|
MxNotificationParam param(c_notificationNewPresenter, NULL);
|
||||||
NotificationManager()->Send(m_objectBackend, ¶m);
|
NotificationManager()->Send(m_entity, ¶m);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
NotificationManager()->Send(m_objectBackend, &MxNotificationParam(c_notificationNewPresenter, NULL));
|
NotificationManager()->Send(m_entity, &MxNotificationParam(c_notificationNewPresenter, NULL));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -103,7 +103,7 @@ MxResult LegoWorldPresenter::StartAction(MxStreamController* p_controller, MxDSA
|
|||||||
delete presenter;
|
delete presenter;
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoManager()->AddPresenter(*this);
|
VideoManager()->RegisterPresenter(*this);
|
||||||
|
|
||||||
result = SUCCESS;
|
result = SUCCESS;
|
||||||
}
|
}
|
||||||
@ -114,11 +114,11 @@ MxResult LegoWorldPresenter::StartAction(MxStreamController* p_controller, MxDSA
|
|||||||
// FUNCTION: LEGO1 0x10066a50
|
// FUNCTION: LEGO1 0x10066a50
|
||||||
void LegoWorldPresenter::ReadyTickle()
|
void LegoWorldPresenter::ReadyTickle()
|
||||||
{
|
{
|
||||||
m_objectBackend = (LegoEntity*) MxPresenter::CreateEntityBackend("LegoWorld");
|
m_entity = (LegoEntity*) MxPresenter::CreateEntity("LegoWorld");
|
||||||
if (m_objectBackend) {
|
if (m_entity) {
|
||||||
m_objectBackend->Create(*m_action);
|
m_entity->Create(*m_action);
|
||||||
Lego()->AddWorld((LegoWorld*) m_objectBackend);
|
Lego()->AddWorld((LegoWorld*) m_entity);
|
||||||
SetBackendLocation(m_action->GetLocation(), m_action->GetDirection(), m_action->GetUp());
|
SetEntityLocation(m_action->GetLocation(), m_action->GetDirection(), m_action->GetUp());
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseExtra();
|
ParseExtra();
|
||||||
|
|||||||
@ -1,15 +1,28 @@
|
|||||||
#include "elevatorbottom.h"
|
#include "elevatorbottom.h"
|
||||||
|
|
||||||
// STUB: LEGO1 0x10017e90
|
DECOMP_SIZE_ASSERT(ElevatorBottom, 0xfc)
|
||||||
|
|
||||||
|
#include "legocontrolmanager.h"
|
||||||
|
#include "legoinputmanager.h"
|
||||||
|
#include "legoomni.h"
|
||||||
|
#include "mxnotificationmanager.h"
|
||||||
|
#include "mxomni.h"
|
||||||
|
|
||||||
|
// FUNCTION: LEGO1 0x10017e90
|
||||||
ElevatorBottom::ElevatorBottom()
|
ElevatorBottom::ElevatorBottom()
|
||||||
{
|
{
|
||||||
// TODO
|
NotificationManager()->Register(this);
|
||||||
|
this->m_unk0xf8 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// STUB: LEGO1 0x10018060
|
// FUNCTION: LEGO1 0x10018060
|
||||||
ElevatorBottom::~ElevatorBottom()
|
ElevatorBottom::~ElevatorBottom()
|
||||||
{
|
{
|
||||||
// TODO
|
if (InputManager()->GetWorld() == this) {
|
||||||
|
InputManager()->ClearWorld();
|
||||||
|
}
|
||||||
|
ControlManager()->Unregister(this);
|
||||||
|
NotificationManager()->Unregister(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// STUB: LEGO1 0x10018150
|
// STUB: LEGO1 0x10018150
|
||||||
|
|||||||
@ -26,7 +26,7 @@ Isle::Isle()
|
|||||||
m_helicopter = NULL;
|
m_helicopter = NULL;
|
||||||
m_bike = NULL;
|
m_bike = NULL;
|
||||||
m_dunebuggy = NULL;
|
m_dunebuggy = NULL;
|
||||||
m_motorcycle = NULL;
|
m_motocycle = NULL;
|
||||||
m_skateboard = NULL;
|
m_skateboard = NULL;
|
||||||
m_racecar = NULL;
|
m_racecar = NULL;
|
||||||
m_jetski = NULL;
|
m_jetski = NULL;
|
||||||
@ -230,7 +230,7 @@ void Isle::VTable0x58(MxCore* p_object)
|
|||||||
m_dunebuggy = (DuneBuggy*) p_object;
|
m_dunebuggy = (DuneBuggy*) p_object;
|
||||||
}
|
}
|
||||||
else if (p_object->IsA("Motorcycle")) {
|
else if (p_object->IsA("Motorcycle")) {
|
||||||
m_motorcycle = (Motorcycle*) p_object;
|
m_motocycle = (Motocycle*) p_object;
|
||||||
}
|
}
|
||||||
else if (p_object->IsA("SkateBoard")) {
|
else if (p_object->IsA("SkateBoard")) {
|
||||||
m_skateboard = (SkateBoard*) p_object;
|
m_skateboard = (SkateBoard*) p_object;
|
||||||
|
|||||||
@ -17,6 +17,13 @@ MxResult IslePathActor::Create(MxDSAction& p_dsAction)
|
|||||||
return MxEntity::Create(p_dsAction);
|
return MxEntity::Create(p_dsAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FUNCTION: LEGO1 0x1001a2a0
|
||||||
|
void IslePathActor::Destroy(MxBool p_fromDestructor)
|
||||||
|
{
|
||||||
|
if (!p_fromDestructor)
|
||||||
|
LegoPathActor::Destroy(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
// STUB: LEGO1 0x1001a350
|
// STUB: LEGO1 0x1001a350
|
||||||
void IslePathActor::VTable0xe0()
|
void IslePathActor::VTable0xe0()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
#include "motorcycle.h"
|
#include "motocycle.h"
|
||||||
|
|
||||||
DECOMP_SIZE_ASSERT(Motorcycle, 0x16c);
|
DECOMP_SIZE_ASSERT(Motocycle, 0x16c);
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100357b0
|
// FUNCTION: LEGO1 0x100357b0
|
||||||
Motorcycle::Motorcycle()
|
Motocycle::Motocycle()
|
||||||
{
|
{
|
||||||
this->m_unk0x13c = 40.0;
|
this->m_unk0x13c = 40.0;
|
||||||
this->m_unk0x150 = 1.75;
|
this->m_unk0x150 = 1.75;
|
||||||
@ -100,7 +100,7 @@ MxAtomId* g_testScript = NULL;
|
|||||||
// GLOBAL: LEGO1 0x100f457c
|
// GLOBAL: LEGO1 0x100f457c
|
||||||
MxAtomId* g_jukeboxwScript = NULL;
|
MxAtomId* g_jukeboxwScript = NULL;
|
||||||
|
|
||||||
// GLOBAL: LEGO1 0x100f4580c
|
// GLOBAL: LEGO1 0x100f4580
|
||||||
MxAtomId* g_sndAnimScript = NULL;
|
MxAtomId* g_sndAnimScript = NULL;
|
||||||
|
|
||||||
// GLOBAL: LEGO1 0x100f4584
|
// GLOBAL: LEGO1 0x100f4584
|
||||||
@ -118,7 +118,7 @@ MxBool g_isWorldActive = TRUE;
|
|||||||
// FUNCTION: LEGO1 0x10015700
|
// FUNCTION: LEGO1 0x10015700
|
||||||
LegoOmni* Lego()
|
LegoOmni* Lego()
|
||||||
{
|
{
|
||||||
return (LegoOmni*) MxOmni::GetInstance();
|
return LegoOmni::GetInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x10015710
|
// FUNCTION: LEGO1 0x10015710
|
||||||
|
|||||||
@ -29,7 +29,7 @@ MxResult LegoPathPresenter::AddToManager()
|
|||||||
MxResult status = FAILURE;
|
MxResult status = FAILURE;
|
||||||
|
|
||||||
if (VideoManager()) {
|
if (VideoManager()) {
|
||||||
VideoManager()->AddPresenter(*this);
|
VideoManager()->RegisterPresenter(*this);
|
||||||
status = SUCCESS;
|
status = SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ MxResult LegoPathPresenter::AddToManager()
|
|||||||
void LegoPathPresenter::Destroy(MxBool p_fromDestructor)
|
void LegoPathPresenter::Destroy(MxBool p_fromDestructor)
|
||||||
{
|
{
|
||||||
if (VideoManager())
|
if (VideoManager())
|
||||||
VideoManager()->RemovePresenter(*this);
|
VideoManager()->UnregisterPresenter(*this);
|
||||||
|
|
||||||
{
|
{
|
||||||
MxAutoLocker lock(&this->m_criticalSection);
|
MxAutoLocker lock(&this->m_criticalSection);
|
||||||
|
|||||||
@ -6,6 +6,12 @@ LegoHideAnimPresenter::LegoHideAnimPresenter()
|
|||||||
Init();
|
Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// STUB: LEGO1 0x1006d9f0
|
||||||
|
LegoHideAnimPresenter::~LegoHideAnimPresenter()
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
// STUB: LEGO1 0x1006da50
|
// STUB: LEGO1 0x1006da50
|
||||||
void LegoHideAnimPresenter::Init()
|
void LegoHideAnimPresenter::Init()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,6 +1,119 @@
|
|||||||
#include "legometerpresenter.h"
|
#include "legometerpresenter.h"
|
||||||
|
|
||||||
#include "decomp.h"
|
#include "decomp.h"
|
||||||
|
#include "mxbitmap.h"
|
||||||
|
#include "mxutil.h"
|
||||||
|
|
||||||
// Uncomment when member class variables are fleshed out.
|
DECOMP_SIZE_ASSERT(LegoMeterPresenter, 0x94)
|
||||||
// DECOMP_SIZE_ASSERT(LegoMeterPresenter, 0x94); // 0x1000a163
|
|
||||||
|
// GLOBAL: LEGO1 0x1010207c
|
||||||
|
const char* g_filterIndex = "FILTER_INDEX";
|
||||||
|
|
||||||
|
// GLOBAL: LEGO1 0x10102094
|
||||||
|
const char* g_type = "TYPE";
|
||||||
|
|
||||||
|
// GLOBAL: LEGO1 0x10102088
|
||||||
|
const char* g_leftToRight = "LEFT_TO_RIGHT";
|
||||||
|
|
||||||
|
// GLOBAL: LEGO1 0x101020ac
|
||||||
|
const char* g_rightToLeft = "RIGHT_TO_LEFT";
|
||||||
|
|
||||||
|
// GLOBAL: LEGO1 0x1010205c
|
||||||
|
const char* g_bottomToTop = "BOTTOM_TO_TOP";
|
||||||
|
|
||||||
|
// GLOBAL: LEGO1 0x101020c0
|
||||||
|
const char* g_topToBottom = "TOP_TO_BOTTOM";
|
||||||
|
|
||||||
|
// GLOBAL: LEGO1 0x101020c8
|
||||||
|
const char* g_variable = "VARIABLE";
|
||||||
|
|
||||||
|
// FUNCTION: LEGO1 0x10043430
|
||||||
|
LegoMeterPresenter::LegoMeterPresenter()
|
||||||
|
{
|
||||||
|
m_layout = 0;
|
||||||
|
m_unk0x6c = 0;
|
||||||
|
m_unk0x84 = 0;
|
||||||
|
m_type = 1;
|
||||||
|
m_flags &= ~Flag_Bit2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FUNCTION: LEGO1 0x10043780
|
||||||
|
LegoMeterPresenter::~LegoMeterPresenter()
|
||||||
|
{
|
||||||
|
delete m_unk0x6c;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FUNCTION: LEGO1 0x10043800
|
||||||
|
void LegoMeterPresenter::ParseExtra()
|
||||||
|
{
|
||||||
|
char buffer[256];
|
||||||
|
|
||||||
|
MxStillPresenter::ParseExtra();
|
||||||
|
*((MxU16*) &buffer[0]) = m_action->GetExtraLength();
|
||||||
|
char* extraData = m_action->GetExtraData();
|
||||||
|
|
||||||
|
if (*((MxU16*) &buffer[0])) {
|
||||||
|
MxU16 len = *((MxU16*) &buffer[0]);
|
||||||
|
memcpy(buffer, extraData, len);
|
||||||
|
buffer[len] = '\0';
|
||||||
|
|
||||||
|
char result[256];
|
||||||
|
if (KeyValueStringParse(buffer, g_type, result)) {
|
||||||
|
if (!strcmpi(result, g_leftToRight)) {
|
||||||
|
m_layout = 0;
|
||||||
|
}
|
||||||
|
else if (!strcmpi(result, g_rightToLeft)) {
|
||||||
|
m_layout = 1;
|
||||||
|
}
|
||||||
|
else if (!strcmpi(result, g_bottomToTop)) {
|
||||||
|
m_layout = 2;
|
||||||
|
}
|
||||||
|
else if (!strcmpi(result, g_topToBottom)) {
|
||||||
|
m_layout = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (KeyValueStringParse(buffer, g_filterIndex, result)) {
|
||||||
|
m_type = atoi(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (KeyValueStringParse(buffer, g_variable, result)) {
|
||||||
|
m_variable = result;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
EndAction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
EndAction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FUNCTION: LEGO1 0x10043990
|
||||||
|
void LegoMeterPresenter::StreamingTickle()
|
||||||
|
{
|
||||||
|
MxStillPresenter::StreamingTickle();
|
||||||
|
m_unk0x6c = new MxU8[m_bitmap->GetBmiStride() * m_bitmap->GetBmiHeightAbs()];
|
||||||
|
if (m_unk0x6c == NULL) {
|
||||||
|
EndAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(m_unk0x6c, m_bitmap->GetBitmapData(), m_bitmap->GetBmiStride() * m_bitmap->GetBmiHeightAbs());
|
||||||
|
|
||||||
|
m_unk0x88 = 0;
|
||||||
|
m_unk0x8a = 0;
|
||||||
|
m_unk0x8c = m_bitmap->GetBmiWidth() - 1;
|
||||||
|
m_unk0x8e = m_bitmap->GetBmiHeightAbs() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FUNCTION: LEGO1 0x10043a30
|
||||||
|
void LegoMeterPresenter::RepeatingTickle()
|
||||||
|
{
|
||||||
|
FUN_10043a50();
|
||||||
|
MxStillPresenter::RepeatingTickle();
|
||||||
|
}
|
||||||
|
|
||||||
|
// STUB: LEGO1 0x10043a50
|
||||||
|
void LegoMeterPresenter::FUN_10043a50()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|||||||
@ -7,13 +7,13 @@
|
|||||||
// FUNCTION: LEGO1 0x1004eb40
|
// FUNCTION: LEGO1 0x1004eb40
|
||||||
LegoTexturePresenter::~LegoTexturePresenter()
|
LegoTexturePresenter::~LegoTexturePresenter()
|
||||||
{
|
{
|
||||||
VideoManager()->RemovePresenter(*this);
|
VideoManager()->UnregisterPresenter(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x1004ebb0
|
// FUNCTION: LEGO1 0x1004ebb0
|
||||||
MxResult LegoTexturePresenter::AddToManager()
|
MxResult LegoTexturePresenter::AddToManager()
|
||||||
{
|
{
|
||||||
VideoManager()->AddPresenter(*this);
|
VideoManager()->RegisterPresenter(*this);
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -114,8 +114,8 @@ MxResult MxTransitionManager::StartTransition(
|
|||||||
tickleManager->RegisterClient(this, p_speed);
|
tickleManager->RegisterClient(this, p_speed);
|
||||||
|
|
||||||
LegoInputManager* inputManager = InputManager();
|
LegoInputManager* inputManager = InputManager();
|
||||||
inputManager->m_unk0x88 = TRUE;
|
inputManager->SetUnknown88(TRUE);
|
||||||
inputManager->m_unk0x336 = FALSE;
|
inputManager->SetUnknown336(FALSE);
|
||||||
|
|
||||||
LegoVideoManager* videoManager = VideoManager();
|
LegoVideoManager* videoManager = VideoManager();
|
||||||
videoManager->SetRender3D(FALSE);
|
videoManager->SetRender3D(FALSE);
|
||||||
@ -486,7 +486,7 @@ void MxTransitionManager::SetWaitIndicator(MxVideoPresenter* p_waitIndicator)
|
|||||||
m_waitIndicator = p_waitIndicator;
|
m_waitIndicator = p_waitIndicator;
|
||||||
|
|
||||||
LegoVideoManager* videoManager = VideoManager();
|
LegoVideoManager* videoManager = VideoManager();
|
||||||
videoManager->RemovePresenter(*m_waitIndicator);
|
videoManager->UnregisterPresenter(*m_waitIndicator);
|
||||||
|
|
||||||
if (m_waitIndicator->GetCurrentTickleState() < MxPresenter::TickleState_Streaming) {
|
if (m_waitIndicator->GetCurrentTickleState() < MxPresenter::TickleState_Streaming) {
|
||||||
m_waitIndicator->Tickle();
|
m_waitIndicator->Tickle();
|
||||||
|
|||||||
@ -13,7 +13,7 @@ class Camera;
|
|||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
// LegoView
|
// LegoView
|
||||||
|
|
||||||
// VTABLE: 0x100dc000
|
// VTABLE: LEGO1 0x100dc000
|
||||||
// SIZE 0x78
|
// SIZE 0x78
|
||||||
class LegoView : public TglSurface {
|
class LegoView : public TglSurface {
|
||||||
public:
|
public:
|
||||||
|
|||||||
@ -18,6 +18,10 @@
|
|||||||
// LIBRARY: LEGO1 0x1008a1c0
|
// LIBRARY: LEGO1 0x1008a1c0
|
||||||
// _free
|
// _free
|
||||||
|
|
||||||
|
// LIBRARY: ISLE 0x407ec0
|
||||||
|
// LIBRARY: LEGO1 0x1008b020
|
||||||
|
// ___CxxFrameHandler
|
||||||
|
|
||||||
// LIBRARY: ISLE 0x408220
|
// LIBRARY: ISLE 0x408220
|
||||||
// LIBRARY: LEGO1 0x1008b400
|
// LIBRARY: LEGO1 0x1008b400
|
||||||
// _atol
|
// _atol
|
||||||
@ -33,6 +37,60 @@
|
|||||||
// LIBRARY: LEGO1 0x1008b5a0
|
// LIBRARY: LEGO1 0x1008b5a0
|
||||||
// _sprintf
|
// _sprintf
|
||||||
|
|
||||||
|
// LIBRARY: LEGO1 0x1008b608
|
||||||
|
// __ftol
|
||||||
|
|
||||||
|
// LIBRARY: LEGO1 0x1008b630
|
||||||
|
// _srand
|
||||||
|
|
||||||
|
// LIBRARY: LEGO1 0x1008b680
|
||||||
|
// _strncmp
|
||||||
|
|
||||||
|
// LIBRARY: LEGO1 0x1008b730
|
||||||
|
// _fprintf
|
||||||
|
|
||||||
|
// LIBRARY: LEGO1 0x1008b780
|
||||||
|
// _fwrite
|
||||||
|
|
||||||
|
// LIBRARY: LEGO1 0x1008b950
|
||||||
|
// _fread
|
||||||
|
|
||||||
|
// LIBRARY: LEGO1 0x1008bbd0
|
||||||
|
// _fclose
|
||||||
|
|
||||||
|
// LIBRARY: LEGO1 0x1008bdd0
|
||||||
|
// _ftell
|
||||||
|
|
||||||
|
// LIBRARY: LEGO1 0x1008bff0
|
||||||
|
// _fopen
|
||||||
|
|
||||||
|
// LIBRARY: LEGO1 0x1008c010
|
||||||
|
// _strncpy
|
||||||
|
|
||||||
|
// LIBRARY: LEGO1 0x1008c110
|
||||||
|
// __strcmpi
|
||||||
|
|
||||||
|
// LIBRARY: LEGO1 0x1008c1e0
|
||||||
|
// __spawnl
|
||||||
|
|
||||||
|
// LIBRARY: LEGO1 0x1008c200
|
||||||
|
// _sscanf
|
||||||
|
|
||||||
|
// LIBRARY: LEGO1 0x1008c410
|
||||||
|
// _strlwr
|
||||||
|
|
||||||
|
// LIBRARY: LEGO1 0x1008c5c0
|
||||||
|
// _fseek
|
||||||
|
|
||||||
|
// LIBRARY: LEGO1 0x1008ca60
|
||||||
|
// _abort
|
||||||
|
|
||||||
|
// LIBRARY: LEGO1 0x100977c0
|
||||||
|
// _itoa
|
||||||
|
|
||||||
|
// LIBRARY: LEGO1 0x10097b10
|
||||||
|
// _strchr
|
||||||
|
|
||||||
// LIBRARY: ISLE 0x4081e0
|
// LIBRARY: ISLE 0x4081e0
|
||||||
// _srand
|
// _srand
|
||||||
|
|
||||||
@ -46,4 +104,22 @@
|
|||||||
// LIBRARY: ISLE 0x409190
|
// LIBRARY: ISLE 0x409190
|
||||||
// __getptd
|
// __getptd
|
||||||
|
|
||||||
|
// LIBRARY: LEGO1 0x100d1ed0
|
||||||
|
// _strnicmp
|
||||||
|
|
||||||
|
// LIBRARY: LEGO1 0x100d1fd0
|
||||||
|
// _strupr
|
||||||
|
|
||||||
|
// LIBRARY: LEGO1 0x100d2130
|
||||||
|
// _vsprintf
|
||||||
|
|
||||||
|
// LIBRARY: LEGO1 0x100d21c2
|
||||||
|
// __CIpow
|
||||||
|
|
||||||
|
// LIBRARY: LEGO1 0x100d21f0
|
||||||
|
// _strstr
|
||||||
|
|
||||||
|
// LIBRARY: LEGO1 0x100d2270
|
||||||
|
// __beginthreadex
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -158,11 +158,15 @@ struct MxDriver {
|
|||||||
// List<MxDriver>::~List<MxDriver>
|
// List<MxDriver>::~List<MxDriver>
|
||||||
|
|
||||||
// Compiler-generated copy ctor
|
// Compiler-generated copy ctor
|
||||||
// Part of this function are two more synthetic sub-routines,
|
|
||||||
// LEGO1 0x1009c400 and LEGO1 0x1009c460
|
|
||||||
// SYNTHETIC: LEGO1 0x1009c290
|
// SYNTHETIC: LEGO1 0x1009c290
|
||||||
// MxDriver::MxDriver
|
// MxDriver::MxDriver
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x1009c400
|
||||||
|
// list<MxDevice,allocator<MxDevice> >::insert
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x1009c460
|
||||||
|
// list<MxDisplayMode,allocator<MxDisplayMode> >::insert
|
||||||
|
|
||||||
// SYNTHETIC: LEGO1 0x1009d450
|
// SYNTHETIC: LEGO1 0x1009d450
|
||||||
// MxDriver::`scalar deleting destructor'
|
// MxDriver::`scalar deleting destructor'
|
||||||
|
|
||||||
@ -223,4 +227,7 @@ class MxDeviceEnumerate {
|
|||||||
// SIZE 0x14
|
// SIZE 0x14
|
||||||
class MxDeviceEnumerate100d9cc8 : public MxDeviceEnumerate {};
|
class MxDeviceEnumerate100d9cc8 : public MxDeviceEnumerate {};
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x1007b590
|
||||||
|
// MxDeviceEnumerate100d9cc8::~MxDeviceEnumerate100d9cc8
|
||||||
|
|
||||||
#endif // MXDIRECT3D_H
|
#endif // MXDIRECT3D_H
|
||||||
|
|||||||
@ -97,6 +97,9 @@ inline double MxStopWatch::ElapsedSeconds() const
|
|||||||
return m_elapsedSeconds;
|
return m_elapsedSeconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x100a6fc0
|
||||||
|
// MxStopWatch::~MxStopWatch
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// MxFrequencyMeter
|
// MxFrequencyMeter
|
||||||
@ -182,4 +185,7 @@ inline double MxFrequencyMeter::ElapsedSeconds() const
|
|||||||
return m_stopWatch.ElapsedSeconds();
|
return m_stopWatch.ElapsedSeconds();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x100abd10
|
||||||
|
// MxFrequencyMeter::~MxFrequencyMeter
|
||||||
|
|
||||||
#endif /* _MxStopWatch_h */
|
#endif /* _MxStopWatch_h */
|
||||||
|
|||||||
@ -115,13 +115,25 @@ class MxType4NotificationParam : public MxActionNotificationParam {
|
|||||||
MxPresenter* m_unk0x14; // 0x14
|
MxPresenter* m_unk0x14; // 0x14
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x100511e0
|
||||||
|
// MxActionNotificationParam::`scalar deleting destructor'
|
||||||
|
|
||||||
// SYNTHETIC: LEGO1 0x100513a0
|
// SYNTHETIC: LEGO1 0x100513a0
|
||||||
// MxEndActionNotificationParam::`scalar deleting destructor'
|
// MxEndActionNotificationParam::`scalar deleting destructor'
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x10051410
|
||||||
|
// MxEndActionNotificationParam::~MxEndActionNotificationParam
|
||||||
|
|
||||||
// SYNTHETIC: LEGO1 0x100b0430
|
// SYNTHETIC: LEGO1 0x100b0430
|
||||||
// MxStartActionNotificationParam::`scalar deleting destructor'
|
// MxStartActionNotificationParam::`scalar deleting destructor'
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x100b04a0
|
||||||
|
// MxStartActionNotificationParam::~MxStartActionNotificationParam
|
||||||
|
|
||||||
// SYNTHETIC: LEGO1 0x100b05c0
|
// SYNTHETIC: LEGO1 0x100b05c0
|
||||||
// MxType4NotificationParam::`scalar deleting destructor'
|
// MxType4NotificationParam::`scalar deleting destructor'
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x100b0630
|
||||||
|
// MxType4NotificationParam::~MxType4NotificationParam
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -43,4 +43,50 @@ struct MxAtomIdCounterCompare {
|
|||||||
|
|
||||||
class MxAtomIdCounterSet : public set<MxAtomIdCounter*, MxAtomIdCounterCompare> {};
|
class MxAtomIdCounterSet : public set<MxAtomIdCounter*, MxAtomIdCounterCompare> {};
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x100ad170
|
||||||
|
// MxAtomIdCounter::~MxAtomIdCounter
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
// TEMPLATE: LEGO1 0x100ad480
|
||||||
|
// _Tree<MxAtomIdCounter *,MxAtomIdCounter *,set<MxAtomIdCounter *,MxAtomIdCounterCompare,allocator<MxAtomIdCounter *> >::_Kfn,MxAtomIdCounterCompare,allocator<MxAtomIdCounter *> >::iterator::_Dec
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
// TEMPLATE: LEGO1 0x100ad780
|
||||||
|
// _Tree<MxAtomIdCounter *,MxAtomIdCounter *,set<MxAtomIdCounter *,MxAtomIdCounterCompare,allocator<MxAtomIdCounter *> >::_Kfn,MxAtomIdCounterCompare,allocator<MxAtomIdCounter *> >::_Lbound
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
// TEMPLATE: LEGO1 0x100ad4d0
|
||||||
|
// _Tree<MxAtomIdCounter *,MxAtomIdCounter *,set<MxAtomIdCounter *,MxAtomIdCounterCompare,allocator<MxAtomIdCounter *> >::_Kfn,MxAtomIdCounterCompare,allocator<MxAtomIdCounter *> >::_Insert
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
// TEMPLATE: LEGO1 0x100af6d0
|
||||||
|
// _Tree<MxAtomIdCounter *,MxAtomIdCounter *,set<MxAtomIdCounter *,MxAtomIdCounterCompare,allocator<MxAtomIdCounter *> >::_Kfn,MxAtomIdCounterCompare,allocator<MxAtomIdCounter *> >::~_Tree<MxAtomIdCounter *,MxAtomIdCounter *,set<MxAtomIdCounter *,MxAtomIdCou
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
// TEMPLATE: LEGO1 0x100af7a0
|
||||||
|
// _Tree<MxAtomIdCounter *,MxAtomIdCounter *,set<MxAtomIdCounter *,MxAtomIdCounterCompare,allocator<MxAtomIdCounter *> >::_Kfn,MxAtomIdCounterCompare,allocator<MxAtomIdCounter *> >::iterator::_Inc
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
// TEMPLATE: LEGO1 0x100af7e0
|
||||||
|
// _Tree<MxAtomIdCounter *,MxAtomIdCounter *,set<MxAtomIdCounter *,MxAtomIdCounterCompare,allocator<MxAtomIdCounter *> >::_Kfn,MxAtomIdCounterCompare,allocator<MxAtomIdCounter *> >::erase
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
// TEMPLATE: LEGO1 0x100afc40
|
||||||
|
// _Tree<MxAtomIdCounter *,MxAtomIdCounter *,set<MxAtomIdCounter *,MxAtomIdCounterCompare,allocator<MxAtomIdCounter *> >::_Kfn,MxAtomIdCounterCompare,allocator<MxAtomIdCounter *> >::_Erase
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
// TEMPLATE: LEGO1 0x100afc80
|
||||||
|
// set<MxAtomIdCounter *,MxAtomIdCounterCompare,allocator<MxAtomIdCounter *> >::~set<MxAtomIdCounter *,MxAtomIdCounterCompare,allocator<MxAtomIdCounter *> >
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
// TEMPLATE: LEGO1 0x100afe40
|
||||||
|
// Set<MxAtomIdCounter *,MxAtomIdCounterCompare>::~Set<MxAtomIdCounter *,MxAtomIdCounterCompare>
|
||||||
|
|
||||||
#endif // MXATOMIDCOUNTER_H
|
#endif // MXATOMIDCOUNTER_H
|
||||||
|
|||||||
@ -33,4 +33,10 @@ class MxAudioPresenter : public MxMediaPresenter {
|
|||||||
MxS32 m_volume;
|
MxS32 m_volume;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x1000d370
|
||||||
|
// MxAudioPresenter::`scalar deleting destructor'
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x1000d3e0
|
||||||
|
// MxAudioPresenter::~MxAudioPresenter
|
||||||
|
|
||||||
#endif // MXAUDIOPRESENTER_H
|
#endif // MXAUDIOPRESENTER_H
|
||||||
|
|||||||
@ -46,6 +46,7 @@ class MxDiskStreamController : public MxStreamController {
|
|||||||
void FUN_100c8670(MxDSStreamingAction* p_streamingAction);
|
void FUN_100c8670(MxDSStreamingAction* p_streamingAction);
|
||||||
void InsertToList74(MxDSBuffer* p_buffer);
|
void InsertToList74(MxDSBuffer* p_buffer);
|
||||||
void FUN_100c7cb0(MxDSStreamingAction* p_action);
|
void FUN_100c7cb0(MxDSStreamingAction* p_action);
|
||||||
|
MxResult FUN_100c7890(MxDSStreamingAction* p_action);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MxStreamListMxDSAction m_list0x64; // 0x64
|
MxStreamListMxDSAction m_list0x64; // 0x64
|
||||||
@ -58,7 +59,6 @@ class MxDiskStreamController : public MxStreamController {
|
|||||||
MxStreamListMxDSAction m_list0xb8; // 0xb8
|
MxStreamListMxDSAction m_list0xb8; // 0xb8
|
||||||
MxBool m_unk0xc4; // 0xc4
|
MxBool m_unk0xc4; // 0xc4
|
||||||
|
|
||||||
MxResult FUN_100c7890(MxDSStreamingAction* p_action);
|
|
||||||
void FUN_100c7970();
|
void FUN_100c7970();
|
||||||
void FUN_100c7ce0(MxDSBuffer* p_buffer);
|
void FUN_100c7ce0(MxDSBuffer* p_buffer);
|
||||||
MxResult FUN_100c7d10();
|
MxResult FUN_100c7d10();
|
||||||
@ -69,6 +69,9 @@ class MxDiskStreamController : public MxStreamController {
|
|||||||
void FUN_100c8720();
|
void FUN_100c8720();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TEMPLATE: LEGO1 0x100c14d0
|
||||||
|
// list<MxDSAction *,allocator<MxDSAction *> >::erase
|
||||||
|
|
||||||
// TEMPLATE: LEGO1 0x100c7330
|
// TEMPLATE: LEGO1 0x100c7330
|
||||||
// list<MxDSAction *,allocator<MxDSAction *> >::_Buynode
|
// list<MxDSAction *,allocator<MxDSAction *> >::_Buynode
|
||||||
|
|
||||||
|
|||||||
@ -20,9 +20,6 @@ class MxDiskStreamProviderThread : public MxThread {
|
|||||||
|
|
||||||
MxResult Run() override;
|
MxResult Run() override;
|
||||||
MxResult StartWithTarget(MxDiskStreamProvider* p_target);
|
MxResult StartWithTarget(MxDiskStreamProvider* p_target);
|
||||||
|
|
||||||
// SYNTHETIC: LEGO1 0x100d10a0
|
|
||||||
// MxDiskStreamProviderThread::`scalar deleting destructor'
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// VTABLE: LEGO1 0x100dd138
|
// VTABLE: LEGO1 0x100dd138
|
||||||
@ -58,9 +55,6 @@ class MxDiskStreamProvider : public MxStreamProvider {
|
|||||||
virtual MxU32 GetLengthInDWords() override; // vtable+0x24
|
virtual MxU32 GetLengthInDWords() override; // vtable+0x24
|
||||||
virtual MxU32* GetBufferForDWords() override; // vtable+0x28
|
virtual MxU32* GetBufferForDWords() override; // vtable+0x28
|
||||||
|
|
||||||
// SYNTHETIC: LEGO1 0x100d1220
|
|
||||||
// MxDiskStreamProvider::`scalar deleting destructor'
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MxDiskStreamProviderThread m_thread; // 0x10
|
MxDiskStreamProviderThread m_thread; // 0x10
|
||||||
MxSemaphore m_busySemaphore; // 0x2c
|
MxSemaphore m_busySemaphore; // 0x2c
|
||||||
@ -70,4 +64,13 @@ class MxDiskStreamProvider : public MxStreamProvider {
|
|||||||
MxStreamListMxDSAction m_list; // 0x54
|
MxStreamListMxDSAction m_list; // 0x54
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x100d10a0
|
||||||
|
// MxDiskStreamProviderThread::`scalar deleting destructor'
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x100d1110
|
||||||
|
// MxDiskStreamProviderThread::~MxDiskStreamProviderThread
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x100d1220
|
||||||
|
// MxDiskStreamProvider::`scalar deleting destructor'
|
||||||
|
|
||||||
#endif // MXDISKSTREAMPROVIDER_H
|
#endif // MXDISKSTREAMPROVIDER_H
|
||||||
|
|||||||
@ -43,6 +43,7 @@ class MxDSAction : public MxDSObject {
|
|||||||
return !strcmp(p_name, MxDSAction::ClassName()) || MxDSObject::IsA(p_name);
|
return !strcmp(p_name, MxDSAction::ClassName()) || MxDSObject::IsA(p_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual undefined4 VTable0x14() override; // vtable+14;
|
||||||
virtual MxU32 GetSizeOnDisk() override; // vtable+18;
|
virtual MxU32 GetSizeOnDisk() override; // vtable+18;
|
||||||
virtual void Deserialize(MxU8** p_source, MxS16 p_unk0x24) override; // vtable+1c;
|
virtual void Deserialize(MxU8** p_source, MxS16 p_unk0x24) override; // vtable+1c;
|
||||||
virtual MxLong GetDuration(); // vtable+24;
|
virtual MxLong GetDuration(); // vtable+24;
|
||||||
|
|||||||
@ -44,6 +44,9 @@ class MxDSActionListCursor : public MxListCursor<MxDSAction*> {
|
|||||||
// TEMPLATE: LEGO1 0x100c9cc0
|
// TEMPLATE: LEGO1 0x100c9cc0
|
||||||
// MxCollection<MxDSAction *>::Compare
|
// MxCollection<MxDSAction *>::Compare
|
||||||
|
|
||||||
|
// TEMPLATE: LEGO1 0x100c9cd0
|
||||||
|
// MxCollection<MxDSAction *>::~MxCollection<MxDSAction *>
|
||||||
|
|
||||||
// TEMPLATE: LEGO1 0x100c9d20
|
// TEMPLATE: LEGO1 0x100c9d20
|
||||||
// MxCollection<MxDSAction *>::Destroy
|
// MxCollection<MxDSAction *>::Destroy
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "mxdsmediaaction.h"
|
#include "mxdsmediaaction.h"
|
||||||
|
|
||||||
|
// VTABLE: LEGO1 0x100dce18
|
||||||
class MxDSEvent : public MxDSMediaAction {
|
class MxDSEvent : public MxDSMediaAction {
|
||||||
public:
|
public:
|
||||||
MxDSEvent();
|
MxDSEvent();
|
||||||
|
|||||||
@ -11,6 +11,9 @@ class MxDSSource : public MxCore {
|
|||||||
public:
|
public:
|
||||||
MxDSSource() : m_lengthInDWords(0), m_pBuffer(NULL), m_position(-1) {}
|
MxDSSource() : m_lengthInDWords(0), m_pBuffer(NULL), m_position(-1) {}
|
||||||
|
|
||||||
|
// FUNCTION: LEGO1 0x100bff60
|
||||||
|
virtual ~MxDSSource() override { delete[] m_pBuffer; }
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100c0010
|
// FUNCTION: LEGO1 0x100c0010
|
||||||
inline virtual const char* ClassName() const override // vtable+0x0c
|
inline virtual const char* ClassName() const override // vtable+0x0c
|
||||||
{
|
{
|
||||||
@ -41,4 +44,7 @@ class MxDSSource : public MxCore {
|
|||||||
MxLong m_position; // 0x10
|
MxLong m_position; // 0x10
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x100c00a0
|
||||||
|
// MxDSSource::`scalar deleting destructor'
|
||||||
|
|
||||||
#endif // MXDSSOURCE_H
|
#endif // MXDSSOURCE_H
|
||||||
|
|||||||
@ -14,12 +14,12 @@ class MxMediaManager : public MxCore {
|
|||||||
MxMediaManager();
|
MxMediaManager();
|
||||||
virtual ~MxMediaManager() override;
|
virtual ~MxMediaManager() override;
|
||||||
|
|
||||||
virtual MxResult Tickle() override; // vtable+08
|
virtual MxResult Tickle() override; // vtable+08
|
||||||
virtual MxResult InitPresenters(); // vtable+14
|
virtual MxResult InitPresenters(); // vtable+14
|
||||||
virtual void Destroy(); // vtable+18
|
virtual void Destroy(); // vtable+18
|
||||||
virtual void AddPresenter(MxPresenter& p_presenter); // vtable+1c
|
virtual void RegisterPresenter(MxPresenter& p_presenter); // vtable+1c
|
||||||
virtual void RemovePresenter(MxPresenter& p_presenter); // vtable+20
|
virtual void UnregisterPresenter(MxPresenter& p_presenter); // vtable+20
|
||||||
virtual void StopPresenters(); // vtable+24
|
virtual void StopPresenters(); // vtable+24
|
||||||
|
|
||||||
MxResult Init();
|
MxResult Init();
|
||||||
|
|
||||||
|
|||||||
@ -52,4 +52,34 @@ class MxNotificationManager : public MxCore {
|
|||||||
void FlushPending(MxCore* p_listener);
|
void FlushPending(MxCore* p_listener);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TEMPLATE: LEGO1 0x100ac320
|
||||||
|
// list<unsigned int,allocator<unsigned int> >::~list<unsigned int,allocator<unsigned int> >
|
||||||
|
|
||||||
|
// FUNCTION: LEGO1 0x100ac3b0
|
||||||
|
// MxIdList::~MxIdList
|
||||||
|
|
||||||
|
// TEMPLATE: LEGO1 0x100ac400
|
||||||
|
// List<unsigned int>::~List<unsigned int>
|
||||||
|
|
||||||
|
// TEMPLATE: LEGO1 0x100ac540
|
||||||
|
// List<MxNotification *>::~List<MxNotification *>
|
||||||
|
|
||||||
|
// TEMPLATE: LEGO1 0x100ac590
|
||||||
|
// list<MxNotification *,allocator<MxNotification *> >::~list<MxNotification *,allocator<MxNotification *> >
|
||||||
|
|
||||||
|
// TEMPLATE: LEGO1 0x100acbf0
|
||||||
|
// list<MxNotification *,allocator<MxNotification *> >::begin
|
||||||
|
|
||||||
|
// TEMPLATE: LEGO1 0x100acc00
|
||||||
|
// list<MxNotification *,allocator<MxNotification *> >::insert
|
||||||
|
|
||||||
|
// TEMPLATE: LEGO1 0x100acc50
|
||||||
|
// list<MxNotification *,allocator<MxNotification *> >::erase
|
||||||
|
|
||||||
|
// TEMPLATE: LEGO1 0x100acca0
|
||||||
|
// list<MxNotification *,allocator<MxNotification *> >::_Buynode
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x100accd0
|
||||||
|
// MxNotificationPtrList::~MxNotificationPtrList
|
||||||
|
|
||||||
#endif // MXNOTIFICATIONMANAGER_H
|
#endif // MXNOTIFICATIONMANAGER_H
|
||||||
|
|||||||
@ -34,14 +34,13 @@ enum NotificationId {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// VTABLE: LEGO1 0x100d56e0
|
// VTABLE: LEGO1 0x100d56e0
|
||||||
|
// SIZE 0x0c
|
||||||
class MxNotificationParam : public MxParam {
|
class MxNotificationParam : public MxParam {
|
||||||
public:
|
public:
|
||||||
inline MxNotificationParam(NotificationId p_type, MxCore* p_sender) : MxParam(), m_type(p_type), m_sender(p_sender)
|
inline MxNotificationParam(NotificationId p_type, MxCore* p_sender) : MxParam(), m_type(p_type), m_sender(p_sender)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~MxNotificationParam() override {}
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x10010390
|
// FUNCTION: LEGO1 0x10010390
|
||||||
virtual MxNotificationParam* Clone() { return new MxNotificationParam(m_type, m_sender); }; // vtable+0x4
|
virtual MxNotificationParam* Clone() { return new MxNotificationParam(m_type, m_sender); }; // vtable+0x4
|
||||||
|
|
||||||
@ -50,8 +49,14 @@ class MxNotificationParam : public MxParam {
|
|||||||
inline NotificationId GetType() const { return m_type; }
|
inline NotificationId GetType() const { return m_type; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
NotificationId m_type; // 0x4
|
NotificationId m_type; // 0x04
|
||||||
MxCore* m_sender; // 0x8
|
MxCore* m_sender; // 0x08
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x10010430
|
||||||
|
// MxNotificationParam::`scalar deleting destructor'
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x100104a0
|
||||||
|
// MxNotificationParam::~MxNotificationParam
|
||||||
|
|
||||||
#endif // MXNOTIFICATIONPARAM_H
|
#endif // MXNOTIFICATIONPARAM_H
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
|
// VTABLE: LEGO1 0x100dc218
|
||||||
class MxOmniCreateParam : public MxParam {
|
class MxOmniCreateParam : public MxParam {
|
||||||
public:
|
public:
|
||||||
__declspec(dllexport) MxOmniCreateParam(
|
__declspec(dllexport) MxOmniCreateParam(
|
||||||
@ -30,4 +31,7 @@ class MxOmniCreateParam : public MxParam {
|
|||||||
MxOmniCreateFlags m_createFlags;
|
MxOmniCreateFlags m_createFlags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// SYNTHETIC: ISLE 0x4014b0
|
||||||
|
// MxOmniCreateParam::~MxOmniCreateParam
|
||||||
|
|
||||||
#endif // MXOMNICREATEPARAM_H
|
#endif // MXOMNICREATEPARAM_H
|
||||||
|
|||||||
@ -1,9 +1,18 @@
|
|||||||
#ifndef MXPARAM_H
|
#ifndef MXPARAM_H
|
||||||
#define MXPARAM_H
|
#define MXPARAM_H
|
||||||
|
|
||||||
|
// VTABLE: ISLE 0x40f018
|
||||||
|
// VTABLE: LEGO1 0x100d56e8
|
||||||
|
// SIZE 0x04
|
||||||
class MxParam {
|
class MxParam {
|
||||||
public:
|
public:
|
||||||
|
// FUNCTION: ISLE 0x401530
|
||||||
|
// FUNCTION: LEGO1 0x10010360
|
||||||
virtual ~MxParam() {}
|
virtual ~MxParam() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// SYNTHETIC: ISLE 0x401540
|
||||||
|
// SYNTHETIC: LEGO1 0x10010370
|
||||||
|
// MxParam::`scalar deleting destructor'
|
||||||
|
|
||||||
#endif // MXPARAM_H
|
#endif // MXPARAM_H
|
||||||
|
|||||||
@ -115,7 +115,7 @@ class MxPresenter : public MxCore {
|
|||||||
|
|
||||||
__declspec(dllexport) virtual void Enable(MxBool p_enable); // vtable+0x54
|
__declspec(dllexport) virtual void Enable(MxBool p_enable); // vtable+0x54
|
||||||
|
|
||||||
MxEntity* CreateEntityBackend(const char* p_name);
|
MxEntity* CreateEntity(const char* p_name);
|
||||||
MxBool IsEnabled();
|
MxBool IsEnabled();
|
||||||
|
|
||||||
inline MxS32 GetCurrentTickleState() const { return this->m_currentTickleState; }
|
inline MxS32 GetCurrentTickleState() const { return this->m_currentTickleState; }
|
||||||
|
|||||||
@ -53,6 +53,9 @@ class MxPresenterListCursor : public MxPtrListCursor<MxPresenter> {
|
|||||||
// TEMPLATE: LEGO1 0x1001ce20
|
// TEMPLATE: LEGO1 0x1001ce20
|
||||||
// MxList<MxPresenter *>::~MxList<MxPresenter *>
|
// MxList<MxPresenter *>::~MxList<MxPresenter *>
|
||||||
|
|
||||||
|
// TEMPLATE: LEGO1 0x1001cf20
|
||||||
|
// MxPtrList<MxPresenter>::~MxPtrList<MxPresenter>
|
||||||
|
|
||||||
// SYNTHETIC: LEGO1 0x1001cf70
|
// SYNTHETIC: LEGO1 0x1001cf70
|
||||||
// MxCollection<MxPresenter *>::`scalar deleting destructor'
|
// MxCollection<MxPresenter *>::`scalar deleting destructor'
|
||||||
|
|
||||||
|
|||||||
@ -53,6 +53,9 @@ class MxRectListCursor : public MxPtrListCursor<MxRect32> {
|
|||||||
// SYNTHETIC: LEGO1 0x100b3d80
|
// SYNTHETIC: LEGO1 0x100b3d80
|
||||||
// MxRectList::`scalar deleting destructor'
|
// MxRectList::`scalar deleting destructor'
|
||||||
|
|
||||||
|
// TEMPLATE: LEGO1 0x100b3df0
|
||||||
|
// MxPtrList<MxRect32>::~MxPtrList<MxRect32>
|
||||||
|
|
||||||
// SYNTHETIC: LEGO1 0x100b3e40
|
// SYNTHETIC: LEGO1 0x100b3e40
|
||||||
// MxCollection<MxRect32 *>::`scalar deleting destructor'
|
// MxCollection<MxRect32 *>::`scalar deleting destructor'
|
||||||
|
|
||||||
|
|||||||
@ -116,12 +116,21 @@ class MxRegionTopBottomListCursor : public MxPtrListCursor<MxRegionTopBottom> {
|
|||||||
// TEMPLATE: LEGO1 0x100c32e0
|
// TEMPLATE: LEGO1 0x100c32e0
|
||||||
// MxCollection<MxRegionTopBottom *>::Compare
|
// MxCollection<MxRegionTopBottom *>::Compare
|
||||||
|
|
||||||
|
// TEMPLATE: LEGO1 0x100c32f0
|
||||||
|
// MxCollection<MxRegionTopBottom *>::~MxCollection<MxRegionTopBottom *>
|
||||||
|
|
||||||
// TEMPLATE: LEGO1 0x100c3340
|
// TEMPLATE: LEGO1 0x100c3340
|
||||||
// MxCollection<MxRegionTopBottom *>::Destroy
|
// MxCollection<MxRegionTopBottom *>::Destroy
|
||||||
|
|
||||||
|
// TEMPLATE: LEGO1 0x100c3350
|
||||||
|
// MxList<MxRegionTopBottom *>::~MxList<MxRegionTopBottom *>
|
||||||
|
|
||||||
// TEMPLATE: LEGO1 0x100c33e0
|
// TEMPLATE: LEGO1 0x100c33e0
|
||||||
// MxPtrList<MxRegionTopBottom>::Destroy
|
// MxPtrList<MxRegionTopBottom>::Destroy
|
||||||
|
|
||||||
|
// TEMPLATE: LEGO1 0x100c3480
|
||||||
|
// MxPtrList<MxRegionTopBottom>::~MxPtrList<MxRegionTopBottom>
|
||||||
|
|
||||||
// SYNTHETIC: LEGO1 0x100c34d0
|
// SYNTHETIC: LEGO1 0x100c34d0
|
||||||
// MxCollection<MxRegionTopBottom *>::`scalar deleting destructor'
|
// MxCollection<MxRegionTopBottom *>::`scalar deleting destructor'
|
||||||
|
|
||||||
@ -167,9 +176,18 @@ class MxRegionTopBottomListCursor : public MxPtrListCursor<MxRegionTopBottom> {
|
|||||||
// TEMPLATE: LEGO1 0x100c4d80
|
// TEMPLATE: LEGO1 0x100c4d80
|
||||||
// MxCollection<MxRegionLeftRight *>::Compare
|
// MxCollection<MxRegionLeftRight *>::Compare
|
||||||
|
|
||||||
|
// TEMPLATE: LEGO1 0x100c4d90
|
||||||
|
// MxCollection<MxRegionLeftRight *>::~MxCollection<MxRegionLeftRight *>
|
||||||
|
|
||||||
// TEMPLATE: LEGO1 0x100c4de0
|
// TEMPLATE: LEGO1 0x100c4de0
|
||||||
// MxCollection<MxRegionLeftRight *>::Destroy
|
// MxCollection<MxRegionLeftRight *>::Destroy
|
||||||
|
|
||||||
|
// TEMPLATE: LEGO1 0x100c4df0
|
||||||
|
// MxList<MxRegionLeftRight *>::~MxList<MxRegionLeftRight *>
|
||||||
|
|
||||||
|
// TEMPLATE: LEGO1 0x100c4f00
|
||||||
|
// MxPtrList<MxRegionLeftRight>::~MxPtrList<MxRegionLeftRight>
|
||||||
|
|
||||||
// SYNTHETIC: LEGO1 0x100c4f50
|
// SYNTHETIC: LEGO1 0x100c4f50
|
||||||
// MxCollection<MxRegionLeftRight *>::`scalar deleting destructor'
|
// MxCollection<MxRegionLeftRight *>::`scalar deleting destructor'
|
||||||
|
|
||||||
|
|||||||
@ -5,12 +5,13 @@
|
|||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
|
// VTABLE: LEGO1 0x100dccf0
|
||||||
// SIZE 0x08
|
// SIZE 0x08
|
||||||
class MxSemaphore {
|
class MxSemaphore {
|
||||||
public:
|
public:
|
||||||
MxSemaphore();
|
MxSemaphore();
|
||||||
|
|
||||||
// Inlined only, no offset
|
// FUNCTION: LEGO1 0x100c87e0
|
||||||
~MxSemaphore() { CloseHandle(m_hSemaphore); }
|
~MxSemaphore() { CloseHandle(m_hSemaphore); }
|
||||||
|
|
||||||
virtual MxResult Init(MxU32 p_initialCount, MxU32 p_maxCount);
|
virtual MxResult Init(MxU32 p_initialCount, MxU32 p_maxCount);
|
||||||
|
|||||||
@ -41,6 +41,9 @@ class MxStreamChunkListCursor : public MxListCursor<MxStreamChunk*> {
|
|||||||
// TEMPLATE: LEGO1 0x100b5930
|
// TEMPLATE: LEGO1 0x100b5930
|
||||||
// MxCollection<MxStreamChunk *>::Compare
|
// MxCollection<MxStreamChunk *>::Compare
|
||||||
|
|
||||||
|
// TEMPLATE: LEGO1 0x100b5940
|
||||||
|
// MxCollection<MxStreamChunk *>::~MxCollection<MxStreamChunk *>
|
||||||
|
|
||||||
// TEMPLATE: LEGO1 0x100b5990
|
// TEMPLATE: LEGO1 0x100b5990
|
||||||
// MxCollection<MxStreamChunk *>::Destroy
|
// MxCollection<MxStreamChunk *>::Destroy
|
||||||
|
|
||||||
|
|||||||
@ -24,6 +24,7 @@ class MxStreamerSubClass1 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FUNCTION: LEGO1 0x100b9110
|
||||||
~MxStreamerSubClass1() { delete[] m_buffer; }
|
~MxStreamerSubClass1() { delete[] m_buffer; }
|
||||||
|
|
||||||
undefined4 GetSize() const { return m_size; }
|
undefined4 GetSize() const { return m_size; }
|
||||||
@ -48,6 +49,7 @@ class MxStreamerSubClass3 : public MxStreamerSubClass1 {
|
|||||||
inline MxStreamerSubClass3() : MxStreamerSubClass1(0x80) {}
|
inline MxStreamerSubClass3() : MxStreamerSubClass1(0x80) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// VTABLE: LEGO1 0x100dc760
|
||||||
class MxStreamerNotification : public MxNotificationParam {
|
class MxStreamerNotification : public MxNotificationParam {
|
||||||
public:
|
public:
|
||||||
inline MxStreamerNotification(NotificationId p_type, MxCore* p_sender, MxStreamController* p_ctrlr)
|
inline MxStreamerNotification(NotificationId p_type, MxCore* p_sender, MxStreamController* p_ctrlr)
|
||||||
@ -56,8 +58,6 @@ class MxStreamerNotification : public MxNotificationParam {
|
|||||||
m_controller = p_ctrlr;
|
m_controller = p_ctrlr;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~MxStreamerNotification() override {}
|
|
||||||
|
|
||||||
virtual MxNotificationParam* Clone() override;
|
virtual MxNotificationParam* Clone() override;
|
||||||
|
|
||||||
MxStreamController* GetController() { return m_controller; }
|
MxStreamController* GetController() { return m_controller; }
|
||||||
@ -113,7 +113,21 @@ class MxStreamer : public MxCore {
|
|||||||
MxStreamerSubClass3 m_subclass2; // 0x20
|
MxStreamerSubClass3 m_subclass2; // 0x20
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
// TEMPLATE: LEGO1 0x100b9090
|
||||||
|
// list<MxStreamController *,allocator<MxStreamController *> >::~list<MxStreamController *,allocator<MxStreamController *> >
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
// SYNTHETIC: LEGO1 0x100b9120
|
// SYNTHETIC: LEGO1 0x100b9120
|
||||||
// MxStreamer::`scalar deleting destructor'
|
// MxStreamer::`scalar deleting destructor'
|
||||||
|
|
||||||
|
// TEMPLATE: LEGO1 0x100b9140
|
||||||
|
// List<MxStreamController *>::~List<MxStreamController *>
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x100b97b0
|
||||||
|
// MxStreamerNotification::`scalar deleting destructor'
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x100b9820
|
||||||
|
// MxStreamerNotification::~MxStreamerNotification
|
||||||
|
|
||||||
#endif // MXSTREAMER_H
|
#endif // MXSTREAMER_H
|
||||||
|
|||||||
@ -41,4 +41,7 @@ class MxStreamProvider : public MxCore {
|
|||||||
// SYNTHETIC: LEGO1 0x100d0870
|
// SYNTHETIC: LEGO1 0x100d0870
|
||||||
// MxStreamProvider::`scalar deleting destructor'
|
// MxStreamProvider::`scalar deleting destructor'
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x100d08e0
|
||||||
|
// MxStreamProvider::~MxStreamProvider
|
||||||
|
|
||||||
#endif // MXSTREAMPROVIDER_H
|
#endif // MXSTREAMPROVIDER_H
|
||||||
|
|||||||
@ -15,18 +15,33 @@ class MxStringListCursor : public MxListCursor<MxString> {
|
|||||||
MxStringListCursor(MxStringList* p_list) : MxListCursor<MxString>(p_list){};
|
MxStringListCursor(MxStringList* p_list) : MxListCursor<MxString>(p_list){};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// VTABLE: LEGO1 0x100dd010
|
||||||
|
// class MxCollection<MxString>
|
||||||
|
|
||||||
|
// VTABLE: LEGO1 0x100dd028
|
||||||
|
// class MxList<MxString>
|
||||||
|
|
||||||
// VTABLE: LEGO1 0x100dd070
|
// VTABLE: LEGO1 0x100dd070
|
||||||
// class MxListCursor<MxString>
|
// class MxListCursor<MxString>
|
||||||
|
|
||||||
// TEMPLATE: LEGO1 0x100cb3c0
|
// TEMPLATE: LEGO1 0x100cb3c0
|
||||||
// MxCollection<MxString>::Compare
|
// MxCollection<MxString>::Compare
|
||||||
|
|
||||||
|
// TEMPLATE: LEGO1 0x100cb420
|
||||||
|
// MxCollection<MxString>::~MxCollection<MxString>
|
||||||
|
|
||||||
// TEMPLATE: LEGO1 0x100cb470
|
// TEMPLATE: LEGO1 0x100cb470
|
||||||
// MxCollection<MxString>::Destroy
|
// MxCollection<MxString>::Destroy
|
||||||
|
|
||||||
// TEMPLATE: LEGO1 0x100cb4c0
|
// TEMPLATE: LEGO1 0x100cb4c0
|
||||||
// MxList<MxString>::~MxList<MxString>
|
// MxList<MxString>::~MxList<MxString>
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x100cb590
|
||||||
|
// MxCollection<MxString>::`scalar deleting destructor'
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x100cb600
|
||||||
|
// MxList<MxString>::`scalar deleting destructor'
|
||||||
|
|
||||||
// TEMPLATE: LEGO1 0x100cbb40
|
// TEMPLATE: LEGO1 0x100cbb40
|
||||||
// MxList<MxString>::Append
|
// MxList<MxString>::Append
|
||||||
|
|
||||||
|
|||||||
@ -50,4 +50,10 @@ class MxTickleManager : public MxCore {
|
|||||||
|
|
||||||
#define TICKLE_MANAGER_NOT_FOUND 0x80000000
|
#define TICKLE_MANAGER_NOT_FOUND 0x80000000
|
||||||
|
|
||||||
|
// TEMPLATE: LEGO1 0x1005a4a0
|
||||||
|
// list<MxTickleClient *,allocator<MxTickleClient *> >::~list<MxTickleClient *,allocator<MxTickleClient *> >
|
||||||
|
|
||||||
|
// TEMPLATE: LEGO1 0x1005a530
|
||||||
|
// List<MxTickleClient *>::~List<MxTickleClient *>
|
||||||
|
|
||||||
#endif // MXTICKLEMANAGER_H
|
#endif // MXTICKLEMANAGER_H
|
||||||
|
|||||||
@ -33,8 +33,11 @@ class MxVariable {
|
|||||||
inline const MxString* GetKey() const { return &m_key; }
|
inline const MxString* GetKey() const { return &m_key; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
MxString m_key;
|
MxString m_key; // 0x04
|
||||||
MxString m_value;
|
MxString m_value; // 0x14
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x1003bf40
|
||||||
|
// MxVariable::~MxVariable
|
||||||
|
|
||||||
#endif // MXVARIABLE_H
|
#endif // MXVARIABLE_H
|
||||||
|
|||||||
@ -26,6 +26,9 @@ class MxVariableTable : public MxHashTable<MxVariable*> {
|
|||||||
// VTABLE: LEGO1 0x100dc1e8
|
// VTABLE: LEGO1 0x100dc1e8
|
||||||
// class MxHashTable<MxVariable *>
|
// class MxHashTable<MxVariable *>
|
||||||
|
|
||||||
|
// VTABLE: LEGO1 0x100dc680
|
||||||
|
// class MxHashTableCursor<MxVariable *>
|
||||||
|
|
||||||
// TEMPLATE: LEGO1 0x100afcd0
|
// TEMPLATE: LEGO1 0x100afcd0
|
||||||
// MxCollection<MxVariable *>::Compare
|
// MxCollection<MxVariable *>::Compare
|
||||||
|
|
||||||
@ -50,6 +53,9 @@ class MxVariableTable : public MxHashTable<MxVariable*> {
|
|||||||
// SYNTHETIC: LEGO1 0x100b0ca0
|
// SYNTHETIC: LEGO1 0x100b0ca0
|
||||||
// MxHashTable<MxVariable *>::`scalar deleting destructor'
|
// MxHashTable<MxVariable *>::`scalar deleting destructor'
|
||||||
|
|
||||||
|
// TEMPLATE: LEGO1 0x100b7680
|
||||||
|
// MxHashTableCursor<MxVariable *>::~MxHashTableCursor<MxVariable *>
|
||||||
|
|
||||||
// TEMPLATE: LEGO1 0x100b7ab0
|
// TEMPLATE: LEGO1 0x100b7ab0
|
||||||
// MxHashTable<MxVariable *>::Resize
|
// MxHashTable<MxVariable *>::Resize
|
||||||
|
|
||||||
|
|||||||
@ -80,6 +80,7 @@ class MxVideoPresenter : public MxMediaPresenter {
|
|||||||
// FUNCTION: LEGO1 0x1000c800
|
// FUNCTION: LEGO1 0x1000c800
|
||||||
virtual MxS32 GetHeight() { return m_alpha ? m_alpha->m_height : m_bitmap->GetBmiHeightAbs(); }; // vtable+0x84
|
virtual MxS32 GetHeight() { return m_alpha ? m_alpha->m_height : m_bitmap->GetBmiHeightAbs(); }; // vtable+0x84
|
||||||
|
|
||||||
|
// VTABLE: LEGO1 0x100dc2bc
|
||||||
// SIZE 0xc
|
// SIZE 0xc
|
||||||
struct AlphaMask {
|
struct AlphaMask {
|
||||||
MxU8* m_bitmask;
|
MxU8* m_bitmask;
|
||||||
|
|||||||
@ -88,6 +88,12 @@ void MxDSAction::CopyFrom(MxDSAction& p_dsAction)
|
|||||||
this->m_unk0x90 = p_dsAction.m_unk0x90;
|
this->m_unk0x90 = p_dsAction.m_unk0x90;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FUNCTION: LEGO1 0x100adbd0
|
||||||
|
undefined4 MxDSAction::VTable0x14()
|
||||||
|
{
|
||||||
|
return MxDSObject::VTable0x14();
|
||||||
|
}
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100adbe0
|
// FUNCTION: LEGO1 0x100adbe0
|
||||||
MxU32 MxDSAction::GetSizeOnDisk()
|
MxU32 MxDSAction::GetSizeOnDisk()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -27,7 +27,7 @@ void MxMusicPresenter::Init()
|
|||||||
void MxMusicPresenter::Destroy(MxBool p_fromDestructor)
|
void MxMusicPresenter::Destroy(MxBool p_fromDestructor)
|
||||||
{
|
{
|
||||||
if (MusicManager()) {
|
if (MusicManager()) {
|
||||||
MusicManager()->RemovePresenter(*this);
|
MusicManager()->UnregisterPresenter(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_criticalSection.Enter();
|
m_criticalSection.Enter();
|
||||||
@ -46,7 +46,7 @@ MxResult MxMusicPresenter::AddToManager()
|
|||||||
|
|
||||||
if (MusicManager()) {
|
if (MusicManager()) {
|
||||||
result = SUCCESS;
|
result = SUCCESS;
|
||||||
MusicManager()->AddPresenter(*this);
|
MusicManager()->RegisterPresenter(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@ -9,7 +9,7 @@ DECOMP_SIZE_ASSERT(MxSoundPresenter, 0x54)
|
|||||||
void MxSoundPresenter::Destroy(MxBool p_fromDestructor)
|
void MxSoundPresenter::Destroy(MxBool p_fromDestructor)
|
||||||
{
|
{
|
||||||
if (MSoundManager())
|
if (MSoundManager())
|
||||||
MSoundManager()->RemovePresenter(*this);
|
MSoundManager()->UnregisterPresenter(*this);
|
||||||
|
|
||||||
this->m_criticalSection.Enter();
|
this->m_criticalSection.Enter();
|
||||||
MxMediaPresenter::Init();
|
MxMediaPresenter::Init();
|
||||||
@ -26,7 +26,7 @@ MxResult MxSoundPresenter::AddToManager()
|
|||||||
|
|
||||||
if (MSoundManager()) {
|
if (MSoundManager()) {
|
||||||
ret = SUCCESS;
|
ret = SUCCESS;
|
||||||
MSoundManager()->AddPresenter(*this);
|
MSoundManager()->RegisterPresenter(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
@ -75,7 +75,7 @@ MxResult MxMediaManager::Tickle()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100b88c0
|
// FUNCTION: LEGO1 0x100b88c0
|
||||||
void MxMediaManager::AddPresenter(MxPresenter& p_presenter)
|
void MxMediaManager::RegisterPresenter(MxPresenter& p_presenter)
|
||||||
{
|
{
|
||||||
MxAutoLocker lock(&this->m_criticalSection);
|
MxAutoLocker lock(&this->m_criticalSection);
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ void MxMediaManager::AddPresenter(MxPresenter& p_presenter)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100b8980
|
// FUNCTION: LEGO1 0x100b8980
|
||||||
void MxMediaManager::RemovePresenter(MxPresenter& p_presenter)
|
void MxMediaManager::UnregisterPresenter(MxPresenter& p_presenter)
|
||||||
{
|
{
|
||||||
MxAutoLocker lock(&this->m_criticalSection);
|
MxAutoLocker lock(&this->m_criticalSection);
|
||||||
MxPresenterListCursor cursor(this->m_presenters);
|
MxPresenterListCursor cursor(this->m_presenters);
|
||||||
|
|||||||
@ -229,7 +229,7 @@ const char* PresenterNameDispatch(const MxDSAction& p_action)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100b5410
|
// FUNCTION: LEGO1 0x100b5410
|
||||||
MxEntity* MxPresenter::CreateEntityBackend(const char* p_name)
|
MxEntity* MxPresenter::CreateEntity(const char* p_name)
|
||||||
{
|
{
|
||||||
char buffer[512];
|
char buffer[512];
|
||||||
char buffer2[512];
|
char buffer2[512];
|
||||||
|
|||||||
@ -33,7 +33,7 @@ MxResult MxEventPresenter::AddToManager()
|
|||||||
|
|
||||||
if (EventManager()) {
|
if (EventManager()) {
|
||||||
ret = SUCCESS;
|
ret = SUCCESS;
|
||||||
EventManager()->AddPresenter(*this);
|
EventManager()->RegisterPresenter(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -43,7 +43,7 @@ MxResult MxEventPresenter::AddToManager()
|
|||||||
void MxEventPresenter::Destroy()
|
void MxEventPresenter::Destroy()
|
||||||
{
|
{
|
||||||
if (EventManager())
|
if (EventManager())
|
||||||
EventManager()->RemovePresenter(*this);
|
EventManager()->UnregisterPresenter(*this);
|
||||||
|
|
||||||
m_criticalSection.Enter();
|
m_criticalSection.Enter();
|
||||||
|
|
||||||
@ -78,7 +78,7 @@ void MxEventPresenter::ReadyTickle()
|
|||||||
// FUNCTION: LEGO1 0x100c2eb0
|
// FUNCTION: LEGO1 0x100c2eb0
|
||||||
void MxEventPresenter::StartingTickle()
|
void MxEventPresenter::StartingTickle()
|
||||||
{
|
{
|
||||||
MxStreamChunk* chunk = NextChunk();
|
MxStreamChunk* chunk = CurrentChunk();
|
||||||
|
|
||||||
if (chunk && m_action->GetElapsedTime() >= chunk->GetTime())
|
if (chunk && m_action->GetElapsedTime() >= chunk->GetTime())
|
||||||
ProgressTickleState(TickleState_Streaming);
|
ProgressTickleState(TickleState_Streaming);
|
||||||
|
|||||||
@ -215,18 +215,20 @@ void MxDiskStreamProvider::PerformWork()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MxDSBuffer* buffer;
|
||||||
|
|
||||||
{
|
{
|
||||||
MxAutoLocker lock(&m_criticalSection);
|
MxAutoLocker lock(&m_criticalSection);
|
||||||
|
|
||||||
if (!m_list.PopFrontStreamingAction(streamingAction))
|
if (!m_list.PopFrontStreamingAction(streamingAction))
|
||||||
return;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (streamingAction->GetUnknowna0()->GetWriteOffset() < 0x20000) {
|
if (streamingAction->GetUnknowna0()->GetWriteOffset() < 0x20000) {
|
||||||
g_unk0x10102878--;
|
g_unk0x10102878--;
|
||||||
}
|
}
|
||||||
|
|
||||||
MxDSBuffer* buffer = streamingAction->GetUnknowna0();
|
buffer = streamingAction->GetUnknowna0();
|
||||||
|
|
||||||
if (m_pFile->GetPosition() == streamingAction->GetBufferOffset() ||
|
if (m_pFile->GetPosition() == streamingAction->GetBufferOffset() ||
|
||||||
m_pFile->Seek(streamingAction->GetBufferOffset(), 0) == 0) {
|
m_pFile->Seek(streamingAction->GetBufferOffset(), 0) == 0) {
|
||||||
@ -251,6 +253,7 @@ void MxDiskStreamProvider::PerformWork()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
if (streamingAction) {
|
if (streamingAction) {
|
||||||
controller->FUN_100c8670(streamingAction);
|
controller->FUN_100c8670(streamingAction);
|
||||||
}
|
}
|
||||||
@ -349,6 +352,8 @@ MxResult MxDiskStreamProvider::FUN_100d1b20(MxDSStreamingAction* p_action)
|
|||||||
p_action->SetUnknown94(unk0x14);
|
p_action->SetUnknown94(unk0x14);
|
||||||
p_action->SetBufferOffset(p_action->GetUnknowna0()->GetUnknown14());
|
p_action->SetBufferOffset(p_action->GetUnknowna0()->GetUnknown14());
|
||||||
delete p_action->GetUnknowna0();
|
delete p_action->GetUnknowna0();
|
||||||
|
p_action->SetUnknowna0(NULL);
|
||||||
|
((MxDiskStreamController*) m_pLookup)->FUN_100c7890(p_action);
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@ -47,12 +47,12 @@ MxRAMStreamProvider::~MxRAMStreamProvider()
|
|||||||
m_bufferSize = 0;
|
m_bufferSize = 0;
|
||||||
m_fileSize = 0;
|
m_fileSize = 0;
|
||||||
|
|
||||||
free(m_pBufferOfFileSize);
|
delete[] m_pBufferOfFileSize;
|
||||||
m_pBufferOfFileSize = NULL;
|
m_pBufferOfFileSize = NULL;
|
||||||
|
|
||||||
m_lengthInDWords = 0;
|
m_lengthInDWords = 0;
|
||||||
|
|
||||||
free(m_bufferForDWords);
|
delete[] m_bufferForDWords;
|
||||||
m_bufferForDWords = NULL;
|
m_bufferForDWords = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
DECOMP_SIZE_ASSERT(MxDisplaySurface, 0xac);
|
DECOMP_SIZE_ASSERT(MxDisplaySurface, 0xac);
|
||||||
|
|
||||||
|
// GLOBAL: LEGO1 0x1010215c
|
||||||
MxU32 g_unk0x1010215c = 0;
|
MxU32 g_unk0x1010215c = 0;
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100ba500
|
// FUNCTION: LEGO1 0x100ba500
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
DECOMP_SIZE_ASSERT(MxStillPresenter, 0x6c);
|
DECOMP_SIZE_ASSERT(MxStillPresenter, 0x6c);
|
||||||
|
|
||||||
// GLOBAL: LEGO1 0x10101eb0
|
// GLOBAL: LEGO1 0x101020e0
|
||||||
const char* g_strBmpIsmap = "BMP_ISMAP";
|
const char* g_strBmpIsmap = "BMP_ISMAP";
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100b9c70
|
// FUNCTION: LEGO1 0x100b9c70
|
||||||
@ -164,7 +164,7 @@ void MxStillPresenter::VTable0x88(MxS32 p_x, MxS32 p_y)
|
|||||||
// FUNCTION: LEGO1 0x100ba140
|
// FUNCTION: LEGO1 0x100ba140
|
||||||
void MxStillPresenter::Enable(MxBool p_enable)
|
void MxStillPresenter::Enable(MxBool p_enable)
|
||||||
{
|
{
|
||||||
MxVideoPresenter::Enable(p_enable);
|
MxPresenter::Enable(p_enable);
|
||||||
|
|
||||||
if (MVideoManager() && (m_alpha || m_bitmap)) {
|
if (MVideoManager() && (m_alpha || m_bitmap)) {
|
||||||
// MxRect32 rect(m_location, MxSize32(GetWidth(), GetHeight()));
|
// MxRect32 rect(m_location, MxSize32(GetWidth(), GetHeight()));
|
||||||
|
|||||||
@ -133,7 +133,7 @@ void MxVideoPresenter::Init()
|
|||||||
void MxVideoPresenter::Destroy(MxBool p_fromDestructor)
|
void MxVideoPresenter::Destroy(MxBool p_fromDestructor)
|
||||||
{
|
{
|
||||||
if (MVideoManager() != NULL)
|
if (MVideoManager() != NULL)
|
||||||
MVideoManager()->RemovePresenter(*this);
|
MVideoManager()->UnregisterPresenter(*this);
|
||||||
|
|
||||||
if (m_unk0x58) {
|
if (m_unk0x58) {
|
||||||
m_unk0x58->Release();
|
m_unk0x58->Release();
|
||||||
@ -504,7 +504,7 @@ MxResult MxVideoPresenter::AddToManager()
|
|||||||
|
|
||||||
if (MVideoManager()) {
|
if (MVideoManager()) {
|
||||||
result = SUCCESS;
|
result = SUCCESS;
|
||||||
MVideoManager()->AddPresenter(*this);
|
MVideoManager()->RegisterPresenter(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@ -32,9 +32,6 @@ class OrientableROI : public ROI {
|
|||||||
const float* GetWorldDirection() const { return m_local2world[2]; }
|
const float* GetWorldDirection() const { return m_local2world[2]; }
|
||||||
const float* GetWorldUp() const { return m_local2world[1]; }
|
const float* GetWorldUp() const { return m_local2world[1]; }
|
||||||
|
|
||||||
// SYNTHETIC: LEGO1 0x100a4630
|
|
||||||
// OrientableROI::`scalar deleting destructor'
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
MxMatrix m_local2world; // 0x10
|
MxMatrix m_local2world; // 0x10
|
||||||
BoundingBox m_world_bounding_box; // 0x58
|
BoundingBox m_world_bounding_box; // 0x58
|
||||||
@ -52,4 +49,10 @@ class OrientableROI : public ROI {
|
|||||||
undefined4 m_unk0xd8; // 0xd8
|
undefined4 m_unk0xd8; // 0xd8
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x100a4630
|
||||||
|
// OrientableROI::`scalar deleting destructor'
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x100aa2f0
|
||||||
|
// OrientableROI::~OrientableROI
|
||||||
|
|
||||||
#endif // ORIENTABLEROI_H
|
#endif // ORIENTABLEROI_H
|
||||||
|
|||||||
@ -30,8 +30,7 @@ void RealtimeView::SetPartsThreshold(float p_threshold)
|
|||||||
// FUNCTION: LEGO1 0x100a5e00
|
// FUNCTION: LEGO1 0x100a5e00
|
||||||
float RealtimeView::GetUserMaxLOD()
|
float RealtimeView::GetUserMaxLOD()
|
||||||
{
|
{
|
||||||
// TODO
|
return g_userMaxLod;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x100a5e10
|
// FUNCTION: LEGO1 0x100a5e10
|
||||||
|
|||||||
@ -108,4 +108,8 @@ class ROI {
|
|||||||
LODListBase* m_lods; // 0x8
|
LODListBase* m_lods; // 0x8
|
||||||
undefined m_unk0xc; // 0xc
|
undefined m_unk0xc; // 0xc
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// SYNTHETIC: LEGO1 0x100a5d50
|
||||||
|
// ROI::~ROI
|
||||||
|
|
||||||
#endif // ROI_H
|
#endif // ROI_H
|
||||||
|
|||||||
@ -36,7 +36,7 @@ class MeshImpl;
|
|||||||
class TextureImpl;
|
class TextureImpl;
|
||||||
class UnkImpl;
|
class UnkImpl;
|
||||||
|
|
||||||
// VTABLE 0x100db910
|
// VTABLE: LEGO1 0x100db910
|
||||||
class RendererImpl : public Renderer {
|
class RendererImpl : public Renderer {
|
||||||
public:
|
public:
|
||||||
RendererImpl() : m_data(0) {}
|
RendererImpl() : m_data(0) {}
|
||||||
@ -105,7 +105,7 @@ void RendererImpl::Destroy()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// VTABLE 0x100db988
|
// VTABLE: LEGO1 0x100db988
|
||||||
class DeviceImpl : public Device {
|
class DeviceImpl : public Device {
|
||||||
public:
|
public:
|
||||||
DeviceImpl() : m_data(0) {}
|
DeviceImpl() : m_data(0) {}
|
||||||
@ -142,7 +142,7 @@ class DeviceImpl : public Device {
|
|||||||
IDirect3DRMDevice2* m_data;
|
IDirect3DRMDevice2* m_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
// VTABLE 0x100db9e8
|
// VTABLE: LEGO1 0x100db9e8
|
||||||
class ViewImpl : public View {
|
class ViewImpl : public View {
|
||||||
public:
|
public:
|
||||||
ViewImpl() : m_data(0) {}
|
ViewImpl() : m_data(0) {}
|
||||||
@ -194,7 +194,7 @@ class ViewImpl : public View {
|
|||||||
IDirect3DRMViewport* m_data;
|
IDirect3DRMViewport* m_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
// VTABLE 0x100dbad8
|
// VTABLE: LEGO1 0x100dbad8
|
||||||
class CameraImpl : public Camera {
|
class CameraImpl : public Camera {
|
||||||
public:
|
public:
|
||||||
CameraImpl() : m_data(0) {}
|
CameraImpl() : m_data(0) {}
|
||||||
@ -219,7 +219,7 @@ class CameraImpl : public Camera {
|
|||||||
IDirect3DRMFrame2* m_data;
|
IDirect3DRMFrame2* m_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
// VTABLE 0x100dbaf8
|
// VTABLE: LEGO1 0x100dbaf8
|
||||||
class LightImpl : public Light {
|
class LightImpl : public Light {
|
||||||
public:
|
public:
|
||||||
LightImpl() : m_data(0) {}
|
LightImpl() : m_data(0) {}
|
||||||
@ -245,7 +245,7 @@ class LightImpl : public Light {
|
|||||||
IDirect3DRMFrame2* m_data;
|
IDirect3DRMFrame2* m_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
// VTABLE 0x100dbb88
|
// VTABLE: LEGO1 0x100dbb88
|
||||||
class MeshImpl : public Mesh {
|
class MeshImpl : public Mesh {
|
||||||
public:
|
public:
|
||||||
MeshImpl() : m_data(0) {}
|
MeshImpl() : m_data(0) {}
|
||||||
@ -285,7 +285,7 @@ class MeshImpl : public Mesh {
|
|||||||
MeshData* m_data;
|
MeshData* m_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
// VTABLE 0x100dba68
|
// VTABLE: LEGO1 0x100dba68
|
||||||
class GroupImpl : public Group {
|
class GroupImpl : public Group {
|
||||||
public:
|
public:
|
||||||
GroupImpl() : m_data(0) {}
|
GroupImpl() : m_data(0) {}
|
||||||
@ -324,7 +324,7 @@ class GroupImpl : public Group {
|
|||||||
IDirect3DRMFrame2* m_data;
|
IDirect3DRMFrame2* m_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
// VTABLE 0x100dbb18
|
// VTABLE: LEGO1 0x100dbb18
|
||||||
class UnkImpl : public Unk {
|
class UnkImpl : public Unk {
|
||||||
public:
|
public:
|
||||||
UnkImpl() : m_data(0) {}
|
UnkImpl() : m_data(0) {}
|
||||||
@ -384,7 +384,7 @@ class TglD3DRMIMAGE {
|
|||||||
int m_texelsAllocatedByClient;
|
int m_texelsAllocatedByClient;
|
||||||
};
|
};
|
||||||
|
|
||||||
// VTABLE 0x100dbb48
|
// VTABLE: LEGO1 0x100dbb48
|
||||||
class TextureImpl : public Texture {
|
class TextureImpl : public Texture {
|
||||||
public:
|
public:
|
||||||
TextureImpl() : m_data(0) {}
|
TextureImpl() : m_data(0) {}
|
||||||
|
|||||||
@ -98,7 +98,7 @@ class Mesh;
|
|||||||
class Texture;
|
class Texture;
|
||||||
class Unk;
|
class Unk;
|
||||||
|
|
||||||
// VTABLE 0x100db980
|
// VTABLE: LEGO1 0x100db980
|
||||||
class Object {
|
class Object {
|
||||||
public:
|
public:
|
||||||
virtual ~Object() {}
|
virtual ~Object() {}
|
||||||
@ -106,7 +106,7 @@ class Object {
|
|||||||
virtual void* ImplementationDataPtr() = 0;
|
virtual void* ImplementationDataPtr() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// VTABLE 0x100db948
|
// VTABLE: LEGO1 0x100db948
|
||||||
class Renderer : public Object {
|
class Renderer : public Object {
|
||||||
public:
|
public:
|
||||||
// vtable+0x08
|
// vtable+0x08
|
||||||
@ -146,7 +146,7 @@ class Renderer : public Object {
|
|||||||
|
|
||||||
Renderer* CreateRenderer();
|
Renderer* CreateRenderer();
|
||||||
|
|
||||||
// VTABLE 0x100db9b8
|
// VTABLE: LEGO1 0x100db9b8
|
||||||
class Device : public Object {
|
class Device : public Object {
|
||||||
public:
|
public:
|
||||||
// vtable+0x08
|
// vtable+0x08
|
||||||
@ -165,7 +165,7 @@ class Device : public Object {
|
|||||||
virtual void InitFromWindowsDevice(Device*) = 0;
|
virtual void InitFromWindowsDevice(Device*) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// VTABLE 0x100dba28
|
// VTABLE: LEGO1 0x100dba28
|
||||||
class View : public Object {
|
class View : public Object {
|
||||||
public:
|
public:
|
||||||
virtual Result Add(const Light*) = 0;
|
virtual Result Add(const Light*) = 0;
|
||||||
@ -219,20 +219,20 @@ class View : public Object {
|
|||||||
) = 0;
|
) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// VTABLE 0x100dbae8
|
// VTABLE: LEGO1 0x100dbae8
|
||||||
class Camera : public Object {
|
class Camera : public Object {
|
||||||
public:
|
public:
|
||||||
virtual Result SetTransformation(FloatMatrix4&) = 0;
|
virtual Result SetTransformation(FloatMatrix4&) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// VTABLE 0x100dbb08
|
// VTABLE: LEGO1 0x100dbb08
|
||||||
class Light : public Object {
|
class Light : public Object {
|
||||||
public:
|
public:
|
||||||
virtual Result SetTransformation(FloatMatrix4&) = 0;
|
virtual Result SetTransformation(FloatMatrix4&) = 0;
|
||||||
virtual Result SetColor(float r, float g, float b) = 0;
|
virtual Result SetColor(float r, float g, float b) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// VTABLE 0x100dbbb0
|
// VTABLE: LEGO1 0x100dbbb0
|
||||||
class Mesh : public Object {
|
class Mesh : public Object {
|
||||||
public:
|
public:
|
||||||
virtual Result SetColor(float r, float g, float b, float a) = 0;
|
virtual Result SetColor(float r, float g, float b, float a) = 0;
|
||||||
@ -249,7 +249,7 @@ class Mesh : public Object {
|
|||||||
virtual Mesh* ShallowClone(Unk*) = 0;
|
virtual Mesh* ShallowClone(Unk*) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// VTABLE 0x100dbaa0
|
// VTABLE: LEGO1 0x100dbaa0
|
||||||
class Group : public Object {
|
class Group : public Object {
|
||||||
public:
|
public:
|
||||||
virtual Result SetTransformation(FloatMatrix4&) = 0;
|
virtual Result SetTransformation(FloatMatrix4&) = 0;
|
||||||
@ -271,7 +271,7 @@ class Group : public Object {
|
|||||||
// Don't know what this is. Seems like another Tgl object which
|
// Don't know what this is. Seems like another Tgl object which
|
||||||
// was not in the leaked Tgl code. My suspicion is that it's
|
// was not in the leaked Tgl code. My suspicion is that it's
|
||||||
// some kind of builder class for creating meshes.
|
// some kind of builder class for creating meshes.
|
||||||
// VTABLE 0x100dbb30
|
// VTABLE: LEGO1 0x100dbb30
|
||||||
class Unk : public Object {
|
class Unk : public Object {
|
||||||
public:
|
public:
|
||||||
virtual Result SetMeshData(
|
virtual Result SetMeshData(
|
||||||
@ -287,7 +287,7 @@ class Unk : public Object {
|
|||||||
virtual Unk* Clone() = 0;
|
virtual Unk* Clone() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// VTABLE 0x100dbb68
|
// VTABLE: LEGO1 0x100dbb68
|
||||||
class Texture : public Object {
|
class Texture : public Object {
|
||||||
public:
|
public:
|
||||||
// vtable+0x08
|
// vtable+0x08
|
||||||
|
|||||||
@ -93,6 +93,22 @@ class ViewLODListManager {
|
|||||||
ViewLODListMap m_map;
|
ViewLODListMap m_map;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// FUNCTION: LEGO1 0x1001dde0
|
||||||
|
// _Lockit::~_Lockit
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
// TEMPLATE: LEGO1 0x100a7890
|
||||||
|
// _Tree<char const *,pair<char const * const,ViewLODList *>,map<char const *,ViewLODList *,ROINameComparator,allocator<ViewLODList *> >::_Kfn,ROINameComparator,allocator<ViewLODList *> >::~_Tree<char const *,pair<char const * const,ViewLODList *>,map<char c
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
// TEMPLATE: LEGO1 0x100a80a0
|
||||||
|
// map<char const *,ViewLODList *,ROINameComparator,allocator<ViewLODList *> >::~map<char const *,ViewLODList *,ROINameComparator,allocator<ViewLODList *> >
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
// TEMPLATE: LEGO1 0x100a70e0
|
||||||
|
// Map<char const *,ViewLODList *,ROINameComparator>::~Map<char const *,ViewLODList *,ROINameComparator>
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// ViewLODList implementation
|
// ViewLODList implementation
|
||||||
|
|||||||
@ -97,6 +97,8 @@ def __init__(self, filename: str, find_str: bool = False) -> None:
|
|||||||
self.find_str = find_str
|
self.find_str = find_str
|
||||||
self._potential_strings = {}
|
self._potential_strings = {}
|
||||||
self._relocated_addrs = set()
|
self._relocated_addrs = set()
|
||||||
|
self.imports = []
|
||||||
|
self.thunks = []
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
logger.debug("Bin %s Enter", self.filename)
|
logger.debug("Bin %s Enter", self.filename)
|
||||||
@ -132,6 +134,8 @@ def __enter__(self):
|
|||||||
sect.virtual_address += self.imagebase
|
sect.virtual_address += self.imagebase
|
||||||
|
|
||||||
self._populate_relocations()
|
self._populate_relocations()
|
||||||
|
self._populate_imports()
|
||||||
|
self._populate_thunks()
|
||||||
|
|
||||||
# This is a (semi) expensive lookup that is not necesssary in every case.
|
# This is a (semi) expensive lookup that is not necesssary in every case.
|
||||||
# We can find strings in the original if we have coverage using STRING markers.
|
# We can find strings in the original if we have coverage using STRING markers.
|
||||||
@ -238,6 +242,78 @@ def _populate_relocations(self):
|
|||||||
(relocated_addr,) = struct.unpack("<I", self.read(addr, 4))
|
(relocated_addr,) = struct.unpack("<I", self.read(addr, 4))
|
||||||
self._relocated_addrs.add(relocated_addr)
|
self._relocated_addrs.add(relocated_addr)
|
||||||
|
|
||||||
|
def _populate_imports(self):
|
||||||
|
"""Parse .idata to find imported DLLs and their functions."""
|
||||||
|
idata_ofs = self.get_section_offset_by_name(".idata")
|
||||||
|
|
||||||
|
def iter_image_import():
|
||||||
|
ofs = idata_ofs
|
||||||
|
while True:
|
||||||
|
# Read 5 dwords until all are zero.
|
||||||
|
image_import_descriptor = struct.unpack("<5I", self.read(ofs, 20))
|
||||||
|
ofs += 20
|
||||||
|
if all(x == 0 for x in image_import_descriptor):
|
||||||
|
break
|
||||||
|
|
||||||
|
(rva_ilt, _, __, dll_name, rva_iat) = image_import_descriptor
|
||||||
|
# Convert relative virtual addresses into absolute
|
||||||
|
yield (
|
||||||
|
self.imagebase + rva_ilt,
|
||||||
|
self.imagebase + dll_name,
|
||||||
|
self.imagebase + rva_iat,
|
||||||
|
)
|
||||||
|
|
||||||
|
image_import_descriptors = list(iter_image_import())
|
||||||
|
|
||||||
|
def iter_imports():
|
||||||
|
# ILT = Import Lookup Table
|
||||||
|
# IAT = Import Address Table
|
||||||
|
# ILT gives us the symbol name of the import.
|
||||||
|
# IAT gives the address. The compiler generated a thunk function
|
||||||
|
# that jumps to the value of this address.
|
||||||
|
for start_ilt, dll_addr, start_iat in image_import_descriptors:
|
||||||
|
dll_name = self.read_string(dll_addr).decode("ascii")
|
||||||
|
ofs_ilt = start_ilt
|
||||||
|
# Address of "__imp__*" symbols.
|
||||||
|
ofs_iat = start_iat
|
||||||
|
while True:
|
||||||
|
(lookup_addr,) = struct.unpack("<L", self.read(ofs_ilt, 4))
|
||||||
|
(import_addr,) = struct.unpack("<L", self.read(ofs_iat, 4))
|
||||||
|
if lookup_addr == 0 or import_addr == 0:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Skip the "Hint" field, 2 bytes
|
||||||
|
name_ofs = lookup_addr + self.imagebase + 2
|
||||||
|
symbol_name = self.read_string(name_ofs).decode("ascii")
|
||||||
|
yield (dll_name, symbol_name, ofs_iat)
|
||||||
|
ofs_ilt += 4
|
||||||
|
ofs_iat += 4
|
||||||
|
|
||||||
|
self.imports = list(iter_imports())
|
||||||
|
|
||||||
|
def _populate_thunks(self):
|
||||||
|
"""For each imported function, we generate a thunk function. The only
|
||||||
|
instruction in the function is a jmp to the address in .idata.
|
||||||
|
Search .text to find these functions."""
|
||||||
|
|
||||||
|
text_sect = self._get_section_by_name(".text")
|
||||||
|
idata_sect = self._get_section_by_name(".idata")
|
||||||
|
start = text_sect.virtual_address
|
||||||
|
ofs = start
|
||||||
|
|
||||||
|
bs = self.read(ofs, text_sect.size_of_raw_data)
|
||||||
|
|
||||||
|
for shift in (0, 2, 4):
|
||||||
|
window = bs[shift:]
|
||||||
|
win_end = 6 * (len(window) // 6)
|
||||||
|
for i, (b0, b1, jmp_ofs) in enumerate(
|
||||||
|
struct.iter_unpack("<2BL", window[:win_end])
|
||||||
|
):
|
||||||
|
if (b0, b1) == (0xFF, 0x25) and idata_sect.contains_vaddr(jmp_ofs):
|
||||||
|
# Record the address of the jmp instruction and the destination in .idata
|
||||||
|
thunk_ofs = ofs + shift + i * 6
|
||||||
|
self.thunks.append((thunk_ofs, jmp_ofs))
|
||||||
|
|
||||||
def _set_section_for_vaddr(self, vaddr: int):
|
def _set_section_for_vaddr(self, vaddr: int):
|
||||||
if self.last_section is not None and self.last_section.contains_vaddr(vaddr):
|
if self.last_section is not None and self.last_section.contains_vaddr(vaddr):
|
||||||
return
|
return
|
||||||
@ -319,6 +395,18 @@ def is_valid_vaddr(self, vaddr: int) -> bool:
|
|||||||
|
|
||||||
return section is not None
|
return section is not None
|
||||||
|
|
||||||
|
def read_string(self, offset: int, chunk_size: int = 1000) -> Optional[bytes]:
|
||||||
|
"""Read until we find a zero byte."""
|
||||||
|
b = self.read(offset, chunk_size)
|
||||||
|
if b is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
return b[: b.index(b"\x00")]
|
||||||
|
except ValueError:
|
||||||
|
# No terminator found, just return what we have
|
||||||
|
return b
|
||||||
|
|
||||||
def read(self, offset: int, size: int) -> Optional[bytes]:
|
def read(self, offset: int, size: int) -> Optional[bytes]:
|
||||||
"""Read (at most) the given number of bytes at the given virtual address.
|
"""Read (at most) the given number of bytes at the given virtual address.
|
||||||
If we return None, the given address points to uninitialized data."""
|
If we return None, the given address points to uninitialized data."""
|
||||||
|
|||||||
2
tools/isledecomp/isledecomp/compare/asm/__init__.py
Normal file
2
tools/isledecomp/isledecomp/compare/asm/__init__.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
from .parse import ParseAsm
|
||||||
|
from .swap import can_resolve_register_differences
|
||||||
152
tools/isledecomp/isledecomp/compare/asm/parse.py
Normal file
152
tools/isledecomp/isledecomp/compare/asm/parse.py
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
"""Converts x86 machine code into text (i.e. assembly). The end goal is to
|
||||||
|
compare the code in the original and recomp binaries, using longest common
|
||||||
|
subsequence (LCS), i.e. difflib.SequenceMatcher.
|
||||||
|
The capstone library takes the raw bytes and gives us the mnemnonic
|
||||||
|
and operand(s) for each instruction. We need to "sanitize" the text further
|
||||||
|
so that virtual addresses are replaced by symbol name or a generic
|
||||||
|
placeholder string."""
|
||||||
|
|
||||||
|
import re
|
||||||
|
from typing import Callable, List, Optional, Tuple
|
||||||
|
from collections import namedtuple
|
||||||
|
from capstone import Cs, CS_ARCH_X86, CS_MODE_32
|
||||||
|
|
||||||
|
disassembler = Cs(CS_ARCH_X86, CS_MODE_32)
|
||||||
|
|
||||||
|
ptr_replace_regex = re.compile(r"ptr \[(0x[0-9a-fA-F]+)\]")
|
||||||
|
|
||||||
|
DisasmLiteInst = namedtuple("DisasmLiteInst", "address, size, mnemonic, op_str")
|
||||||
|
|
||||||
|
|
||||||
|
def from_hex(string: str) -> Optional[int]:
|
||||||
|
try:
|
||||||
|
return int(string, 16)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class ParseAsm:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
relocate_lookup: Optional[Callable[[int], bool]] = None,
|
||||||
|
name_lookup: Optional[Callable[[int], str]] = None,
|
||||||
|
) -> None:
|
||||||
|
self.relocate_lookup = relocate_lookup
|
||||||
|
self.name_lookup = name_lookup
|
||||||
|
self.replacements = {}
|
||||||
|
self.number_placeholders = True
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
self.replacements = {}
|
||||||
|
|
||||||
|
def is_relocated(self, addr: int) -> bool:
|
||||||
|
if callable(self.relocate_lookup):
|
||||||
|
return self.relocate_lookup(addr)
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def lookup(self, addr: int) -> Optional[str]:
|
||||||
|
"""Return a replacement name for this address if we find one."""
|
||||||
|
if (cached := self.replacements.get(addr, None)) is not None:
|
||||||
|
return cached
|
||||||
|
|
||||||
|
if callable(self.name_lookup):
|
||||||
|
if (name := self.name_lookup(addr)) is not None:
|
||||||
|
self.replacements[addr] = name
|
||||||
|
return name
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def replace(self, addr: int) -> str:
|
||||||
|
"""Same function as lookup above, but here we return a placeholder
|
||||||
|
if there is no better name to use."""
|
||||||
|
if (name := self.lookup(addr)) is not None:
|
||||||
|
return name
|
||||||
|
|
||||||
|
# The placeholder number corresponds to the number of addresses we have
|
||||||
|
# already replaced. This is so the number will be consistent across the diff
|
||||||
|
# if we can replace some symbols with actual names in recomp but not orig.
|
||||||
|
idx = len(self.replacements) + 1
|
||||||
|
placeholder = f"<OFFSET{idx}>" if self.number_placeholders else "<OFFSET>"
|
||||||
|
self.replacements[addr] = placeholder
|
||||||
|
return placeholder
|
||||||
|
|
||||||
|
def sanitize(self, inst: DisasmLiteInst) -> Tuple[str, str]:
|
||||||
|
if len(inst.op_str) == 0:
|
||||||
|
# Nothing to sanitize
|
||||||
|
return (inst.mnemonic, "")
|
||||||
|
|
||||||
|
# For jumps or calls, if the entire op_str is a hex number, the value
|
||||||
|
# is a relative offset.
|
||||||
|
# Otherwise (i.e. it looks like `dword ptr [address]`) it is an
|
||||||
|
# absolute indirect that we will handle below.
|
||||||
|
# Providing the starting address of the function to capstone.disasm has
|
||||||
|
# automatically resolved relative offsets to an absolute address.
|
||||||
|
# We will have to undo this for some of the jumps or they will not match.
|
||||||
|
op_str_address = from_hex(inst.op_str)
|
||||||
|
|
||||||
|
if op_str_address is not None:
|
||||||
|
if inst.mnemonic == "call":
|
||||||
|
return (inst.mnemonic, self.replace(op_str_address))
|
||||||
|
|
||||||
|
if inst.mnemonic == "jmp":
|
||||||
|
# The unwind section contains JMPs to other functions.
|
||||||
|
# If we have a name for this address, use it. If not,
|
||||||
|
# do not create a new placeholder. We will instead
|
||||||
|
# fall through to generic jump handling below.
|
||||||
|
potential_name = self.lookup(op_str_address)
|
||||||
|
if potential_name is not None:
|
||||||
|
return (inst.mnemonic, potential_name)
|
||||||
|
|
||||||
|
if inst.mnemonic.startswith("j"):
|
||||||
|
# i.e. if this is any jump
|
||||||
|
# Show the jump offset rather than the absolute address
|
||||||
|
jump_displacement = op_str_address - (inst.address + inst.size)
|
||||||
|
return (inst.mnemonic, hex(jump_displacement))
|
||||||
|
|
||||||
|
def filter_out_ptr(match):
|
||||||
|
"""Helper for re.sub, see below"""
|
||||||
|
offset = from_hex(match.group(1))
|
||||||
|
|
||||||
|
if offset is not None:
|
||||||
|
# We assume this is always an address to replace
|
||||||
|
placeholder = self.replace(offset)
|
||||||
|
return f"ptr [{placeholder}]"
|
||||||
|
|
||||||
|
# Strict regex should ensure we can read the hex number.
|
||||||
|
# But just in case: return the string with no changes
|
||||||
|
return match.group(0)
|
||||||
|
|
||||||
|
op_str = ptr_replace_regex.sub(filter_out_ptr, inst.op_str)
|
||||||
|
|
||||||
|
# Performance hack:
|
||||||
|
# Skip this step if there is nothing left to consider replacing.
|
||||||
|
if "0x" in op_str:
|
||||||
|
# Replace immediate values with name or placeholder (where appropriate)
|
||||||
|
words = op_str.split(", ")
|
||||||
|
for i, word in enumerate(words):
|
||||||
|
try:
|
||||||
|
inttest = int(word, 16)
|
||||||
|
# If this value is a virtual address, it is referenced absolutely,
|
||||||
|
# which means it must be in the relocation table.
|
||||||
|
if self.is_relocated(inttest):
|
||||||
|
words[i] = self.replace(inttest)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
op_str = ", ".join(words)
|
||||||
|
|
||||||
|
return inst.mnemonic, op_str
|
||||||
|
|
||||||
|
def parse_asm(self, data: bytes, start_addr: Optional[int] = 0) -> List[str]:
|
||||||
|
asm = []
|
||||||
|
|
||||||
|
for inst in disassembler.disasm_lite(data, start_addr):
|
||||||
|
# Use heuristics to disregard some differences that aren't representative
|
||||||
|
# of the accuracy of a function (e.g. global offsets)
|
||||||
|
result = self.sanitize(DisasmLiteInst(*inst))
|
||||||
|
# mnemonic + " " + op_str
|
||||||
|
asm.append(" ".join(result))
|
||||||
|
|
||||||
|
return asm
|
||||||
80
tools/isledecomp/isledecomp/compare/asm/swap.py
Normal file
80
tools/isledecomp/isledecomp/compare/asm/swap.py
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
import re
|
||||||
|
|
||||||
|
REGISTER_LIST = set(
|
||||||
|
[
|
||||||
|
"ax",
|
||||||
|
"bp",
|
||||||
|
"bx",
|
||||||
|
"cx",
|
||||||
|
"di",
|
||||||
|
"dx",
|
||||||
|
"eax",
|
||||||
|
"ebp",
|
||||||
|
"ebx",
|
||||||
|
"ecx",
|
||||||
|
"edi",
|
||||||
|
"edx",
|
||||||
|
"esi",
|
||||||
|
"esp",
|
||||||
|
"si",
|
||||||
|
"sp",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
WORDS = re.compile(r"\w+")
|
||||||
|
|
||||||
|
|
||||||
|
def get_registers(line: str):
|
||||||
|
to_replace = []
|
||||||
|
# use words regex to find all matching positions:
|
||||||
|
for match in WORDS.finditer(line):
|
||||||
|
reg = match.group(0)
|
||||||
|
if reg in REGISTER_LIST:
|
||||||
|
to_replace.append((reg, match.start()))
|
||||||
|
return to_replace
|
||||||
|
|
||||||
|
|
||||||
|
def replace_register(
|
||||||
|
lines: list[str], start_line: int, reg: str, replacement: str
|
||||||
|
) -> list[str]:
|
||||||
|
return [
|
||||||
|
line.replace(reg, replacement) if i >= start_line else line
|
||||||
|
for i, line in enumerate(lines)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# Is it possible to make new_asm the same as original_asm by swapping registers?
|
||||||
|
def can_resolve_register_differences(original_asm, new_asm):
|
||||||
|
# Split the ASM on spaces to get more granularity, and so
|
||||||
|
# that we don't modify the original arrays passed in.
|
||||||
|
original_asm = [part for line in original_asm for part in line.split()]
|
||||||
|
new_asm = [part for line in new_asm for part in line.split()]
|
||||||
|
|
||||||
|
# Swapping ain't gonna help if the lengths are different
|
||||||
|
if len(original_asm) != len(new_asm):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Look for the mismatching lines
|
||||||
|
for i, original_line in enumerate(original_asm):
|
||||||
|
new_line = new_asm[i]
|
||||||
|
if new_line != original_line:
|
||||||
|
# Find all the registers to replace
|
||||||
|
to_replace = get_registers(original_line)
|
||||||
|
|
||||||
|
for replace in to_replace:
|
||||||
|
(reg, reg_index) = replace
|
||||||
|
replacing_reg = new_line[reg_index : reg_index + len(reg)]
|
||||||
|
if replacing_reg in REGISTER_LIST:
|
||||||
|
if replacing_reg != reg:
|
||||||
|
# Do a three-way swap replacing in all the subsequent lines
|
||||||
|
temp_reg = "&" * len(reg)
|
||||||
|
new_asm = replace_register(new_asm, i, replacing_reg, temp_reg)
|
||||||
|
new_asm = replace_register(new_asm, i, reg, replacing_reg)
|
||||||
|
new_asm = replace_register(new_asm, i, temp_reg, reg)
|
||||||
|
else:
|
||||||
|
# No replacement to do, different code, bail out
|
||||||
|
return False
|
||||||
|
# Check if the lines are now the same
|
||||||
|
for i, original_line in enumerate(original_asm):
|
||||||
|
if new_asm[i] != original_line:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
@ -1,11 +1,14 @@
|
|||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
from typing import List, Optional
|
import difflib
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import Iterable, List, Optional
|
||||||
from isledecomp.cvdump.demangler import demangle_string_const
|
from isledecomp.cvdump.demangler import demangle_string_const
|
||||||
from isledecomp.cvdump import Cvdump, CvdumpAnalysis
|
from isledecomp.cvdump import Cvdump, CvdumpAnalysis
|
||||||
from isledecomp.parser import DecompCodebase
|
from isledecomp.parser import DecompCodebase
|
||||||
from isledecomp.dir import walk_source_dir
|
from isledecomp.dir import walk_source_dir
|
||||||
from isledecomp.types import SymbolType
|
from isledecomp.types import SymbolType
|
||||||
|
from isledecomp.compare.asm import ParseAsm, can_resolve_register_differences
|
||||||
from .db import CompareDb, MatchInfo
|
from .db import CompareDb, MatchInfo
|
||||||
from .lines import LinesDb
|
from .lines import LinesDb
|
||||||
|
|
||||||
@ -13,6 +16,24 @@
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class DiffReport:
|
||||||
|
orig_addr: int
|
||||||
|
recomp_addr: int
|
||||||
|
name: str
|
||||||
|
udiff: Optional[List[str]] = None
|
||||||
|
ratio: float = 0.0
|
||||||
|
is_effective_match: bool = False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def effective_ratio(self) -> float:
|
||||||
|
return 1.0 if self.is_effective_match else self.ratio
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
"""For debug purposes. Proper diff printing (with coloring) is in another module."""
|
||||||
|
return f"{self.name} (0x{self.orig_addr:x}) {self.ratio*100:.02f}%{'*' if self.is_effective_match else ''}"
|
||||||
|
|
||||||
|
|
||||||
class Compare:
|
class Compare:
|
||||||
# pylint: disable=too-many-instance-attributes
|
# pylint: disable=too-many-instance-attributes
|
||||||
def __init__(self, orig_bin, recomp_bin, pdb_file, code_dir):
|
def __init__(self, orig_bin, recomp_bin, pdb_file, code_dir):
|
||||||
@ -27,6 +48,7 @@ def __init__(self, orig_bin, recomp_bin, pdb_file, code_dir):
|
|||||||
self._load_cvdump()
|
self._load_cvdump()
|
||||||
self._load_markers()
|
self._load_markers()
|
||||||
self._find_original_strings()
|
self._find_original_strings()
|
||||||
|
self._match_thunks()
|
||||||
|
|
||||||
def _load_cvdump(self):
|
def _load_cvdump(self):
|
||||||
logger.info("Parsing %s ...", self.pdb_file)
|
logger.info("Parsing %s ...", self.pdb_file)
|
||||||
@ -126,6 +148,46 @@ def _find_original_strings(self):
|
|||||||
|
|
||||||
self._db.match_string(addr, string)
|
self._db.match_string(addr, string)
|
||||||
|
|
||||||
|
def _match_thunks(self):
|
||||||
|
orig_byaddr = {
|
||||||
|
addr: (dll.upper(), name) for (dll, name, addr) in self.orig_bin.imports
|
||||||
|
}
|
||||||
|
recomp_byname = {
|
||||||
|
(dll.upper(), name): addr for (dll, name, addr) in self.recomp_bin.imports
|
||||||
|
}
|
||||||
|
# Combine these two dictionaries. We don't care about imports from recomp
|
||||||
|
# not found in orig because:
|
||||||
|
# 1. They shouldn't be there
|
||||||
|
# 2. They are already identified via cvdump
|
||||||
|
orig_to_recomp = {
|
||||||
|
addr: recomp_byname.get(pair, None) for addr, pair in orig_byaddr.items()
|
||||||
|
}
|
||||||
|
|
||||||
|
# Now: we have the IAT offset in each matched up, so we need to make
|
||||||
|
# the connection between the thunk functions.
|
||||||
|
# We already have the symbol name we need from the PDB.
|
||||||
|
orig_thunks = {
|
||||||
|
iat_ofs: func_ofs for (func_ofs, iat_ofs) in self.orig_bin.thunks
|
||||||
|
}
|
||||||
|
recomp_thunks = {
|
||||||
|
iat_ofs: func_ofs for (func_ofs, iat_ofs) in self.recomp_bin.thunks
|
||||||
|
}
|
||||||
|
|
||||||
|
for orig, recomp in orig_to_recomp.items():
|
||||||
|
self._db.set_pair(orig, recomp, SymbolType.POINTER)
|
||||||
|
thunk_from_orig = orig_thunks.get(orig, None)
|
||||||
|
thunk_from_recomp = recomp_thunks.get(recomp, None)
|
||||||
|
|
||||||
|
if thunk_from_orig is not None and thunk_from_recomp is not None:
|
||||||
|
self._db.set_function_pair(thunk_from_orig, thunk_from_recomp)
|
||||||
|
# Don't compare thunk functions for now. The comparison isn't
|
||||||
|
# "useful" in the usual sense. We are only looking at the 6
|
||||||
|
# bytes of the jmp instruction and not the larger context of
|
||||||
|
# where this function is. Also: these will always match 100%
|
||||||
|
# because we are searching for a match to register this as a
|
||||||
|
# function in the first place.
|
||||||
|
self._db.skip_compare(thunk_from_orig)
|
||||||
|
|
||||||
def get_one_function(self, addr: int) -> Optional[MatchInfo]:
|
def get_one_function(self, addr: int) -> Optional[MatchInfo]:
|
||||||
"""i.e. verbose mode for reccmp"""
|
"""i.e. verbose mode for reccmp"""
|
||||||
return self._db.get_one_function(addr)
|
return self._db.get_one_function(addr)
|
||||||
@ -133,8 +195,84 @@ def get_one_function(self, addr: int) -> Optional[MatchInfo]:
|
|||||||
def get_functions(self) -> List[MatchInfo]:
|
def get_functions(self) -> List[MatchInfo]:
|
||||||
return self._db.get_matches(SymbolType.FUNCTION)
|
return self._db.get_matches(SymbolType.FUNCTION)
|
||||||
|
|
||||||
def compare_functions(self):
|
def _compare_function(self, match: MatchInfo) -> DiffReport:
|
||||||
pass
|
if match.size == 0:
|
||||||
|
# Report a failed match to make the user aware of the empty function.
|
||||||
|
return DiffReport(
|
||||||
|
orig_addr=match.orig_addr,
|
||||||
|
recomp_addr=match.recomp_addr,
|
||||||
|
name=match.name,
|
||||||
|
)
|
||||||
|
|
||||||
|
orig_raw = self.orig_bin.read(match.orig_addr, match.size)
|
||||||
|
recomp_raw = self.recomp_bin.read(match.recomp_addr, match.size)
|
||||||
|
|
||||||
|
def orig_should_replace(addr: int) -> bool:
|
||||||
|
return addr > self.orig_bin.imagebase and self.orig_bin.is_relocated_addr(
|
||||||
|
addr
|
||||||
|
)
|
||||||
|
|
||||||
|
def recomp_should_replace(addr: int) -> bool:
|
||||||
|
return (
|
||||||
|
addr > self.recomp_bin.imagebase
|
||||||
|
and self.recomp_bin.is_relocated_addr(addr)
|
||||||
|
)
|
||||||
|
|
||||||
|
def orig_lookup(addr: int) -> Optional[str]:
|
||||||
|
m = self._db.get_by_orig(addr)
|
||||||
|
if m is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return m.match_name()
|
||||||
|
|
||||||
|
def recomp_lookup(addr: int) -> Optional[str]:
|
||||||
|
m = self._db.get_by_recomp(addr)
|
||||||
|
if m is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return m.match_name()
|
||||||
|
|
||||||
|
orig_parse = ParseAsm(
|
||||||
|
relocate_lookup=orig_should_replace, name_lookup=orig_lookup
|
||||||
|
)
|
||||||
|
recomp_parse = ParseAsm(
|
||||||
|
relocate_lookup=recomp_should_replace, name_lookup=recomp_lookup
|
||||||
|
)
|
||||||
|
|
||||||
|
orig_asm = orig_parse.parse_asm(orig_raw, match.orig_addr)
|
||||||
|
recomp_asm = recomp_parse.parse_asm(recomp_raw, match.recomp_addr)
|
||||||
|
|
||||||
|
diff = difflib.SequenceMatcher(None, orig_asm, recomp_asm)
|
||||||
|
ratio = diff.ratio()
|
||||||
|
|
||||||
|
if ratio != 1.0:
|
||||||
|
# Check whether we can resolve register swaps which are actually
|
||||||
|
# perfect matches modulo compiler entropy.
|
||||||
|
is_effective_match = can_resolve_register_differences(orig_asm, recomp_asm)
|
||||||
|
unified_diff = difflib.unified_diff(orig_asm, recomp_asm, n=10)
|
||||||
|
else:
|
||||||
|
is_effective_match = False
|
||||||
|
unified_diff = []
|
||||||
|
|
||||||
|
return DiffReport(
|
||||||
|
orig_addr=match.orig_addr,
|
||||||
|
recomp_addr=match.recomp_addr,
|
||||||
|
name=match.name,
|
||||||
|
udiff=unified_diff,
|
||||||
|
ratio=ratio,
|
||||||
|
is_effective_match=is_effective_match,
|
||||||
|
)
|
||||||
|
|
||||||
|
def compare_function(self, addr: int) -> Optional[DiffReport]:
|
||||||
|
match = self.get_one_function(addr)
|
||||||
|
if match is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return self._compare_function(match)
|
||||||
|
|
||||||
|
def compare_functions(self) -> Iterable[DiffReport]:
|
||||||
|
for match in self.get_functions():
|
||||||
|
yield self._compare_function(match)
|
||||||
|
|
||||||
def compare_variables(self):
|
def compare_variables(self):
|
||||||
pass
|
pass
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
addresses/symbols that we want to compare between the original and recompiled binaries."""
|
addresses/symbols that we want to compare between the original and recompiled binaries."""
|
||||||
import sqlite3
|
import sqlite3
|
||||||
import logging
|
import logging
|
||||||
from collections import namedtuple
|
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
from isledecomp.types import SymbolType
|
from isledecomp.types import SymbolType
|
||||||
|
|
||||||
@ -16,12 +15,35 @@
|
|||||||
size int,
|
size int,
|
||||||
should_skip int default(FALSE)
|
should_skip int default(FALSE)
|
||||||
);
|
);
|
||||||
|
CREATE INDEX `symbols_or` ON `symbols` (orig_addr);
|
||||||
CREATE INDEX `symbols_re` ON `symbols` (recomp_addr);
|
CREATE INDEX `symbols_re` ON `symbols` (recomp_addr);
|
||||||
CREATE INDEX `symbols_na` ON `symbols` (compare_type, name);
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
MatchInfo = namedtuple("MatchInfo", "orig_addr, recomp_addr, size, name")
|
class MatchInfo:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
ctype: Optional[int],
|
||||||
|
orig: Optional[int],
|
||||||
|
recomp: Optional[int],
|
||||||
|
name: Optional[str],
|
||||||
|
size: Optional[int],
|
||||||
|
) -> None:
|
||||||
|
self.compare_type = SymbolType(ctype) if ctype is not None else None
|
||||||
|
self.orig_addr = orig
|
||||||
|
self.recomp_addr = recomp
|
||||||
|
self.name = name
|
||||||
|
self.size = size
|
||||||
|
|
||||||
|
def match_name(self) -> str:
|
||||||
|
"""Combination of the name and compare type.
|
||||||
|
Intended for name substitution in the diff. If there is a diff,
|
||||||
|
it will be more obvious what this symbol indicates."""
|
||||||
|
if self.name is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
ctype = self.compare_type.name if self.compare_type is not None else "UNK"
|
||||||
|
return f"{self.name} ({ctype})"
|
||||||
|
|
||||||
|
|
||||||
def matchinfo_factory(_, row):
|
def matchinfo_factory(_, row):
|
||||||
@ -61,7 +83,7 @@ def get_unmatched_strings(self) -> List[str]:
|
|||||||
|
|
||||||
def get_one_function(self, addr: int) -> Optional[MatchInfo]:
|
def get_one_function(self, addr: int) -> Optional[MatchInfo]:
|
||||||
cur = self._db.execute(
|
cur = self._db.execute(
|
||||||
"""SELECT orig_addr, recomp_addr, size, name
|
"""SELECT compare_type, orig_addr, recomp_addr, name, size
|
||||||
FROM `symbols`
|
FROM `symbols`
|
||||||
WHERE compare_type = ?
|
WHERE compare_type = ?
|
||||||
AND orig_addr = ?
|
AND orig_addr = ?
|
||||||
@ -74,9 +96,31 @@ def get_one_function(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]:
|
||||||
|
cur = self._db.execute(
|
||||||
|
"""SELECT compare_type, orig_addr, recomp_addr, name, size
|
||||||
|
FROM `symbols`
|
||||||
|
WHERE orig_addr = ?
|
||||||
|
""",
|
||||||
|
(addr,),
|
||||||
|
)
|
||||||
|
cur.row_factory = matchinfo_factory
|
||||||
|
return cur.fetchone()
|
||||||
|
|
||||||
|
def get_by_recomp(self, addr: int) -> Optional[MatchInfo]:
|
||||||
|
cur = self._db.execute(
|
||||||
|
"""SELECT compare_type, orig_addr, recomp_addr, name, size
|
||||||
|
FROM `symbols`
|
||||||
|
WHERE recomp_addr = ?
|
||||||
|
""",
|
||||||
|
(addr,),
|
||||||
|
)
|
||||||
|
cur.row_factory = matchinfo_factory
|
||||||
|
return cur.fetchone()
|
||||||
|
|
||||||
def get_matches(self, compare_type: SymbolType) -> List[MatchInfo]:
|
def get_matches(self, compare_type: SymbolType) -> List[MatchInfo]:
|
||||||
cur = self._db.execute(
|
cur = self._db.execute(
|
||||||
"""SELECT orig_addr, recomp_addr, size, name
|
"""SELECT compare_type, orig_addr, recomp_addr, name, size
|
||||||
FROM `symbols`
|
FROM `symbols`
|
||||||
WHERE compare_type = ?
|
WHERE compare_type = ?
|
||||||
AND orig_addr IS NOT NULL
|
AND orig_addr IS NOT NULL
|
||||||
@ -90,14 +134,20 @@ def get_matches(self, compare_type: SymbolType) -> List[MatchInfo]:
|
|||||||
|
|
||||||
return cur.fetchall()
|
return cur.fetchall()
|
||||||
|
|
||||||
def set_function_pair(self, orig: int, recomp: int) -> bool:
|
def set_pair(
|
||||||
"""For lineref match or _entry"""
|
self, orig: int, recomp: int, compare_type: Optional[SymbolType] = None
|
||||||
|
) -> bool:
|
||||||
|
compare_value = compare_type.value if compare_type is not None else None
|
||||||
cur = self._db.execute(
|
cur = self._db.execute(
|
||||||
"UPDATE `symbols` SET orig_addr = ?, compare_type = ? WHERE recomp_addr = ?",
|
"UPDATE `symbols` SET orig_addr = ?, compare_type = ? WHERE recomp_addr = ?",
|
||||||
(orig, SymbolType.FUNCTION.value, recomp),
|
(orig, compare_value, recomp),
|
||||||
)
|
)
|
||||||
|
|
||||||
return cur.rowcount > 0
|
return cur.rowcount > 0
|
||||||
|
|
||||||
|
def set_function_pair(self, orig: int, recomp: int) -> bool:
|
||||||
|
"""For lineref match or _entry"""
|
||||||
|
self.set_pair(orig, recomp, SymbolType.FUNCTION)
|
||||||
# TODO: Both ways required?
|
# TODO: Both ways required?
|
||||||
|
|
||||||
def skip_compare(self, orig: int):
|
def skip_compare(self, orig: int):
|
||||||
|
|||||||
@ -36,7 +36,7 @@
|
|||||||
|
|
||||||
# e.g. `S_GDATA32: [0003:000004A4], Type: T_32PRCHAR(0470), g_set`
|
# e.g. `S_GDATA32: [0003:000004A4], Type: T_32PRCHAR(0470), g_set`
|
||||||
_gdata32_regex = re.compile(
|
_gdata32_regex = re.compile(
|
||||||
r"S_GDATA32: \[(?P<section>\w{4}):(?P<offset>\w{8})\], Type:\s*(?P<type>\S+), (?P<name>\S+)"
|
r"S_GDATA32: \[(?P<section>\w{4}):(?P<offset>\w{8})\], Type:\s*(?P<type>\S+), (?P<name>.+)"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -26,17 +26,3 @@ def print_diff(udiff, plain):
|
|||||||
|
|
||||||
def get_file_in_script_dir(fn):
|
def get_file_in_script_dir(fn):
|
||||||
return os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])), fn)
|
return os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])), fn)
|
||||||
|
|
||||||
|
|
||||||
class OffsetPlaceholderGenerator:
|
|
||||||
def __init__(self):
|
|
||||||
self.counter = 0
|
|
||||||
self.replacements = {}
|
|
||||||
|
|
||||||
def get(self, replace_addr):
|
|
||||||
if replace_addr in self.replacements:
|
|
||||||
return self.replacements[replace_addr]
|
|
||||||
self.counter += 1
|
|
||||||
replacement = f"<OFFSET{self.counter}>"
|
|
||||||
self.replacements[replace_addr] = replacement
|
|
||||||
return replacement
|
|
||||||
|
|||||||
179
tools/isledecomp/tests/test_sanitize.py
Normal file
179
tools/isledecomp/tests/test_sanitize.py
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
from typing import Optional
|
||||||
|
import pytest
|
||||||
|
from isledecomp.compare.asm.parse import DisasmLiteInst, ParseAsm
|
||||||
|
|
||||||
|
|
||||||
|
def mock_inst(mnemonic: str, op_str: str) -> DisasmLiteInst:
|
||||||
|
"""Mock up the named tuple DisasmLite from just a mnemonic and op_str.
|
||||||
|
To be used for tests on sanitize that do not require the instruction address
|
||||||
|
or size. i.e. any non-jump instruction."""
|
||||||
|
return DisasmLiteInst(0, 0, mnemonic, op_str)
|
||||||
|
|
||||||
|
|
||||||
|
identity_cases = [
|
||||||
|
("", ""),
|
||||||
|
("sti", ""),
|
||||||
|
("push", "ebx"),
|
||||||
|
("ret", ""),
|
||||||
|
("ret", "4"),
|
||||||
|
("mov", "eax, 0x1234"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("mnemonic, op_str", identity_cases)
|
||||||
|
def test_identity(mnemonic, op_str):
|
||||||
|
"""Confirm that nothing is substituted."""
|
||||||
|
p = ParseAsm()
|
||||||
|
inst = mock_inst(mnemonic, op_str)
|
||||||
|
result = p.sanitize(inst)
|
||||||
|
assert result == (mnemonic, op_str)
|
||||||
|
|
||||||
|
|
||||||
|
ptr_replace_cases = [
|
||||||
|
("byte ptr [0x5555]", "byte ptr [<OFFSET1>]"),
|
||||||
|
("word ptr [0x5555]", "word ptr [<OFFSET1>]"),
|
||||||
|
("dword ptr [0x5555]", "dword ptr [<OFFSET1>]"),
|
||||||
|
("qword ptr [0x5555]", "qword ptr [<OFFSET1>]"),
|
||||||
|
("eax, dword ptr [0x5555]", "eax, dword ptr [<OFFSET1>]"),
|
||||||
|
("dword ptr [0x5555], eax", "dword ptr [<OFFSET1>], eax"),
|
||||||
|
("dword ptr [0x5555], 0", "dword ptr [<OFFSET1>], 0"),
|
||||||
|
("dword ptr [0x5555], 8", "dword ptr [<OFFSET1>], 8"),
|
||||||
|
# Same value, assumed to be an addr in the first appearance
|
||||||
|
# because it is designated as 'ptr', but we have not provided the
|
||||||
|
# relocation table lookup method so we do not replace the second appearance.
|
||||||
|
("dword ptr [0x5555], 0x5555", "dword ptr [<OFFSET1>], 0x5555"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("start, end", ptr_replace_cases)
|
||||||
|
def test_ptr_replace(start, end):
|
||||||
|
"""Anything in square brackets (with the 'ptr' prefix) will always be replaced."""
|
||||||
|
p = ParseAsm()
|
||||||
|
inst = mock_inst("", start)
|
||||||
|
(_, op_str) = p.sanitize(inst)
|
||||||
|
assert op_str == end
|
||||||
|
|
||||||
|
|
||||||
|
call_replace_cases = [
|
||||||
|
("ebx", "ebx"),
|
||||||
|
("0x1234", "<OFFSET1>"),
|
||||||
|
("dword ptr [0x1234]", "dword ptr [<OFFSET1>]"),
|
||||||
|
("dword ptr [ecx + 0x10]", "dword ptr [ecx + 0x10]"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("start, end", call_replace_cases)
|
||||||
|
def test_call_replace(start, end):
|
||||||
|
"""Call with hex operand is always replaced.
|
||||||
|
Otherwise, ptr replacement rules apply, but skip `this` calls."""
|
||||||
|
p = ParseAsm()
|
||||||
|
inst = mock_inst("call", start)
|
||||||
|
(_, op_str) = p.sanitize(inst)
|
||||||
|
assert op_str == end
|
||||||
|
|
||||||
|
|
||||||
|
def test_jump_displacement():
|
||||||
|
"""Display jump displacement (offset from end of jump instruction)
|
||||||
|
instead of destination address."""
|
||||||
|
p = ParseAsm()
|
||||||
|
inst = DisasmLiteInst(0x1000, 2, "je", "0x1000")
|
||||||
|
(_, op_str) = p.sanitize(inst)
|
||||||
|
assert op_str == "-0x2"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xfail(reason="Not implemented yet")
|
||||||
|
def test_jmp_table():
|
||||||
|
"""Should detect the characteristic jump table instruction
|
||||||
|
(for a switch statement) and use placeholder."""
|
||||||
|
p = ParseAsm()
|
||||||
|
inst = mock_inst("jmp", "dword ptr [eax*4 + 0x5555]")
|
||||||
|
(_, op_str) = p.sanitize(inst)
|
||||||
|
assert op_str == "dword ptr [eax*4 + <OFFSET1>]"
|
||||||
|
|
||||||
|
|
||||||
|
name_replace_cases = [
|
||||||
|
("byte ptr [0x5555]", "byte ptr [_substitute_]"),
|
||||||
|
("word ptr [0x5555]", "word ptr [_substitute_]"),
|
||||||
|
("dword ptr [0x5555]", "dword ptr [_substitute_]"),
|
||||||
|
("qword ptr [0x5555]", "qword ptr [_substitute_]"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("start, end", name_replace_cases)
|
||||||
|
def test_name_replace(start, end):
|
||||||
|
"""Make sure the name lookup function is called if present"""
|
||||||
|
|
||||||
|
def substitute(_: int) -> str:
|
||||||
|
return "_substitute_"
|
||||||
|
|
||||||
|
p = ParseAsm(name_lookup=substitute)
|
||||||
|
inst = mock_inst("mov", start)
|
||||||
|
(_, op_str) = p.sanitize(inst)
|
||||||
|
assert op_str == end
|
||||||
|
|
||||||
|
|
||||||
|
def test_replacement_cache():
|
||||||
|
p = ParseAsm()
|
||||||
|
inst = mock_inst("inc", "dword ptr [0x1234]")
|
||||||
|
|
||||||
|
(_, op_str) = p.sanitize(inst)
|
||||||
|
assert op_str == "dword ptr [<OFFSET1>]"
|
||||||
|
|
||||||
|
(_, op_str) = p.sanitize(inst)
|
||||||
|
assert op_str == "dword ptr [<OFFSET1>]"
|
||||||
|
|
||||||
|
|
||||||
|
def test_replacement_numbering():
|
||||||
|
"""If we can use the name lookup for the first address but not the second,
|
||||||
|
the second replacement should be <OFFSET2> not <OFFSET1>."""
|
||||||
|
|
||||||
|
def substitute_1234(addr: int) -> Optional[str]:
|
||||||
|
return "_substitute_" if addr == 0x1234 else None
|
||||||
|
|
||||||
|
p = ParseAsm(name_lookup=substitute_1234)
|
||||||
|
|
||||||
|
(_, op_str) = p.sanitize(mock_inst("inc", "dword ptr [0x1234]"))
|
||||||
|
assert op_str == "dword ptr [_substitute_]"
|
||||||
|
|
||||||
|
(_, op_str) = p.sanitize(mock_inst("inc", "dword ptr [0x5555]"))
|
||||||
|
assert op_str == "dword ptr [<OFFSET2>]"
|
||||||
|
|
||||||
|
|
||||||
|
def test_relocate_lookup():
|
||||||
|
"""Immediate values would be relocated if they are actually addresses.
|
||||||
|
So we can use the relocation table to check whether a given value is an
|
||||||
|
address or just some number."""
|
||||||
|
|
||||||
|
def relocate_lookup(addr: int) -> bool:
|
||||||
|
return addr == 0x1234
|
||||||
|
|
||||||
|
p = ParseAsm(relocate_lookup=relocate_lookup)
|
||||||
|
(_, op_str) = p.sanitize(mock_inst("mov", "eax, 0x1234"))
|
||||||
|
assert op_str == "eax, <OFFSET1>"
|
||||||
|
|
||||||
|
(_, op_str) = p.sanitize(mock_inst("mov", "eax, 0x5555"))
|
||||||
|
assert op_str == "eax, 0x5555"
|
||||||
|
|
||||||
|
|
||||||
|
def test_jump_to_function():
|
||||||
|
"""A jmp instruction can lead us directly to a function. This can be found
|
||||||
|
in the unwind section at the end of a function. However: we do not want to
|
||||||
|
assume this is the case for all jumps. Only replace the jump with a name
|
||||||
|
if we can find it using our lookup."""
|
||||||
|
|
||||||
|
def substitute_1234(addr: int) -> Optional[str]:
|
||||||
|
return "_substitute_" if addr == 0x1234 else None
|
||||||
|
|
||||||
|
p = ParseAsm(name_lookup=substitute_1234)
|
||||||
|
inst = DisasmLiteInst(0x1000, 2, "jmp", "0x1234")
|
||||||
|
(_, op_str) = p.sanitize(inst)
|
||||||
|
assert op_str == "_substitute_"
|
||||||
|
|
||||||
|
# Should not replace this jump.
|
||||||
|
# 0x1000 (start addr)
|
||||||
|
# + 2 (size of jump instruction)
|
||||||
|
# + 0x5555 (displacement, the value we want)
|
||||||
|
# = 0x6557
|
||||||
|
inst = DisasmLiteInst(0x1000, 2, "jmp", "0x6557")
|
||||||
|
(_, op_str) = p.sanitize(inst)
|
||||||
|
assert op_str == "0x5555"
|
||||||
@ -2,167 +2,20 @@
|
|||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import base64
|
import base64
|
||||||
import difflib
|
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import re
|
|
||||||
|
|
||||||
from isledecomp import (
|
from isledecomp import (
|
||||||
Bin,
|
Bin,
|
||||||
get_file_in_script_dir,
|
get_file_in_script_dir,
|
||||||
OffsetPlaceholderGenerator,
|
|
||||||
print_diff,
|
print_diff,
|
||||||
)
|
)
|
||||||
from isledecomp.compare import Compare as IsleCompare
|
from isledecomp.compare import Compare as IsleCompare
|
||||||
|
|
||||||
from capstone import Cs, CS_ARCH_X86, CS_MODE_32
|
|
||||||
import colorama
|
|
||||||
from pystache import Renderer
|
from pystache import Renderer
|
||||||
|
import colorama
|
||||||
|
|
||||||
|
colorama.init()
|
||||||
REGISTER_LIST = set(
|
|
||||||
[
|
|
||||||
"ax",
|
|
||||||
"bp",
|
|
||||||
"bx",
|
|
||||||
"cx",
|
|
||||||
"di",
|
|
||||||
"dx",
|
|
||||||
"eax",
|
|
||||||
"ebp",
|
|
||||||
"ebx",
|
|
||||||
"ecx",
|
|
||||||
"edi",
|
|
||||||
"edx",
|
|
||||||
"esi",
|
|
||||||
"esp",
|
|
||||||
"si",
|
|
||||||
"sp",
|
|
||||||
]
|
|
||||||
)
|
|
||||||
WORDS = re.compile(r"\w+")
|
|
||||||
|
|
||||||
|
|
||||||
def sanitize(file, placeholder_generator, mnemonic, op_str):
|
|
||||||
op_str_is_number = False
|
|
||||||
try:
|
|
||||||
int(op_str, 16)
|
|
||||||
op_str_is_number = True
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if (mnemonic in ["call", "jmp"]) and op_str_is_number:
|
|
||||||
# Filter out "calls" because the offsets we're not currently trying to
|
|
||||||
# match offsets. As long as there's a call in the right place, it's
|
|
||||||
# probably accurate.
|
|
||||||
op_str = placeholder_generator.get(int(op_str, 16))
|
|
||||||
else:
|
|
||||||
|
|
||||||
def filter_out_ptr(ptype, op_str):
|
|
||||||
try:
|
|
||||||
ptrstr = ptype + " ptr ["
|
|
||||||
start = op_str.index(ptrstr) + len(ptrstr)
|
|
||||||
end = op_str.index("]", start)
|
|
||||||
|
|
||||||
# This will throw ValueError if not hex
|
|
||||||
inttest = int(op_str[start:end], 16)
|
|
||||||
|
|
||||||
return (
|
|
||||||
op_str[0:start] + placeholder_generator.get(inttest) + op_str[end:]
|
|
||||||
)
|
|
||||||
except ValueError:
|
|
||||||
return op_str
|
|
||||||
|
|
||||||
# Filter out dword ptrs where the pointer is to an offset
|
|
||||||
op_str = filter_out_ptr("dword", op_str)
|
|
||||||
op_str = filter_out_ptr("word", op_str)
|
|
||||||
op_str = filter_out_ptr("byte", op_str)
|
|
||||||
|
|
||||||
# Use heuristics to filter out any args that look like offsets
|
|
||||||
words = op_str.split(" ")
|
|
||||||
for i, word in enumerate(words):
|
|
||||||
try:
|
|
||||||
inttest = int(word, 16)
|
|
||||||
if file.is_relocated_addr(inttest):
|
|
||||||
words[i] = placeholder_generator.get(inttest)
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
op_str = " ".join(words)
|
|
||||||
|
|
||||||
return mnemonic, op_str
|
|
||||||
|
|
||||||
|
|
||||||
def parse_asm(disassembler, file, asm_addr, size):
|
|
||||||
asm = []
|
|
||||||
data = file.read(asm_addr, size)
|
|
||||||
placeholder_generator = OffsetPlaceholderGenerator()
|
|
||||||
for i in disassembler.disasm(data, 0):
|
|
||||||
# Use heuristics to disregard some differences that aren't representative
|
|
||||||
# of the accuracy of a function (e.g. global offsets)
|
|
||||||
mnemonic, op_str = sanitize(file, placeholder_generator, i.mnemonic, i.op_str)
|
|
||||||
if op_str is None:
|
|
||||||
asm.append(mnemonic)
|
|
||||||
else:
|
|
||||||
asm.append(f"{mnemonic} {op_str}")
|
|
||||||
return asm
|
|
||||||
|
|
||||||
|
|
||||||
def get_registers(line: str):
|
|
||||||
to_replace = []
|
|
||||||
# use words regex to find all matching positions:
|
|
||||||
for match in WORDS.finditer(line):
|
|
||||||
reg = match.group(0)
|
|
||||||
if reg in REGISTER_LIST:
|
|
||||||
to_replace.append((reg, match.start()))
|
|
||||||
return to_replace
|
|
||||||
|
|
||||||
|
|
||||||
def replace_register(
|
|
||||||
lines: list[str], start_line: int, reg: str, replacement: str
|
|
||||||
) -> list[str]:
|
|
||||||
return [
|
|
||||||
line.replace(reg, replacement) if i >= start_line else line
|
|
||||||
for i, line in enumerate(lines)
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
# Is it possible to make new_asm the same as original_asm by swapping registers?
|
|
||||||
def can_resolve_register_differences(original_asm, new_asm):
|
|
||||||
# Split the ASM on spaces to get more granularity, and so
|
|
||||||
# that we don't modify the original arrays passed in.
|
|
||||||
original_asm = [part for line in original_asm for part in line.split()]
|
|
||||||
new_asm = [part for line in new_asm for part in line.split()]
|
|
||||||
|
|
||||||
# Swapping ain't gonna help if the lengths are different
|
|
||||||
if len(original_asm) != len(new_asm):
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Look for the mismatching lines
|
|
||||||
for i, original_line in enumerate(original_asm):
|
|
||||||
new_line = new_asm[i]
|
|
||||||
if new_line != original_line:
|
|
||||||
# Find all the registers to replace
|
|
||||||
to_replace = get_registers(original_line)
|
|
||||||
|
|
||||||
for replace in to_replace:
|
|
||||||
(reg, reg_index) = replace
|
|
||||||
replacing_reg = new_line[reg_index : reg_index + len(reg)]
|
|
||||||
if replacing_reg in REGISTER_LIST:
|
|
||||||
if replacing_reg != reg:
|
|
||||||
# Do a three-way swap replacing in all the subsequent lines
|
|
||||||
temp_reg = "&" * len(reg)
|
|
||||||
new_asm = replace_register(new_asm, i, replacing_reg, temp_reg)
|
|
||||||
new_asm = replace_register(new_asm, i, reg, replacing_reg)
|
|
||||||
new_asm = replace_register(new_asm, i, temp_reg, reg)
|
|
||||||
else:
|
|
||||||
# No replacement to do, different code, bail out
|
|
||||||
return False
|
|
||||||
# Check if the lines are now the same
|
|
||||||
for i, original_line in enumerate(original_asm):
|
|
||||||
if new_asm[i] != original_line:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def gen_html(html_file, data):
|
def gen_html(html_file, data):
|
||||||
@ -197,9 +50,88 @@ def gen_svg(svg_file, name_svg, icon, svg_implemented_funcs, total_funcs, raw_ac
|
|||||||
svgfile.write(output_data)
|
svgfile.write(output_data)
|
||||||
|
|
||||||
|
|
||||||
# Do the actual work
|
def get_percent_color(value: float) -> str:
|
||||||
def main():
|
"""Return colorama ANSI escape character for the given decimal value."""
|
||||||
# pylint: disable=too-many-locals, too-many-nested-blocks, too-many-branches, too-many-statements
|
if value == 1.0:
|
||||||
|
return colorama.Fore.GREEN
|
||||||
|
if value > 0.8:
|
||||||
|
return colorama.Fore.YELLOW
|
||||||
|
|
||||||
|
return colorama.Fore.RED
|
||||||
|
|
||||||
|
|
||||||
|
def percent_string(
|
||||||
|
ratio: float, is_effective: bool = False, is_plain: bool = False
|
||||||
|
) -> str:
|
||||||
|
"""Helper to construct a percentage string from the given ratio.
|
||||||
|
If is_effective (i.e. effective match), indicate that with the asterisk.
|
||||||
|
If is_plain, don't use colorama ANSI codes."""
|
||||||
|
|
||||||
|
percenttext = f"{(ratio * 100):.2f}%"
|
||||||
|
effective_star = "*" if is_effective else ""
|
||||||
|
|
||||||
|
if is_plain:
|
||||||
|
return percenttext + effective_star
|
||||||
|
|
||||||
|
return "".join(
|
||||||
|
[
|
||||||
|
get_percent_color(ratio),
|
||||||
|
percenttext,
|
||||||
|
colorama.Fore.RED if is_effective else "",
|
||||||
|
effective_star,
|
||||||
|
colorama.Style.RESET_ALL,
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def print_match_verbose(match, show_both_addrs: bool = False, is_plain: bool = False):
|
||||||
|
percenttext = percent_string(
|
||||||
|
match.effective_ratio, match.is_effective_match, is_plain
|
||||||
|
)
|
||||||
|
|
||||||
|
if show_both_addrs:
|
||||||
|
addrs = f"0x{match.orig_addr:x} / 0x{match.recomp_addr:x}"
|
||||||
|
else:
|
||||||
|
addrs = hex(match.orig_addr)
|
||||||
|
|
||||||
|
if match.effective_ratio == 1.0:
|
||||||
|
ok_text = (
|
||||||
|
"OK!"
|
||||||
|
if is_plain
|
||||||
|
else (colorama.Fore.GREEN + "✨ OK! ✨" + colorama.Style.RESET_ALL)
|
||||||
|
)
|
||||||
|
if match.ratio == 1.0:
|
||||||
|
print(f"{addrs}: {match.name} 100% match.\n\n{ok_text}\n\n")
|
||||||
|
else:
|
||||||
|
print(
|
||||||
|
f"{addrs}: {match.name} Effective 100%% match. (Differs in register allocation only)\n\n{ok_text} (still differs in register allocation)\n\n"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
print_diff(match.udiff, is_plain)
|
||||||
|
|
||||||
|
print(
|
||||||
|
f"\n{match.name} is only {percenttext} similar to the original, diff above"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def print_match_oneline(match, show_both_addrs: bool = False, is_plain: bool = False):
|
||||||
|
percenttext = percent_string(
|
||||||
|
match.effective_ratio, match.is_effective_match, is_plain
|
||||||
|
)
|
||||||
|
|
||||||
|
if show_both_addrs:
|
||||||
|
addrs = f"0x{match.orig_addr:x} / 0x{match.recomp_addr:x}"
|
||||||
|
else:
|
||||||
|
addrs = hex(match.orig_addr)
|
||||||
|
|
||||||
|
print(f" {match.name} ({addrs}) is {percenttext} similar to the original")
|
||||||
|
|
||||||
|
|
||||||
|
def parse_args() -> argparse.Namespace:
|
||||||
|
def virtual_address(value) -> int:
|
||||||
|
"""Helper method for argparse, verbose parameter"""
|
||||||
|
return int(value, 16)
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
allow_abbrev=False,
|
allow_abbrev=False,
|
||||||
description="Recompilation Compare: compare an original EXE with a recompiled EXE + PDB.",
|
description="Recompilation Compare: compare an original EXE with a recompiled EXE + PDB.",
|
||||||
@ -226,6 +158,7 @@ def main():
|
|||||||
"--verbose",
|
"--verbose",
|
||||||
"-v",
|
"-v",
|
||||||
metavar="<offset>",
|
metavar="<offset>",
|
||||||
|
type=virtual_address,
|
||||||
help="Print assembly diff for specific function (original file's offset)",
|
help="Print assembly diff for specific function (original file's offset)",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
@ -258,198 +191,103 @@ def main():
|
|||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if not os.path.isfile(args.original):
|
||||||
|
parser.error(f"Original binary {args.original} does not exist")
|
||||||
|
|
||||||
|
if not os.path.isfile(args.recompiled):
|
||||||
|
parser.error(f"Recompiled binary {args.recompiled} does not exist")
|
||||||
|
|
||||||
|
if not os.path.isfile(args.pdb):
|
||||||
|
parser.error(f"Symbols PDB {args.pdb} does not exist")
|
||||||
|
|
||||||
|
if not os.path.isdir(args.decomp_dir):
|
||||||
|
parser.error(f"Source directory {args.decomp_dir} does not exist")
|
||||||
|
|
||||||
|
return args
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
args = parse_args()
|
||||||
logging.basicConfig(level=args.loglevel, format="[%(levelname)s] %(message)s")
|
logging.basicConfig(level=args.loglevel, format="[%(levelname)s] %(message)s")
|
||||||
|
|
||||||
colorama.init()
|
with Bin(args.original, find_str=True) as origfile, Bin(
|
||||||
|
args.recompiled
|
||||||
verbose = None
|
) as recompfile:
|
||||||
found_verbose_target = False
|
if args.verbose is not None:
|
||||||
if args.verbose:
|
|
||||||
try:
|
|
||||||
verbose = int(args.verbose, 16)
|
|
||||||
except ValueError:
|
|
||||||
parser.error("invalid verbose argument")
|
|
||||||
html_path = args.html
|
|
||||||
|
|
||||||
plain = args.no_color
|
|
||||||
|
|
||||||
original = args.original
|
|
||||||
if not os.path.isfile(original):
|
|
||||||
parser.error(f"Original binary {original} does not exist")
|
|
||||||
|
|
||||||
recomp = args.recompiled
|
|
||||||
if not os.path.isfile(recomp):
|
|
||||||
parser.error(f"Recompiled binary {recomp} does not exist")
|
|
||||||
|
|
||||||
syms = args.pdb
|
|
||||||
if not os.path.isfile(syms):
|
|
||||||
parser.error(f"Symbols PDB {syms} does not exist")
|
|
||||||
|
|
||||||
source = args.decomp_dir
|
|
||||||
if not os.path.isdir(source):
|
|
||||||
parser.error(f"Source directory {source} does not exist")
|
|
||||||
|
|
||||||
svg = args.svg
|
|
||||||
|
|
||||||
with Bin(original, find_str=True) as origfile, Bin(recomp) as recompfile:
|
|
||||||
if verbose is not None:
|
|
||||||
# Mute logger events from compare engine
|
# Mute logger events from compare engine
|
||||||
logging.getLogger("isledecomp.compare.db").setLevel(logging.CRITICAL)
|
logging.getLogger("isledecomp.compare.db").setLevel(logging.CRITICAL)
|
||||||
logging.getLogger("isledecomp.compare.lines").setLevel(logging.CRITICAL)
|
logging.getLogger("isledecomp.compare.lines").setLevel(logging.CRITICAL)
|
||||||
|
|
||||||
isle_compare = IsleCompare(origfile, recompfile, syms, source)
|
isle_compare = IsleCompare(origfile, recompfile, args.pdb, args.decomp_dir)
|
||||||
|
|
||||||
print()
|
print()
|
||||||
|
|
||||||
capstone_disassembler = Cs(CS_ARCH_X86, CS_MODE_32)
|
### Compare one or none.
|
||||||
|
|
||||||
|
if args.verbose is not None:
|
||||||
|
match = isle_compare.compare_function(args.verbose)
|
||||||
|
if match is None:
|
||||||
|
print(f"Failed to find the function with address 0x{args.verbose:x}")
|
||||||
|
return
|
||||||
|
|
||||||
|
print_match_verbose(
|
||||||
|
match, show_both_addrs=args.print_rec_addr, is_plain=args.no_color
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
### Compare everything.
|
||||||
|
|
||||||
function_count = 0
|
function_count = 0
|
||||||
total_accuracy = 0
|
total_accuracy = 0
|
||||||
total_effective_accuracy = 0
|
total_effective_accuracy = 0
|
||||||
htmlinsert = []
|
htmlinsert = []
|
||||||
|
|
||||||
matches = []
|
for match in isle_compare.compare_functions():
|
||||||
if verbose is not None:
|
print_match_oneline(
|
||||||
match = isle_compare.get_one_function(verbose)
|
match, show_both_addrs=args.print_rec_addr, is_plain=args.no_color
|
||||||
if match is not None:
|
)
|
||||||
found_verbose_target = True
|
|
||||||
matches = [match]
|
|
||||||
else:
|
|
||||||
matches = isle_compare.get_functions()
|
|
||||||
|
|
||||||
for match in matches:
|
|
||||||
# The effective_ratio is the ratio when ignoring differing register
|
|
||||||
# allocation vs the ratio is the true ratio.
|
|
||||||
ratio = 0.0
|
|
||||||
effective_ratio = 0.0
|
|
||||||
if match.size:
|
|
||||||
origasm = parse_asm(
|
|
||||||
capstone_disassembler,
|
|
||||||
origfile,
|
|
||||||
match.orig_addr,
|
|
||||||
match.size,
|
|
||||||
)
|
|
||||||
recompasm = parse_asm(
|
|
||||||
capstone_disassembler,
|
|
||||||
recompfile,
|
|
||||||
match.recomp_addr,
|
|
||||||
match.size,
|
|
||||||
)
|
|
||||||
|
|
||||||
diff = difflib.SequenceMatcher(None, origasm, recompasm)
|
|
||||||
ratio = diff.ratio()
|
|
||||||
effective_ratio = ratio
|
|
||||||
|
|
||||||
if ratio != 1.0:
|
|
||||||
# Check whether we can resolve register swaps which are actually
|
|
||||||
# perfect matches modulo compiler entropy.
|
|
||||||
if can_resolve_register_differences(origasm, recompasm):
|
|
||||||
effective_ratio = 1.0
|
|
||||||
else:
|
|
||||||
ratio = 0
|
|
||||||
|
|
||||||
percenttext = f"{(effective_ratio * 100):.2f}%"
|
|
||||||
if not plain:
|
|
||||||
if effective_ratio == 1.0:
|
|
||||||
percenttext = (
|
|
||||||
colorama.Fore.GREEN + percenttext + colorama.Style.RESET_ALL
|
|
||||||
)
|
|
||||||
elif effective_ratio > 0.8:
|
|
||||||
percenttext = (
|
|
||||||
colorama.Fore.YELLOW + percenttext + colorama.Style.RESET_ALL
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
percenttext = (
|
|
||||||
colorama.Fore.RED + percenttext + colorama.Style.RESET_ALL
|
|
||||||
)
|
|
||||||
|
|
||||||
if effective_ratio == 1.0 and ratio != 1.0:
|
|
||||||
if plain:
|
|
||||||
percenttext += "*"
|
|
||||||
else:
|
|
||||||
percenttext += colorama.Fore.RED + "*" + colorama.Style.RESET_ALL
|
|
||||||
|
|
||||||
if args.print_rec_addr:
|
|
||||||
addrs = f"0x{match.orig_addr:x} / 0x{match.recomp_addr:x}"
|
|
||||||
else:
|
|
||||||
addrs = hex(match.orig_addr)
|
|
||||||
|
|
||||||
if not verbose:
|
|
||||||
print(
|
|
||||||
f" {match.name} ({addrs}) is {percenttext} similar to the original"
|
|
||||||
)
|
|
||||||
|
|
||||||
function_count += 1
|
function_count += 1
|
||||||
total_accuracy += ratio
|
total_accuracy += match.ratio
|
||||||
total_effective_accuracy += effective_ratio
|
total_effective_accuracy += match.effective_ratio
|
||||||
|
|
||||||
if match.size:
|
# If html, record the diffs to an HTML file
|
||||||
udiff = difflib.unified_diff(origasm, recompasm, n=10)
|
if args.html is not None:
|
||||||
|
htmlinsert.append(
|
||||||
# If verbose, print the diff for that function to the output
|
{
|
||||||
if verbose:
|
"address": f"0x{match.orig_addr:x}",
|
||||||
if effective_ratio == 1.0:
|
"name": match.name,
|
||||||
ok_text = (
|
"matching": match.effective_ratio,
|
||||||
"OK!"
|
"diff": "\n".join(match.udiff),
|
||||||
if plain
|
}
|
||||||
else (
|
|
||||||
colorama.Fore.GREEN
|
|
||||||
+ "✨ OK! ✨"
|
|
||||||
+ colorama.Style.RESET_ALL
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if ratio == 1.0:
|
|
||||||
print(f"{addrs}: {match.name} 100% match.\n\n{ok_text}\n\n")
|
|
||||||
else:
|
|
||||||
print(
|
|
||||||
f"{addrs}: {match.name} Effective 100%% match. (Differs in register allocation only)\n\n{ok_text} (still differs in register allocation)\n\n"
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
print_diff(udiff, plain)
|
|
||||||
|
|
||||||
print(
|
|
||||||
f"\n{match.name} is only {percenttext} similar to the original, diff above"
|
|
||||||
)
|
|
||||||
|
|
||||||
# If html, record the diffs to an HTML file
|
|
||||||
if html_path:
|
|
||||||
htmlinsert.append(
|
|
||||||
{
|
|
||||||
"address": f"0x{match.orig_addr:x}",
|
|
||||||
"name": match.name,
|
|
||||||
"matching": effective_ratio,
|
|
||||||
"diff": "\n".join(udiff),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
if html_path:
|
|
||||||
gen_html(html_path, json.dumps(htmlinsert))
|
|
||||||
|
|
||||||
if verbose:
|
|
||||||
if not found_verbose_target:
|
|
||||||
print(f"Failed to find the function with address 0x{verbose:x}")
|
|
||||||
else:
|
|
||||||
implemented_funcs = function_count
|
|
||||||
|
|
||||||
if args.total:
|
|
||||||
function_count = int(args.total)
|
|
||||||
|
|
||||||
if function_count > 0:
|
|
||||||
effective_accuracy = total_effective_accuracy / function_count * 100
|
|
||||||
actual_accuracy = total_accuracy / function_count * 100
|
|
||||||
print(
|
|
||||||
f"\nTotal effective accuracy {effective_accuracy:.2f}% across {function_count} functions ({actual_accuracy:.2f}% actual accuracy)"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if svg:
|
## Generate files and show summary.
|
||||||
gen_svg(
|
|
||||||
svg,
|
if args.html is not None:
|
||||||
os.path.basename(original),
|
gen_html(args.html, json.dumps(htmlinsert))
|
||||||
args.svg_icon,
|
|
||||||
implemented_funcs,
|
implemented_funcs = function_count
|
||||||
function_count,
|
|
||||||
total_effective_accuracy,
|
if args.total:
|
||||||
)
|
function_count = int(args.total)
|
||||||
|
|
||||||
|
if function_count > 0:
|
||||||
|
effective_accuracy = total_effective_accuracy / function_count * 100
|
||||||
|
actual_accuracy = total_accuracy / function_count * 100
|
||||||
|
print(
|
||||||
|
f"\nTotal effective accuracy {effective_accuracy:.2f}% across {function_count} functions ({actual_accuracy:.2f}% actual accuracy)"
|
||||||
|
)
|
||||||
|
|
||||||
|
if args.svg is not None:
|
||||||
|
gen_svg(
|
||||||
|
args.svg,
|
||||||
|
os.path.basename(args.original),
|
||||||
|
args.svg_icon,
|
||||||
|
implemented_funcs,
|
||||||
|
function_count,
|
||||||
|
total_effective_accuracy,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user