performace

This commit is contained in:
Milxnor
2023-06-11 14:34:35 -04:00
parent 8bdd33d936
commit ed0c9005e6
10 changed files with 269 additions and 107 deletions

View File

@@ -17,6 +17,11 @@ FNetworkObjectList& UNetDriver::GetNetworkObjectList()
return *(*(TSharedPtr<FNetworkObjectList>*)(__int64(this) + Offsets::NetworkObjectList));
}
bool ShouldUseNetworkObjectList()
{
return Fortnite_Version < 20;
}
void UNetDriver::RemoveNetworkActor(AActor* Actor)
{
GetNetworkObjectList().Remove(Actor);
@@ -35,7 +40,8 @@ void UNetDriver::TickFlushHook(UNetDriver* NetDriver)
{
static auto ReplicationDriverOffset = NetDriver->GetOffset("ReplicationDriver", false);
if (ReplicationDriverOffset == -1)
// if (ReplicationDriverOffset == -1)
if (ReplicationDriverOffset == -1 || Fortnite_Version >= 20)
{
NetDriver->ServerReplicateActors();
}
@@ -149,98 +155,148 @@ void UNetDriver::ServerReplicateActors_BuildConsiderList(std::vector<FNetworkObj
{
std::vector<AActor*> ActorsToRemove;
auto& ActiveObjects = GetNetworkObjectList().ActiveNetworkObjects;
auto World = GetWorld();
for (const TSharedPtr<FNetworkObjectInfo>& ActorInfo : ActiveObjects)
if (ShouldUseNetworkObjectList())
{
if (!ActorInfo->bPendingNetUpdate && UGameplayStatics::GetTimeSeconds(GetWorld()) <= ActorInfo->NextUpdateTime)
auto& ActiveObjects = GetNetworkObjectList().ActiveNetworkObjects;
auto World = GetWorld();
for (const TSharedPtr<FNetworkObjectInfo>& ActorInfo : ActiveObjects)
{
continue;
}
auto Actor = ActorInfo->Actor;
if (!Actor)
continue;
if (Actor->IsPendingKillPending())
// if (Actor->IsPendingKill())
{
ActorsToRemove.push_back(Actor);
continue;
}
static auto RemoteRoleOffset = Actor->GetOffset("RemoteRole");
if (Actor->Get<ENetRole>(RemoteRoleOffset) == ENetRole::ROLE_None)
{
ActorsToRemove.push_back(Actor);
continue;
}
// We should add a NetDriverName check but I don't believe it is needed.
// We should check if the actor is initialized here.
// We should check the level stuff here.
static auto NetDormancyOffset = Actor->GetOffset("NetDormancy");
if (Actor->Get<ENetDormancy>(NetDormancyOffset) == ENetDormancy::DORM_Initial && Actor->IsNetStartupActor()) // IsDormInitialStartupActor
{
continue;
}
// We should check NeedsLoadForClient here.
// We should make sure the actor is in the same world here but I don't believe it is needed.
if (ActorInfo->LastNetReplicateTime == 0)
{
ActorInfo->LastNetReplicateTime = UGameplayStatics::GetTimeSeconds(World);
ActorInfo->OptimalNetUpdateDelta = 1.0f / Actor->GetNetUpdateFrequency();
}
const float ScaleDownStartTime = 2.0f;
const float ScaleDownTimeRange = 5.0f;
const float LastReplicateDelta = UGameplayStatics::GetTimeSeconds(World) - ActorInfo->LastNetReplicateTime;
if (LastReplicateDelta > ScaleDownStartTime)
{
static auto MinNetUpdateFrequencyOffset = Actor->GetOffset("MinNetUpdateFrequency");
if (Actor->Get<float>(MinNetUpdateFrequencyOffset) == 0.0f)
if (!ActorInfo->bPendingNetUpdate && UGameplayStatics::GetTimeSeconds(GetWorld()) <= ActorInfo->NextUpdateTime)
{
Actor->Get<float>(MinNetUpdateFrequencyOffset) = 2.0f;
continue;
}
const float MinOptimalDelta = 1.0f / Actor->GetNetUpdateFrequency(); // Don't go faster than NetUpdateFrequency
const float MaxOptimalDelta = max(1.0f / Actor->GetMinNetUpdateFrequency(), MinOptimalDelta); // Don't go slower than MinNetUpdateFrequency (or NetUpdateFrequency if it's slower)
auto Actor = ActorInfo->Actor;
const float Alpha = std::clamp((LastReplicateDelta - ScaleDownStartTime) / ScaleDownTimeRange, 0.0f, 1.0f); // should we use fmath?
ActorInfo->OptimalNetUpdateDelta = std::lerp(MinOptimalDelta, MaxOptimalDelta, Alpha); // should we use fmath?
if (!Actor)
continue;
if (Actor->IsPendingKillPending())
// if (Actor->IsPendingKill())
{
ActorsToRemove.push_back(Actor);
continue;
}
static auto RemoteRoleOffset = Actor->GetOffset("RemoteRole");
if (Actor->Get<ENetRole>(RemoteRoleOffset) == ENetRole::ROLE_None)
{
ActorsToRemove.push_back(Actor);
continue;
}
// We should add a NetDriverName check but I don't believe it is needed.
// We should check if the actor is initialized here.
// We should check the level stuff here.
static auto NetDormancyOffset = Actor->GetOffset("NetDormancy");
if (Actor->Get<ENetDormancy>(NetDormancyOffset) == ENetDormancy::DORM_Initial && Actor->IsNetStartupActor()) // IsDormInitialStartupActor
{
continue;
}
// We should check NeedsLoadForClient here.
// We should make sure the actor is in the same world here but I don't believe it is needed.
if (ActorInfo->LastNetReplicateTime == 0)
{
ActorInfo->LastNetReplicateTime = UGameplayStatics::GetTimeSeconds(World);
ActorInfo->OptimalNetUpdateDelta = 1.0f / Actor->GetNetUpdateFrequency();
}
const float ScaleDownStartTime = 2.0f;
const float ScaleDownTimeRange = 5.0f;
const float LastReplicateDelta = UGameplayStatics::GetTimeSeconds(World) - ActorInfo->LastNetReplicateTime;
if (LastReplicateDelta > ScaleDownStartTime)
{
static auto MinNetUpdateFrequencyOffset = Actor->GetOffset("MinNetUpdateFrequency");
if (Actor->Get<float>(MinNetUpdateFrequencyOffset) == 0.0f)
{
Actor->Get<float>(MinNetUpdateFrequencyOffset) = 2.0f;
}
const float MinOptimalDelta = 1.0f / Actor->GetNetUpdateFrequency(); // Don't go faster than NetUpdateFrequency
const float MaxOptimalDelta = max(1.0f / Actor->GetMinNetUpdateFrequency(), MinOptimalDelta); // Don't go slower than MinNetUpdateFrequency (or NetUpdateFrequency if it's slower)
const float Alpha = std::clamp((LastReplicateDelta - ScaleDownStartTime) / ScaleDownTimeRange, 0.0f, 1.0f); // should we use fmath?
ActorInfo->OptimalNetUpdateDelta = std::lerp(MinOptimalDelta, MaxOptimalDelta, Alpha); // should we use fmath?
}
if (!ActorInfo->bPendingNetUpdate)
{
constexpr bool bUseAdapativeNetFrequency = false;
const float NextUpdateDelta = bUseAdapativeNetFrequency ? ActorInfo->OptimalNetUpdateDelta : 1.0f / Actor->GetNetUpdateFrequency();
// then set the next update time
float ServerTickTime = 1.f / 30;
ActorInfo->NextUpdateTime = UGameplayStatics::GetTimeSeconds(World) + FRand() * ServerTickTime + NextUpdateDelta;
static auto TimeOffset = GetOffset("Time");
ActorInfo->LastNetUpdateTime = Get<float>(TimeOffset);
}
ActorInfo->bPendingNetUpdate = false;
OutConsiderList.push_back(ActorInfo.Get());
static void (*CallPreReplication)(AActor*, UNetDriver*) = decltype(CallPreReplication)(Addresses::CallPreReplication);
CallPreReplication(Actor, this);
}
}
else
{
auto Actors = UGameplayStatics::GetAllActorsOfClass(GetWorld(), AActor::StaticClass());
if (!ActorInfo->bPendingNetUpdate)
for (int i = 0; i < Actors.Num(); ++i)
{
constexpr bool bUseAdapativeNetFrequency = false;
const float NextUpdateDelta = bUseAdapativeNetFrequency ? ActorInfo->OptimalNetUpdateDelta : 1.0f / Actor->GetNetUpdateFrequency();
auto Actor = Actors.at(i);
// then set the next update time
float ServerTickTime = 1.f / 30;
ActorInfo->NextUpdateTime = UGameplayStatics::GetTimeSeconds(World) + FRand() * ServerTickTime + NextUpdateDelta;
static auto TimeOffset = GetOffset("Time");
ActorInfo->LastNetUpdateTime = Get<float>(TimeOffset);
if (Actor->IsPendingKillPending())
// if (Actor->IsPendingKill())
{
ActorsToRemove.push_back(Actor);
continue;
}
static auto RemoteRoleOffset = Actor->GetOffset("RemoteRole");
if (Actor->Get<ENetRole>(RemoteRoleOffset) == ENetRole::ROLE_None)
{
ActorsToRemove.push_back(Actor);
continue;
}
// We should add a NetDriverName check but I don't believe it is needed.
// We should check if the actor is initialized here.
// We should check the level stuff here.
static auto NetDormancyOffset = Actor->GetOffset("NetDormancy");
if (Actor->Get<ENetDormancy>(NetDormancyOffset) == ENetDormancy::DORM_Initial && Actor->IsNetStartupActor()) // IsDormInitialStartupActor
{
continue;
}
auto ActorInfo = new FNetworkObjectInfo;
ActorInfo->Actor = Actor;
OutConsiderList.push_back(ActorInfo);
static void (*CallPreReplication)(AActor*, UNetDriver*) = decltype(CallPreReplication)(Addresses::CallPreReplication);
CallPreReplication(Actor, this);
}
ActorInfo->bPendingNetUpdate = false;
OutConsiderList.push_back(ActorInfo.Get());
static void (*CallPreReplication)(AActor*, UNetDriver*) = decltype(CallPreReplication)(Addresses::CallPreReplication);
CallPreReplication(Actor, this);
Actors.Free();
}
for (auto Actor : ActorsToRemove)
@@ -401,7 +457,9 @@ int32 UNetDriver::ServerReplicateActors()
}
std::vector<FNetworkObjectInfo*> ConsiderList;
ConsiderList.reserve(GetNetworkObjectList().ActiveNetworkObjects.Num());
if (ShouldUseNetworkObjectList())
ConsiderList.reserve(GetNetworkObjectList().ActiveNetworkObjects.Num());
// std::cout << "ConsiderList.size(): " << GetNetworkObjectList(NetDriver).ActiveNetworkObjects.Num() << '\n';
@@ -424,10 +482,13 @@ int32 UNetDriver::ServerReplicateActors()
if (!Connection->GetViewTarget())
continue;
if (Connection->GetPlayerController())
if (Addresses::SendClientAdjustment)
{
static void (*SendClientAdjustment)(APlayerController*) = decltype(SendClientAdjustment)(Addresses::SendClientAdjustment);
SendClientAdjustment(Connection->GetPlayerController());
if (Connection->GetPlayerController())
{
static void (*SendClientAdjustment)(APlayerController*) = decltype(SendClientAdjustment)(Addresses::SendClientAdjustment);
SendClientAdjustment(Connection->GetPlayerController());
}
}
// Make weak ptr once for IsActorDormant call
@@ -513,8 +574,15 @@ int32 UNetDriver::ServerReplicateActors()
}
}
enum class EChannelCreateFlags : uint32_t
{
None = (1 << 0),
OpenedLocally = (1 << 1)
};
static UChannel* (*CreateChannel)(UNetConnection*, int, bool, int32_t) = decltype(CreateChannel)(Addresses::CreateChannel);
static __int64 (*ReplicateActor)(UActorChannel*) = decltype(ReplicateActor)(Addresses::ReplicateActor);
static UObject* (*CreateChannelByName)(UNetConnection* Connection, FName* ChName, EChannelCreateFlags CreateFlags, int32_t ChannelIndex) = decltype(CreateChannelByName)(Addresses::CreateChannel);
static __int64 (*SetChannelActor)(UActorChannel*, AActor*) = decltype(SetChannelActor)(Addresses::SetChannelActor);
if (!Channel)
@@ -524,7 +592,18 @@ int32 UNetDriver::ServerReplicateActors()
if (bLevelInitializedForActor)
{
Channel = (UActorChannel*)CreateChannel(Connection, 2, true, -1);
if (Engine_Version >= 422)
{
FString ActorStr = L"Actor";
FName ActorName = UKismetStringLibrary::Conv_StringToName(ActorStr);
int ChannelIndex = -1; // 4294967295
Channel = (UActorChannel*)CreateChannelByName(Connection, &ActorName, EChannelCreateFlags::OpenedLocally, ChannelIndex);
}
else
{
Channel = (UActorChannel*)CreateChannel(Connection, 2, true, -1);
}
if (Channel)
{

View File

@@ -130,6 +130,18 @@ public:
static void TickFlushHook(UNetDriver* NetDriver);
int& GetMaxInternetClientRate()
{
static auto MaxInternetClientRateOffset = GetOffset("MaxInternetClientRate");
return Get<int>(MaxInternetClientRateOffset);
}
int& GetMaxClientRate()
{
static auto MaxClientRateOffset = GetOffset("MaxClientRate");
return Get<int>(MaxClientRateOffset);
}
FNetGUIDCache* GetGuidCache()
{
static auto GuidCacheOffset = GetOffset("WorldPackage") + 8; // checked for 1.11

View File

@@ -7,9 +7,15 @@
struct FRotator
{
#ifdef ABOVE_S20
double Pitch;
double Yaw;
double Roll;
#else
float Pitch;
float Yaw;
float Roll;
#endif
FQuat Quaternion();

View File

@@ -1,11 +1,19 @@
#pragma once
#include "inc.h"
struct FVector
{
public:
float X;
float Y;
float Z;
#ifdef ABOVE_S20
using VectorDataType = double;
#else
using VectorDataType = float;
#endif
VectorDataType X;
VectorDataType Y;
VectorDataType Z;
bool CompareVectors(const FVector& A)
{
@@ -13,7 +21,7 @@ public:
}
FVector() : X(0), Y(0), Z(0) {}
FVector(float x, float y, float z) : X(x), Y(y), Z(z) {}
FVector(VectorDataType x, VectorDataType y, VectorDataType z) : X(x), Y(y), Z(z) {}
FVector operator+(const FVector& A)
{
@@ -25,17 +33,17 @@ public:
return FVector{ this->X - A.X, this->Y - A.Y, this->Z - A.Z };
}
FORCEINLINE float SizeSquared() const
FORCEINLINE VectorDataType SizeSquared() const
{
return X * X + Y * Y + Z * Z;
}
FORCEINLINE float operator|(const FVector& V) const
FORCEINLINE VectorDataType operator|(const FVector& V) const
{
return X * V.X + Y * V.Y + Z * V.Z;
}
FVector operator*(const float A)
FVector operator*(const VectorDataType A)
{
return FVector{ this->X * A, this->Y * A, this->Z * A };
}

View File

@@ -66,14 +66,6 @@ void UWorld::Listen()
FURL URL = FURL();
URL.Port = Port - (Engine_Version >= 426);
FString Error;
if (!NewNetDriver->InitListen(GetWorld(), URL, false, Error))
{
LOG_ERROR(LogNet, "Failed to init listen!");
return;
}
NewNetDriver->SetWorld(GetWorld());
// LEVEL COLLECTIONS
@@ -85,6 +77,21 @@ void UWorld::Listen()
*(UNetDriver**)(__int64(LevelCollections.AtPtr(0, LevelCollectionSize)) + 0x10) = NewNetDriver;
*(UNetDriver**)(__int64(LevelCollections.AtPtr(1, LevelCollectionSize)) + 0x10) = NewNetDriver;
FString Error;
if (!NewNetDriver->InitListen(GetWorld(), URL, false, Error))
{
LOG_ERROR(LogNet, "Failed to init listen!");
return;
}
const bool bLanSpeed = false;
if (!bLanSpeed && (NewNetDriver->GetMaxInternetClientRate() < NewNetDriver->GetMaxClientRate()) && (NewNetDriver->GetMaxInternetClientRate() > 2500))
{
NewNetDriver->GetMaxClientRate() = NewNetDriver->GetMaxInternetClientRate();
}
LOG_INFO(LogNet, "Listening on port {}!", Port + Globals::AmountOfListens - 1);
}

View File

@@ -467,6 +467,10 @@ void Offsets::FindAll()
Offsets::NetworkObjectList = 0x490;
Offsets::ReplicationFrame = 0x2C8;
}
if (Fortnite_Version >= 20 && Fortnite_Version < 22)
{
Offsets::ReplicationFrame = 0x3D8;
}
Offsets::IsNetRelevantFor = FindIsNetRelevantForOffset();
Offsets::Script = Offsets::Children + 8 + 4 + 4;

View File

@@ -256,6 +256,8 @@ void ChangeLevels()
constexpr bool bUseSwitchLevel = false;
constexpr bool bShouldRemoveLocalPlayer = true;
LOG_INFO(LogDev, "FindGIsClient(): 0x{:x}", FindGIsClient() - __int64(GetModuleHandleW(0)));
FString LevelB = Engine_Version < 424
? L"open Athena_Terrain" : Engine_Version >= 500 ? Engine_Version >= 501
? L"open Asteria_Terrain"
@@ -371,7 +373,8 @@ DWORD WINAPI Main(LPVOID)
Addresses::Print();
LOG_INFO(LogDev, "Fortnite_CL: {}", Fortnite_CL);
LOG_INFO(LogDev, "Version: {}", Fortnite_Version);
LOG_INFO(LogDev, "Fortnite_Version: {}", Fortnite_Version);
LOG_INFO(LogDev, "Engine_Version: {}", Engine_Version);
CreateThread(0, 0, GuiThread, 0, 0, 0);
@@ -434,8 +437,6 @@ DWORD WINAPI Main(LPVOID)
Hooking::MinHook::Hook((PVOID)Addresses::KickPlayer, (PVOID)AGameSession::KickPlayerHook, (PVOID*)&AGameSession::KickPlayerOriginal);
LOG_INFO(LogDev, "Built on {} {}", __DATE__, __TIME__);
LOG_INFO(LogDev, "[bNoMCP] {}", Globals::bNoMCP);
LOG_INFO(LogDev, "[bGoingToPlayEvent] {}", Globals::bGoingToPlayEvent);
LOG_INFO(LogDev, "Size: 0x{:x}", sizeof(TMap<FName, void*>));
Hooking::MinHook::Hook((PVOID)Addresses::ActorGetNetMode, (PVOID)GetNetModeHook2, nullptr);
@@ -525,6 +526,8 @@ DWORD WINAPI Main(LPVOID)
ChangeLevels();
LOG_INFO(LogDev, "Switch levels.");
auto AddressesToNull = Addresses::GetFunctionsToNull();
auto ServerCheatAllIndex = GetFunctionIdxOrPtr(FindObject<UFunction>(L"/Script/FortniteGame.FortPlayerController.ServerCheatAll"));
@@ -794,6 +797,7 @@ DWORD WINAPI Main(LPVOID)
Hooking::MinHook::Hook(FortPlayerPawnAthenaDefault, FindObject<UFunction>(L"/Script/FortniteGame.FortPlayerPawn.ServerSendZiplineState"),
AFortPlayerPawn::ServerSendZiplineStateHook, nullptr, false);
Hooking::MinHook::Hook((PVOID)GetFunctionIdxOrPtr(FindObject<UFunction>(L"/Script/FortniteGame.FortPlayerPawn.ServerOnExitVehicle"), true), AFortPlayerPawn::ServerOnExitVehicleHook, (PVOID*)&AFortPlayerPawn::ServerOnExitVehicleOriginal);
if (Fortnite_Version == 1.11 || Fortnite_Version > 1.8)
@@ -994,6 +998,7 @@ DWORD WINAPI Main(LPVOID)
uint64 ServerRemoveInventoryItemFunctionCallBeginFunctionAddr = 0;
// if (Engine_Version >= 419)
if (Fortnite_Version < 20)
{
std::vector<uint8_t> ServerRemoveInventoryItemCallFunctionStarts = Engine_Version == 416
? std::vector<uint8_t>{ 0x44, 0x88, 0x4C }

View File

@@ -65,8 +65,17 @@ static inline uintptr_t FindBytes(Memcury::Scanner& Scanner, const std::vector<u
static inline uint64 FindStaticFindObject(int StringSkip = 1)
{
// ServerStatReplicatorInst then first jmp??
if (Engine_Version == 500)
return Memcury::Scanner::FindPattern("40 55 53 56 57 41 54 41 55 41 56 41 57 48 8D AC 24 ? ? ? ? 48 81 EC ? ? ? ? 48 8B 05 ? ? ? ? 48 33 C4 48 89 85 ? ? ? ? 45 33 F6 4C 8B E1 45 0F B6 E9 49 8B F8 41 8B C6").Get();
{
auto addr = Memcury::Scanner::FindPattern("40 55 53 56 57 41 54 41 55 41 56 41 57 48 8D AC 24 ? ? ? ? 48 81 EC ? ? ? ? 48 8B 05 ? ? ? ? 48 33 C4 48 89 85 ? ? ? ? 45 33 F6 4C 8B E1 45 0F B6 E9 49 8B F8 41 8B C6", false).Get();
if (!addr)
addr = Memcury::Scanner::FindPattern("48 89 5C 24 ? 48 89 74 24 ? 4C 89 64 24 ? 55 41 55 41 57 48 8B EC 48 83 EC 60 45 8A E1 4C 8B E9 48 83 FA").Get(); // 20.00
return addr;
}
if (Engine_Version >= 427) // ok so like the func is split up in ida idfk what to do about it
{
@@ -608,6 +617,8 @@ static inline uint64 FindSetWorld()
SetWorldIndex = 0x73;
else if (Fortnite_Season >= 19 && Fortnite_Season < 21)
SetWorldIndex = 0x7A;
if (Fortnite_Version == 20.40)
SetWorldIndex = 0x7B;
// static auto DefaultNetDriver = FindObject("/Script/Engine.Default__NetDriver");
return SetWorldIndex;
@@ -1447,7 +1458,12 @@ static inline uint64 FindChangeGameSessionId()
static inline uint64 FindDispatchRequest()
{
auto Addrr = Memcury::Scanner::FindStringRef(L"MCP-Profile: Dispatching request to %s", true, 0, Fortnite_Version >= 19).Get();
auto Addrr = Memcury::Scanner::FindStringRef(L"MCP-Profile: Dispatching request to %s", false, 0, Fortnite_Version >= 19).Get();
if (!Addrr)
{
return 0;
}
for (int i = 0; i < 1000; i++)
{
@@ -1477,6 +1493,9 @@ static inline uint64 FindMcpIsDedicatedServerOffset()
static inline uint64 FindGIsClient()
{
if (Fortnite_Version >= 20)
return 0;
// if (Fortnite_Version == 2.5)
// return __int64(GetModuleHandleW(0)) + 0x46AD734;
/* if (Fortnite_Version == 1.72)
@@ -1821,9 +1840,12 @@ static inline uint64 FindCantBuild()
if (!add)
add = Memcury::Scanner::FindPattern("48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 41 56 41 57 48 83 EC 60 49 8B E9 4D 8B F8 48 8B DA 48 8B F9 BE ? ? ? ? 48").Get(); // 5.00
if (!add)
add = Memcury::Scanner::FindPattern("48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 41 56 41 57 48 83 EC 70 49 8B E9 4D 8B F8 48 8B DA 48 8B F9").Get(); // 20.00
return add;
auto CreateBuildingActorAddr = Memcury::Scanner(GetFunctionIdxOrPtr(FindObject<UFunction>("/Script/FortniteGame.FortAIController.CreateBuildingActor")));
auto CreateBuildingActorAddr = Memcury::Scanner(GetFunctionIdxOrPtr(FindObject<UFunction>(L"/Script/FortniteGame.FortAIController.CreateBuildingActor")));
auto LikeHuh = Memcury::Scanner(FindBytes(CreateBuildingActorAddr, { 0x40, 0x88 }, 3000));
auto callaa = Memcury::Scanner(FindBytes(LikeHuh, { 0xE8 }));
@@ -1848,6 +1870,8 @@ static inline uint64 FindSendClientAdjustment()
{
if (Fortnite_Version <= 3.2)
return Memcury::Scanner::FindPattern("40 53 48 83 EC 20 48 8B 99 ? ? ? ? 48 39 99 ? ? ? ? 74 0A 48 83 B9").Get();
if (Fortnite_Version >= 20)
return Memcury::Scanner::FindPattern("40 53 48 83 EC 20 48 8B 99 ? ? ? ? 48 39 99 ? ? ? ? 74 0A 48 83 B9").Get();
return 0;
}
@@ -1866,6 +1890,9 @@ static inline uint64 FindReplicateActor()
return addr;
}
if (Fortnite_Version >= 20)
return Memcury::Scanner::FindPattern("48 8B C4 48 89 58 10 48 89 70 18 48 89 78 20 55 41 54 41 55 41 56 41 57 48 8D A8 ? ? ? ? 48 81 EC ? ? ? ? 48 8B 05 ? ? ? ? 48 33 C4 48 89 85 ? ? ? ? 4C 8D 69 68").Get();
return 0;
}
@@ -1873,6 +1900,8 @@ static inline uint64 FindCreateChannel()
{
if (Fortnite_Version <= 3.2)
return Memcury::Scanner::FindPattern("40 56 57 41 54 41 55 41 57 48 83 EC 60 48 8B 01 41 8B F9 45 0F B6 E0").Get();
if (Fortnite_Version >= 20)
return Memcury::Scanner::FindPattern("48 89 5C 24 ? 48 89 74 24 ? 44 89 4C 24 ? 55 57 41 54 41 56 41 57 48 8B EC 48 83 EC 50 45 33 E4 48 8D 05 ? ? ? ? 44 38 25").Get();
return 0;
}
@@ -1890,6 +1919,8 @@ static inline uint64 FindSetChannelActor()
return aa;
}
if (Fortnite_Version >= 20)
return Memcury::Scanner::FindPattern("40 55 53 56 57 41 54 41 56 41 57 48 8D AC 24 ? ? ? ? 48 81 EC ? ? ? ? 45 33 E4 48 8D 3D ? ? ? ? 44 89 A5").Get();
return 0;
}
@@ -1902,6 +1933,8 @@ static inline uint64 FindCallPreReplication()
return Memcury::Scanner::FindPattern("48 85 D2 0F 84 ? ? ? ? 48 8B C4 55 57 41 54 48 8D 68 A1 48 81 EC ? ? ? ? 48 89 58 08 4C").Get();
if (Fortnite_Version >= 2.5 && Fortnite_Version <= 3.2)
return Memcury::Scanner::FindPattern("48 85 D2 0F 84 ? ? ? ? 56 41 56 48 83 EC 38 4C 8B F2").Get();
if (Fortnite_Version >= 20)
return Memcury::Scanner::FindPattern("48 85 D2 0F 84 ? ? ? ? 48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 41 56 41 57 48 83 EC 40 F6 41 58 30 48 8B EA 48 8B D9 40 B6 01").Get();
return 0;
}

View File

@@ -263,9 +263,15 @@ static inline bool ButtonCentered(const std::string& text, bool bNewLine = true)
static inline void InputVector(const std::string& baseText, FVector* vec)
{
#ifdef ABOVE_S20
ImGui::InputDouble((baseText + " X").c_str(), &vec->X);
ImGui::InputDouble((baseText + " Y").c_str(), &vec->Y);
ImGui::InputDouble((baseText + " Z").c_str(), &vec->Z);
#else
ImGui::InputFloat((baseText + " X").c_str(), &vec->X);
ImGui::InputFloat((baseText + " Y").c_str(), &vec->Y);
ImGui::InputFloat((baseText + " Z").c_str(), &vec->Z);
#endif
}
static int Width = 640;

View File

@@ -59,6 +59,8 @@ inline bool IsRestartingSupported()
return Engine_Version >= 419 && Engine_Version < 424;
}
// #define ABOVE_S20
/*
enum class AllocatorType