From acb311c64327996f8c393ee3368a2a380a7640f4 Mon Sep 17 00:00:00 2001 From: Gray <84999745+Milxnor@users.noreply.github.com> Date: Sun, 17 Mar 2024 20:48:21 -0400 Subject: [PATCH] work on 21.00 --- .../FortAthenaAIBotSpawnerData.h | 27 ++++++++++ ...naAISpawnerDataComponent_CosmeticLoadout.h | 14 +++++ ...AthenaAISpawnerDataComponent_SpawnParams.h | 13 +++++ Project Reboot 3.0/NetDriver.cpp | 13 ++++- Project Reboot 3.0/Project Reboot 3.0.vcxproj | 3 ++ .../Project Reboot 3.0.vcxproj.filters | 13 ++++- Project Reboot 3.0/World.cpp | 9 +++- Project Reboot 3.0/addresses.cpp | 3 +- Project Reboot 3.0/ai.h | 37 ++++++++++++++ Project Reboot 3.0/commands.cpp | 51 +++++++++++++++++++ Project Reboot 3.0/dllmain.cpp | 13 +++-- Project Reboot 3.0/finder.h | 12 +++-- Project Reboot 3.0/hooking.h | 4 +- 13 files changed, 198 insertions(+), 14 deletions(-) create mode 100644 Project Reboot 3.0/FortAthenaAIBotSpawnerData.h create mode 100644 Project Reboot 3.0/FortAthenaAISpawnerDataComponent_CosmeticLoadout.h create mode 100644 Project Reboot 3.0/FortAthenaAISpawnerDataComponent_SpawnParams.h diff --git a/Project Reboot 3.0/FortAthenaAIBotSpawnerData.h b/Project Reboot 3.0/FortAthenaAIBotSpawnerData.h new file mode 100644 index 0000000..7066f42 --- /dev/null +++ b/Project Reboot 3.0/FortAthenaAIBotSpawnerData.h @@ -0,0 +1,27 @@ +#pragma once + +#include "reboot.h" +#include "FortAthenaAISpawnerDataComponent_SpawnParams.h" +#include "FortAthenaAISpawnerDataComponent_CosmeticLoadout.h" + +class UFortAthenaAIBotSpawnerData : public UObject +{ +public: + UFortAthenaAISpawnerDataComponent_SpawnParams*& GetSpawnParamsComponent() + { + static auto SpawnParamsComponentOffset = GetOffset("SpawnParamsComponent"); + return Get(SpawnParamsComponentOffset); + } + + UFortAthenaAISpawnerDataComponent_CosmeticLoadout*& GetCosmeticComponent() + { + static auto CosmeticComponentOffset = GetOffset("CosmeticComponent"); + return Get(CosmeticComponentOffset); + } + + static UClass* StaticClass() + { + static auto Class = FindObject(L"/Script/FortniteGame.FortAthenaAIBotSpawnerData"); + return Class; + } +}; \ No newline at end of file diff --git a/Project Reboot 3.0/FortAthenaAISpawnerDataComponent_CosmeticLoadout.h b/Project Reboot 3.0/FortAthenaAISpawnerDataComponent_CosmeticLoadout.h new file mode 100644 index 0000000..bcc7439 --- /dev/null +++ b/Project Reboot 3.0/FortAthenaAISpawnerDataComponent_CosmeticLoadout.h @@ -0,0 +1,14 @@ +#pragma once + +#include "reboot.h" +#include "FortPlayerController.h" + +class UFortAthenaAISpawnerDataComponent_CosmeticLoadout : public UObject +{ +public: + FFortAthenaLoadout* GetCosmeticLoadout() + { + static auto CosmeticLoadoutOffset = GetOffset("CosmeticLoadout"); + return GetPtr(CosmeticLoadoutOffset); + } +}; \ No newline at end of file diff --git a/Project Reboot 3.0/FortAthenaAISpawnerDataComponent_SpawnParams.h b/Project Reboot 3.0/FortAthenaAISpawnerDataComponent_SpawnParams.h new file mode 100644 index 0000000..c9c45cf --- /dev/null +++ b/Project Reboot 3.0/FortAthenaAISpawnerDataComponent_SpawnParams.h @@ -0,0 +1,13 @@ +#pragma once + +#include "reboot.h" + +class UFortAthenaAISpawnerDataComponent_SpawnParams : public UObject +{ +public: + UClass*& GetPawnClass() + { + static auto PawnClassOffset = GetOffset("PawnClass"); + return Get(PawnClassOffset); + } +}; \ No newline at end of file diff --git a/Project Reboot 3.0/NetDriver.cpp b/Project Reboot 3.0/NetDriver.cpp index fa84500..d539e2a 100644 --- a/Project Reboot 3.0/NetDriver.cpp +++ b/Project Reboot 3.0/NetDriver.cpp @@ -565,6 +565,13 @@ void SetChannelActorForDestroy(UActorChannel* Channel, FActorDestructionInfo* De } } +enum ESetChannelActorFlags +{ + None = 0, + SkipReplicatorCreation = (1 << 0), + SkipMarkActive = (1 << 1), +}; + TSet* GetClientVisibleLevelNames(UNetConnection* NetConnection) { return (TSet*)(__int64(NetConnection) + 0x336C8); @@ -613,6 +620,7 @@ int32 UNetDriver::ServerReplicateActors() 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); + static __int64 (*SetChannelActor2)(UActorChannel*, AActor*, ESetChannelActorFlags) = decltype(SetChannelActor2)(Addresses::SetChannelActor); for (int32 i = 0; i < this->GetClientConnections().Num(); i++) { @@ -823,7 +831,10 @@ int32 UNetDriver::ServerReplicateActors() if (Channel) { - SetChannelActor(Channel, Actor); + if (Engine_Version >= 500) + SetChannelActor(Channel, Actor); + else + SetChannelActor2(Channel, Actor, ESetChannelActorFlags::None); } } diff --git a/Project Reboot 3.0/Project Reboot 3.0.vcxproj b/Project Reboot 3.0/Project Reboot 3.0.vcxproj index 66aa25e..0dfaf06 100644 --- a/Project Reboot 3.0/Project Reboot 3.0.vcxproj +++ b/Project Reboot 3.0/Project Reboot 3.0.vcxproj @@ -328,6 +328,9 @@ + + + diff --git a/Project Reboot 3.0/Project Reboot 3.0.vcxproj.filters b/Project Reboot 3.0/Project Reboot 3.0.vcxproj.filters index 841b174..d4f44cb 100644 --- a/Project Reboot 3.0/Project Reboot 3.0.vcxproj.filters +++ b/Project Reboot 3.0/Project Reboot 3.0.vcxproj.filters @@ -961,10 +961,19 @@ Engine\Source\Runtime\Engine\Classes\Engine - - + + Reboot\Public + + FortniteGame\Source\FortniteGame\Public\AI + + + FortniteGame\Source\FortniteGame\Public\AI + + + FortniteGame\Source\FortniteGame\Public\AI + diff --git a/Project Reboot 3.0/World.cpp b/Project Reboot 3.0/World.cpp index 3ce6b0d..2ff8d60 100644 --- a/Project Reboot 3.0/World.cpp +++ b/Project Reboot 3.0/World.cpp @@ -78,13 +78,20 @@ void UWorld::Listen() *(UNetDriver**)(__int64(LevelCollections.AtPtr(1, LevelCollectionSize)) + 0x10) = NewNetDriver; FString Error; + + LOG_INFO(LogNet, "Calling InitListen!"); - if (!NewNetDriver->InitListen(GetWorld(), URL, false, Error)) + AWorldSettings* WorldSettings = GetWorldSettings(); + const bool bReuseAddressAndPort = false; // WorldSettings ? WorldSettings->bReuseAddressAndPort : false; + + if (!NewNetDriver->InitListen(GetWorld(), URL, bReuseAddressAndPort, Error)) { LOG_ERROR(LogNet, "Failed to init listen!"); return; } + LOG_INFO(LogNet, "Called InitListen!"); + const bool bLanSpeed = false; if (!bLanSpeed && (NewNetDriver->GetMaxInternetClientRate() < NewNetDriver->GetMaxClientRate()) && (NewNetDriver->GetMaxInternetClientRate() > 2500)) diff --git a/Project Reboot 3.0/addresses.cpp b/Project Reboot 3.0/addresses.cpp index b79ea3d..998fc2a 100644 --- a/Project Reboot 3.0/addresses.cpp +++ b/Project Reboot 3.0/addresses.cpp @@ -526,6 +526,7 @@ void Offsets::Print() LOG_INFO(LogDev, "ReplicationFrame: 0x{:x}", ReplicationFrame); LOG_INFO(LogDev, "ClientWorldPackageName: 0x{:x}", ClientWorldPackageName); LOG_INFO(LogDev, "NetworkObjectList: 0x{:x}", NetworkObjectList); + LOG_INFO(LogDev, "IsNetRelevantFor: 0x{:x}", IsNetRelevantFor); LOG_INFO(LogDev, "Script: 0x{:x}", Script); LOG_INFO(LogDev, "PropertyClass: 0x{:x}", PropertyClass); } @@ -671,7 +672,7 @@ std::vector Addresses::GetFunctionsToNull() toNull.push_back(Memcury::Scanner::FindPattern("48 89 5C 24 ? 57 48 83 EC 20 48 8B 41 20 48 8B FA 48 8B D9 BA ? ? ? ? 83 78 08 03 0F 8D").Get()); // some constructor crash toNull.push_back(Memcury::Scanner::FindPattern("4C 89 44 24 ? 53 55 56 57 41 54 41 55 41 56 41 57 48 83 EC 68 48 8D 05 ? ? ? ? 0F").Get()); // soem constructor crash (gets called by ^) toNull.push_back(Memcury::Scanner::FindPattern("48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 48 83 EC 30 48 8B F9 48 8B CA E8").Get()); - toNull.push_back(Memcury::Scanner::FindPattern("48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 41 55 41 56 48 83 EC 60 45 33 F6 4C 8D 2D ? ? ? ? 48 8B DA 48 8B E9 48 85").Get()); + toNull.push_back(Memcury::Scanner::FindPattern("48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 41 ? 41 ? 48 83 EC 60 45 33 F6 4C 8D ? ? ? ? ? 48 8B DA").Get()); // crash 2 (20.40 & 21.00) } } diff --git a/Project Reboot 3.0/ai.h b/Project Reboot 3.0/ai.h index 739b672..2c9af18 100644 --- a/Project Reboot 3.0/ai.h +++ b/Project Reboot 3.0/ai.h @@ -14,6 +14,7 @@ #include "FortBotNameSettings.h" #include "KismetTextLibrary.h" #include "FortAthenaAIBotCustomizationData.h" +#include "FortAthenaAIBotSpawnerData.h" using UNavigationSystemV1 = UObject; using UNavigationSystemConfig = UObject; @@ -235,6 +236,42 @@ static void SetupNavConfig(const FName& AgentName) SetNavigationSystem(NavSystemOverride); } +static AFortPlayerPawn* SpawnAIFromSpawnerData(const FVector& Location, UFortAthenaAIBotSpawnerData* SpawnerData) +{ + auto SpawnParamsComponent = SpawnerData->GetSpawnParamsComponent(); + + if (!SpawnParamsComponent) + { + LOG_INFO(LogAI, "Invalid SpawnParamsComponent for AI!"); + return nullptr; + } + + auto PawnClass = SpawnerData->GetSpawnParamsComponent()->GetPawnClass(); + + LOG_INFO(LogAI, "PawnClass: {}", __int64(PawnClass)); + + if (!PawnClass) + { + LOG_INFO(LogAI, "Invalid PawnClass for AI!"); + return nullptr; + } + + LOG_INFO(LogAI, "PawnClass Name: {}", PawnClass->GetFullName()); + auto Pawn = GetWorld()->SpawnActor(PawnClass, Location); + + if (!Pawn) + { + LOG_INFO(LogAI, "Failed to spawn pawn!"); + return nullptr; + } + + auto CharacterToApply = SpawnerData->GetCosmeticComponent()->GetCosmeticLoadout()->GetCharacter(); + LOG_INFO(LogAI, "CharacterToApply: {}", __int64(CharacterToApply)); + ApplyCID(Pawn, CharacterToApply, true); // bruhh + + return Pawn; +} + static AFortPlayerPawn* SpawnAIFromCustomizationData(const FVector& Location, UFortAthenaAIBotCustomizationData* CustomizationData) { static auto PawnClassOffset = CustomizationData->GetOffset("PawnClass"); diff --git a/Project Reboot 3.0/commands.cpp b/Project Reboot 3.0/commands.cpp index d861336..fc5209f 100644 --- a/Project Reboot 3.0/commands.cpp +++ b/Project Reboot 3.0/commands.cpp @@ -1,5 +1,7 @@ #include "commands.h" +#include "FortAthenaAIBotSpawnerData.h" + void ServerCheatHook(AFortPlayerControllerAthena* PlayerController, FString Msg) { if (!Msg.Data.Data || Msg.Data.Num() <= 0) @@ -698,6 +700,55 @@ void ServerCheatHook(AFortPlayerControllerAthena* PlayerController, FString Msg) SendMessageToConsole(PlayerController, L"Failed to spawn!"); } } + else if (Command == "spawnbottest2") + { + // FortniteGame/Plugins/GameFeatures/CosmosGameplay/Content/AI/NPCs/Cosmos/AISpawnerData/BP_AIBotSpawnerData_Cosmos + // /Game/Athena/AI/NPCs/Base/AISpawnerData/BP_AIBotSpawnerData_NPC_Base.BP_AIBotSpawnerData_NPC_Base_C + // /CosmosGameplay/AI/NPCs/Cosmos/AISpawnerData/BP_AIBotSpawnerData_Cosmos.BP_AIBotSpawnerData_Cosmos_C + + if (NumArgs < 1) + { + SendMessageToConsole(PlayerController, L"Please provide a customization object!"); + return; + } + + auto Pawn = ReceivingController->GetPawn(); + + if (!Pawn) + { + SendMessageToConsole(PlayerController, L"No pawn to spawn bot at!"); + return; + } + + static auto BlueprintGeneratedClassClass = FindObject(L"/Script/Engine.BlueprintGeneratedClass"); + auto SpawnerDataClass = LoadObject(Arguments[1], BlueprintGeneratedClassClass); + // auto SpawnerData = LoadObject(Arguments[1], UFortAthenaAIBotSpawnerData::StaticClass()); + + if (!SpawnerDataClass) + { + SendMessageToConsole(PlayerController, L"Invalid SpawnerDataClass!"); + return; + } + + auto DefaultSpawnerData = Cast(SpawnerDataClass->CreateDefaultObject()); + + if (!SpawnerDataClass) + { + SendMessageToConsole(PlayerController, L"Invalid DefaultSpawnerData!"); + return; + } + + auto NewPawn = SpawnAIFromSpawnerData(Pawn->GetActorLocation(), DefaultSpawnerData); + + if (NewPawn) + { + SendMessageToConsole(PlayerController, L"Spawned!"); + } + else + { + SendMessageToConsole(PlayerController, L"Failed to spawn!"); + } + } else if (Command == "spawnbot") { auto Pawn = ReceivingController->GetPawn(); diff --git a/Project Reboot 3.0/dllmain.cpp b/Project Reboot 3.0/dllmain.cpp index 560b1de..d21498d 100644 --- a/Project Reboot 3.0/dllmain.cpp +++ b/Project Reboot 3.0/dllmain.cpp @@ -690,9 +690,9 @@ void ChangeLevels() if (bUseSwitchLevel) { - static auto SwitchLevel = FindObject(L"/Script/Engine.PlayerController.SwitchLevel"); + static auto SwitchLevelFn = FindObject(L"/Script/Engine.PlayerController.SwitchLevel"); - LocalPC->ProcessEvent(SwitchLevel, &Level); + LocalPC->ProcessEvent(SwitchLevelFn, &Level); if (FindGIsServer()) { @@ -1284,12 +1284,15 @@ DWORD WINAPI Main(LPVOID) Hooking::MinHook::Hook(FindObject(L"/Script/FortniteGame.Default__FortWeaponRangedMountedCannon"), FindObject(L"/Script/FortniteGame.FortWeaponRangedMountedCannon.ServerFireActorInCannon"), AFortWeaponRangedMountedCannon::ServerFireActorInCannonHook, nullptr, false); - static auto NetMulticast_Athena_BatchedDamageCuesFn = FindObject(L"/Script/FortniteGame.FortPawn.NetMulticast_Athena_BatchedDamageCues") ? FindObject(L"/Script/FortniteGame.FortPawn.NetMulticast_Athena_BatchedDamageCues") : FindObject(L"/Script/FortniteGame.FortPlayerPawnAthena.NetMulticast_Athena_BatchedDamageCues"); - Hooking::MinHook::Hook(FortPlayerPawnAthenaDefault, FindObject(L"/Script/FortniteGame.FortPlayerPawn.ServerSendZiplineState"), AFortPlayerPawn::ServerSendZiplineStateHook, nullptr, false); - Hooking::MinHook::Hook((PVOID)GetFunctionIdxOrPtr(FindObject(L"/Script/FortniteGame.FortPlayerPawn.ServerOnExitVehicle"), true), AFortPlayerPawn::ServerOnExitVehicleHook, (PVOID*)&AFortPlayerPawn::ServerOnExitVehicleOriginal); + static auto NetMulticast_Athena_BatchedDamageCuesFn = FindObject(L"/Script/FortniteGame.FortPawn.NetMulticast_Athena_BatchedDamageCues") ? FindObject(L"/Script/FortniteGame.FortPawn.NetMulticast_Athena_BatchedDamageCues") : FindObject(L"/Script/FortniteGame.FortPlayerPawnAthena.NetMulticast_Athena_BatchedDamageCues"); + + if (Fortnite_Version < 21) + { + Hooking::MinHook::Hook((PVOID)GetFunctionIdxOrPtr(FindObject(L"/Script/FortniteGame.FortPlayerPawn.ServerOnExitVehicle"), true), AFortPlayerPawn::ServerOnExitVehicleHook, (PVOID*)&AFortPlayerPawn::ServerOnExitVehicleOriginal); + } if (Fortnite_Version == 1.11 || Fortnite_Version > 1.8) { diff --git a/Project Reboot 3.0/finder.h b/Project Reboot 3.0/finder.h index 58cd6c5..7a5ee01 100644 --- a/Project Reboot 3.0/finder.h +++ b/Project Reboot 3.0/finder.h @@ -1792,8 +1792,10 @@ static inline uint64 FindReplicateActor() return addr; } - if (Fortnite_Version >= 20) + if (std::floor(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(); + if (Fortnite_Version >= 21) // 21.00 + 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 ? ? ? ? 45 33 FF 4C 8D 69 68 44 38 3D").Get(); return 0; } @@ -1802,7 +1804,7 @@ static inline uint64 FindCreateChannel() { if (Fortnite_Version <= 3.3) 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) + if (Fortnite_Version >= 20) // 21.00 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; @@ -1826,8 +1828,10 @@ static inline uint64 FindSetChannelActor() return aa; } - if (Fortnite_Version >= 20) + if (std::floor(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(); + if (Fortnite_Version >= 21) + return Memcury::Scanner::FindPattern("48 89 5C 24 ? 55 56 57 41 54 41 55 41 56 41 57 48 8D AC 24 ? ? ? ? 48 81 EC ? ? ? ? 33 FF 4C 8D 35 ? ? ? ? 89 BD").Get(); return 0; } @@ -1842,6 +1846,8 @@ static inline uint64 FindCallPreReplication() return Memcury::Scanner::FindPattern("48 85 D2 0F 84 ? ? ? ? 56 41 56 48 83 EC 38 4C 8B F2").Get(); if (std::floor(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(); + if (Fortnite_Version >= 21) + 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 4C 8B F2").Get(); return 0; } diff --git a/Project Reboot 3.0/hooking.h b/Project Reboot 3.0/hooking.h index 6b32486..f542149 100644 --- a/Project Reboot 3.0/hooking.h +++ b/Project Reboot 3.0/hooking.h @@ -152,13 +152,15 @@ inline __int64 GetFunctionIdxOrPtr(UFunction* Function, bool bBreakWhenHitRet = auto NativeAddr = __int64(Function->GetFunc()); + LOG_INFO(LogDev, "Getting name!") + auto FuncName = Function->GetName(); std::wstring ValidateWStr = (std::wstring(FuncName.begin(), FuncName.end()) + L"_Validate"); const wchar_t* ValidateWCStr = ValidateWStr.c_str(); bool bHasValidateFunc = Memcury::Scanner::FindStringRef(ValidateWCStr, false).Get(); - // LOG_INFO(LogDev, "[{}] bHasValidateFunc: {}", Function->GetName(), bHasValidateFunc); + LOG_INFO(LogDev, "[{}] bHasValidateFunc: {}", Function->GetName(), bHasValidateFunc); // LOG_INFO(LogDev, "NativeAddr: 0x{:x}", __int64(NativeAddr) - __int64(GetModuleHandleW(0))); bool bFoundValidate = !bHasValidateFunc;