Skip to content

Commit

Permalink
Fix CInstance misalingment in x86
Browse files Browse the repository at this point in the history
- Added OLinkedList struct for older runners
  - Shouldn't impact x64, due to various static_asserts
- Added "MembersOnly" alignment option to CInstance, fixing some compatibility
  - CInstance::GetMembers now prints an error if it can't determine the correct alignment.
- Fixed InvokeWithObject using Object.AsReal instead of instance.AsReal.
  • Loading branch information
Archie-osu committed Jun 20, 2024
1 parent 290c3a4 commit ea9e6b0
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 11 deletions.
2 changes: 1 addition & 1 deletion YYToolkit/source/YYTK/Module Interface/Interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1556,7 +1556,7 @@ namespace YYTK
}

// Get the instance ID from the instance
int32_t instance_id = static_cast<int32_t>(Object.AsReal());
int32_t instance_id = static_cast<int32_t>(instance.AsReal());

// Skip inactive instances / instances that don't exist
CInstance* object_instance = nullptr;
Expand Down
22 changes: 18 additions & 4 deletions YYToolkit/source/YYTK/Shared.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -393,8 +393,10 @@ size_t YYTK::RValue::length()
CInstanceInternal& YYTK::CInstance::GetMembers()
{
YYTKInterface* module_interface = GetYYTKInterface();

// SequenceInstanceOnly is used in most new games that v3 is targetting
if (!module_interface)
return this->Unmasked.Members;
return this->SequenceInstanceOnly.Members;

RValue self_id_builtin;
module_interface->GetBuiltin(
Expand All @@ -406,10 +408,22 @@ CInstanceInternal& YYTK::CInstance::GetMembers()

int32_t self_id = static_cast<int32_t>(self_id_builtin.AsReal());

if (this->Unmasked.Members.m_ID == self_id)
return this->Unmasked.Members;
if (this->MembersOnly.Members.m_ID == self_id)
return this->MembersOnly.Members;

if (this->SequenceInstanceOnly.Members.m_ID == self_id)
return this->SequenceInstanceOnly.Members;

if (this->WithSkeletonMask.Members.m_ID == self_id)
return this->WithSkeletonMask.Members;

module_interface->PrintError(
__FILE__,
__LINE__,
"Failed to determine CInstance member offset! Report this to GitHub and include the game name!"
);

return this->Masked.Members;
return this->SequenceInstanceOnly.Members;
}
#endif // YYTK_DEFINE_INTERNAL

Expand Down
37 changes: 31 additions & 6 deletions YYToolkit/source/YYTK/Shared.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

#define YYTK_MAJOR 3
#define YYTK_MINOR 3
#define YYTK_PATCH 1
#define YYTK_PATCH 2

#ifndef YYTK_CPP_VERSION
#ifndef _MSVC_LANG
Expand Down Expand Up @@ -2042,17 +2042,32 @@ namespace YYTK
}
};

// Newer struct, later renamed to LinkedList - OLinkedList is used in older x86 games,
// and causes misalingment due to alignment changing from 8-bytes in x64 to 4-bytes in x86.
template <typename T>
struct LinkedList
{
T* m_First;
T* m_Last;
int32_t m_Count;
int32_t m_DeleteType;
};
#ifdef _WIN64
static_assert(sizeof(LinkedList<CInstance>) == 0x18);
#endif // _WIN64

template <typename T>
struct OLinkedList
{
T* m_First;
T* m_Last;
int32_t m_Count;
};
#ifdef _WIN64
static_assert(sizeof(OLinkedList<CInstance>) == 0x18);
static_assert(sizeof(OLinkedList<CInstance>) == sizeof(LinkedList<CInstance>));
#endif // _WIN64

enum eBuffer_Type : int32_t
{
eBuffer_None = 0x0,
Expand Down Expand Up @@ -2259,7 +2274,7 @@ namespace YYTK
int32_t m_PhysicsGravityX;
int32_t m_PhysicsGravityY;
float m_PhysicsPixelToMeters;
LinkedList<CInstance> m_ActiveInstances;
OLinkedList<CInstance> m_ActiveInstances;
LinkedList<CInstance> m_InactiveInstances;
CInstance* m_MarkedFirst;
CInstance* m_MarkedLast;
Expand Down Expand Up @@ -2577,16 +2592,26 @@ namespace YYTK
// Use GetMembers() to get a CInstanceVariables reference.
union
{
// Islets 1.0.0.3 Steam (x86), GM 2022.6
struct
{
public:
CInstanceInternal Members;
} MembersOnly;
#ifdef _WIN64
static_assert(sizeof(MembersOnly) == 0xF8);
#endif // _WIN64

// 2023.x => 2023.8 (and presumably 2023.11)
struct
{
private:
PVOID m_SequenceInstance;
public:
CInstanceInternal Members;
} Unmasked;
} SequenceInstanceOnly;
#ifdef _WIN64
static_assert(sizeof(Unmasked) == 0x100);
static_assert(sizeof(SequenceInstanceOnly) == 0x100);
#endif // _WIN64

// 2022.1 => 2023.1 (may be used later, haven't checked)
Expand All @@ -2597,9 +2622,9 @@ namespace YYTK
PVOID m_SequenceInstance;
public:
CInstanceInternal Members;
} Masked;
} WithSkeletonMask;
#ifdef _WIN64
static_assert(sizeof(Masked) == 0x108);
static_assert(sizeof(WithSkeletonMask) == 0x108);
#endif // _WIN64
};
public:
Expand Down

0 comments on commit ea9e6b0

Please sign in to comment.