diff --git a/code/components/gta-streaming-five/include/sfDefinitions.h b/code/components/gta-streaming-five/include/sfDefinitions.h new file mode 100644 index 0000000000..b59c494cff --- /dev/null +++ b/code/components/gta-streaming-five/include/sfDefinitions.h @@ -0,0 +1,203 @@ +/* + * This file is part of the CitizenFX project - http://citizen.re/ + * + * See LICENSE and MENTIONS in the root of the source tree for information + * regarding licensing. + */ + +#pragma once + +#include + +class GMemoryHeap +{ +public: + virtual void m_00() = 0; + virtual void m_08() = 0; + virtual void m_10() = 0; + virtual void m_18() = 0; + virtual void m_20() = 0; + virtual void m_28() = 0; + virtual void m_30() = 0; + virtual void m_38() = 0; + virtual void m_40() = 0; + virtual void m_48() = 0; + virtual void* Alloc(uint32_t size) = 0; + virtual void m_58() = 0; + virtual void Free(void* memory) = 0; +}; + +// Unification of GRefCountBase and GRefCountBaseNTS. Once the Scaleform bits +// are further researched this will require splitting up. +class GRefCountBase +{ +public: + virtual ~GRefCountBase() = default; + + void* operator new(size_t size); + void operator delete(void* ptr); + void operator delete[](void* ptr); + +private: + volatile long RefCount; +}; + +class GFxObjectInterface; +class GFxValue; + +class GFxFunctionHandler : public GRefCountBase +{ +public: + struct Params + { + GFxValue* pRetVal; + void* pMovie; + GFxValue* pThis; + GFxValue* pArgsWithThisRef; + GFxValue* pArgs; + uint32_t ArgCount; + void* pUserData; + }; + + virtual ~GFxFunctionHandler() {} + virtual void Call(const Params& params) = 0; +}; + +class GFxMovieRoot +{ +public: + virtual void m_00() = 0; + virtual void m_08() = 0; + virtual void m_10() = 0; + virtual void m_18() = 0; + virtual void m_20() = 0; + virtual void m_28() = 0; + virtual void m_30() = 0; + virtual void m_38() = 0; + virtual void m_40() = 0; + virtual void m_48() = 0; + virtual void m_50() = 0; + virtual void m_58() = 0; + virtual void m_60() = 0; + virtual void m_68() = 0; + virtual void m_70() = 0; + virtual void CreateFunction(GFxValue* value, GFxFunctionHandler* pfc, void* puserData = nullptr) = 0; + virtual void SetVariable(const char* path, const GFxValue& value, int type) = 0; +}; + +class GFxValue +{ +public: + struct DisplayInfo + { + double X; + double Y; + double Rotation; + double XScale; + double YScale; + double Alpha; + bool Visible; + double Z; + double XRotation; + double YRotation; + double ZScale; + double FOV; + float ViewMatrix3D[4][4]; + float ProjectionMatrix3D[4][4]; + uint16_t VarsSet; + }; + +protected: + enum ValueTypeControl + { + VTC_ConvertBit = 0x80, + VTC_ManagedBit = 0x40, + + VTC_TypeMask = VTC_ConvertBit | 0x0F, + }; + +public: + enum ValueType + { + VT_Undefined = 0x00, + VT_Null = 0x01, + VT_Boolean = 0x02, + VT_Number = 0x03, + VT_String = 0x04, + VT_StringW = 0x05, + VT_Object = 0x06, + VT_Array = 0x07, + VT_DisplayObject = 0x08, + + VT_ConvertBoolean = VTC_ConvertBit | VT_Boolean, + VT_ConvertNumber = VTC_ConvertBit | VT_Number, + VT_ConvertString = VTC_ConvertBit | VT_String, + VT_ConvertStringW = VTC_ConvertBit | VT_StringW + }; + + union ValueUnion + { + double NValue; + bool BValue; + const char* pString; + const char** pStringManaged; + const wchar_t* pStringW; + void* pData; + }; + + inline GFxValue() + { + pObjectInterface = nullptr; + Type = VT_Undefined; + mValue.pData = nullptr; + } + + inline GFxValue(const char* str) + { + pObjectInterface = nullptr; + Type = VT_String; + mValue.pString = str; + } + + inline ~GFxValue() + { + if (Type & VTC_ManagedBit) + { + ReleaseManagedValue(); + } + } + + inline ValueType GetType() const + { + return ValueType(Type & VTC_TypeMask); + } + + inline bool IsDisplayObject() const + { + return (Type & VTC_TypeMask) == VT_DisplayObject; + } + + inline double GetNumber() const + { + assert(GetType() == VT_Number); + return mValue.NValue; + } + + inline const char* GetString() const + { + assert((Type & VTC_TypeMask) == VT_String); + return (Type & VTC_ManagedBit) ? *mValue.pStringManaged : mValue.pString; + } + + void ReleaseManagedValue(); + bool CreateEmptyMovieClip(GFxValue* movieClip, const char* instanceName, int depth); + bool GetDisplayInfo(DisplayInfo* info); + bool SetDisplayInfo(const DisplayInfo& info); + bool Invoke(const char* name, GFxValue* presult, const GFxValue* pargs, int nargs); + bool GetMember(const char* name, GFxValue* pval) const; + +private: + GFxObjectInterface* pObjectInterface; + ValueType Type; + ValueUnion mValue; +}; diff --git a/code/components/gta-streaming-five/src/ScaleformHacks.cpp b/code/components/gta-streaming-five/src/ScaleformHacks.cpp index 02a4f08263..1bd1c009ba 100644 --- a/code/components/gta-streaming-five/src/ScaleformHacks.cpp +++ b/code/components/gta-streaming-five/src/ScaleformHacks.cpp @@ -3,48 +3,23 @@ #include #include +#include #include #include #include -struct GFxObjectInterface -{ - -}; - -struct GFxValue; - static hook::cdecl_stub __GFxObjectInterface_CreateEmptyMovieClip([]() { return hook::get_pattern("4D 8B E0 4C 8B F9 48 85 DB 75 18 48", -0x25); }); -struct GFxDisplayInfo -{ - double X; - double Y; - double Rotation; - double XScale; - double YScale; - double Alpha; - bool Visible; - double Z; - double XRotation; - double YRotation; - double ZScale; - double FOV; - float ViewMatrix3D[4][4]; - float ProjectionMatrix3D[4][4]; - uint16_t VarsSet; -}; - -static hook::cdecl_stub __GFxObjectInterface_GetDisplayInfo([]() +static hook::cdecl_stub __GFxObjectInterface_GetDisplayInfo([]() { return hook::get_pattern("83 65 9B 00 83 65 97 00 F2", -0x60); }); -static hook::cdecl_stub __GFxObjectInterface_SetDisplayInfo([]() +static hook::cdecl_stub __GFxObjectInterface_SetDisplayInfo([]() { return hook::get_pattern("48 8B 5A 08 0F 29 70 B8 0F 29 78 A8", -0x1D); }); @@ -64,214 +39,60 @@ static hook::cdecl_stub0x7EFFFFFD - if (depth > 0x7EFFFFFD) - { - depth = 0x7EFFFFFD; - } - - return __GFxObjectInterface_CreateEmptyMovieClip(pObjectInterface, mValue.pData, movieClip, instanceName, depth); - } - - inline bool GetDisplayInfo(GFxDisplayInfo* info) - { - return __GFxObjectInterface_GetDisplayInfo(pObjectInterface, mValue.pData, info); - } - - inline bool SetDisplayInfo(const GFxDisplayInfo& info) - { - return __GFxObjectInterface_SetDisplayInfo(pObjectInterface, mValue.pData, info); - } + __GFxObjectInterface_ObjectRelease(pObjectInterface, this, mValue.pData); + pObjectInterface = nullptr; +} - inline bool Invoke(const char* name, GFxValue* presult, const GFxValue* pargs, int nargs) +bool GFxValue::CreateEmptyMovieClip(GFxValue* movieClip, const char* instanceName, int depth) +{ + // CreateEmptyMovieClip will fail if depth >0x7EFFFFFD + if (depth > 0x7EFFFFFD) { - return __GFxObjectInterface_Invoke(pObjectInterface, mValue.pData, presult, name, (GFxValue*)pargs, nargs, IsDisplayObject()); + depth = 0x7EFFFFFD; } - inline bool GetMember(const char* name, GFxValue* pval) const - { - return __GFxObjectInterface_GetMember(pObjectInterface, mValue.pData, name, pval, IsDisplayObject()); - } -}; + return __GFxObjectInterface_CreateEmptyMovieClip(pObjectInterface, mValue.pData, movieClip, instanceName, depth); +} -class GFxMemoryHeap +bool GFxValue::GetDisplayInfo(GFxValue::DisplayInfo* info) { -public: - virtual void m_00() = 0; - virtual void m_08() = 0; - virtual void m_10() = 0; - virtual void m_18() = 0; - virtual void m_20() = 0; - virtual void m_28() = 0; - virtual void m_30() = 0; - virtual void m_38() = 0; - virtual void m_40() = 0; - virtual void m_48() = 0; - virtual void* Alloc(uint32_t size) = 0; - virtual void m_58() = 0; - virtual void Free(void* memory) = 0; -}; - -GFxMemoryHeap** g_gfxMemoryHeap;// = (GFxMemoryHeap**)0x142CBB3E8; + return __GFxObjectInterface_GetDisplayInfo(pObjectInterface, mValue.pData, info); +} -class GFxRefCountBase +bool GFxValue::SetDisplayInfo(const GFxValue::DisplayInfo& info) { -private: - volatile int refCount; + return __GFxObjectInterface_SetDisplayInfo(pObjectInterface, mValue.pData, info); +} -public: - virtual ~GFxRefCountBase() = default; +bool GFxValue::Invoke(const char* name, GFxValue* presult, const GFxValue* pargs, int nargs) +{ + return __GFxObjectInterface_Invoke(pObjectInterface, mValue.pData, presult, name, (GFxValue*)pargs, nargs, IsDisplayObject()); +} - inline void* operator new(size_t size) - { - return (*g_gfxMemoryHeap)->Alloc(size); - } +bool GFxValue::GetMember(const char* name, GFxValue* pval) const +{ + return __GFxObjectInterface_GetMember(pObjectInterface, mValue.pData, name, pval, IsDisplayObject()); +} - inline void operator delete(void* ptr) - { - (*g_gfxMemoryHeap)->Free(ptr); - } +GMemoryHeap** g_gfxMemoryHeap;// = (GFxMemoryHeap**)0x142CBB3E8; - inline void operator delete[](void* ptr) - { - (*g_gfxMemoryHeap)->Free(ptr); - } -}; +void* GRefCountBase::operator new(size_t size) +{ + //assert(size <= static_cast(std::numeric_limits::max())); + return (*g_gfxMemoryHeap)->Alloc(static_cast(size)); +} -class GFxFunctionHandler : public GFxRefCountBase +void GRefCountBase::operator delete(void* ptr) { -public: - struct Params - { - GFxValue* pRetVal; - void* pMovie; - GFxValue* pThis; - GFxValue* pArgsWithThisRef; - GFxValue* pArgs; - uint32_t ArgCount; - void* pUserData; - }; - - virtual ~GFxFunctionHandler() {} - - virtual void Call(const Params& params) = 0; -}; + (*g_gfxMemoryHeap)->Free(ptr); +} -class GFxMovieRoot +void GRefCountBase::operator delete[](void* ptr) { -public: - virtual void m_00() = 0; - virtual void m_08() = 0; - virtual void m_10() = 0; - virtual void m_18() = 0; - virtual void m_20() = 0; - virtual void m_28() = 0; - virtual void m_30() = 0; - virtual void m_38() = 0; - virtual void m_40() = 0; - virtual void m_48() = 0; - virtual void m_50() = 0; - virtual void m_58() = 0; - virtual void m_60() = 0; - virtual void m_68() = 0; - virtual void m_70() = 0; - virtual void CreateFunction(GFxValue* value, GFxFunctionHandler* pfc, void* puserData = nullptr) = 0; - virtual void SetVariable(const char* path, const GFxValue& value, int type) = 0; -}; + (*g_gfxMemoryHeap)->Free(ptr); +} static hook::cdecl_stub _getScaleformASRoot([]() { @@ -295,7 +116,7 @@ class OverlayMethodFunctionHandler : public GFxFunctionHandler return; } - int movieId = params.pArgs[0].mValue.NValue; + int movieId = static_cast(params.pArgs[0].GetNumber()); auto& clipVal = g_overlayClips[movieId]; @@ -401,7 +222,7 @@ namespace sf if (clip) { - GFxDisplayInfo dispInfo; + GFxValue::DisplayInfo dispInfo; dispInfo.VarsSet = 0x1 | 0x2 | 0x8 | 0x10 | 0x20; // x, y, xscale, yscale, alpha dispInfo.X = x; dispInfo.Y = y; @@ -514,7 +335,7 @@ static HookFunction hookFunction([]() g_gfxId = hook::get_address(hook::get_pattern("66 C7 45 E4 01 01 E8", 0x2A)); } - g_gfxMemoryHeap = hook::get_address(hook::get_pattern("F0 FF 4A 08 75 0E 48 8B 0D", 9)); + g_gfxMemoryHeap = hook::get_address(hook::get_pattern("F0 FF 4A 08 75 0E 48 8B 0D", 9)); // scaleform -> game call hook, for debug logging