respawning on older versions

fixed respawning on pre s6, fixed a crash for some s5 builds, work on ai a bit, start on blueprint decompiler
This commit is contained in:
Milxnor
2023-05-20 10:22:47 -04:00
parent bb5a5620e8
commit 33433ea9de
30 changed files with 2082 additions and 77 deletions

View File

@@ -0,0 +1,14 @@
#pragma once
#include "BuildingGameplayActor.h"
class ABuildingItemWeaponUpgradeActor : public ABuildingGameplayActor // ABuildingItemCollectorActor
{
public:
static class UClass* StaticClass()
{
static UClass* Class = FindObject<UClass>(L"/Script/FortniteGame.BuildingItemWeaponUpgradeActor");
return Class;
}
};

View File

@@ -16,13 +16,16 @@ class UStruct : public UField
{
public:
int GetPropertiesSize();
UStruct* GetSuperStruct() { return *(UStruct**)(__int64(this) + Offsets::SuperStruct); } // idk if this is in UStruct
TArray<uint8_t> GetScript() { return *(TArray<uint8_t>*)(__int64(this) + Offsets::Script); }
};
class UClass : public UStruct
{
public:
UObject* CreateDefaultObject();
UClass* GetSuperStruct() { return *(UClass**)(__int64(this) + Offsets::SuperStruct); } // idk if this is in UStruct
};
class UFunction : public UStruct

View File

@@ -0,0 +1 @@
#pragma once

View File

@@ -0,0 +1,13 @@
#pragma once
#include "reboot.h"
class UFortAthenaAIBotCustomizationData : public UObject // UPrimaryDataAsset
{
public:
static UClass* StaticClass()
{
static auto Class = FindObject<UClass>("/Script/FortniteGame.FortAthenaAIBotCustomizationData");
return Class;
}
};

View File

@@ -0,0 +1,36 @@
#pragma once
#include "reboot.h"
#include "Text.h"
enum class EBotNamingMode : uint8 // idk if this changes
{
RealName = 0,
SkinName = 1,
Anonymous = 2,
Custom = 3,
EBotNamingMode_MAX = 4,
};
class UFortBotNameSettings : public UObject
{
public:
EBotNamingMode& GetNamingMode()
{
static auto NamingModeOffset = GetOffset("NamingMode");
return Get<EBotNamingMode>(NamingModeOffset);
}
FText& GetOverrideName()
{
static auto OverrideNameOffset = GetOffset("OverrideName");
return Get<FText>(OverrideNameOffset);
}
bool ShouldAddPlayerIDSuffix()
{
static auto bAddPlayerIDSuffixOffset = GetOffset("bAddPlayerIDSuffix");
return Get<bool>(bAddPlayerIDSuffixOffset);
}
};

View File

