mirror of
https://github.com/Milxnor/Project-Reboot-3.0.git
synced 2026-01-13 02:42:22 +01:00
fix 1.11 replication, fix some ltm specific stuff, start on shadow stones, fix some events not having foundations, fix s4-s6 gadgets, fix clear inventory on some versions
420 lines
10 KiB
C++
420 lines
10 KiB
C++
#pragma once
|
|
|
|
#include "UObjectGlobals.h"
|
|
#include "Engine.h"
|
|
// #include "World.h"
|
|
|
|
#include "RandomStream.h"
|
|
#include "Class.h"
|
|
#include "globals.h"
|
|
#include <set>
|
|
|
|
#include "NetSerialization.h"
|
|
|
|
/* enum class REBOOT_ERROR : uint8
|
|
{
|
|
FAILED_STRINGREF = 1,
|
|
FAILED_CREATE_NETDRIVER = 2,
|
|
FAILED_LISTEN = 3
|
|
}; */
|
|
|
|
extern inline UObject* (*StaticLoadObjectOriginal)(UClass*, UObject*, const wchar_t* InName, const wchar_t* Filename, uint32_t LoadFlags, UObject* Sandbox, bool bAllowObjectReconciliation) = nullptr;
|
|
|
|
template <typename T = UObject>
|
|
static inline T* FindObject(const TCHAR* Name, UClass* Class = nullptr, UObject* Outer = nullptr)
|
|
{
|
|
auto res = (T*)StaticFindObject/*<T>*/(Class, Outer, Name);
|
|
return res;
|
|
}
|
|
|
|
template <typename T = UObject>
|
|
static inline T* LoadObject(const TCHAR* Name, UClass* Class = T::StaticClass(), UObject* Outer = nullptr)
|
|
{
|
|
if (!StaticLoadObjectOriginal)
|
|
{
|
|
std::wstring NameWStr = std::wstring(Name);
|
|
LOG_WARN(LogDev, "We should load {} but static load object is null!", std::string(NameWStr.begin(), NameWStr.end()));
|
|
return FindObject<T>(Name, Class, Outer);
|
|
}
|
|
|
|
auto Object = (T*)StaticLoadObjectOriginal(Class, Outer, Name, nullptr, 0, nullptr, false);
|
|
|
|
if (!Object)
|
|
{
|
|
LOG_WARN(LogDev, "Failed to load object!");
|
|
}
|
|
|
|
return Object;
|
|
}
|
|
|
|
template <typename T = UObject>
|
|
static inline T* LoadObject(const std::string& NameStr, UClass* Class = nullptr, UObject* Outer = nullptr)
|
|
{
|
|
auto NameCWSTR = std::wstring(NameStr.begin(), NameStr.end()).c_str();
|
|
return (T*)StaticLoadObjectOriginal(Class, Outer, NameCWSTR, nullptr, 0, nullptr, false);
|
|
}
|
|
|
|
template <typename T = UObject>
|
|
static inline T* FindObject(const std::string& NameStr, UClass* Class = nullptr, UObject* Outer = nullptr)
|
|
{
|
|
std::string name = NameStr;
|
|
auto NameCWSTR = std::wstring(name.begin(), name.end()).c_str();
|
|
return StaticFindObject<T>(Class, Outer, NameCWSTR);
|
|
}
|
|
|
|
static inline UEngine* GetEngine()
|
|
{
|
|
static UEngine* Engine = FindObject<UEngine>(L"/Engine/Transient.FortEngine_0");
|
|
|
|
if (!Engine)
|
|
{
|
|
__int64 starting = 2147482000;
|
|
|
|
for (__int64 i = starting; i < (starting + 1000); i++)
|
|
{
|
|
if (Engine = FindObject<UEngine>("/Engine/Transient.FortEngine_" + std::to_string(i)))
|
|
break;
|
|
}
|
|
}
|
|
|
|
return Engine;
|
|
}
|
|
|
|
static inline class UWorld* GetWorld()
|
|
{
|
|
static UObject* Engine = GetEngine();
|
|
static auto GameViewportOffset = Engine->GetOffset("GameViewport");
|
|
auto GameViewport = Engine->Get<UObject*>(GameViewportOffset);
|
|
|
|
static auto WorldOffset = GameViewport->GetOffset("World");
|
|
|
|
return GameViewport->Get<class UWorld*>(WorldOffset);
|
|
}
|
|
|
|
static TArray<UObject*>& GetLocalPlayers()
|
|
{
|
|
static UObject* Engine = GetEngine();
|
|
|
|
static auto GameInstanceOffset = Engine->GetOffset("GameInstance");
|
|
UObject* GameInstance = Engine->Get(GameInstanceOffset);
|
|
|
|
static auto LocalPlayersOffset = GameInstance->GetOffset("LocalPlayers");
|
|
|
|
return GameInstance->Get<TArray<UObject*>>(LocalPlayersOffset);
|
|
}
|
|
|
|
static UObject* GetLocalPlayer()
|
|
{
|
|
auto& LocalPlayers = GetLocalPlayers();
|
|
|
|
return LocalPlayers.Num() ? LocalPlayers.At(0) : nullptr;
|
|
}
|
|
|
|
static inline UObject* GetLocalPlayerController()
|
|
{
|
|
auto LocalPlayer = GetLocalPlayer();
|
|
|
|
if (!LocalPlayer)
|
|
return nullptr;
|
|
|
|
static auto PlayerControllerOffset = LocalPlayer->GetOffset("PlayerController");
|
|
|
|
return LocalPlayer->Get(PlayerControllerOffset);
|
|
}
|
|
|
|
template <typename T>
|
|
static __forceinline T* Cast(UObject* Object, bool bCheckType = true)
|
|
{
|
|
if (bCheckType)
|
|
{
|
|
if (Object && Object->IsA(T::StaticClass()))
|
|
{
|
|
return (T*)Object;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return (T*)Object;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
extern inline int AmountOfRestarts = 0; // DO NOT CHANGE
|
|
extern inline FRandomStream ReplicationRandStream = (0);
|
|
extern inline int32 GSRandSeed = 0;
|
|
extern inline std::set<std::string> ReplicatedActors = {};
|
|
|
|
inline uint8_t GetFieldMask(void* Property, int additional = 0)
|
|
{
|
|
if (!Property)
|
|
return -1;
|
|
|
|
// 3 = sizeof(FieldSize) + sizeof(ByteOffset) + sizeof(ByteMask)
|
|
|
|
if (Engine_Version <= 420)
|
|
return *(uint8_t*)(__int64(Property) + (112 + 3 + additional));
|
|
else if (Engine_Version >= 421 && Engine_Version <= 424)
|
|
return *(uint8_t*)(__int64(Property) + (112 + 3 + additional));
|
|
else if (Engine_Version >= 425)
|
|
return *(uint8_t*)(__int64(Property) + (120 + 3 + additional));
|
|
|
|
return -1;
|
|
}
|
|
|
|
inline bool ReadBitfield(void* Addr, uint8_t FieldMask)
|
|
{
|
|
auto Bitfield = (PlaceholderBitfield*)Addr;
|
|
|
|
// niceeeee
|
|
|
|
if (FieldMask == 0x1)
|
|
return Bitfield->First;
|
|
else if (FieldMask == 0x2)
|
|
return Bitfield->Second;
|
|
else if (FieldMask == 0x4)
|
|
return Bitfield->Third;
|
|
else if (FieldMask == 0x8)
|
|
return Bitfield->Fourth;
|
|
else if (FieldMask == 0x10)
|
|
return Bitfield->Fifth;
|
|
else if (FieldMask == 0x20)
|
|
return Bitfield->Sixth;
|
|
else if (FieldMask == 0x40)
|
|
return Bitfield->Seventh;
|
|
else if (FieldMask == 0x80)
|
|
return Bitfield->Eighth;
|
|
else if (FieldMask == 0xFF)
|
|
return *(bool*)Bitfield;
|
|
|
|
return false;
|
|
}
|
|
|
|
inline void SetBitfield(void* Addr, uint8_t FieldMask, bool NewVal)
|
|
{
|
|
auto Bitfield = (PlaceholderBitfield*)Addr;
|
|
|
|
// niceeeee
|
|
|
|
if (FieldMask == 0x1)
|
|
Bitfield->First = NewVal;
|
|
else if (FieldMask == 0x2)
|
|
Bitfield->Second = NewVal;
|
|
else if (FieldMask == 0x4)
|
|
Bitfield->Third = NewVal;
|
|
else if (FieldMask == 0x8)
|
|
Bitfield->Fourth = NewVal;
|
|
else if (FieldMask == 0x10)
|
|
Bitfield->Fifth = NewVal;
|
|
else if (FieldMask == 0x20)
|
|
Bitfield->Sixth = NewVal;
|
|
else if (FieldMask == 0x40)
|
|
Bitfield->Seventh = NewVal;
|
|
else if (FieldMask == 0x80)
|
|
Bitfield->Eighth = NewVal;
|
|
else if (FieldMask == 0xFF)
|
|
*(bool*)Bitfield = NewVal;
|
|
}
|
|
|
|
template<typename T = UObject>
|
|
inline std::vector<T*> GetAllObjectsOfClass(UClass* Class)
|
|
{
|
|
std::vector<T*> Objects;
|
|
|
|
if (!Class)
|
|
return Objects;
|
|
|
|
auto ObjectNum = ChunkedObjects ? ChunkedObjects->Num() : UnchunkedObjects ? UnchunkedObjects->Num() : 0;
|
|
|
|
for (int i = 0; i < ObjectNum; i++)
|
|
{
|
|
auto Object = GetObjectByIndex(i);
|
|
|
|
if (!Object)
|
|
continue;
|
|
|
|
if (Object->IsA(Class))
|
|
Objects.push_back(Object);
|
|
}
|
|
|
|
return Objects;
|
|
}
|
|
|
|
inline void* FindPropertyStruct(const std::string& StructName, const std::string& MemberName, bool bWarnIfNotFound = true)
|
|
{
|
|
UObject* Struct = FindObject(StructName);
|
|
|
|
if (!Struct)
|
|
{
|
|
if (bWarnIfNotFound)
|
|
LOG_WARN(LogFinder, "Unable to find struct4 {}", StructName);
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
// LOG_INFO(LogFinder, "Struct: {}", Struct->GetFullName());
|
|
|
|
auto getFNameOfProp = [](void* Property) -> FName*
|
|
{
|
|
FName* NamePrivate = nullptr;
|
|
|
|
if (Engine_Version >= 425)
|
|
NamePrivate = (FName*)(__int64(Property) + 0x28);
|
|
else
|
|
NamePrivate = &((UField*)Property)->NamePrivate;
|
|
|
|
return NamePrivate;
|
|
};
|
|
|
|
for (auto CurrentClass = Struct; CurrentClass; CurrentClass = *(UObject**)(__int64(CurrentClass) + Offsets::SuperStruct))
|
|
{
|
|
void* Property = *(void**)(__int64(CurrentClass) + Offsets::Children);
|
|
|
|
if (Property)
|
|
{
|
|
std::string PropName = getFNameOfProp(Property)->ToString();
|
|
|
|
if (PropName == MemberName)
|
|
{
|
|
return Property;
|
|
}
|
|
|
|
while (Property)
|
|
{
|
|
// LOG_INFO(LogFinder, "PropName: {}", PropName);
|
|
|
|
if (PropName == MemberName)
|
|
{
|
|
return Property;
|
|
}
|
|
|
|
Property = Engine_Version >= 425 ? *(void**)(__int64(Property) + 0x20) : ((UField*)Property)->Next;
|
|
PropName = Property ? getFNameOfProp(Property)->ToString() : "";
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bWarnIfNotFound)
|
|
LOG_WARN(LogFinder, "Unable to find6 {}", MemberName);
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
inline int FindOffsetStruct(const std::string& StructName, const std::string& MemberName, bool bWarnIfNotFound = true)
|
|
{
|
|
UObject* Struct = FindObject(StructName);
|
|
|
|
if (!Struct)
|
|
{
|
|
if (bWarnIfNotFound)
|
|
LOG_WARN(LogFinder, "Unable to find struct {}", StructName);
|
|
|
|
return 0;
|
|
}
|
|
|
|
// LOG_INFO(LogFinder, "Struct: {}", Struct->GetFullName());
|
|
|
|
auto getFNameOfProp = [](void* Property) -> FName*
|
|
{
|
|
FName* NamePrivate = nullptr;
|
|
|
|
if (Engine_Version >= 425)
|
|
NamePrivate = (FName*)(__int64(Property) + 0x28);
|
|
else
|
|
NamePrivate = &((UField*)Property)->NamePrivate;
|
|
|
|
return NamePrivate;
|
|
};
|
|
|
|
for (auto CurrentClass = Struct; CurrentClass; CurrentClass = *(UObject**)(__int64(CurrentClass) + Offsets::SuperStruct))
|
|
{
|
|
void* Property = *(void**)(__int64(CurrentClass) + Offsets::Children);
|
|
|
|
if (Property)
|
|
{
|
|
std::string PropName = getFNameOfProp(Property)->ToString();
|
|
|
|
if (PropName == MemberName)
|
|
{
|
|
return *(int*)(__int64(Property) + Offsets::Offset_Internal);
|
|
}
|
|
|
|
while (Property)
|
|
{
|
|
// LOG_INFO(LogFinder, "PropName: {}", PropName);
|
|
|
|
if (PropName == MemberName)
|
|
{
|
|
return *(int*)(__int64(Property) + Offsets::Offset_Internal);
|
|
}
|
|
|
|
Property = Engine_Version >= 425 ? *(void**)(__int64(Property) + 0x20) : ((UField*)Property)->Next;
|
|
PropName = Property ? getFNameOfProp(Property)->ToString() : "";
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bWarnIfNotFound)
|
|
LOG_WARN(LogFinder, "Unable to find1 {}", MemberName);
|
|
|
|
return -1;
|
|
}
|
|
|
|
// template <typename T>
|
|
static void CopyStruct(void* Dest, void* Src, size_t Size, UStruct* Struct = nullptr)
|
|
{
|
|
memcpy_s(Dest, Size, Src, Size);
|
|
|
|
if (Struct)
|
|
{
|
|
/* if (std::is_same<T, FFastArraySerializerItem>::value)
|
|
{
|
|
|
|
} */
|
|
|
|
// TODO: Loop through all the children, check type, if it is ArrayProperty then we need to properly copy it over.
|
|
}
|
|
}
|
|
|
|
template <typename T = __int64>
|
|
static T* Alloc(size_t Size = sizeof(T), bool bUseRealloc = false)
|
|
{
|
|
return bUseRealloc ? (T*)FMemory::Realloc(0, Size, 0) : (T*)VirtualAlloc(0, Size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
|
}
|
|
|
|
namespace MemberOffsets
|
|
{
|
|
namespace FortPlayerPawnAthena
|
|
{
|
|
extern inline int LastFallDistance = 0;
|
|
}
|
|
namespace FortPlayerPawn
|
|
{
|
|
extern inline int CorrectTags = 0;
|
|
}
|
|
namespace FortPlayerState
|
|
{
|
|
extern inline int PawnDeathLocation = 0;
|
|
}
|
|
namespace FortPlayerStateAthena
|
|
{
|
|
extern inline int DeathInfo = 0;
|
|
extern inline int KillScore = 0;
|
|
extern inline int TeamKillScore = 0;
|
|
}
|
|
namespace DeathReport
|
|
{
|
|
extern inline int Tags = 0, KillerPlayerState = 0, KillerPawn = 0, DamageCauser = 0;
|
|
}
|
|
namespace DeathInfo
|
|
{
|
|
extern inline int bDBNO = 0, Downer = 0, FinisherOrDowner = 0, DeathCause = 0, Distance = 0, DeathLocation = 0, bInitialized = 0, DeathTags = 0;
|
|
}
|
|
}
|
|
|
|
static inline float GetMaxTickRateHook() { return 30.f; }
|
|
|
|
#define VALIDATEOFFSET(offset) if (!offset) LOG_WARN(LogDev, "[{}] Invalid offset", __FUNCTIONNAME__);
|
|
|
|
#define GET_PLAYLIST(GameState) static auto CurrentPlaylistDataOffset = GameState->GetOffset("CurrentPlaylistData", false); \
|
|
auto CurrentPlaylist = CurrentPlaylistDataOffset == -1 && Fortnite_Version < 6 ? nullptr : GameState->GetCurrentPlaylist(); |