@@ -976,10 +976,14 @@ int AFortGameModeAthena::Athena_PickTeamHook(AFortGameModeAthena* GameMode, uint
CurrentTeamMembers++;
auto PlayerStateObjectItem = GetItemByIndex(PlayerState->InternalIndex);
TWeakObjectPtr<AFortPlayerStateAthena> WeakPlayerState{};
WeakPlayerState.ObjectIndex = PlayerState->InternalIndex;
WeakPlayerState.ObjectSerialNumber = GetItemByIndex(PlayerState->InternalIndex)->SerialNumber;
WeakPlayerState.ObjectSerialNumber = PlayerStateObjectItem ? PlayerStateObjectItem->SerialNumber : 0;
if (PlayerStateObjectItem)
{
if (auto TeamsArrayContainer = GameState->GetTeamsArrayContainer())
{
auto& TeamArray = TeamsArrayContainer->TeamsArray.at(NextTeamIndex);
@@ -988,6 +992,7 @@ int AFortGameModeAthena::Athena_PickTeamHook(AFortGameModeAthena* GameMode, uint
TeamArray.Add(WeakPlayerState);
}
}
return NextTeamIndex;
}

View File

@@ -1206,9 +1206,6 @@ void AFortPlayerController::ClientOnPawnDiedHook(AFortPlayerController* PlayerCo
if (!DeadPawn || !GameState || !DeadPlayerState)
return ClientOnPawnDiedOriginal(PlayerController, DeathReport);
static auto DeathInfoStruct = FindObject<UStruct>(L"/Script/FortniteGame.DeathInfo");
static auto DeathInfoStructSize = DeathInfoStruct->GetPropertiesSize();
auto DeathLocation = DeadPawn->GetActorLocation();
static auto FallDamageEnumValue = 1;
@@ -1217,8 +1214,8 @@ void AFortPlayerController::ClientOnPawnDiedHook(AFortPlayerController* PlayerCo
if (Fortnite_Version > 1.8 || Fortnite_Version == 1.11)
{
auto DeathInfo = (void*)(__int64(DeadPlayerState) + MemberOffsets::FortPlayerStateAthena::DeathInfo); // Alloc<void>(DeathInfoStructSize);
RtlSecureZeroMemory(DeathInfo, DeathInfoStructSize); // TODO FREE THE DEATHTAGS
auto DeathInfo = DeadPlayerState->GetDeathInfo(); // Alloc<void>(DeathInfoStructSize);
DeadPlayerState->ClearDeathInfo();
auto/*&*/ Tags = MemberOffsets::FortPlayerPawn::CorrectTags == 0 ? FGameplayTagContainer()
: DeadPawn->Get<FGameplayTagContainer>(MemberOffsets::FortPlayerPawn::CorrectTags);
@@ -1425,13 +1422,13 @@ void AFortPlayerController::ClientOnPawnDiedHook(AFortPlayerController* PlayerCo
{
if (DamageCauser->IsA(FortProjectileBaseClass))
{
LOG_INFO(LogDev, "From a projectile!");
// LOG_INFO(LogDev, "From a projectile!");
auto Owner = Cast<AFortWeapon>(DamageCauser->GetOwner());
KillerWeaponDef = Owner->IsValidLowLevel() ? Owner->GetWeaponData() : nullptr; // I just added the IsValidLowLevel check because what if the weapon destroys?
}
if (auto Weapon = Cast<AFortWeapon>(DamageCauser))
{
LOG_INFO(LogDev, "From a weapon!");
// LOG_INFO(LogDev, "From a weapon!");
KillerWeaponDef = Weapon->GetWeaponData();
}
}
@@ -1517,6 +1514,8 @@ void AFortPlayerController::ClientOnPawnDiedHook(AFortPlayerController* PlayerCo
// AllPlayerBotsToTick.remov3lbah
}
DeadPlayerState->EndDBNOAbilities();
return ClientOnPawnDiedOriginal(PlayerController, DeathReport);
}

View File

@@ -71,6 +71,14 @@ static bool ApplyCID(AFortPlayerPawn* Pawn, UObject* CID, bool bUseServerChooseP
if (!PlayerController)
return false;
if (bUseServerChoosePart)
{
if (Pawn)
{
}
}
/* auto PCCosmeticLoadout = PlayerController->GetCosmeticLoadout();
if (!PCCosmeticLoadout)
@@ -197,9 +205,9 @@ public:
}
}
void ClientOnPawnRevived(AController* EventInstigator)
void ClientOnPawnRevived(AController* EventInstigator) // actually zone // idk what this actually does but i call it
{
static auto ClientOnPawnRevivedFn = FindObject<UFunction>("/Script/FortniteGame.FortPlayerControllerZone.ClientOnPawnRevived");
static auto ClientOnPawnRevivedFn = FindObject<UFunction>(L"/Script/FortniteGame.FortPlayerControllerZone.ClientOnPawnRevived");
this->ProcessEvent(ClientOnPawnRevivedFn, &EventInstigator);
}

View File

@@ -3,6 +3,7 @@
#include "FortPlayerController.h"
#include "FortGadgetItemDefinition.h"
#include "FortPlayerControllerAthena.h"
#include "FortPlayerPawnAthena.h"
FFortAthenaLoadout* AFortPlayerPawn::GetCosmeticLoadout()
{
@@ -69,35 +70,7 @@ void AFortPlayerPawn::ServerReviveFromDBNOHook(AFortPlayerPawn* Pawn, AControlle
else
*/
static auto GAB_AthenaDBNOClass = FindObject<UClass>(L"/Game/Abilities/NPC/Generic/GAB_AthenaDBNO.Default__GAB_AthenaDBNO_C");
auto DBNOPawnASC = PlayerState->GetAbilitySystemComponent();
if (!DBNOPawnASC)
return;
FGameplayAbilitySpec* DBNOSpec = nullptr;
UObject* ClassToFind = GAB_AthenaDBNOClass->ClassPrivate;
auto compareAbilities = [&DBNOSpec, &ClassToFind](FGameplayAbilitySpec* Spec) {
auto CurrentAbility = Spec->GetAbility();
if (CurrentAbility->ClassPrivate == ClassToFind)
{
DBNOSpec = Spec;
return;
}
};
LoopSpecs(DBNOPawnASC, compareAbilities);
if (!DBNOSpec)
return;
DBNOPawnASC->ClientCancelAbility(DBNOSpec->GetHandle(), DBNOSpec->GetActivationInfo());
DBNOPawnASC->ClientEndAbility(DBNOSpec->GetHandle(), DBNOSpec->GetActivationInfo());
DBNOPawnASC->ServerEndAbility(DBNOSpec->GetHandle(), DBNOSpec->GetActivationInfo(), nullptr);
PlayerState->EndDBNOAbilities();
Pawn->SetDBNO(false);
Pawn->SetHasPlayedDying(false);
@@ -108,6 +81,14 @@ void AFortPlayerPawn::ServerReviveFromDBNOHook(AFortPlayerPawn* Pawn, AControlle
PlayerController->ClientOnPawnRevived(EventInstigator); // We should call the function that calls this.
PlayerController->RespawnPlayerAfterDeath(false); // nooo
if (auto PawnAthena = Cast<AFortPlayerPawnAthena>(Pawn)) // im too lazy to make another hook for fortplayerpawnathena
{
if (!PawnAthena->IsDBNO())
{
PawnAthena->GetDBNORevivalStacking() = 0;
}
}
}
void AFortPlayerPawn::ServerHandlePickupWithRequestedSwapHook(UObject* Context, FFrame* Stack, void* Ret)

View File

@@ -7,5 +7,11 @@ class AFortPlayerPawnAthena : public AFortPlayerPawn
public:
static inline void (*OnCapsuleBeginOverlapOriginal)(UObject* Context, FFrame* Stack, void* Ret);
uint8& GetDBNORevivalStacking()
{
static auto DBNORevivalStackingOffset = GetOffset("DBNORevivalStacking");
return Get<uint8>(DBNORevivalStackingOffset);
}
static void OnCapsuleBeginOverlapHook(UObject* Context, FFrame* Stack, void* Ret);
};

View File

@@ -1,5 +1,38 @@
#include "FortPlayerState.h"
void AFortPlayerState::EndDBNOAbilities()
{
static auto GAB_AthenaDBNOClass = FindObject<UClass>(L"/Game/Abilities/NPC/Generic/GAB_AthenaDBNO.Default__GAB_AthenaDBNO_C");
auto ASC = this->GetAbilitySystemComponent();
if (!ASC)
return;
FGameplayAbilitySpec* DBNOSpec = nullptr;
UObject* ClassToFind = GAB_AthenaDBNOClass->ClassPrivate;
auto compareAbilities = [&DBNOSpec, &ClassToFind](FGameplayAbilitySpec* Spec) {
auto CurrentAbility = Spec->GetAbility();
if (CurrentAbility->ClassPrivate == ClassToFind)
{
DBNOSpec = Spec;
return;
}
};
LoopSpecs(ASC, compareAbilities);
if (!DBNOSpec)
return;
ASC->ClientCancelAbility(DBNOSpec->GetHandle(), DBNOSpec->GetActivationInfo());
ASC->ClientEndAbility(DBNOSpec->GetHandle(), DBNOSpec->GetActivationInfo());
ASC->ServerEndAbility(DBNOSpec->GetHandle(), DBNOSpec->GetActivationInfo(), nullptr);
}
bool AFortPlayerState::AreUniqueIDsIdentical(FUniqueNetIdRepl* A, FUniqueNetIdRepl* B)
{
return A->IsIdentical(B);

View File

@@ -19,11 +19,13 @@ public:
return this->Get<int>(WorldPlayerIdOffset);
}
void EndDBNOAbilities();
static bool AreUniqueIDsIdentical(FUniqueNetIdRepl* A, FUniqueNetIdRepl* B);
static UClass* StaticClass()
{
static auto Class = FindObject<UClass>("/Script/FortniteGame.FortPlayerState");
static auto Class = FindObject<UClass>(L"/Script/FortniteGame.FortPlayerState");
return Class;
}
};

View File

@@ -123,6 +123,11 @@ public:
return GetPtr<FDeathInfo>(MemberOffsets::FortPlayerStateAthena::DeathInfo);
}
void ClearDeathInfo()
{
RtlSecureZeroMemory(GetDeathInfo(), FDeathInfo::GetStructSize()); // TODO FREE THE DEATHTAGS
}
static void ServerSetInAircraftHook(UObject* Context, FFrame& Stack, void* Ret);
static UClass* StaticClass()

View File

@@ -148,7 +148,7 @@ APawn* AGameModeBase::SpawnDefaultPawnForHook(AGameModeBase* GameMode, AControll
/* auto DeathInfo = (void*)(__int64(PlayerStateAthena) + MemberOffsets::FortPlayerStateAthena::DeathInfo);
FVector DeathLocation = MemberOffsets::DeathInfo::DeathLocation != -1 ? *(FVector*)(__int64(DeathInfo) + MemberOffsets::DeathInfo::DeathLocation) : FVector(0, 0, 0);
bIsRespawning = !(DeathLocation == FVector(0, 0, 0)); // bro kms */
bIsRespawning = !(DeathLocation.CompareVectors(FVector(0, 0, 0))); // bro kms */
auto ASC = PlayerStateAthena->GetAbilitySystemComponent();
auto GameState = ((AFortGameModeAthena*)GameMode)->GetGameStateAthena();

View File

@@ -9,6 +9,8 @@
#include <random>
#include "Package.h"S
#include "AssertionMacros.h"
#include "bots.h"
#include "gui.h"
FNetworkObjectList& UNetDriver::GetNetworkObjectList()
{
@@ -24,6 +26,11 @@ void UNetDriver::RemoveNetworkActor(AActor* Actor)
void UNetDriver::TickFlushHook(UNetDriver* NetDriver)
{
/* if (bEnableBotTick)
{
Bots::Tick();
} */
if (Globals::bStartedListening)
{
static auto ReplicationDriverOffset = NetDriver->GetOffset("ReplicationDriver", false);

View File

@@ -157,14 +157,14 @@ UPackage* UObject::GetOutermost() const
bool UObject::IsA(UStruct* otherClass)
{
UClass* super = ClassPrivate;
UStruct* super = ClassPrivate;
while (super)
{
if (otherClass == super)
return true;
super = *(UClass**)(__int64(super) + Offsets::SuperStruct);
super = super->GetSuperStruct();
}
return false;
@@ -174,7 +174,7 @@ UFunction* UObject::FindFunction(const std::string& ShortFunctionName)
{
// We could also loop through children.
UClass* super = ClassPrivate;
UStruct* super = ClassPrivate;
while (super)
{

View File

@@ -5,7 +5,7 @@
void APlayerController::ServerChangeName(FString& S)
{
static auto ServerChangeNameFn = FindObject<UFunction>("/Script/Engine.PlayerController.ServerChangeName");
static auto ServerChangeNameFn = FindObject<UFunction>(L"/Script/Engine.PlayerController.ServerChangeName");
this->ProcessEvent(ServerChangeNameFn, &S);
}

View File

@@ -256,6 +256,7 @@
<ClCompile Include="PlayerState.cpp" />
<ClCompile Include="reboot.cpp" />
<ClCompile Include="SavePackage.cpp" />
<ClCompile Include="ScriptDisassembler.cpp" />
<ClCompile Include="UnrealMath.cpp" />
<ClCompile Include="UnrealNames.cpp" />
<ClCompile Include="UObjectGlobals.cpp" />
@@ -289,6 +290,7 @@
<ClInclude Include="BuildingFoundation.h" />
<ClInclude Include="BuildingGameplayActor.h" />
<ClInclude Include="BuildingGameplayActorSpawnMachine.h" />
<ClInclude Include="BuildingItemWeaponUpgradeActor.h" />
<ClInclude Include="BuildingRift.h" />
<ClInclude Include="BuildingSMActor.h" />
<ClInclude Include="BuildingStructuralSupportSystem.h" />
@@ -319,6 +321,8 @@
<ClInclude Include="finder.h" />
<ClInclude Include="FortAbilitySet.h" />
<ClInclude Include="FortAIEncounterInfo.h" />
<ClInclude Include="FortAthenaAIBotCharacterCustomization.h" />
<ClInclude Include="FortAthenaAIBotCustomizationData.h" />
<ClInclude Include="FortAthenaCreativePortal.h" />
<ClInclude Include="FortAthenaMapInfo.h" />
<ClInclude Include="FortAthenaMutator.h" />
@@ -339,6 +343,7 @@
<ClInclude Include="FortAthenaSupplyDrop.h" />
<ClInclude Include="FortAthenaVehicle.h" />
<ClInclude Include="FortAthenaVehicleSpawner.h" />
<ClInclude Include="FortBotNameSettings.h" />
<ClInclude Include="FortDecoItemDefinition.h" />
<ClInclude Include="FortGadgetItemDefinition.h" />
<ClInclude Include="FortGameMode.h" />
@@ -442,6 +447,7 @@
<ClInclude Include="ReversePredicate.h" />
<ClInclude Include="Rotator.h" />
<ClInclude Include="ScriptDelegates.h" />
<ClInclude Include="ScriptDisassembler.h" />
<ClInclude Include="ScriptInterface.h" />
<ClInclude Include="Set.h" />
<ClInclude Include="SharedPointer.h" />

View File

@@ -289,6 +289,9 @@
<ClCompile Include="FortPawn.cpp">
<Filter>FortniteGame\Source\FortniteGame\Private\Player</Filter>
</ClCompile>
<ClCompile Include="ScriptDisassembler.cpp">
<Filter>Engine\Source\Developer\ScriptDisassembler\Private</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="log.h" />
@@ -913,6 +916,21 @@
<ClInclude Include="EnvQueryTypes.h">
<Filter>Engine\Source\Runtime\AIModule\Classes\EnvironmentQuery</Filter>
</ClInclude>
<ClInclude Include="ScriptDisassembler.h">
<Filter>Engine\Source\Developer\ScriptDisassembler\Public</Filter>
</ClInclude>
<ClInclude Include="FortBotNameSettings.h">
<Filter>FortniteGame\Source\FortniteGame\Public\AI</Filter>
</ClInclude>
<ClInclude Include="FortAthenaAIBotCharacterCustomization.h">
<Filter>FortniteGame\Source\FortniteGame\Public\AI</Filter>
</ClInclude>
<ClInclude Include="FortAthenaAIBotCustomizationData.h">
<Filter>FortniteGame\Source\FortniteGame\Public\AI</Filter>
</ClInclude>
<ClInclude Include="BuildingItemWeaponUpgradeActor.h">
<Filter>FortniteGame\Source\FortniteGame\Public\Building\GameplayActors</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="Engine">
@@ -1167,6 +1185,18 @@
<Filter Include="Engine\Source\Runtime\AIModule\Classes\EnvironmentQuery">
<UniqueIdentifier>{9b5483b5-3984-4fe1-96d2-e37d72642efd}</UniqueIdentifier>
</Filter>
<Filter Include="Engine\Source\Developer">
<UniqueIdentifier>{4c658de2-f9aa-4a42-9d7c-21014cb29b3d}</UniqueIdentifier>
</Filter>
<Filter Include="Engine\Source\Developer\ScriptDisassembler">
<UniqueIdentifier>{f64d3dc0-39df-46a5-a451-2f9011ecbad1}</UniqueIdentifier>
</Filter>
<Filter Include="Engine\Source\Developer\ScriptDisassembler\Public">
<UniqueIdentifier>{1df3fb86-ba8f-446d-be0c-cfeb7ec94137}</UniqueIdentifier>
</Filter>
<Filter Include="Engine\Source\Developer\ScriptDisassembler\Private">
<UniqueIdentifier>{45f601de-1a88-490c-a74a-5cf729b16dfb}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<None Include="UnrealEngine.cpp">

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,50 @@
#pragma once
#include "Array.h"
#include <fstream>
#include "reboot.h"
class FKismetBytecodeDisassembler
{
private:
std::vector<uint8> Script;
std::string Indents;
std::ofstream Stream;
public:
void DisassembleStructure(UFunction* Source);
int32 ReadINT(int32& ScriptIndex);
uint64 ReadQWORD(int32& ScriptIndex);
uint8 ReadBYTE(int32& ScriptIndex);
std::string ReadName(int32& ScriptIndex);
uint16 ReadWORD(int32& ScriptIndex);
float ReadFLOAT(int32& ScriptIndex);
CodeSkipSizeType ReadSkipCount(int32& ScriptIndex);
std::string ReadString(int32& ScriptIndex);
std::string ReadString8(int32& ScriptIndex);
std::string ReadString16(int32& ScriptIndex);
uint8 SerializeExpr(int32& ScriptIndex);
void ProcessCastByte(int32 CastType, int32& ScriptIndex);
void ProcessCommon(int32& ScriptIndex, uint8 Opcode);
void AddIndent()
{
Indents += (" ");
}
void DropIndent()
{
// Blah, this is awful
// Indents.LeftInline(Indents.Len() - 2);
Indents = Indents.substr(2);
}
template <typename T>
T* ReadPointer(int32& ScriptIndex)
{
return (T*)ReadQWORD(ScriptIndex);
}
};

View File

@@ -457,6 +457,7 @@ void Offsets::FindAll()
}
Offsets::IsNetRelevantFor = FindIsNetRelevantForOffset();
Offsets::Script = Offsets::Children + 8 + 4 + 4;
}
void Offsets::Print()
@@ -468,7 +469,7 @@ void Offsets::Print()
LOG_INFO(LogDev, "Func: 0x{:x}", Func);
LOG_INFO(LogDev, "ServerReplicateActors: 0x{:x}", ServerReplicateActors);
LOG_INFO(LogDev, "ReplicationFrame: 0x{:x}", ReplicationFrame);
LOG_INFO(LogDev, "IsNetRelevantFor: 0x{:x}", IsNetRelevantFor);
LOG_INFO(LogDev, "Script: 0x{:x}", Script);
}
void Addresses::Init()

View File

@@ -95,6 +95,7 @@ namespace Offsets
extern inline uint64 IsNetRelevantFor = 0;
extern inline uint64 NetworkObjectList = 0;
extern inline uint64 ClientWorldPackageName = 0;
extern inline uint64 Script = 0;
void FindAll();
void Print();

View File

@@ -11,6 +11,9 @@
#include "FortGameModeAthena.h"
#include "FortGameStateAthena.h"
#include "FortPlayerControllerAthena.h"
#include "FortBotNameSettings.h"
#include "KismetTextLibrary.h"
#include "FortAthenaAIBotCustomizationData.h"
using UNavigationSystemV1 = UObject;
using UNavigationSystemConfig = UObject;
@@ -229,7 +232,7 @@ static void SetupNavConfig(const FName& AgentName)
SetNavigationSystem(NavSystemOverride);
}
static AFortPlayerPawn* SpawnAIFromCustomizationData(const FVector& Location, UObject* CustomizationData)
static AFortPlayerPawn* SpawnAIFromCustomizationData(const FVector& Location, UFortAthenaAIBotCustomizationData* CustomizationData)
{
static auto PawnClassOffset = CustomizationData->GetOffset("PawnClass");
auto PawnClass = CustomizationData->Get<UClass*>(PawnClassOffset);
@@ -242,12 +245,38 @@ static AFortPlayerPawn* SpawnAIFromCustomizationData(const FVector& Location, UO
auto Pawn = GetWorld()->SpawnActor<AFortPlayerPawn>(PawnClass, Location);
if (!Pawn)
{
LOG_INFO(LogAI, "Failed to spawn pawn!");
return nullptr;
}
auto Controller = Pawn->GetController();
if (!Controller)
{
LOG_INFO(LogAI, "No controller!");
Pawn->K2_DestroyActor();
return nullptr;
}
auto PlayerState = Controller->GetPlayerState();
if (!PlayerState)
{
LOG_INFO(LogAI, "No PlayerState!");
Controller->K2_DestroyActor();
Pawn->K2_DestroyActor();
return nullptr;
}
static auto CharacterCustomizationOffset = CustomizationData->GetOffset("CharacterCustomization");
auto CharacterCustomization = CustomizationData->Get(CharacterCustomizationOffset);
auto CharacterCustomizationLoadoutOffset = CharacterCustomization->GetOffset("CustomizationLoadout");
auto CharacterCustomizationLoadout = CharacterCustomization->GetPtr<FFortAthenaLoadout>(CharacterCustomizationLoadoutOffset);
auto CharacterToApply = CharacterCustomizationLoadout->GetCharacter();
ApplyCID(Pawn, CharacterCustomizationLoadout->GetCharacter());
ApplyCID(Pawn, CharacterToApply, true); // bruhh
struct FItemAndCount
{
@@ -259,30 +288,77 @@ static AFortPlayerPawn* SpawnAIFromCustomizationData(const FVector& Location, UO
static auto StartupInventoryOffset = CustomizationData->GetOffset("StartupInventory");
auto StartupInventory = CustomizationData->Get(StartupInventoryOffset);
static auto StartupInventoryItemsOffset = StartupInventory->GetOffset("Items");
auto& StartupInventoryItems = StartupInventory->Get<TArray<FItemAndCount>>(StartupInventoryItemsOffset);
auto Controller = Pawn->GetController();
LOG_INFO(LogDev, "Controller: {} StartupInventoryItems.Num: {}", Controller ? Controller->GetFullName() : "InvalidObject", StartupInventoryItems.Num());
std::vector<std::pair<UFortItemDefinition*, int>> ItemsToGrant;
if (Controller)
if (Fortnite_Version < 13)
{
/* static auto InventoryOffset = Controller->GetOffset("Inventory");
auto Inventory = Controller->Get<AFortInventory*>(InventoryOffset);
auto& StartupInventoryItems = StartupInventory->Get<TArray<UFortItemDefinition*>>(StartupInventoryItemsOffset);
for (int i = 0; i < StartupInventoryItems.Num(); i++)
{
auto pair = Inventory->AddItem(StartupInventoryItems.at(i).Item, nullptr, StartupInventoryItems.at(i).Count);
ItemsToGrant.push_back({ StartupInventoryItems.at(i), 1 });
}
}
else
{
auto& StartupInventoryItems = StartupInventory->Get<TArray<FItemAndCount>>(StartupInventoryItemsOffset);
for (int i = 0; i < StartupInventoryItems.Num(); i++)
{
ItemsToGrant.push_back({ StartupInventoryItems.at(i).Item, StartupInventoryItems.at(i).Count });
}
}
static auto InventoryOffset = Controller->GetOffset("Inventory");
auto Inventory = Controller->Get<AFortInventory*>(InventoryOffset);
if (Inventory)
{
for (int i = 0; i < ItemsToGrant.size(); i++)
{
auto pair = Inventory->AddItem(ItemsToGrant.at(i).first, nullptr, ItemsToGrant.at(i).second);
LOG_INFO(LogDev, "pair.first.size(): {}", pair.first.size());
if (pair.first.size() > 0)
{
if (auto weaponDef = Cast<UFortWeaponItemDefinition>(StartupInventoryItems.at(i).Item))
if (auto weaponDef = Cast<UFortWeaponItemDefinition>(ItemsToGrant.at(i).first))
Pawn->EquipWeaponDefinition(weaponDef, pair.first.at(0)->GetItemEntry()->GetItemGuid());
}
} */
}
// Inventory->Update(); // crashes idk why
Inventory->Update();
}
static auto BotNameSettingsOffset = CustomizationData->GetOffset("BotNameSettings");
auto BotNameSettings = CustomizationData->Get<UFortBotNameSettings*>(BotNameSettingsOffset);
FString Name;
if (BotNameSettings)
{
static int CurrentId = 0; // scuffed!
static auto DisplayNameOffset = FindOffsetStruct("/Script/FortniteGame.FortItemDefinition", "DisplayName");
switch (BotNameSettings->GetNamingMode())
{
case EBotNamingMode::Custom:
Name = UKismetTextLibrary::Conv_TextToString(BotNameSettings->GetOverrideName());
break;
case EBotNamingMode::SkinName:
Name = CharacterToApply ? UKismetTextLibrary::Conv_TextToString(*(FText*)(__int64(CharacterCustomizationLoadout->GetCharacter()) + DisplayNameOffset)) : L"InvalidCharacter";
Name.Set((std::wstring(Name.Data.Data) += std::to_wstring(CurrentId++)).c_str());
break;
default:
Name = L"Unknown";
break;
}
}
if (Name.Data.Data && Name.Data.Num() > 0)
{
Controller->ServerChangeName(Name);
}
return Pawn;

View File

@@ -252,6 +252,9 @@ namespace Bots
static void Tick()
{
if (AllPlayerBotsToTick.size() == 0)
return;
auto GameState = Cast<AFortGameStateAthena>(GetWorld()->GetGameState());
auto GameMode = Cast<AFortGameModeAthena>(GetWorld()->GetGameMode());
@@ -311,3 +314,8 @@ namespace Bots
// AllBuildingContainers.Free();
}
}
namespace Bosses
{
}

View File

@@ -10,6 +10,7 @@
#include "FortLootPackage.h"
#include "bots.h"
#include "FortAthenaMutator_Bots.h"
#include "ai.h"
bool IsOperator(APlayerState* PlayerState, AFortPlayerController* PlayerController)
{
@@ -646,6 +647,43 @@ void ServerCheatHook(AFortPlayerControllerAthena* PlayerController, FString Msg)
SendMessageToConsole(PlayerController, L"Not a valid class!");
}
}
else if (Command == "spawnbottest")
{
// /Game/Athena/AI/MANG/BotData/
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;
}
auto CustomizationData = LoadObject<UFortAthenaAIBotCustomizationData>(Arguments[1], UFortAthenaAIBotCustomizationData::StaticClass());
if (!CustomizationData)
{
SendMessageToConsole(PlayerController, L"Invalid CustomizationData!");
return;
}
auto NewPawn = SpawnAIFromCustomizationData(Pawn->GetActorLocation(), CustomizationData);
if (NewPawn)
{
SendMessageToConsole(PlayerController, L"Spawned!");
}
else
{
SendMessageToConsole(PlayerController, L"Failed to spawn!");
}
}
else if (Command == "spawnbot")
{
auto Pawn = ReceivingController->GetPawn();

View File

@@ -179,11 +179,6 @@ void ProcessEventHook(UObject* Object, UFunction* Function, void* Parameters)
if (!Object || !Function)
return;
if (bEnableBotTick)
{
Bots::Tick();
}
if (Globals::bLogProcessEvent)
{
auto FunctionName = Function->GetName(); // UKismetSystemLibrary::GetPathName(Function).ToString();

View File

@@ -761,6 +761,11 @@ 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)
{
Hooking::MinHook::Hook(FortPlayerPawnAthenaDefault, FindObject<UFunction>(L"/Script/FortniteGame.FortPlayerPawn.ServerReviveFromDBNO"),
AFortPlayerPawn::ServerReviveFromDBNOHook, nullptr, false);
}
static auto FortGameplayAbilityAthena_PeriodicItemGrantDefault = FindObject<UFortGameplayAbilityAthena_PeriodicItemGrant>(L"/Script/FortniteGame.Default__FortGameplayAbilityAthena_PeriodicItemGrant");
@@ -1008,12 +1013,6 @@ DWORD WINAPI Main(LPVOID)
static auto GameplayEventDataSize = FindObject<UStruct>(L"/Script/GameplayAbilities.GameplayEventData")->GetPropertiesSize();
LOG_INFO(LogDev, "GameplayEventDataSize: 0x{:x} {}", GameplayEventDataSize, GameplayEventDataSize);
if (Fortnite_Version == 1.11 || Fortnite_Version > 1.8)
{
Hooking::MinHook::Hook(FortPlayerPawnAthenaDefault, FindObject<UFunction>(L"/Script/FortniteGame.FortPlayerPawn.ServerReviveFromDBNO"),
AFortPlayerPawn::ServerReviveFromDBNOHook, nullptr, false);
}
{
int increaseOffset = 0x10;

View File

@@ -12,6 +12,8 @@ typedef short int16;
typedef int int32;
typedef __int64 int64;
typedef unsigned int uint32;
typedef char ANSICHAR;
typedef uint32_t CodeSkipSizeType;
typedef unsigned __int64 uint64;
extern inline int Engine_Version = 0; // For example, 420, 421, etc. // Prevent using this when possible.