From 3405177d20af4ec560bbccf64229beae553deb99 Mon Sep 17 00:00:00 2001 From: Milxnor Date: Sun, 7 May 2023 17:34:24 -0400 Subject: [PATCH] i broke the whole project but its fine complete pickup rewrite, idle pawns --- Project Reboot 3.0/AbilitySystemComponent.h | 4 +- Project Reboot 3.0/Array.h | 32 +++ Project Reboot 3.0/AttributeSet.h | 24 +- Project Reboot 3.0/BGA.h | 59 +++- Project Reboot 3.0/BuildingContainer.cpp | 15 +- Project Reboot 3.0/Class.h | 23 ++ Project Reboot 3.0/EngineTypes.cpp | 19 ++ Project Reboot 3.0/EngineTypes.h | 5 + Project Reboot 3.0/FortAbilitySet.h | 2 +- Project Reboot 3.0/FortAthenaSupplyDrop.cpp | 17 +- Project Reboot 3.0/FortGadgetItemDefinition.h | 6 + Project Reboot 3.0/FortGameModeAthena.cpp | 94 ++++--- Project Reboot 3.0/FortGameModeAthena.h | 7 + Project Reboot 3.0/FortGameStateAthena.cpp | 10 + Project Reboot 3.0/FortGameStateAthena.h | 1 + Project Reboot 3.0/FortInventory.cpp | 94 ++++--- Project Reboot 3.0/FortInventory.h | 2 + Project Reboot 3.0/FortItem.cpp | 35 +++ Project Reboot 3.0/FortItem.h | 66 +++-- Project Reboot 3.0/FortKismetLibrary.cpp | 60 +++- Project Reboot 3.0/FortKismetLibrary.h | 8 +- Project Reboot 3.0/FortLootPackage.cpp | 16 +- Project Reboot 3.0/FortPawn.cpp | 10 + Project Reboot 3.0/FortPawn.h | 1 + Project Reboot 3.0/FortPickup.cpp | 258 +++++++++--------- Project Reboot 3.0/FortPickup.h | 122 +++++++-- Project Reboot 3.0/FortPlayerController.cpp | 89 ++++-- Project Reboot 3.0/FortPlayerController.h | 14 + .../FortPlayerControllerAthena.cpp | 3 + Project Reboot 3.0/FortPlayerPawn.cpp | 5 +- Project Reboot 3.0/FortPlayerStateAthena.h | 14 + Project Reboot 3.0/GameModeBase.cpp | 32 ++- Project Reboot 3.0/GameModeBase.h | 3 + Project Reboot 3.0/KismetSystemLibrary.h | 172 ++++++++++++ Project Reboot 3.0/OnlineReplStructs.h | 22 ++ Project Reboot 3.0/PlayerController.cpp | 6 + Project Reboot 3.0/PlayerController.h | 2 + Project Reboot 3.0/PlayerState.cpp | 20 ++ Project Reboot 3.0/PlayerState.h | 3 + Project Reboot 3.0/Project Reboot 3.0.vcxproj | 1 + .../Project Reboot 3.0.vcxproj.filters | 12 +- Project Reboot 3.0/Transform.h | 6 +- Project Reboot 3.0/World.h | 12 +- Project Reboot 3.0/bots.h | 248 +++++++++++++++++ Project Reboot 3.0/commands.h | 82 +++++- Project Reboot 3.0/die.h | 6 + Project Reboot 3.0/dllmain.cpp | 3 - Project Reboot 3.0/finder.h | 2 +- Project Reboot 3.0/gui.h | 17 +- Project Reboot 3.0/log.h | 1 + Project Reboot 3.0/reboot.h | 12 +- 51 files changed, 1439 insertions(+), 338 deletions(-) create mode 100644 Project Reboot 3.0/bots.h diff --git a/Project Reboot 3.0/AbilitySystemComponent.h b/Project Reboot 3.0/AbilitySystemComponent.h index c290cf1..2a078d9 100644 --- a/Project Reboot 3.0/AbilitySystemComponent.h +++ b/Project Reboot 3.0/AbilitySystemComponent.h @@ -54,10 +54,10 @@ public: this->ProcessEvent(fn, &UAbilitySystemComponent_ClientActivateAbilityFailed_Params); } - TArray& GetSpawnedAttributes() + TArray& GetSpawnedAttributes() { static auto SpawnedAttributesOffset = GetOffset("SpawnedAttributes"); - return Get>(SpawnedAttributesOffset); + return Get>(SpawnedAttributesOffset); } FGameplayAbilitySpecContainer* GetActivatableAbilities() diff --git a/Project Reboot 3.0/Array.h b/Project Reboot 3.0/Array.h index 0684f84..5941185 100644 --- a/Project Reboot 3.0/Array.h +++ b/Project Reboot 3.0/Array.h @@ -52,6 +52,37 @@ public: return DefaultCalculateSlackReserve(NumElements, NumBytesPerElement, false); } + void ResizeArray(SizeType NewNum, SIZE_T NumBytesPerElement) + { + const SizeType CurrentMax = ArrayMax; + SizeType v3 = NewNum; + if (NewNum) + { + /* SizeType v6 = (unsigned __int64)FMemory::QuantizeSize(4 * NewNum, 0) >> 2; + // if (v3 > (int)v6) + // LODWORD(v6) = 0x7FFFFFFF; + v3 = v6; */ + } + + if (v3 != CurrentMax && (Data || v3)) + Data = (InElementType*)FMemory::Realloc(Data, NumBytesPerElement * v3, 0); + + ArrayNum = v3; // ? + ArrayMax = v3; + } + + void CopyFromArray(TArray& OtherArray, SIZE_T NumBytesPerElement = sizeof(InElementType)) + { + if (!OtherArray.ArrayNum && !ArrayMax) + { + ArrayMax = 0; + return; + } + + ResizeArray(OtherArray.ArrayNum, NumBytesPerElement); + memcpy(this->Data, OtherArray.Data, NumBytesPerElement * OtherArray.ArrayNum); + } + /* FORCENOINLINE void ResizeForCopy(SizeType NewMax, SizeType PrevMax, int ElementSize = sizeof(InElementType)) { @@ -303,6 +334,7 @@ public: // VirtualFree(Data, 0, MEM_RELEASE); } + Data = nullptr; ArrayNum = 0; ArrayMax = 0; } diff --git a/Project Reboot 3.0/AttributeSet.h b/Project Reboot 3.0/AttributeSet.h index 720f627..138ada1 100644 --- a/Project Reboot 3.0/AttributeSet.h +++ b/Project Reboot 3.0/AttributeSet.h @@ -10,6 +10,26 @@ public: struct FGameplayAttribute { FString AttributeName; - void* Attribute; - UStruct* AttributeOwner; + void* Attribute; // Property + UStruct* AttributeOwner; + + std::string GetAttributeName() + { + return AttributeName.ToString(); + } + + std::string GetAttributePropertyName() + { + if (!Attribute) + return "INVALIDATTRIBUTE"; + + FName* NamePrivate = nullptr; + + if (Engine_Version >= 425) + NamePrivate = (FName*)(__int64(Attribute) + 0x28); + else + NamePrivate = &((UField*)Attribute)->NamePrivate; + + return NamePrivate->ToString(); + } }; \ No newline at end of file diff --git a/Project Reboot 3.0/BGA.h b/Project Reboot 3.0/BGA.h index 940740b..44cbdfc 100644 --- a/Project Reboot 3.0/BGA.h +++ b/Project Reboot 3.0/BGA.h @@ -5,8 +5,9 @@ #include "FortLootPackage.h" #include "FortPickup.h" #include "BuildingGameplayActor.h" +#include "KismetSystemLibrary.h" -void SpawnBGAs() // hahah not "proper", there's a function that we can hook and it gets called on each spawner whenever playlist gets set, but it's fine. +static inline void SpawnBGAs() // hahah not "proper", there's a function that we can hook and it gets called on each spawner whenever playlist gets set, but it's fine. { static auto BGAConsumableSpawnerClass = FindObject("/Script/FortniteGame.BGAConsumableSpawner"); @@ -23,6 +24,9 @@ void SpawnBGAs() // hahah not "proper", there's a function that we can hook and { auto BGAConsumableSpawner = AllBGAConsumableSpawners.at(i); auto SpawnLocation = BGAConsumableSpawner->GetActorLocation(); + + static auto bAlignSpawnedActorsToSurfaceOffset = BGAConsumableSpawner->GetOffset("bAlignSpawnedActorsToSurface"); + const bool bAlignSpawnedActorsToSurface = BGAConsumableSpawner->Get(bAlignSpawnedActorsToSurfaceOffset); FTransform SpawnTransform{}; SpawnTransform.Translation = SpawnLocation; @@ -55,20 +59,63 @@ void SpawnBGAs() // hahah not "proper", there's a function that we can hook and continue; } - bool bDeferConstruction = false; // hm? + bool bDeferConstruction = true; // hm? FActorSpawnParameters SpawnParameters{}; - // SpawnParameters.ObjectFlags = RF_Transactional; // idk fortnite does this i think + // SpawnParameters.ObjectFlags = RF_Transactional; // idk fortnite does this i think // i think its acutally suppsoed to be |= RF_Transient SpawnParameters.bDeferConstruction = bDeferConstruction; auto ConsumableActor = GetWorld()->SpawnActor(StrongConsumableClass, SpawnTransform, SpawnParameters); if (ConsumableActor) { - if (bDeferConstruction) - UGameplayStatics::FinishSpawningActor(ConsumableActor, SpawnTransform); // what + FTransform FinalSpawnTransform = SpawnTransform; - ConsumableActor->InitializeBuildingActor(nullptr, nullptr, true); // idk UFortKismetLibrary::SpawnBuildingGameplayActor does this + if (bAlignSpawnedActorsToSurface) + { + // I DONT KNOW + + /* FHitResult* NewHit = Alloc(FHitResult::GetStructSize()); + + FVector StartLocation = FinalSpawnTransform.Translation; + FVector EndLocation = StartLocation - FVector(0, 0, 1000); + + bool bTraceComplex = true; // idk + FName ProfileName = UKismetStringLibrary::Conv_StringToName(L"FindGroundLocationAt"); + + UKismetSystemLibrary::LineTraceSingleByProfile(ConsumableActor, StartLocation, EndLocation, ProfileName, bTraceComplex, + TArray(), EDrawDebugTrace::None, &NewHit, true, FLinearColor(), FLinearColor(), 0); + + // UKismetSystemLibrary::LineTraceSingle(ConsumableActor, StartLocation, EndLocation, + // ETraceTypeQuery::TraceTypeQuery1, bTraceComplex, TArray(), EDrawDebugTrace::None, true, FLinearColor(), FLinearColor(), 0, &NewHit); + + bool IsBlockingHit = NewHit && NewHit->IsBlockingHit(); // Should we check ret of linetracesingle? + + if (IsBlockingHit) + { + FinalSpawnTransform.Translation = NewHit->GetLocation(); + } + else + { + FinalSpawnTransform.Translation = FVector(0, 0, 0); + } + + */ + } + + if (FinalSpawnTransform.Translation == FVector(0, 0, 0)) + { + LOG_WARN(LogGame, "Invalid BGA spawn location!"); + // ConsumableActor->K2_DestroyActor(); // ?? + continue; + } + + if (bDeferConstruction) + UGameplayStatics::FinishSpawningActor(ConsumableActor, FinalSpawnTransform); + + // ConsumableActor->InitializeBuildingActor(nullptr, nullptr, true); // idk UFortKismetLibrary::SpawnBuildingGameplayActor does this + + LOG_INFO(LogDev, "Spawned BGA {} at {} {} {}", ConsumableActor->GetName(), FinalSpawnTransform.Translation.X, FinalSpawnTransform.Translation.Y, FinalSpawnTransform.Translation.Z); } } } diff --git a/Project Reboot 3.0/BuildingContainer.cpp b/Project Reboot 3.0/BuildingContainer.cpp index 10978be..1ac59d4 100644 --- a/Project Reboot 3.0/BuildingContainer.cpp +++ b/Project Reboot 3.0/BuildingContainer.cpp @@ -6,10 +6,11 @@ bool ABuildingContainer::SpawnLoot(AFortPawn* Pawn) { + auto GameMode = Cast(GetWorld()->GetGameMode()); FVector LocationToSpawnLoot = this->GetActorLocation() + this->GetActorRightVector() * 70.f + FVector{ 0, 0, 50 }; static auto SearchLootTierGroupOffset = this->GetOffset("SearchLootTierGroup"); - auto RedirectedLootTier = Cast(GetWorld()->GetGameMode())->RedirectLootTier(this->Get(SearchLootTierGroupOffset)); + auto RedirectedLootTier = GameMode->RedirectLootTier(this->Get(SearchLootTierGroupOffset)); // LOG_INFO(LogInteraction, "RedirectedLootTier: {}", RedirectedLootTier.ToString()); @@ -20,7 +21,17 @@ bool ABuildingContainer::SpawnLoot(AFortPawn* Pawn) for (int i = 0; i < LootDrops.size(); i++) { auto& lootDrop = LootDrops.at(i); - AFortPickup::SpawnPickup(lootDrop->GetItemDefinition(), LocationToSpawnLoot, lootDrop->GetCount(), EFortPickupSourceTypeFlag::Container, EFortPickupSpawnSource::Unset, lootDrop->GetLoadedAmmo()); + + PickupCreateData CreateData{}; + CreateData.bToss = true; + // CreateData.PawnOwner = Pawn; + CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(lootDrop->GetItemDefinition(), lootDrop->GetCount(), lootDrop->GetLoadedAmmo()); + CreateData.SpawnLocation = LocationToSpawnLoot; + CreateData.SourceType = EFortPickupSourceTypeFlag::GetContainerValue(); + CreateData.bRandomRotation = true; + CreateData.bShouldFreeItemEntryWhenDeconstructed = true; + + auto NewPickup = AFortPickup::SpawnPickup(CreateData); } return true; diff --git a/Project Reboot 3.0/Class.h b/Project Reboot 3.0/Class.h index 094414f..84301ac 100644 --- a/Project Reboot 3.0/Class.h +++ b/Project Reboot 3.0/Class.h @@ -3,6 +3,8 @@ #include "Object.h" #include "addresses.h" +#include "UnrealString.h" +#include "Map.h" struct UField : UObject { @@ -28,3 +30,24 @@ class UFunction : public UStruct public: void*& GetFunc() { return *(void**)(__int64(this) + Offsets::Func); } }; + +class UEnum : public UField +{ +public: + int64 GetValue(const std::string& EnumMemberName) + { + auto Names = (TArray>*)(__int64(this) + sizeof(UField) + sizeof(FString)); + + for (int i = 0; i < Names->Num(); i++) + { + auto& Pair = Names->At(i); + auto& Name = Pair.Key(); + auto Value = Pair.Value(); + + if (Name.ComparisonIndex.Value && Name.ToString().contains(EnumMemberName)) + return Value; + } + + return -1; + } +}; \ No newline at end of file diff --git a/Project Reboot 3.0/EngineTypes.cpp b/Project Reboot 3.0/EngineTypes.cpp index dda784f..10ac534 100644 --- a/Project Reboot 3.0/EngineTypes.cpp +++ b/Project Reboot 3.0/EngineTypes.cpp @@ -11,4 +11,23 @@ UStruct* FHitResult::GetStruct() int FHitResult::GetStructSize() { return GetStruct()->GetPropertiesSize(); +} + +bool FHitResult::IsBlockingHit() +{ + // return true; + static auto bBlockingHitOffset = FindOffsetStruct("/Script/Engine.HitResult", "bBlockingHit"); + static auto bBlockingHitFieldMask = GetFieldMask(FindPropertyStruct("/Script/Engine.HitResult", "bBlockingHit")); + return ReadBitfield((PlaceholderBitfield*)(__int64(this) + bBlockingHitOffset), bBlockingHitFieldMask); +} + +FVector& FHitResult::GetLocation() +{ + static auto LocationOffset = FindOffsetStruct("/Script/Engine.HitResult", "Location"); + return *(FVector*)(__int64(this) + LocationOffset); +} + +void FHitResult::CopyFromHitResult(FHitResult* Other) +{ + this->GetLocation() = Other->GetLocation(); } \ No newline at end of file diff --git a/Project Reboot 3.0/EngineTypes.h b/Project Reboot 3.0/EngineTypes.h index 2566be8..620a44f 100644 --- a/Project Reboot 3.0/EngineTypes.h +++ b/Project Reboot 3.0/EngineTypes.h @@ -1,6 +1,7 @@ #pragma once #include "Object.h" +#include "Vector.h" #include "DelegateCombinations.h" @@ -17,6 +18,10 @@ struct FHitResult { static class UStruct* GetStruct(); static int GetStructSize(); + + bool IsBlockingHit(); + FVector& GetLocation(); + void CopyFromHitResult(FHitResult* Other); }; struct FTimerHandle diff --git a/Project Reboot 3.0/FortAbilitySet.h b/Project Reboot 3.0/FortAbilitySet.h index bfc6a0a..5a4a7b5 100644 --- a/Project Reboot 3.0/FortAbilitySet.h +++ b/Project Reboot 3.0/FortAbilitySet.h @@ -83,7 +83,7 @@ public: if (!AbilityClass) continue; - LOG_INFO(LogDev, "Giving AbilityClass {}", AbilityClass->GetFullName()); + // LOG_INFO(LogDev, "Giving AbilityClass {}", AbilityClass->GetFullName()); AbilitySystemComponent->GiveAbilityEasy(AbilityClass, SourceObject); } diff --git a/Project Reboot 3.0/FortAthenaSupplyDrop.cpp b/Project Reboot 3.0/FortAthenaSupplyDrop.cpp index 3b91b49..73d2bd9 100644 --- a/Project Reboot 3.0/FortAthenaSupplyDrop.cpp +++ b/Project Reboot 3.0/FortAthenaSupplyDrop.cpp @@ -44,7 +44,14 @@ AFortPickup* AFortAthenaSupplyDrop::SpawnGameModePickupHook(UObject* Context, FF LOG_INFO(LogDev, "Spawning GameModePickup with ItemDefinition: {}", ItemDefinition->GetFullName()); - *Ret = AFortPickup::SpawnPickup(ItemDefinition, Position, NumberToSpawn, EFortPickupSourceTypeFlag::Other, EFortPickupSpawnSource::SupplyDrop, -1, TriggeringPawn, PickupClass); + PickupCreateData CreateData; + CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(ItemDefinition, NumberToSpawn, -1); + CreateData.SpawnLocation = Position; + CreateData.PawnOwner = TriggeringPawn; + CreateData.Source = EFortPickupSpawnSource::GetSupplyDropValue(); + CreateData.OverrideClass = PickupClass; + + *Ret = AFortPickup::SpawnPickup(CreateData); return *Ret; } @@ -67,7 +74,13 @@ AFortPickup* AFortAthenaSupplyDrop::SpawnPickupHook(UObject* Context, FFrame& St if (!ItemDefinition) return nullptr; - *Ret = AFortPickup::SpawnPickup(ItemDefinition, Position, NumberToSpawn, EFortPickupSourceTypeFlag::Other, EFortPickupSpawnSource::SupplyDrop, -1, TriggeringPawn); + PickupCreateData CreateData; + CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(ItemDefinition, NumberToSpawn, -1); + CreateData.SpawnLocation = Position; + CreateData.PawnOwner = TriggeringPawn; + CreateData.Source = EFortPickupSpawnSource::GetSupplyDropValue(); + + *Ret = AFortPickup::SpawnPickup(CreateData); return *Ret; } diff --git a/Project Reboot 3.0/FortGadgetItemDefinition.h b/Project Reboot 3.0/FortGadgetItemDefinition.h index 616adf5..1de6d6e 100644 --- a/Project Reboot 3.0/FortGadgetItemDefinition.h +++ b/Project Reboot 3.0/FortGadgetItemDefinition.h @@ -30,6 +30,12 @@ public: return ReadBitfieldValue(bDestroyGadgetWhenTrackedAttributesIsZeroOffset, bDestroyGadgetWhenTrackedAttributesIsZeroFieldMask); } + TArray& GetTrackedAttributes() + { + static auto TrackedAttributesOffset = GetOffset("TrackedAttributes"); + return Get>(TrackedAttributesOffset); + } + UAttributeSet* GetAttributeSet() { static auto AttributeSetOffset = this->GetOffset("AttributeSet", false); diff --git a/Project Reboot 3.0/FortGameModeAthena.cpp b/Project Reboot 3.0/FortGameModeAthena.cpp index 0299ef4..4e42aad 100644 --- a/Project Reboot 3.0/FortGameModeAthena.cpp +++ b/Project Reboot 3.0/FortGameModeAthena.cpp @@ -8,6 +8,7 @@ #include "FortLootPackage.h" #include "FortPlayerPawn.h" #include "FortPickup.h" +#include "bots.h" #include "FortAbilitySet.h" #include "NetSerialization.h" @@ -553,6 +554,11 @@ bool AFortGameModeAthena::Athena_ReadyToStartMatchHook(AFortGameModeAthena* Game GetWorld()->Listen(); + if (AmountOfBotsToSpawn != 0) + { + Bots::SpawnBotsAtPlayerStarts(AmountOfBotsToSpawn); + } + // GameState->OnRep_CurrentPlaylistInfo(); // return false; @@ -698,6 +704,15 @@ bool AFortGameModeAthena::Athena_ReadyToStartMatchHook(AFortGameModeAthena* Game int AFortGameModeAthena::Athena_PickTeamHook(AFortGameModeAthena* GameMode, uint8 preferredTeam, AActor* Controller) { + bool bIsBot = false; + + auto PlayerState = ((APlayerController*)Controller)->GetPlayerState(); + + if (PlayerState) + { + bIsBot = PlayerState->IsBot(); + } + // VERY BASIC IMPLEMENTATION LOG_INFO(LogTeams, "PickTeam called!"); @@ -939,7 +954,7 @@ void AFortGameModeAthena::Athena_HandleStartingNewPlayerHook(AFortGameModeAthena float UpZ = 50; - EFortPickupSourceTypeFlag SpawnFlag = EFortPickupSourceTypeFlag::Container; + uint8 SpawnFlag = EFortPickupSourceTypeFlag::GetContainerValue(); bool bTest = false; bool bPrintWarmup = false; @@ -947,25 +962,22 @@ void AFortGameModeAthena::Athena_HandleStartingNewPlayerHook(AFortGameModeAthena for (int i = 0; i < SpawnIsland_FloorLoot_Actors.Num(); i++) { ABuildingContainer* CurrentActor = (ABuildingContainer*)SpawnIsland_FloorLoot_Actors.at(i); + auto Location = CurrentActor->GetActorLocation(); + Location.Z += UpZ; + std::vector LootDrops = PickLootDrops(SpawnIslandTierGroup, bPrintWarmup); + + for (auto& LootDrop : LootDrops) { - auto Location = CurrentActor->GetActorLocation(); - Location.Z += UpZ; + PickupCreateData CreateData; + CreateData.bToss = true; + CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(LootDrop->GetItemDefinition(), LootDrop->GetCount(), LootDrop->GetLoadedAmmo()); + CreateData.SpawnLocation = Location; + CreateData.SourceType = SpawnFlag; + CreateData.bRandomRotation = true; + CreateData.bShouldFreeItemEntryWhenDeconstructed = true; - std::vector LootDrops = PickLootDrops(SpawnIslandTierGroup, bPrintWarmup); - - if (bPrintWarmup) - { - std::cout << "\n\n"; - } - - if (LootDrops.size()) - { - for (auto& LootDrop : LootDrops) - { - auto Pickup = AFortPickup::SpawnPickup(LootDrop->GetItemDefinition(), Location, LootDrop->GetCount(), SpawnFlag, EFortPickupSpawnSource::Unset, LootDrop->GetLoadedAmmo()); - } - } + auto Pickup = AFortPickup::SpawnPickup(CreateData); } if (!bTest) @@ -979,33 +991,31 @@ void AFortGameModeAthena::Athena_HandleStartingNewPlayerHook(AFortGameModeAthena for (int i = 0; i < BRIsland_FloorLoot_Actors.Num(); i++) { ABuildingContainer* CurrentActor = (ABuildingContainer*)BRIsland_FloorLoot_Actors.at(i); - - // CurrentActor->K2_DestroyActor(); spawned++; - // continue; - auto Location = CurrentActor->GetActorLocation(); Location.Z += UpZ; std::vector LootDrops = PickLootDrops(BRIslandTierGroup, bPrint); - if (bPrint) - std::cout << "\n"; - - if (LootDrops.size()) + for (auto& LootDrop : LootDrops) { - for (auto& LootDrop : LootDrops) - { - auto Pickup = AFortPickup::SpawnPickup(LootDrop->GetItemDefinition(), Location, LootDrop->GetCount(), SpawnFlag, EFortPickupSpawnSource::Unset, LootDrop->GetLoadedAmmo()); - } + PickupCreateData CreateData; + CreateData.bToss = true; + CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(LootDrop->GetItemDefinition(), LootDrop->GetCount(), LootDrop->GetLoadedAmmo()); + CreateData.SpawnLocation = Location; + CreateData.SourceType = SpawnFlag; + CreateData.bRandomRotation = true; + CreateData.bShouldFreeItemEntryWhenDeconstructed = true; + + auto Pickup = AFortPickup::SpawnPickup(CreateData); } if (!bTest) CurrentActor->K2_DestroyActor(); } - // SpawnIsland_FloorLoot_Actors.Free(); - // BRIsland_FloorLoot_Actors.Free(); + SpawnIsland_FloorLoot_Actors.Free(); + BRIsland_FloorLoot_Actors.Free(); LOG_INFO(LogDev, "Spawned loot!"); } @@ -1058,7 +1068,7 @@ void AFortGameModeAthena::Athena_HandleStartingNewPlayerHook(AFortGameModeAthena static auto SquadIdOffset = PlayerStateAthena->GetOffset("SquadId", false); if (SquadIdOffset != -1) - PlayerStateAthena->GetSquadId() = PlayerStateAthena->GetTeamIndex() - 2; + PlayerStateAthena->GetSquadId() = PlayerStateAthena->GetTeamIndex() - 2; // wrong place to do this // idk if this is needed @@ -1075,9 +1085,6 @@ void AFortGameModeAthena::Athena_HandleStartingNewPlayerHook(AFortGameModeAthena static auto OnRep_bHasStartedPlayingFn = FindObject(L"/Script/FortniteGame.FortPlayerState.OnRep_bHasStartedPlaying"); PlayerStateAthena->ProcessEvent(OnRep_bHasStartedPlayingFn); - LOG_INFO(LogDev, "Old ID: {}", PlayerStateAthena->GetWorldPlayerId()); - LOG_INFO(LogDev, "PlayerID: {}", PlayerStateAthena->GetPlayerID()); - PlayerStateAthena->GetWorldPlayerId() = PlayerStateAthena->GetPlayerID(); auto PlayerAbilitySet = GetPlayerAbilitySet(); @@ -1088,9 +1095,15 @@ void AFortGameModeAthena::Athena_HandleStartingNewPlayerHook(AFortGameModeAthena PlayerAbilitySet->GiveToAbilitySystem(AbilitySystemComponent); } - struct FUniqueNetIdReplExperimental + struct FUniqueNetIdWrapper { - unsigned char ahh[0x0028]; + unsigned char UnknownData00[0x1]; // 0x0000(0x0001) MISSED OFFSET + }; + + struct FUniqueNetIdReplExperimental : public FUniqueNetIdWrapper + { + unsigned char UnknownData00[0x17]; // 0x0001(0x0017) MISSED OFFSET + TArray ReplicationBytes; // 0x0018(0x0010) (ZeroConstructor, Transient, Protected, NativeAccessSpecifierProtected) }; static auto PlayerCameraManagerOffset = NewPlayer->GetOffset("PlayerCameraManager"); @@ -1105,12 +1118,10 @@ void AFortGameModeAthena::Athena_HandleStartingNewPlayerHook(AFortGameModeAthena PlayerCameraManager->Get(ViewRollMaxOffset) = 0; } - /* FUniqueNetIdReplExperimental Bugha{}; */ static auto UniqueIdOffset = PlayerStateAthena->GetOffset("UniqueId"); auto PlayerStateUniqueId = PlayerStateAthena->GetPtr(UniqueIdOffset); { - LOG_INFO(LogDev, "bruh"); static auto GameMemberInfoArrayOffset = GameState->GetOffset("GameMemberInfoArray", false); // if (false) @@ -1150,7 +1161,7 @@ void AFortGameModeAthena::Athena_HandleStartingNewPlayerHook(AFortGameModeAthena ((FGameMemberInfo*)GameMemberInfo)->SquadId = PlayerStateAthena->GetSquadId(); ((FGameMemberInfo*)GameMemberInfo)->TeamIndex = PlayerStateAthena->GetTeamIndex(); // GameMemberInfo->MemberUniqueId = PlayerStateUniqueId; - CopyStruct(&((FGameMemberInfo*)GameMemberInfo)->MemberUniqueId, PlayerStateUniqueId, FUniqueNetIdRepl::GetSizeOfStruct()); + ((FUniqueNetIdRepl*)&((FGameMemberInfo*)GameMemberInfo)->MemberUniqueId)->CopyFromAnotherUniqueId(PlayerStateUniqueId); } static auto GameMemberInfoArray_MembersOffset = FindOffsetStruct("/Script/FortniteGame.GameMemberInfoArray", "Members"); @@ -1260,7 +1271,8 @@ void AFortGameModeAthena::Athena_HandleStartingNewPlayerHook(AFortGameModeAthena if (LevelSaveComponent) { static auto AccountIdOfOwnerOffset = LevelSaveComponent->GetOffset("AccountIdOfOwner"); - CopyStruct(LevelSaveComponent->GetPtr(AccountIdOfOwnerOffset), PlayerStateUniqueId, FUniqueNetIdRepl::GetSizeOfStruct()); + LevelSaveComponent->GetPtr(AccountIdOfOwnerOffset)->CopyFromAnotherUniqueId(PlayerStateUniqueId); + // CopyStruct(LevelSaveComponent->GetPtr(AccountIdOfOwnerOffset), PlayerStateUniqueId, FUniqueNetIdRepl::GetSizeOfStruct()); // LevelSaveComponent->Get(AccountIdOfOwnerOffset) = PlayerStateUniqueId; static auto bIsLoadedOffset = LevelSaveComponent->GetOffset("bIsLoaded"); diff --git a/Project Reboot 3.0/FortGameModeAthena.h b/Project Reboot 3.0/FortGameModeAthena.h index 98ab025..a637fd7 100644 --- a/Project Reboot 3.0/FortGameModeAthena.h +++ b/Project Reboot 3.0/FortGameModeAthena.h @@ -8,6 +8,7 @@ #include "FortSafeZoneIndicator.h" #include "GameplayStatics.h" #include "FortAbilitySet.h" +#include "FortPlayerControllerAthena.h" #include "FortItemDefinition.h" struct FAircraftFlightInfo @@ -233,6 +234,12 @@ public: return Get>(StartingItemsOffset); } + TArray& GetAlivePlayers() + { + static auto AlivePlayersOffset = GetOffset("AlivePlayers"); + return Get>(AlivePlayersOffset); + } + FName RedirectLootTier(const FName& LootTier); UClass* GetVehicleClassOverride(UClass* DefaultClass); diff --git a/Project Reboot 3.0/FortGameStateAthena.cpp b/Project Reboot 3.0/FortGameStateAthena.cpp index 712e1dc..a95b7eb 100644 --- a/Project Reboot 3.0/FortGameStateAthena.cpp +++ b/Project Reboot 3.0/FortGameStateAthena.cpp @@ -243,4 +243,14 @@ void AFortGameStateAthena::OnRep_CurrentPlaylistInfo() if (OnRep_CurrentPlaylistInfo) this->ProcessEvent(OnRep_CurrentPlaylistInfo); } +} + +void AFortGameStateAthena::OnRep_PlayersLeft() +{ + static auto OnRep_PlayersLeftFn = FindObject("/Script/FortniteGame.FortGameStateAthena.OnRep_PlayersLeft"); + + if (!OnRep_PlayersLeftFn) + return; + + this->ProcessEvent(OnRep_PlayersLeftFn); } \ No newline at end of file diff --git a/Project Reboot 3.0/FortGameStateAthena.h b/Project Reboot 3.0/FortGameStateAthena.h index efa0816..a20e06c 100644 --- a/Project Reboot 3.0/FortGameStateAthena.h +++ b/Project Reboot 3.0/FortGameStateAthena.h @@ -104,6 +104,7 @@ public: bool IsPlayerBuildableClass(UClass* Class); void OnRep_GamePhase(); void OnRep_CurrentPlaylistInfo(); + void OnRep_PlayersLeft(); }; static void* ConstructOnGamePhaseStepChangedParams(EAthenaGamePhaseStep GamePhaseStep) diff --git a/Project Reboot 3.0/FortInventory.cpp b/Project Reboot 3.0/FortInventory.cpp index b41b968..0e6d95e 100644 --- a/Project Reboot 3.0/FortInventory.cpp +++ b/Project Reboot 3.0/FortInventory.cpp @@ -110,7 +110,13 @@ std::pair, std::vector> AFortInventory::AddI if (!Pawn) return std::make_pair(NewItemInstances, ModifiedItemInstances); - AFortPickup::SpawnPickup(ItemDefinition, Pawn->GetActorLocation(), Count, EFortPickupSourceTypeFlag::Player, EFortPickupSpawnSource::Unset, -1, Cast(Pawn)); + PickupCreateData CreateData; + CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(ItemDefinition, Count, -1); + CreateData.SpawnLocation = Pawn->GetActorLocation(); + CreateData.PawnOwner = Cast(Pawn); + CreateData.SourceType = EFortPickupSourceTypeFlag::GetPlayerValue(); + + AFortPickup::SpawnPickup(CreateData); return std::make_pair(NewItemInstances, ModifiedItemInstances); } @@ -126,21 +132,21 @@ std::pair, std::vector> AFortInventory::AddI NewItemInstances.push_back(NewItemInstance); - static auto FortItemEntryStruct = FindObject(L"/Script/FortniteGame.FortItemEntry"); - static auto FortItemEntrySize = *(int*)(__int64(FortItemEntryStruct) + Offsets::PropertiesSize); - bool bEnableStateValues = false; // Addresses::FreeEntry; if (bEnableStateValues) { - FFortItemEntryStateValue* StateValue = Alloc(FFortItemEntryStateValue::GetStructSize(), true); - StateValue->GetIntValue() = bShowItemToast; - StateValue->GetStateType() = EFortItemEntryState::ShouldShowItemToast; - NewItemInstance->GetItemEntry()->GetStateValues().AddPtr(StateValue, FFortItemEntryStateValue::GetStructSize()); + // FFortItemEntryStateValue* StateValue = Alloc(FFortItemEntryStateValue::GetStructSize(), true); + PadHexA8 StateValue{}; + ((FFortItemEntryStateValue*)&StateValue)->GetIntValue() = bShowItemToast; + ((FFortItemEntryStateValue*)&StateValue)->GetStateType() = EFortItemEntryState::ShouldShowItemToast; + ((FFortItemEntryStateValue*)&StateValue)->GetNameValue() = FName(0); + + NewItemInstance->GetItemEntry()->GetStateValues().AddPtr((FFortItemEntryStateValue*)&StateValue, FFortItemEntryStateValue::GetStructSize()); } ItemInstances.Add(NewItemInstance); - auto ReplicatedEntryIdx = GetItemList().GetReplicatedEntries().Add(*NewItemInstance->GetItemEntry(), FortItemEntrySize); + auto ReplicatedEntryIdx = GetItemList().GetReplicatedEntries().Add(*NewItemInstance->GetItemEntry(), FFortItemEntry::GetStructSize()); // GetItemList().GetReplicatedEntries().AtPtr(ReplicatedEntryIdx, FFortItemEntry::GetStructSize())->GetIsReplicatedCopy() = true; if (FortPlayerController && WorldItemDefinition->IsValidLowLevel()) @@ -267,55 +273,61 @@ bool AFortInventory::RemoveItem(const FGuid& ItemGuid, bool* bShouldUpdate, int int OldCount = Count; + bool bLikeReallyForce = false; + if (Count < 0) // idk why i have this { Count = 0; bForceRemoval = true; + bLikeReallyForce = true; } - auto NewCount = ReplicatedEntry->GetCount() - Count; - auto& ItemInstances = GetItemList().GetItemInstances(); auto& ReplicatedEntries = GetItemList().GetReplicatedEntries(); - bool bOverrideChangeStackSize = false; - - if (ItemDefinition->ShouldPersistWhenFinalStackEmpty() && !bForceRemoval) + if (!bLikeReallyForce) { - bool bIsFinalStack = true; + auto NewCount = ReplicatedEntry->GetCount() - Count; - for (int i = 0; i < ItemInstances.Num(); i++) + bool bOverrideChangeStackSize = false; + + if (ItemDefinition->ShouldPersistWhenFinalStackEmpty()) { - auto ItemInstance = ItemInstances.at(i); + bool bIsFinalStack = true; - if (ItemInstance->GetItemEntry()->GetItemDefinition() == ItemDefinition && ItemInstance->GetItemEntry()->GetItemGuid() != ItemGuid) + for (int i = 0; i < ItemInstances.Num(); i++) { - bIsFinalStack = false; - break; + auto ItemInstance = ItemInstances.at(i); + + if (ItemInstance->GetItemEntry()->GetItemDefinition() == ItemDefinition && ItemInstance->GetItemEntry()->GetItemGuid() != ItemGuid) + { + bIsFinalStack = false; + break; + } + } + + if (bIsFinalStack) + { + NewCount = NewCount < 0 ? 0 : NewCount; // min(NewCount, 0) or something i forgot + bOverrideChangeStackSize = true; } } - if (bIsFinalStack) + if (OldCount != -1 && (NewCount > 0 || bOverrideChangeStackSize)) { - NewCount = NewCount < 0 ? 0 : NewCount; // min(NewCount, 0) or something i forgot - bOverrideChangeStackSize = true; + ItemInstance->GetItemEntry()->GetCount() = NewCount; + ReplicatedEntry->GetCount() = NewCount; + + GetItemList().MarkItemDirty(ItemInstance->GetItemEntry()); + GetItemList().MarkItemDirty(ReplicatedEntry); + + return true; } + + if (NewCount < 0) // Hm + return false; } - if (OldCount != -1 && (NewCount > 0 || bOverrideChangeStackSize)) - { - ItemInstance->GetItemEntry()->GetCount() = NewCount; - ReplicatedEntry->GetCount() = NewCount; - - GetItemList().MarkItemDirty(ItemInstance->GetItemEntry()); - GetItemList().MarkItemDirty(ReplicatedEntry); - - return true; - } - - if (NewCount < 0) // Hm - return false; - static auto FortItemEntryStruct = FindObject(L"/Script/FortniteGame.FortItemEntry"); static auto FortItemEntrySize = FortItemEntryStruct->GetPropertiesSize(); @@ -556,4 +568,10 @@ FFortItemEntry* AFortInventory::FindReplicatedEntry(const FGuid& Guid) } return nullptr; -} \ No newline at end of file +} + +/* UClass* AFortInventory::StaticClass() +{ + static auto Class = FindObject("/Script/FortniteGame.FortInventory"); + return Class; +} */ \ No newline at end of file diff --git a/Project Reboot 3.0/FortInventory.h b/Project Reboot 3.0/FortInventory.h index ebc1f92..726de37 100644 --- a/Project Reboot 3.0/FortInventory.h +++ b/Project Reboot 3.0/FortInventory.h @@ -110,4 +110,6 @@ public: UFortItem* FindItemInstance(const FGuid& Guid); FFortItemEntry* FindReplicatedEntry(const FGuid& Guid); + + // static UClass* StaticClass(); }; \ No newline at end of file diff --git a/Project Reboot 3.0/FortItem.cpp b/Project Reboot 3.0/FortItem.cpp index 5f5fce1..8488188 100644 --- a/Project Reboot 3.0/FortItem.cpp +++ b/Project Reboot 3.0/FortItem.cpp @@ -1,5 +1,40 @@ #include "FortItem.h" +#include "FortWeaponItemDefinition.h" + +FFortItemEntry* FFortItemEntry::MakeItemEntry(UFortItemDefinition* ItemDefinition, int Count, int LoadedAmmo, float Durability) +{ + auto Entry = // (FFortItemEntry*)FMemory::Realloc(0, GetStructSize(), 0); + Alloc(GetStructSize()); + + if (!Entry) + return nullptr; + + if (LoadedAmmo == -1) + { + if (auto WeaponDef = Cast(ItemDefinition)) // bPreventDefaultPreload ? + LoadedAmmo = WeaponDef->GetClipSize(); + else + LoadedAmmo = 0; + } + + Entry->MostRecentArrayReplicationKey = -1; // idk if we need to set this + Entry->ReplicationID = -1; + Entry->ReplicationKey = -1; + + Entry->GetItemDefinition() = ItemDefinition; + Entry->GetCount() = Count; + Entry->GetLoadedAmmo() = LoadedAmmo; + Entry->GetDurability() = Durability; + Entry->GetGameplayAbilitySpecHandle() = FGameplayAbilitySpecHandle(-1); + Entry->GetParentInventory().ObjectIndex = -1; + // We want to add StateValues.Add(DurabilityInitialized); orwnatefc erwgearf yk + // CoCreateGuid((GUID*)&Entry->GetItemGuid()); + // Entry->DoesUpdateStatsOnCollection() = true; // I think fortnite does this? + + return Entry; +} + void UFortItem::SetOwningControllerForTemporaryItem(UObject* Controller) { static auto SOCFTIFn = FindObject(L"/Script/FortniteGame.FortItem.SetOwningControllerForTemporaryItem"); diff --git a/Project Reboot 3.0/FortItem.h b/Project Reboot 3.0/FortItem.h index 9a8d90c..7548c8e 100644 --- a/Project Reboot 3.0/FortItem.h +++ b/Project Reboot 3.0/FortItem.h @@ -8,7 +8,7 @@ #include "reboot.h" -enum class EFortItemEntryState : uint8_t // idk if this changes +enum class EFortItemEntryState : uint8_t // this changes but its fineee { NoneState = 0, NewItemCount = 1, @@ -74,6 +74,13 @@ struct FFortItemEntry : FFastArraySerializerItem return *(bool*)(__int64(this) + bIsReplicatedCopyOffset); } + bool& DoesUpdateStatsOnCollection() + { + // added like s8+ or somethingf idsk it was on 10.40 but not 7.40 + static auto bUpdateStatsOnCollectionOffset = FindOffsetStruct("/Script/FortniteGame.FortItemEntry", "bUpdateStatsOnCollection"); + return *(bool*)(__int64(this) + bUpdateStatsOnCollectionOffset); + } + class UFortItemDefinition*& GetItemDefinition() { static auto ItemDefinitionOffset = FindOffsetStruct("/Script/FortniteGame.FortItemEntry", "ItemDefinition"); @@ -116,6 +123,12 @@ struct FFortItemEntry : FFastArraySerializerItem return *(FGameplayAbilitySpecHandle*)(__int64(this) + GameplayAbilitySpecHandleOffset); } + TArray& GetGenericAttributeValues() + { + static auto GenericAttributeValuesOffset = FindOffsetStruct("/Script/FortniteGame.FortItemEntry", "GenericAttributeValues"); + return *(TArray*)(__int64(this) + GenericAttributeValuesOffset); + } + TWeakObjectPtr& GetParentInventory() { static auto ParentInventoryOffset = FindOffsetStruct("/Script/FortniteGame.FortItemEntry", "ParentInventory"); @@ -144,6 +157,20 @@ struct FFortItemEntry : FFastArraySerializerItem if (!bCopyGuid) this->GetItemGuid() = OldGuid; + static auto GenericAttributeValuesOffset = FindOffsetStruct("/Script/FortniteGame.FortItemEntry", "GenericAttributeValues", false); + + if (GenericAttributeValuesOffset != -1) + { + // proper copying + + this->GetGenericAttributeValues().CopyFromArray(OtherItemEntry->GetGenericAttributeValues()); + + /* for (int i = 0; i < OtherItemEntry->GetGenericAttributeValues().Num(); i++) + { + this->GetGenericAttributeValues().Add(OtherItemEntry->GetGenericAttributeValues().at(i)); + } */ + } + // should we do this? this->MostRecentArrayReplicationKey = -1; @@ -163,29 +190,7 @@ struct FFortItemEntry : FFastArraySerializerItem return StructSize; } - static FFortItemEntry* MakeItemEntry(UFortItemDefinition* ItemDefinition, int Count = 1, int LoadedAmmo = 0, float Durability = 0x3F800000) - { - auto Entry = // (FFortItemEntry*)FMemory::Realloc(0, GetStructSize(), 0); - Alloc(GetStructSize()); - - if (!Entry) - return nullptr; - - Entry->MostRecentArrayReplicationKey = -1; // idk if we need to set this - Entry->ReplicationID = -1; - Entry->ReplicationKey = -1; - - Entry->GetItemDefinition() = ItemDefinition; - Entry->GetCount() = Count; - Entry->GetLoadedAmmo() = LoadedAmmo; - Entry->GetDurability() = Durability; - Entry->GetGameplayAbilitySpecHandle() = FGameplayAbilitySpecHandle(-1); - Entry->GetParentInventory().ObjectIndex = -1; - // CoCreateGuid((GUID*)&Entry->GetItemGuid()); - // Entry->bUpdateStatsOnCollection = true; // Idk what this does but fortnite does it i think - - return Entry; - } + static FFortItemEntry* MakeItemEntry(UFortItemDefinition* ItemDefinition, int Count = 1, int LoadedAmmo = 0, float Durability = 0x3F800000); // We need to find a better way for below... Especially since we can't do either method for season 5 or 6. @@ -196,6 +201,19 @@ struct FFortItemEntry : FFastArraySerializerItem static __int64 (*FreeEntryOriginal)(__int64 Entry) = decltype(FreeEntryOriginal)(Addresses::FreeEntry); FreeEntryOriginal(__int64(Entry)); } + else + { + static auto GenericAttributeValuesOffset = FindOffsetStruct("/Script/FortniteGame.FortItemEntry", "GenericAttributeValues", false); + + if (GenericAttributeValuesOffset != -1) + { + Entry->GetGenericAttributeValues().Free(); + } + + Entry->GetStateValues().Free(); + } + + RtlZeroMemory(Entry, FFortItemEntry::GetStructSize()); } static void FreeArrayOfEntries(TArray& tarray) diff --git a/Project Reboot 3.0/FortKismetLibrary.cpp b/Project Reboot 3.0/FortKismetLibrary.cpp index 67ccfc8..08bbb4d 100644 --- a/Project Reboot 3.0/FortKismetLibrary.cpp +++ b/Project Reboot 3.0/FortKismetLibrary.cpp @@ -135,8 +135,12 @@ void UFortKismetLibrary::SpawnItemVariantPickupInWorldHook(UObject* Context, FFr auto& Position = ParamsPtr->GetPosition(); LOG_INFO(LogDev, "{} {} {}", Position.X, Position.Y, Position.Z); - - auto Pickup = AFortPickup::SpawnPickup(ItemDefinition, Position, ParamsPtr->GetNumberToSpawn(), ParamsPtr->GetSourceType(), ParamsPtr->GetSource()); + + PickupCreateData CreateData{}; + CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(ItemDefinition, ParamsPtr->GetNumberToSpawn(), -1); + CreateData.SourceType = ParamsPtr->GetSourceType(); + CreateData.Source = ParamsPtr->GetSource(); + auto Pickup = AFortPickup::SpawnPickup(CreateData); return SpawnItemVariantPickupInWorldOriginal(Context, Stack, Ret); } @@ -165,7 +169,13 @@ bool UFortKismetLibrary::SpawnInstancedPickupInWorldHook(UObject* Context, FFram Stack.StepCompiledIn(&bRandomRotation); Stack.StepCompiledIn(&bBlockedFromAutoPickup); - auto Pickup = AFortPickup::SpawnPickup(ItemDefinition, Position, NumberToSpawn, EFortPickupSourceTypeFlag::Other, EFortPickupSpawnSource::Unset, -1, nullptr, nullptr, bToss); + PickupCreateData CreateData; + CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(ItemDefinition, NumberToSpawn, -1); + CreateData.SpawnLocation = Position; + CreateData.bToss = bToss; + CreateData.bShouldFreeItemEntryWhenDeconstructed = true; + + auto Pickup = AFortPickup::SpawnPickup(CreateData); *Ret = Pickup; return *Ret; @@ -192,8 +202,8 @@ void UFortKismetLibrary::CreateTossAmmoPickupForWeaponItemDefinitionAtLocationHo UFortWeaponItemDefinition* WeaponItemDefinition; FGameplayTagContainer SourceTags; FVector Location; - EFortPickupSourceTypeFlag SourceTypeFlag; - EFortPickupSpawnSource SpawnSource; + uint8 SourceTypeFlag; + uint8 SpawnSource; Stack.StepCompiledIn(&WorldContextObject); Stack.StepCompiledIn(&WeaponItemDefinition); @@ -213,7 +223,13 @@ void UFortKismetLibrary::CreateTossAmmoPickupForWeaponItemDefinitionAtLocationHo if (!AmmoDefinition) return CreateTossAmmoPickupForWeaponItemDefinitionAtLocationOriginal(Context, Stack, Ret); - auto AmmoPickup = AFortPickup::SpawnPickup(AmmoDefinition, Location, Count, SourceTypeFlag, SpawnSource); + PickupCreateData CreateData; + CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(AmmoDefinition, Count, 0); + CreateData.SourceType = SourceTypeFlag; + CreateData.Source = SpawnSource; + CreateData.SpawnLocation = Location; + + auto AmmoPickup = AFortPickup::SpawnPickup(CreateData); return CreateTossAmmoPickupForWeaponItemDefinitionAtLocationOriginal(Context, Stack, Ret); } @@ -460,8 +476,8 @@ AFortPickup* UFortKismetLibrary::K2_SpawnPickupInWorldWithClassHook(UObject* Con bool bRandomRotation; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) bool bBlockedFromAutoPickup; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) int PickupInstigatorHandle; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) - EFortPickupSourceTypeFlag SourceType; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) - EFortPickupSpawnSource Source; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + uint8 SourceType; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + uint8 Source; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) AFortPlayerController* OptionalOwnerPC; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) bool bPickupOnlyRelevantToOwner; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) @@ -487,12 +503,20 @@ AFortPickup* UFortKismetLibrary::K2_SpawnPickupInWorldWithClassHook(UObject* Con LOG_INFO(LogDev, "PickupClass: {}", PickupClass ? PickupClass->GetFullName() : "InvalidObject"); LOG_INFO(LogDev, __FUNCTION__); + + PickupCreateData CreateData; + CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(ItemDefinition, NumberToSpawn, -1); + CreateData.Source = Source; + CreateData.SourceType = SourceType; + CreateData.OverrideClass = PickupClass; + CreateData.bToss = bToss; + CreateData.bRandomRotation = bRandomRotation; - auto aa = AFortPickup::SpawnPickup(ItemDefinition, Position, NumberToSpawn, SourceType, Source, -1, nullptr, PickupClass, bToss); + auto NewPickup = AFortPickup::SpawnPickup(CreateData); K2_SpawnPickupInWorldWithClassOriginal(Context, Stack, Ret); - *Ret = aa; + *Ret = NewPickup; return *Ret; } @@ -508,8 +532,8 @@ AFortPickup* UFortKismetLibrary::K2_SpawnPickupInWorldHook(UObject* Context, FFr bool bRandomRotation; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) bool bBlockedFromAutoPickup; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) int PickupInstigatorHandle; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) - EFortPickupSourceTypeFlag SourceType; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) - EFortPickupSpawnSource Source; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + uint8 SourceType; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + uint8 Source; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) AFortPlayerController* OptionalOwnerPC; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) bool bPickupOnlyRelevantToOwner; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) @@ -535,11 +559,19 @@ AFortPickup* UFortKismetLibrary::K2_SpawnPickupInWorldHook(UObject* Context, FFr auto Pawn = OptionalOwnerPC ? OptionalOwnerPC->GetMyFortPawn() : nullptr; - auto aa = AFortPickup::SpawnPickup(ItemDefinition, Position, NumberToSpawn, SourceType, Source, -1, Pawn, AFortPickup::StaticClass(), bToss); + PickupCreateData CreateData; + CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(ItemDefinition, NumberToSpawn, -1); + CreateData.SpawnLocation = Position; + CreateData.bToss = bToss; + CreateData.bRandomRotation = bRandomRotation; + CreateData.PawnOwner = Pawn; + CreateData.bShouldFreeItemEntryWhenDeconstructed = true; + + auto NewPickup = AFortPickup::SpawnPickup(CreateData); K2_SpawnPickupInWorldOriginal(Context, Stack, Ret); - *Ret = aa; + *Ret = NewPickup; return *Ret; } diff --git a/Project Reboot 3.0/FortKismetLibrary.h b/Project Reboot 3.0/FortKismetLibrary.h index 59ac013..5a21618 100644 --- a/Project Reboot 3.0/FortKismetLibrary.h +++ b/Project Reboot 3.0/FortKismetLibrary.h @@ -35,16 +35,16 @@ struct FSpawnItemVariantParams return *(int*)(__int64(this) + NumberToSpawnOffset); } - EFortPickupSourceTypeFlag& GetSourceType() + uint8& GetSourceType() { static auto SourceTypeOffset = FindOffsetStruct("/Script/FortniteGame.SpawnItemVariantParams", "SourceType"); - return *(EFortPickupSourceTypeFlag*)(__int64(this) + SourceTypeOffset); + return *(uint8*)(__int64(this) + SourceTypeOffset); } - EFortPickupSpawnSource& GetSource() + uint8& GetSource() { static auto SourceOffset = FindOffsetStruct("/Script/FortniteGame.SpawnItemVariantParams", "Source"); - return *(EFortPickupSpawnSource*)(__int64(this) + SourceOffset); + return *(uint8*)(__int64(this) + SourceOffset); } FVector& GetDirection() diff --git a/Project Reboot 3.0/FortLootPackage.cpp b/Project Reboot 3.0/FortLootPackage.cpp index 0c60f29..2e9712c 100644 --- a/Project Reboot 3.0/FortLootPackage.cpp +++ b/Project Reboot 3.0/FortLootPackage.cpp @@ -69,7 +69,7 @@ static T* PickWeightedElement(const std::map& Elements, std::function TotalWeight = std::accumulate(Elements.begin(), Elements.end(), 0.0f, [&](float acc, const std::pair& p) { auto Weight = GetWeightFn(p.second); - if (bPrint) + if (bPrint && Weight != 0) { LOG_INFO(LogLoot, "Adding weight: {}", Weight); } @@ -282,7 +282,7 @@ void PickLootDropsFromLootPackage(const std::vector& LPTables, cons return; if (bPrint) - LOG_INFO(LogLoot, "PickLootDropsFromLootPackage selected package {} with loot package category {} from LootPackageIDMap of size: {}", PickedPackageRowName.ToString(), LootPackageCategory, LootPackageIDMap.size()); + LOG_INFO(LogLoot, "PickLootDropsFromLootPackage selected package {} with loot package category {} with weight {} from LootPackageIDMap of size: {}", PickedPackageRowName.ToString(), LootPackageCategory, PickedPackage->GetWeight(), LootPackageIDMap.size()); if (PickedPackage->GetLootPackageCall().Data.Num() > 1) { @@ -358,12 +358,20 @@ void PickLootDropsFromLootPackage(const std::vector& LPTables, cons { auto AmmoData = WeaponItemDefinition->GetAmmoData(); - int AmmoCount = AmmoData->GetDropCount(); // idk about this one + if (AmmoData) + { + int AmmoCount = AmmoData->GetDropCount(); // idk about this one - OutEntries->push_back(LootDrop(FFortItemEntry::MakeItemEntry(WeaponItemDefinition->GetAmmoData(), AmmoCount))); + OutEntries->push_back(LootDrop(FFortItemEntry::MakeItemEntry(AmmoData, AmmoCount))); + } } } + if (bPrint) + { + LOG_INFO(LogLoot, "Adding Item: {}", ItemDefinition->GetPathName()); + } + FinalCount -= CurrentCountForEntry; } } diff --git a/Project Reboot 3.0/FortPawn.cpp b/Project Reboot 3.0/FortPawn.cpp index 579caa5..7e04174 100644 --- a/Project Reboot 3.0/FortPawn.cpp +++ b/Project Reboot 3.0/FortPawn.cpp @@ -48,6 +48,16 @@ void AFortPawn::SetHealth(float NewHealth) this->ProcessEvent(SetHealthFn, &NewHealth); } +void AFortPawn::SetMaxHealth(float NewHealthVal) +{ + static auto SetMaxHealthFn = FindObject("/Script/FortniteGame.FortPawn.SetMaxHealth"); + + if (!SetMaxHealthFn) + return; + + this->ProcessEvent(SetMaxHealthFn, &NewHealthVal); +} + void AFortPawn::SetShield(float NewShield) { static auto SetShieldFn = FindObject("/Script/FortniteGame.FortPawn.SetShield"); diff --git a/Project Reboot 3.0/FortPawn.h b/Project Reboot 3.0/FortPawn.h index 3179e23..ee6c647 100644 --- a/Project Reboot 3.0/FortPawn.h +++ b/Project Reboot 3.0/FortPawn.h @@ -28,6 +28,7 @@ public: } void SetHealth(float NewHealth); + void SetMaxHealth(float NewHealthVal); void SetShield(float NewShield); static void NetMulticast_Athena_BatchedDamageCuesHook(UObject* Context, FFrame* Stack, void* Ret); static void MovingEmoteStoppedHook(UObject* Context, FFrame* Stack, void* Ret); diff --git a/Project Reboot 3.0/FortPickup.cpp b/Project Reboot 3.0/FortPickup.cpp index 09db872..5e26e42 100644 --- a/Project Reboot 3.0/FortPickup.cpp +++ b/Project Reboot 3.0/FortPickup.cpp @@ -10,12 +10,12 @@ #include "GameplayStatics.h" #include "gui.h" -void AFortPickup::TossPickup(FVector FinalLocation, AFortPawn* ItemOwner, int OverrideMaxStackCount, bool bToss, EFortPickupSourceTypeFlag InPickupSourceTypeFlags, EFortPickupSpawnSource InPickupSpawnSource) +void AFortPickup::TossPickup(FVector FinalLocation, AFortPawn* ItemOwner, int OverrideMaxStackCount, bool bToss, uint8 InPickupSourceTypeFlags, uint8 InPickupSpawnSource) { static auto fn = FindObject(L"/Script/FortniteGame.FortPickup.TossPickup"); struct { FVector FinalLocation; AFortPawn* ItemOwner; int OverrideMaxStackCount; bool bToss; - EFortPickupSourceTypeFlag InPickupSourceTypeFlags; EFortPickupSpawnSource InPickupSpawnSource; } + uint8 InPickupSourceTypeFlags; uint8 InPickupSpawnSource; } AFortPickup_TossPickup_Params{FinalLocation, ItemOwner, OverrideMaxStackCount, bToss, InPickupSourceTypeFlags, InPickupSpawnSource}; this->ProcessEvent(fn, &AFortPickup_TossPickup_Params); @@ -29,145 +29,151 @@ void AFortPickup::SpawnMovementComponent() this->Get(MovementComponentOffset) = UGameplayStatics::SpawnObject(ProjectileMovementComponentClass, this); } -AFortPickup* AFortPickup::SpawnPickup(FFortItemEntry* ItemEntry, FVector Location, - EFortPickupSourceTypeFlag PickupSource, EFortPickupSpawnSource SpawnSource, - class AFortPawn* Pawn, UClass* OverrideClass, bool bToss, int OverrideCount, AFortPickup* IgnoreCombinePickup) +AFortPickup* AFortPickup::SpawnPickup(PickupCreateData& PickupData) { - if (bToss) - { - PickupSource |= EFortPickupSourceTypeFlag::Tossed; - } + if (PickupData.Source == -1) + PickupData.Source = 0; + if (PickupData.SourceType == -1) + PickupData.SourceType = -1; + + /* if (PickupData.bToss) + { + PickupData.SourceType |= EFortPickupSourceTypeFlag::Tossed; + } */ - // static auto FortPickupClass = FindObject(L"/Script/FortniteGame.FortPickup"); static auto FortPickupAthenaClass = FindObject(L"/Script/FortniteGame.FortPickupAthena"); - auto PlayerState = Pawn ? Cast(Pawn->GetPlayerState()) : nullptr; + auto PlayerState = PickupData.PawnOwner ? Cast(PickupData.PawnOwner->GetPlayerState()) : nullptr; FActorSpawnParameters SpawnParameters{}; // SpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn; - if (auto Pickup = GetWorld()->SpawnActor(OverrideClass ? OverrideClass : FortPickupAthenaClass, Location, FQuat(), FVector(1, 1, 1), SpawnParameters)) + auto Pickup = GetWorld()->SpawnActor(PickupData.OverrideClass ? PickupData.OverrideClass : FortPickupAthenaClass, PickupData.SpawnLocation, FQuat(), FVector(1, 1, 1), SpawnParameters); + + if (!Pickup) + return nullptr; + + static auto bRandomRotationOffset = Pickup->GetOffset("bRandomRotation", false); + + if (bRandomRotationOffset != -1) + Pickup->Get(bRandomRotationOffset) = PickupData.bRandomRotation; + + static auto PawnWhoDroppedPickupOffset = Pickup->GetOffset("PawnWhoDroppedPickup"); + Pickup->Get(PawnWhoDroppedPickupOffset) = PickupData.PawnOwner; + + auto PrimaryPickupItemEntry = Pickup->GetPrimaryPickupItemEntry(); + + if (Addresses::PickupInitialize) { - static auto PawnWhoDroppedPickupOffset = Pickup->GetOffset("PawnWhoDroppedPickup"); - Pickup->Get(PawnWhoDroppedPickupOffset) = Pawn; + static void (*SetupPickup)(AFortPickup * Pickup, __int64 ItemEntry, TArray MultiItemPickupEntriesIGuess, bool bSplitOnPickup) + = decltype(SetupPickup)(Addresses::PickupInitialize); - auto PrimaryPickupItemEntry = Pickup->GetPrimaryPickupItemEntry(); + TArray MultiItemPickupEntriesIGuess{}; + SetupPickup(Pickup, __int64(PickupData.ItemEntry), MultiItemPickupEntriesIGuess, false); + FFortItemEntry::FreeArrayOfEntries(MultiItemPickupEntriesIGuess); + } + else + { + PrimaryPickupItemEntry->CopyFromAnotherItemEntry(PickupData.ItemEntry); + } - if (Addresses::PickupInitialize) + static auto PickupSourceTypeFlagsOffset = Pickup->GetOffset("PickupSourceTypeFlags", false); + + if (PickupSourceTypeFlagsOffset != -1) + { + // Pickup->Get(PickupSourceTypeFlagsOffset) |= (int)PickupData.SourceType; // Assuming its the same enum on older versions. // (it is not the same) + } + + if (Pickup->Get(PawnWhoDroppedPickupOffset)) + { + // TODO Add EFortItemEntryState::DroppedFromPickup or whatever if it isn't found already. + } + + PrimaryPickupItemEntry->GetCount() = PickupData.OverrideCount == -1 ? PickupData.ItemEntry->GetCount() : PickupData.OverrideCount; + + auto PickupLocationData = Pickup->GetPickupLocationData(); + + auto CanCombineWithPickup = [&](AActor* OtherPickupActor) -> bool + { + auto OtherPickup = (AFortPickup*)OtherPickupActor; + + if (OtherPickup == PickupData.IgnoreCombineTarget || Pickup->GetPickupLocationData()->GetCombineTarget()) + return false; + + if (OtherPickup->GetPickupLocationData()->GetTossState() != EFortPickupTossState::AtRest) + return false; + + if (PrimaryPickupItemEntry->GetItemDefinition() == OtherPickup->GetPrimaryPickupItemEntry()->GetItemDefinition()) { - static void (*SetupPickup)(AFortPickup* Pickup, __int64 ItemEntry, TArray MultiItemPickupEntriesIGuess, bool bSplitOnPickup) - = decltype(SetupPickup)(Addresses::PickupInitialize); - - TArray MultiItemPickupEntriesIGuess{}; - SetupPickup(Pickup, __int64(ItemEntry), MultiItemPickupEntriesIGuess, false); - FFortItemEntry::FreeArrayOfEntries(MultiItemPickupEntriesIGuess); - } - else - { - PrimaryPickupItemEntry->CopyFromAnotherItemEntry(ItemEntry); - } - - static auto PickupSourceTypeFlagsOffset = Pickup->GetOffset("PickupSourceTypeFlags", false); - - if (PickupSourceTypeFlagsOffset != -1) - Pickup->Get(PickupSourceTypeFlagsOffset) |= (int)PickupSource; // Assuming its the same enum on older versions. - - PrimaryPickupItemEntry->GetCount() = OverrideCount == -1 ? ItemEntry->GetCount() : OverrideCount; - - // PrimaryPickupItemEntry->GetItemGuid() = OldGuid; - - // Pickup->OnRep_PrimaryPickupItemEntry(); - - // static auto OptionalOwnerIDOffset = Pickup->GetOffset("OptionalOwnerID"); - // Pickup->Get(OptionalOwnerIDOffset) = PlayerState ? PlayerState->GetWorldPlayerId() : -1; - - auto PickupLocationData = Pickup->GetPickupLocationData(); - - auto CanCombineWithPickup = [&](AActor* OtherPickupActor) -> bool - { - auto OtherPickup = (AFortPickup*)OtherPickupActor; - - if (OtherPickup == IgnoreCombinePickup || OtherPickup->GetPickupLocationData()->GetCombineTarget()) + if (OtherPickup->GetPrimaryPickupItemEntry()->GetCount() >= PrimaryPickupItemEntry->GetItemDefinition()->GetMaxStackSize()) // Other pickup is already at the max size. return false; - if (PrimaryPickupItemEntry->GetItemDefinition() == OtherPickup->GetPrimaryPickupItemEntry()->GetItemDefinition()) - { - // auto IncomingCount = OtherPickup->GetPrimaryPickupItemEntry()->GetCount(); - - // if (PrimaryPickupItemEntry->GetCount() + IncomingCount == PrimaryPickupItemEntry->GetItemDefinition()->GetMaxStackSize()) - // return false; - - if (OtherPickup->GetPrimaryPickupItemEntry()->GetCount() == PrimaryPickupItemEntry->GetItemDefinition()->GetMaxStackSize()) // Other pickup is already at the max size. - return false; - - return true; - } - - return false; - }; - - if (Addresses::CombinePickupLea) - { - PickupLocationData->GetCombineTarget() = (AFortPickup*)Pickup->GetClosestActor(AFortPickup::StaticClass(), 4, CanCombineWithPickup); + return true; } - if (!PickupLocationData->GetCombineTarget()) // I don't think we should call TossPickup for every pickup anyways. - { - Pickup->TossPickup(Location, Pawn, 0, bToss, PickupSource, SpawnSource); - } - else - { - auto ActorLocation = Pickup->GetActorLocation(); - auto CurrentActorLocation = PickupLocationData->GetCombineTarget()->GetActorLocation(); + return false; + }; - int Dist = float(sqrtf(powf(CurrentActorLocation.X - ActorLocation.X, 2.0) + powf(CurrentActorLocation.Y - ActorLocation.Y, 2.0) + powf(CurrentActorLocation.Z - ActorLocation.Z, 2.0))) / 100.f; - - // LOG_INFO(LogDev, "Distance: {}", Dist); - - // our little remake of tosspickup - - PickupLocationData->GetLootFinalPosition() = Location; - PickupLocationData->GetLootInitialPosition() = Pickup->GetActorLocation(); - PickupLocationData->GetFlyTime() = 1.f / Dist; // Higher the dist quicker it should be. // not right - PickupLocationData->GetItemOwner() = Pawn; - PickupLocationData->GetFinalTossRestLocation() = PickupLocationData->GetCombineTarget()->GetActorLocation(); // Pickup->GetActorLocation() // ong ong proper - - Pickup->OnRep_PickupLocationData(); - Pickup->ForceNetUpdate(); - } - - if (PickupSource == EFortPickupSourceTypeFlag::Container) // crashes if we do this then tosspickup - { - static auto bTossedFromContainerOffset = Pickup->GetOffset("bTossedFromContainer"); - Pickup->Get(bTossedFromContainerOffset) = true; - // Pickup->OnRep_TossedFromContainer(); - } - - if (Fortnite_Version < 6) - { - Pickup->SpawnMovementComponent(); - } - - return Pickup; + if (Addresses::CombinePickupLea && bEnableCombinePickup) + { + PickupLocationData->GetCombineTarget() = (AFortPickup*)Pickup->GetClosestActor(AFortPickup::StaticClass(), 4, CanCombineWithPickup); } - return nullptr; + if (!PickupLocationData->GetCombineTarget()) // I don't think we should call TossPickup for every pickup anyways. + { + Pickup->TossPickup(PickupData.SpawnLocation, PickupData.PawnOwner, 0, PickupData.bToss, PickupData.SourceType, PickupData.Source); + } + else + { + auto ActorLocation = Pickup->GetActorLocation(); + auto CurrentActorLocation = PickupLocationData->GetCombineTarget()->GetActorLocation(); + + int Dist = float(sqrtf(powf(CurrentActorLocation.X - ActorLocation.X, 2.0) + powf(CurrentActorLocation.Y - ActorLocation.Y, 2.0) + powf(CurrentActorLocation.Z - ActorLocation.Z, 2.0))) / 100.f; + + // LOG_INFO(LogDev, "Distance: {}", Dist); + + // our little remake of tosspickup + + PickupLocationData->GetLootFinalPosition() = PickupData.SpawnLocation; + PickupLocationData->GetLootInitialPosition() = Pickup->GetActorLocation(); + PickupLocationData->GetFlyTime() = 1.f / Dist; // Higher the dist quicker it should be. // not right + PickupLocationData->GetItemOwner() = PickupData.PawnOwner; + PickupLocationData->GetFinalTossRestLocation() = PickupLocationData->GetCombineTarget()->GetActorLocation(); + + Pickup->OnRep_PickupLocationData(); + Pickup->ForceNetUpdate(); + } + + if (EFortPickupSourceTypeFlag::GetEnum() && PickupData.SourceType == EFortPickupSourceTypeFlag::GetContainerValue()) // crashes if we do this then tosspickup + { + static auto bTossedFromContainerOffset = Pickup->GetOffset("bTossedFromContainer"); + Pickup->Get(bTossedFromContainerOffset) = true; + // Pickup->OnRep_TossedFromContainer(); + } + + if (Fortnite_Version < 6) + { + Pickup->SpawnMovementComponent(); + } + + return Pickup; } -AFortPickup* AFortPickup::SpawnPickup(UFortItemDefinition* ItemDef, FVector Location, int Count, EFortPickupSourceTypeFlag PickupSource, EFortPickupSpawnSource SpawnSource, - int LoadedAmmo, AFortPawn* Pawn, UClass* OverrideClass, bool bToss, AFortPickup* IgnoreCombinePickup) +AFortPickup* AFortPickup::SpawnPickup(FFortItemEntry* ItemEntry, FVector Location, + uint8 PickupSource, uint8 SpawnSource, + class AFortPawn* Pawn, UClass* OverrideClass, bool bToss, int OverrideCount, AFortPickup* IgnoreCombinePickup) { - if (LoadedAmmo == -1) - { - if (auto WeaponDef = Cast(ItemDef)) // bPreventDefaultPreload ? - LoadedAmmo = WeaponDef->GetClipSize(); - else - LoadedAmmo = 0; - } + PickupCreateData CreateData; + CreateData.ItemEntry = ItemEntry; + CreateData.SpawnLocation = Location; + CreateData.Source = SpawnSource; + CreateData.SourceType = PickupSource; + CreateData.PawnOwner = Pawn; + CreateData.OverrideClass = OverrideClass; + CreateData.bToss = bToss; + CreateData.IgnoreCombineTarget = IgnoreCombinePickup; + CreateData.OverrideCount = OverrideCount; - auto ItemEntry = FFortItemEntry::MakeItemEntry(ItemDef, Count, LoadedAmmo); - auto Pickup = SpawnPickup(ItemEntry, Location, PickupSource, SpawnSource, Pawn, OverrideClass, bToss, -1, IgnoreCombinePickup); - // VirtualFree(ItemEntry); - return Pickup; + return AFortPickup::SpawnPickup(CreateData); } void AFortPickup::CombinePickupHook(AFortPickup* Pickup) @@ -195,8 +201,14 @@ void AFortPickup::CombinePickupHook(AFortPickup* Pickup) auto ItemOwner = Pickup->GetPickupLocationData()->GetItemOwner(); - auto NewOverStackPickup = AFortPickup::SpawnPickup(ItemDefinition, PickupToCombineInto->GetActorLocation(), OverStackCount, - EFortPickupSourceTypeFlag::Player, EFortPickupSpawnSource::Unset, -1, ItemOwner, nullptr, false, PickupToCombineInto); + PickupCreateData CreateData; + CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(ItemDefinition, OverStackCount, 0); + CreateData.SpawnLocation = PickupToCombineInto->GetActorLocation(); + CreateData.PawnOwner = ItemOwner; + CreateData.SourceType = EFortPickupSourceTypeFlag::GetPlayerValue(); + CreateData.IgnoreCombineTarget = PickupToCombineInto; + + auto NewOverStackPickup = AFortPickup::SpawnPickup(CreateData); } PickupToCombineInto->GetPrimaryPickupItemEntry()->GetCount() += CountToAdd; @@ -300,7 +312,7 @@ char AFortPickup::CompletePickupAnimationHook(AFortPickup* Pickup) if (ItemInstanceToSwap && ItemDefinitionToSwap->CanBeDropped() && !bHasSwapped && ItemDefGoingInPrimary) // swap { auto SwappedPickup = SpawnPickup(ItemEntryToSwap, PawnLoc, - EFortPickupSourceTypeFlag::Player, EFortPickupSpawnSource::Unset, Pawn); + EFortPickupSourceTypeFlag::GetPlayerValue(), 0, Pawn); auto CurrentWeapon = Pawn->GetCurrentWeapon(); @@ -373,7 +385,7 @@ char AFortPickup::CompletePickupAnimationHook(AFortPickup* Pickup) int LoadedAmmo = 0; // SpawnPickup(ItemDefinitionToSpawn, PawnLoc, AmountToSpawn, EFortPickupSourceTypeFlag::Player, EFortPickupSpawnSource::Unset, -1, Pawn); - SpawnPickup(PickupEntry, PawnLoc, EFortPickupSourceTypeFlag::Player, EFortPickupSpawnSource::Unset, Pawn, nullptr, true, AmountToSpawn); + SpawnPickup(PickupEntry, PawnLoc, EFortPickupSourceTypeFlag::GetPlayerValue(), 0, Pawn, nullptr, true, AmountToSpawn); cpyCount -= AmountToSpawn; bForceOverflow = false; } diff --git a/Project Reboot 3.0/FortPickup.h b/Project Reboot 3.0/FortPickup.h index 2813fae..0e055ca 100644 --- a/Project Reboot 3.0/FortPickup.h +++ b/Project Reboot 3.0/FortPickup.h @@ -2,33 +2,99 @@ #include "Actor.h" #include "FortPawn.h" +#include "Class.h" -enum class EFortPickupSourceTypeFlag : uint8_t +namespace EFortPickupSourceTypeFlag { - Other = 0, - Player = 1, - Destruction = 2, - Container = 3, - AI = 4, - Tossed = 5, - FloorLoot = 6, - EFortPickupSourceTypeFlag_MAX = 7 + static inline UEnum* GetEnum() + { + static auto Enum = FindObject("/Script/FortniteGame.EFortPickupSourceTypeFlag"); + return Enum; + } + + static inline int64 GetPlayerValue() + { + static auto PlayerValue = GetEnum() ? GetEnum()->GetValue("Player") : -1; + return PlayerValue; + } + + static inline int64 GetContainerValue() + { + static auto ContainerValue = GetEnum() ? GetEnum()->GetValue("Container") : -1; + return ContainerValue; + } + + static inline int64 GetFloorLootValue() + { + static auto FloorLootValue = GetEnum() ? GetEnum()->GetValue("FloorLoot") : -1; + return FloorLootValue; + } + + static inline int64 GetOtherValue() + { + static auto OtherValue = GetEnum() ? GetEnum()->GetValue("Other") : -1; + return OtherValue; + } + + static inline int64 GetTossedValue() + { + static auto TossedValue = GetEnum() ? GetEnum()->GetValue("Tossed") : -1; + return TossedValue; + } +} + +namespace EFortPickupSpawnSource +{ + static inline UEnum* GetEnum() + { + static auto Enum = FindObject("/Script/FortniteGame.EFortPickupSpawnSource"); + return Enum; + } + + static inline int64 GetPlayerEliminationValue() + { + static auto PlayerEliminationValue = GetEnum() ? GetEnum()->GetValue("PlayerElimination") : -1; + return PlayerEliminationValue; + } + + static inline int64 GetSupplyDropValue() + { + static auto SupplyDropValue = GetEnum() ? GetEnum()->GetValue("SupplyDrop") : -1; + return SupplyDropValue; + } +} + +struct PickupCreateData +{ + FFortItemEntry* ItemEntry = nullptr; + AFortPawn* PawnOwner = nullptr; + int OverrideCount = -1; + UClass* OverrideClass = nullptr; + bool bToss = false; + class AFortPickup* IgnoreCombineTarget = nullptr; + bool bRandomRotation = false; + uint8 SourceType = 0; + uint8 Source = 0; + FVector SpawnLocation = FVector(0, 0, 0); + bool bShouldFreeItemEntryWhenDeconstructed = false; + + ~PickupCreateData() + { + if (bShouldFreeItemEntryWhenDeconstructed) + { + + } + } }; -enum class EFortPickupSpawnSource : uint8_t +enum class EFortPickupTossState : uint8 { - Unset = 0, - PlayerElimination = 1, - Chest = 2, - SupplyDrop = 3, - AmmoBox = 4, - Drone = 5, - ItemSpawner = 6, - EFortPickupSpawnSource_MAX = 7 + NotTossed = 0, + InProgress = 1, + AtRest = 2, + EFortPickupTossState_MAX = 3, }; -ENUM_CLASS_FLAGS(EFortPickupSourceTypeFlag) - struct FFortPickupLocationData { AFortPawn*& GetPickupTarget() @@ -43,6 +109,12 @@ struct FFortPickupLocationData return *(float*)(__int64(this) + FlyTimeOffset); } + EFortPickupTossState& GetTossState() + { + static auto TossStateOffset = FindOffsetStruct("/Script/FortniteGame.FortPickupLocationData", "TossState"); + return *(EFortPickupTossState*)(__int64(this) + TossStateOffset); + } + AFortPawn*& GetItemOwner() { static auto ItemOwnerOffset = FindOffsetStruct("/Script/FortniteGame.FortPickupLocationData", "ItemOwner"); @@ -91,7 +163,7 @@ class AFortPickup : public AActor public: static inline char (*CompletePickupAnimationOriginal)(AFortPickup* Pickup); - void TossPickup(FVector FinalLocation, class AFortPawn* ItemOwner, int OverrideMaxStackCount, bool bToss, EFortPickupSourceTypeFlag InPickupSourceTypeFlags, EFortPickupSpawnSource InPickupSpawnSource); + void TossPickup(FVector FinalLocation, class AFortPawn* ItemOwner, int OverrideMaxStackCount, bool bToss, uint8 InPickupSourceTypeFlags, uint8 InPickupSpawnSource); void SpawnMovementComponent(); // BAD You probably don't wanna use unless absolutely necessary void OnRep_PrimaryPickupItemEntry() @@ -118,14 +190,12 @@ public: this->ProcessEvent(OnRep_PickupLocationDataFn); } + static AFortPickup* SpawnPickup(PickupCreateData& PickupData); + static AFortPickup* SpawnPickup(FFortItemEntry* ItemEntry, FVector Location, - EFortPickupSourceTypeFlag PickupSource = EFortPickupSourceTypeFlag::Other, EFortPickupSpawnSource SpawnSource = EFortPickupSpawnSource::Unset, + uint8 PickupSource = 0, uint8 SpawnSource = 0, class AFortPawn* Pawn = nullptr, UClass* OverrideClass = nullptr, bool bToss = true, int OverrideCount = -1, AFortPickup* IgnoreCombinePickup = nullptr); - static AFortPickup* SpawnPickup(class UFortItemDefinition* ItemDef, FVector Location, int Count, - EFortPickupSourceTypeFlag PickupSource = EFortPickupSourceTypeFlag::Other, EFortPickupSpawnSource SpawnSource = EFortPickupSpawnSource::Unset, - int LoadedAmmo = -1, class AFortPawn* Pawn = nullptr, UClass* OverrideClass = nullptr, bool bToss = true, AFortPickup* IgnoreCombinePickup = nullptr); - static void CombinePickupHook(AFortPickup* Pickup); static char CompletePickupAnimationHook(AFortPickup* Pickup); diff --git a/Project Reboot 3.0/FortPlayerController.cpp b/Project Reboot 3.0/FortPlayerController.cpp index 83cbf22..29f86e2 100644 --- a/Project Reboot 3.0/FortPlayerController.cpp +++ b/Project Reboot 3.0/FortPlayerController.cpp @@ -111,8 +111,12 @@ void AFortPlayerController::DropAllItems(const std::vector if (bRemoveIfNotDroppable && !WorldItemDefinition->CanBeDropped()) continue; - AFortPickup::SpawnPickup(WorldItemDefinition, Location, ItemEntry->GetCount(), EFortPickupSourceTypeFlag::Player, EFortPickupSpawnSource::Unset, - ItemEntry->GetLoadedAmmo()); + PickupCreateData CreateData; + CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(WorldItemDefinition, ItemEntry->GetCount(), ItemEntry->GetLoadedAmmo()); + CreateData.SpawnLocation = Location; + CreateData.SourceType = EFortPickupSourceTypeFlag::GetPlayerValue(); + + AFortPickup::SpawnPickup(CreateData); } for (auto& Pair : GuidAndCountsToRemove) @@ -587,8 +591,12 @@ void AFortPlayerController::ServerAttemptInteractHook(UObject* Context, FFrame* { auto Entry = ItemCollection->GetOutputItemEntry()->AtPtr(z, FFortItemEntry::GetStructSize()); - AFortPickup::SpawnPickup(Entry->GetItemDefinition(), LocationToSpawnLoot, Entry->GetCount(), - EFortPickupSourceTypeFlag::Other, EFortPickupSpawnSource::Unset, Entry->GetLoadedAmmo(), PlayerController->GetMyFortPawn()); + PickupCreateData CreateData; + CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(Entry->GetItemDefinition(), Entry->GetCount(), Entry->GetLoadedAmmo()); + CreateData.SpawnLocation = LocationToSpawnLoot; + CreateData.PawnOwner = PlayerController->GetMyFortPawn(); // hmm + + AFortPickup::SpawnPickup(CreateData); } static auto bCurrentInteractionSuccessOffset = ItemCollector->GetOffset("bCurrentInteractionSuccess", false); @@ -840,6 +848,8 @@ void AFortPlayerController::ServerCreateBuildingActorHook(UObject* Context, FFra bool bBuildFree = PlayerController->DoesBuildFree(); + LOG_INFO(LogDev, "MatInstance->GetItemEntry()->GetCount(): {}", MatInstance->GetItemEntry()->GetCount()); + bool bShouldDestroy = MatInstance && MatInstance->GetItemEntry() ? MatInstance->GetItemEntry()->GetCount() < 10 : true; if (bShouldDestroy && !bBuildFree) @@ -950,6 +960,7 @@ void AFortPlayerController::ServerAttemptInventoryDropHook(AFortPlayerController return; } + // TODO If the player is in a vehicle and has a vehicle weapon, don't let them drop. auto WorldInventory = PlayerController->GetWorldInventory(); auto ReplicatedEntry = WorldInventory->FindReplicatedEntry(ItemGuid); @@ -966,8 +977,25 @@ void AFortPlayerController::ServerAttemptInventoryDropHook(AFortPlayerController if (!ItemDefinition->ShouldIgnoreRespawningOnDrop() && (DropBehaviorOffset != -1 ? ItemDefinition->GetDropBehavior() != EWorldItemDropBehavior::DestroyOnDrop : true)) { + /* if (auto GadgetItemDefintiion = Cast(ItemDefinition)) + { + for (int i = 0; i < GadgetItemDefintiion->GetTrackedAttributes().Num(); i++) + { + LOG_INFO(LogDev, "[{}] TrackedAttribute Attribute Name {}", i, GadgetItemDefintiion->GetTrackedAttributes().at(i).GetAttributePropertyName()); + + PadHexA8 StateValue{}; // Alloc(FFortItemEntryStateValue::GetStructSize(), true); + ((FFortItemEntryStateValue*)&StateValue)->GetIntValue() = 1; + ((FFortItemEntryStateValue*)&StateValue)->GetStateType() = EFortItemEntryState::GenericAttributeValueSet; + ((FFortItemEntryStateValue*)&StateValue)->GetNameValue() = FName(0); + + ReplicatedEntry->GetStateValues().AddPtr((FFortItemEntryStateValue*)&StateValue, FFortItemEntryStateValue::GetStructSize()); + + ReplicatedEntry->GetGenericAttributeValues().Add(9); + } + } */ + auto Pickup = AFortPickup::SpawnPickup(ReplicatedEntry, Pawn->GetActorLocation(), - EFortPickupSourceTypeFlag::Player, EFortPickupSpawnSource::Unset, Pawn, nullptr, true, Count); + EFortPickupSourceTypeFlag::GetPlayerValue(), 0, Pawn, nullptr, true, Count); if (!Pickup) return; @@ -1338,8 +1366,13 @@ void AFortPlayerController::ClientOnPawnDiedHook(AFortPlayerController* PlayerCo if (!ShouldBeDropped) continue; - AFortPickup::SpawnPickup(WorldItemDefinition, DeathLocation, ItemEntry->GetCount(), EFortPickupSourceTypeFlag::Player, EFortPickupSpawnSource::PlayerElimination, - ItemEntry->GetLoadedAmmo()); + PickupCreateData CreateData; + CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(WorldItemDefinition, ItemEntry->GetCount(), ItemEntry->GetLoadedAmmo()); + CreateData.SourceType = EFortPickupSourceTypeFlag::GetPlayerValue(); + CreateData.Source = EFortPickupSpawnSource::GetPlayerEliminationValue(); + CreateData.SpawnLocation = DeathLocation; + + AFortPickup::SpawnPickup(CreateData); GuidAndCountsToRemove.push_back({ ItemEntry->GetItemGuid(), ItemEntry->GetCount() }); // WorldInventory->RemoveItem(ItemEntry->GetItemGuid(), nullptr, ItemEntry->GetCount()); @@ -1433,29 +1466,39 @@ void AFortPlayerController::ClientOnPawnDiedHook(AFortPlayerController* PlayerCo { // wtf - auto AllPlayerStates = UGameplayStatics::GetAllActorsOfClass(GetWorld(), AFortPlayerStateAthena::StaticClass()); - - bool bDidSomeoneWin = AllPlayerStates.Num() == 0; - - for (int i = 0; i < AllPlayerStates.Num(); i++) + if (GameState->GetGamePhase() > EAthenaGamePhase::Warmup) { - if (((AFortPlayerStateAthena*)AllPlayerStates.at(i))->GetPlace() <= 1) + auto AllPlayerStates = UGameplayStatics::GetAllActorsOfClass(GetWorld(), AFortPlayerStateAthena::StaticClass()); + + bool bDidSomeoneWin = AllPlayerStates.Num() == 0; + + for (int i = 0; i < AllPlayerStates.Num(); i++) { - bDidSomeoneWin = true; - break; + auto CurrentPlayerState = (AFortPlayerStateAthena*)AllPlayerStates.at(i); + + if (CurrentPlayerState->GetPlace() <= 1) + { + bDidSomeoneWin = true; + break; + } + } + + LOG_INFO(LogDev, "bDidSomeoneWin: {}", bDidSomeoneWin); + + // if (GameState->GetGamePhase() == EAthenaGamePhase::EndGame) + if (bDidSomeoneWin) + { + CreateThread(0, 0, RestartThread, 0, 0, 0); } } - - LOG_INFO(LogDev, "bDidSomeoneWin: {}", bDidSomeoneWin); - - // if (GameState->GetGamePhase() == EAthenaGamePhase::EndGame) - if (bDidSomeoneWin) - { - CreateThread(0, 0, RestartThread, 0, 0, 0); - } } } + if (DeadPlayerState->IsBot()) + { + // AllPlayerBotsToTick. + } + return ClientOnPawnDiedOriginal(PlayerController, DeathReport); } diff --git a/Project Reboot 3.0/FortPlayerController.h b/Project Reboot 3.0/FortPlayerController.h index adb2697..441ae65 100644 --- a/Project Reboot 3.0/FortPlayerController.h +++ b/Project Reboot 3.0/FortPlayerController.h @@ -108,6 +108,20 @@ public: return NewAndModifiedInstances.first.size() > 0 ? NewAndModifiedInstances.first[0] : nullptr; } + TSet& GetGadgetTrackedAttributeItemInstanceIds() // actually in zone + { + static auto GadgetTrackedAttributeItemInstanceIdsOffset = GetOffset("GadgetTrackedAttributeItemInstanceIds"); + return Get>(GadgetTrackedAttributeItemInstanceIdsOffset); + } + + bool IsPlayingEmote() + { + static auto IsPlayingEmoteFn = FindObject("/Script/FortniteGame.FortPlayerController.IsPlayingEmote"); + bool Ret; + this->ProcessEvent(IsPlayingEmoteFn, &Ret); + return Ret; + } + bool& ShouldTryPickupSwap() { static auto bTryPickupSwapOffset = GetOffset("bTryPickupSwap"); diff --git a/Project Reboot 3.0/FortPlayerControllerAthena.cpp b/Project Reboot 3.0/FortPlayerControllerAthena.cpp index 30ed309..16ae693 100644 --- a/Project Reboot 3.0/FortPlayerControllerAthena.cpp +++ b/Project Reboot 3.0/FortPlayerControllerAthena.cpp @@ -105,6 +105,9 @@ void AFortPlayerControllerAthena::EndGhostModeHook(AFortPlayerControllerAthena* auto PickaxeInstance = PlayerController->AddPickaxeToInventory(); WorldInventory->Update(); + WorldInventory->ForceNetUpdate(); + PlayerController->ForceNetUpdate(); + if (PickaxeInstance) { PlayerController->ClientEquipItem(PickaxeInstance->GetItemEntry()->GetItemGuid(), true); diff --git a/Project Reboot 3.0/FortPlayerPawn.cpp b/Project Reboot 3.0/FortPlayerPawn.cpp index cf30935..3f8c1ed 100644 --- a/Project Reboot 3.0/FortPlayerPawn.cpp +++ b/Project Reboot 3.0/FortPlayerPawn.cpp @@ -6,7 +6,10 @@ FFortAthenaLoadout* AFortPlayerPawn::GetCosmeticLoadout() { - static auto CosmeticLoadoutOffset = GetOffset("CosmeticLoadout"); + static auto CosmeticLoadoutOffset = GetOffset("CosmeticLoadout", false); + + if (CosmeticLoadoutOffset == -1) + CosmeticLoadoutOffset = GetOffset("CustomizationLoadout"); if (CosmeticLoadoutOffset == -1) return nullptr; diff --git a/Project Reboot 3.0/FortPlayerStateAthena.h b/Project Reboot 3.0/FortPlayerStateAthena.h index 2b9964b..89e9c81 100644 --- a/Project Reboot 3.0/FortPlayerStateAthena.h +++ b/Project Reboot 3.0/FortPlayerStateAthena.h @@ -26,6 +26,20 @@ public: return Get(PlaceOffset); } + bool IsInAircraft() + { + static auto bInAircraftOffset = GetOffset("bInAircraft"); + static auto bInAircraftFieldMask = GetFieldMask(GetProperty("bInAircraft")); + return ReadBitfieldValue(bInAircraftOffset, bInAircraftFieldMask); + } + + bool HasThankedBusDriver() + { + static auto bThankedBusDriverOffset = GetOffset("bThankedBusDriver"); + static auto bThankedBusDriverFieldMask = GetFieldMask(GetProperty("bThankedBusDriver")); + return ReadBitfieldValue(bThankedBusDriverOffset, bThankedBusDriverFieldMask); + } + void ClientReportKill(AFortPlayerStateAthena* Player) { static auto ClientReportKillFn = FindObject("/Script/FortniteGame.FortPlayerStateAthena.ClientReportKill"); diff --git a/Project Reboot 3.0/GameModeBase.cpp b/Project Reboot 3.0/GameModeBase.cpp index 93eebee..c59d8c4 100644 --- a/Project Reboot 3.0/GameModeBase.cpp +++ b/Project Reboot 3.0/GameModeBase.cpp @@ -23,9 +23,39 @@ UClass* AGameModeBase::GetDefaultPawnClassForController(AController* InControlle return AGameModeBase_GetDefaultPawnClassForController_Params.ReturnValue; } +void AGameModeBase::ChangeName(AController* Controller, const FString& NewName, bool bNameChange) +{ + static auto ChangeNameFn = FindObject("/Script/Engine.GameModeBase.ChangeName"); + + struct + { + AController* Controller; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + struct FString NewName; // (Parm, ZeroConstructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + bool bNameChange; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + } AGameModeBase_ChangeName_Params{ Controller, NewName, bNameChange }; + + this->ProcessEvent(ChangeNameFn, &AGameModeBase_ChangeName_Params); +} + +AActor* AGameModeBase::K2_FindPlayerStart(AController* Player, FString IncomingName) +{ + static auto K2_FindPlayerStartFn = FindObject("/Script/Engine.GameModeBase.K2_FindPlayerStart"); + + struct + { + AController* Player; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + FString IncomingName; // (Parm, ZeroConstructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + AActor* ReturnValue; // (Parm, OutParm, ZeroConstructor, ReturnParm, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + } AGameModeBase_K2_FindPlayerStart_Params{ Player, IncomingName }; + + this->ProcessEvent(K2_FindPlayerStartFn, &AGameModeBase_K2_FindPlayerStart_Params); + + return AGameModeBase_K2_FindPlayerStart_Params.ReturnValue; +} + APawn* AGameModeBase::SpawnDefaultPawnForHook(AGameModeBase* GameMode, AController* NewPlayer, AActor* StartSpot) { - LOG_INFO(LogDev, "SpawnDefaultPawnFor: 0x{:x}!", __int64(_ReturnAddress()) - __int64(GetModuleHandleW(0))); + // LOG_INFO(LogDev, "SpawnDefaultPawnFor: 0x{:x}!", __int64(_ReturnAddress()) - __int64(GetModuleHandleW(0))); // auto PawnClass = GameMode->GetDefaultPawnClassForController(NewPlayer); // LOG_INFO(LogDev, "PawnClass: {}", PawnClass->GetFullName()); diff --git a/Project Reboot 3.0/GameModeBase.h b/Project Reboot 3.0/GameModeBase.h index dae256e..e097274 100644 --- a/Project Reboot 3.0/GameModeBase.h +++ b/Project Reboot 3.0/GameModeBase.h @@ -4,11 +4,14 @@ #include "Controller.h" #include "Pawn.h" +#include "UnrealString.h" class AGameModeBase : public AActor // AInfo { public: UClass* GetDefaultPawnClassForController(AController* InController); + void ChangeName(AController* Controller, const FString& NewName, bool bNameChange); + AActor* K2_FindPlayerStart(AController* Player, FString IncomingName); static APawn* SpawnDefaultPawnForHook(AGameModeBase* GameMode, AController* NewPlayer, AActor* StartSpot); }; \ No newline at end of file diff --git a/Project Reboot 3.0/KismetSystemLibrary.h b/Project Reboot 3.0/KismetSystemLibrary.h index 7e84fa3..589d599 100644 --- a/Project Reboot 3.0/KismetSystemLibrary.h +++ b/Project Reboot 3.0/KismetSystemLibrary.h @@ -5,6 +5,73 @@ #include "reboot.h" +enum class EDrawDebugTrace : uint8_t +{ + None = 0, + ForOneFrame = 1, + ForDuration = 2, + Persistent = 3, + EDrawDebugTrace_MAX = 4 +}; + +enum class ETraceTypeQuery : uint8_t +{ + TraceTypeQuery1 = 0, + TraceTypeQuery2 = 1, + TraceTypeQuery3 = 2, + TraceTypeQuery4 = 3, + TraceTypeQuery5 = 4, + TraceTypeQuery6 = 5, + TraceTypeQuery7 = 6, + TraceTypeQuery8 = 7, + TraceTypeQuery9 = 8, + TraceTypeQuery10 = 9, + TraceTypeQuery11 = 10, + TraceTypeQuery12 = 11, + TraceTypeQuery13 = 12, + TraceTypeQuery14 = 13, + TraceTypeQuery15 = 14, + TraceTypeQuery16 = 15, + TraceTypeQuery17 = 16, + TraceTypeQuery18 = 17, + TraceTypeQuery19 = 18, + TraceTypeQuery20 = 19, + TraceTypeQuery21 = 20, + TraceTypeQuery22 = 21, + TraceTypeQuery23 = 22, + TraceTypeQuery24 = 23, + TraceTypeQuery25 = 24, + TraceTypeQuery26 = 25, + TraceTypeQuery27 = 26, + TraceTypeQuery28 = 27, + TraceTypeQuery29 = 28, + TraceTypeQuery30 = 29, + TraceTypeQuery31 = 30, + TraceTypeQuery32 = 31, + TraceTypeQuery_MAX = 32, + ETraceTypeQuery_MAX = 33 +}; + +struct FLinearColor +{ + float R; // 0x0000(0x0004) (Edit, BlueprintVisible, ZeroConstructor, SaveGame, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + float G; // 0x0004(0x0004) (Edit, BlueprintVisible, ZeroConstructor, SaveGame, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + float B; // 0x0008(0x0004) (Edit, BlueprintVisible, ZeroConstructor, SaveGame, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + float A; // 0x000C(0x0004) (Edit, BlueprintVisible, ZeroConstructor, SaveGame, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + + inline FLinearColor() + : R(0), G(0), B(0), A(0) + { } + + inline FLinearColor(float r, float g, float b, float a) + : R(r), + G(g), + B(b), + A(a) + { } + +}; + class UKismetSystemLibrary : public UObject { public: @@ -35,4 +102,109 @@ public: KismetSystemLibrary->ProcessEvent(fn, &UKismetSystemLibrary_ExecuteConsoleCommand_Params); } + + static bool LineTraceSingle(UObject* WorldContextObject, FVector Start, FVector End, ETraceTypeQuery TraceChannel, bool bTraceComplex, + TArray ActorsToIgnore, EDrawDebugTrace DrawDebugType, bool bIgnoreSelf, FLinearColor TraceColor, FLinearColor TraceHitColor, + float DrawTime, FHitResult** OutHit) + { + static auto LineTraceSingleFn = FindObject("/Script/Engine.KismetSystemLibrary.LineTraceSingle"); + + if (!LineTraceSingleFn) + return false; + + struct UKismetSystemLibrary_LineTraceSingle_Params + { + UObject* WorldContextObject; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + FVector Start; // (ConstParm, Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + FVector End; // (ConstParm, Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + ETraceTypeQuery TraceChannel; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + bool bTraceComplex; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + TArray ActorsToIgnore; // (ConstParm, Parm, OutParm, ZeroConstructor, ReferenceParm, NativeAccessSpecifierPublic) + EDrawDebugTrace DrawDebugType; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + FHitResult OutHit; // (Parm, OutParm, IsPlainOldData, NoDestructor, ContainsInstancedReference, NativeAccessSpecifierPublic) + bool bIgnoreSelf; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + FLinearColor TraceColor; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, AdvancedDisplay, HasGetValueTypeHash, NativeAccessSpecifierPublic) + FLinearColor TraceHitColor; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, AdvancedDisplay, HasGetValueTypeHash, NativeAccessSpecifierPublic) + float DrawTime; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, AdvancedDisplay, HasGetValueTypeHash, NativeAccessSpecifierPublic) + bool ReturnValue; // (Parm, OutParm, ZeroConstructor, ReturnParm, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + }; + + static auto ReturnValueOffset = FindOffsetStruct("/Script/Engine.KismetSystemLibrary.LineTraceSingle", "ReturnValue"); + static auto OutHitOffset = FindOffsetStruct("/Script/Engine.KismetSystemLibrary.LineTraceSingle", "OutHit"); + static auto bIgnoreSelfOffset = FindOffsetStruct("/Script/Engine.KismetSystemLibrary.LineTraceSingle", "bIgnoreSelf"); + + static auto ParamsSize = LineTraceSingleFn->GetPropertiesSize(); + auto Params = Alloc(ParamsSize); + + ((UKismetSystemLibrary_LineTraceSingle_Params*)Params)->WorldContextObject = WorldContextObject; + ((UKismetSystemLibrary_LineTraceSingle_Params*)Params)->Start = Start; + ((UKismetSystemLibrary_LineTraceSingle_Params*)Params)->End = End; + ((UKismetSystemLibrary_LineTraceSingle_Params*)Params)->TraceChannel = TraceChannel; + ((UKismetSystemLibrary_LineTraceSingle_Params*)Params)->bTraceComplex = bTraceComplex; + *(bool*)(__int64(Params) + bIgnoreSelfOffset) = bIgnoreSelf; + + static auto KismetSystemLibrary = FindObject("/Script/Engine.Default__KismetSystemLibrary"); + KismetSystemLibrary->ProcessEvent(LineTraceSingleFn, Params); + + if (OutHit) + *OutHit = (FHitResult*)(__int64(Params) + OutHitOffset); + + return *(bool*)(__int64(Params) + ReturnValueOffset); + + // free params frfr + } + + static bool LineTraceSingleByProfile(UObject* WorldContextObject, const FVector& Start, const FVector& End, FName ProfileName, bool bTraceComplex, + const TArray& ActorsToIgnore, EDrawDebugTrace DrawDebugType, FHitResult** OutHit, bool bIgnoreSelf, const FLinearColor& TraceColor, + const FLinearColor& TraceHitColor, float DrawTime) + { + auto LineTraceSingleByProfileFn = FindObject("/Script/Engine.KismetSystemLibrary.LineTraceSingleByProfile"); + + if (!LineTraceSingleByProfileFn) + return false; + + struct UKismetSystemLibrary_LineTraceSingleByProfile_Params + { + UObject* WorldContextObject; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + FVector Start; // (ConstParm, Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + FVector End; // (ConstParm, Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + FName ProfileName; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + bool bTraceComplex; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + TArray ActorsToIgnore; // (ConstParm, Parm, OutParm, ZeroConstructor, ReferenceParm, NativeAccessSpecifierPublic) + EDrawDebugTrace DrawDebugType; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + FHitResult OutHit; // (Parm, OutParm, IsPlainOldData, NoDestructor, ContainsInstancedReference, NativeAccessSpecifierPublic) + bool bIgnoreSelf; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + FLinearColor TraceColor; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, AdvancedDisplay, HasGetValueTypeHash, NativeAccessSpecifierPublic) + FLinearColor TraceHitColor; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, AdvancedDisplay, HasGetValueTypeHash, NativeAccessSpecifierPublic) + float DrawTime; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, AdvancedDisplay, HasGetValueTypeHash, NativeAccessSpecifierPublic) + bool ReturnValue; // (Parm, OutParm, ZeroConstructor, ReturnParm, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + }; + + static auto ParamSize = LineTraceSingleByProfileFn->GetPropertiesSize(); + auto Params = Alloc(ParamSize); + + static auto WorldContextObjectOffset = FindOffsetStruct("/Script/Engine.KismetSystemLibrary.LineTraceSingleByProfile", "WorldContextObject"); + static auto StartOffset = FindOffsetStruct("/Script/Engine.KismetSystemLibrary.LineTraceSingleByProfile", "Start"); + static auto EndOffset = FindOffsetStruct("/Script/Engine.KismetSystemLibrary.LineTraceSingleByProfile", "End"); + static auto ProfileNameOffset = FindOffsetStruct("/Script/Engine.KismetSystemLibrary.LineTraceSingleByProfile", "ProfileName"); + static auto bTraceComplexOffset = FindOffsetStruct("/Script/Engine.KismetSystemLibrary.LineTraceSingleByProfile", "bTraceComplex"); + static auto ReturnValueOffset = FindOffsetStruct("/Script/Engine.KismetSystemLibrary.LineTraceSingleByProfile", "ReturnValue"); + static auto OutHitOffset = FindOffsetStruct("/Script/Engine.KismetSystemLibrary.LineTraceSingleByProfile", "OutHit"); + static auto bIgnoreSelfOffset = FindOffsetStruct("/Script/Engine.KismetSystemLibrary.LineTraceSingleByProfile", "bIgnoreSelf"); + + *(UObject**)(__int64(Params) + WorldContextObjectOffset) = WorldContextObject; + *(FVector*)(__int64(Params) + StartOffset) = Start; + *(FVector*)(__int64(Params) + EndOffset) = End; + *(FName*)(__int64(Params) + ProfileNameOffset) = ProfileName; + *(bool*)(__int64(Params) + bTraceComplexOffset) = bTraceComplex; + *(bool*)(__int64(Params) + bIgnoreSelfOffset) = bIgnoreSelf; + + static auto KismetSystemLibrary = FindObject("/Script/Engine.Default__KismetSystemLibrary"); + KismetSystemLibrary->ProcessEvent(LineTraceSingleByProfileFn, Params); + + if (OutHit) + *OutHit = (FHitResult*)(__int64(Params) + OutHitOffset); + + return *(bool*)(__int64(Params) + ReturnValueOffset); + } }; \ No newline at end of file diff --git a/Project Reboot 3.0/OnlineReplStructs.h b/Project Reboot 3.0/OnlineReplStructs.h index 15760d3..bbc83f3 100644 --- a/Project Reboot 3.0/OnlineReplStructs.h +++ b/Project Reboot 3.0/OnlineReplStructs.h @@ -18,5 +18,27 @@ struct FUniqueNetIdRepl // : public FUniqueNetIdWrapper return Size; } + TArray& GetReplicationBytes() + { + static auto ReplicationBytesOffset = FindOffsetStruct("/Script/Engine.UniqueNetIdRepl", "ReplicationBytes"); + return *(TArray*)(__int64(this) + ReplicationBytesOffset); + } + + void CopyFromAnotherUniqueId(FUniqueNetIdRepl* OtherUniqueId) + { + CopyStruct(this, OtherUniqueId, GetSizeOfStruct(), GetStruct()); + + auto& ReplicationBytes = GetReplicationBytes(); + + ReplicationBytes.Free(); + + // Now this is what we call 1 to 1 array copying. + + for (int i = 0; i < OtherUniqueId->GetReplicationBytes().Num(); i++) + { + ReplicationBytes.Add(OtherUniqueId->GetReplicationBytes().at(i)); + } + } + /* bool IsEqual(FUniqueNetIdRepl* Other) */ }; \ No newline at end of file diff --git a/Project Reboot 3.0/PlayerController.cpp b/Project Reboot 3.0/PlayerController.cpp index c96854a..ac77738 100644 --- a/Project Reboot 3.0/PlayerController.cpp +++ b/Project Reboot 3.0/PlayerController.cpp @@ -3,6 +3,12 @@ #include "reboot.h" +void APlayerController::ServerChangeName(FString& S) +{ + static auto ServerChangeNameFn = FindObject("/Script/Engine.PlayerController.ServerChangeName"); + this->ProcessEvent(ServerChangeNameFn, &S); +} + UCheatManager*& APlayerController::SpawnCheatManager(UClass* CheatManagerClass) { GetCheatManager() = UGameplayStatics::SpawnObject(CheatManagerClass, this, true); diff --git a/Project Reboot 3.0/PlayerController.h b/Project Reboot 3.0/PlayerController.h index 547d041..5ba9913 100644 --- a/Project Reboot 3.0/PlayerController.h +++ b/Project Reboot 3.0/PlayerController.h @@ -4,6 +4,7 @@ #include "Controller.h" #include "CheatManager.h" +#include "UnrealString.h" #include "Rotator.h" class APlayerController : public AController @@ -39,6 +40,7 @@ public: return this->Get(CheatManagerOffset); } + void ServerChangeName(FString& S); UCheatManager*& SpawnCheatManager(UClass* CheatManagerClass); FRotator GetControlRotation(); void Possess(class APawn* Pawn); diff --git a/Project Reboot 3.0/PlayerState.cpp b/Project Reboot 3.0/PlayerState.cpp index ab66644..c32e4ce 100644 --- a/Project Reboot 3.0/PlayerState.cpp +++ b/Project Reboot 3.0/PlayerState.cpp @@ -28,4 +28,24 @@ int& APlayerState::GetPlayerID() } return Get(PlayerIDOffset); +} + +bool APlayerState::IsBot() +{ + static auto bIsABotOffset = GetOffset("bIsABot"); + static auto bIsABotFieldMask = GetFieldMask(GetProperty("bIsABot")); + return ReadBitfieldValue(bIsABotOffset, bIsABotFieldMask); +} + +void APlayerState::SetIsBot(bool NewValue) +{ + static auto bIsABotOffset = GetOffset("bIsABot"); + static auto bIsABotFieldMask = GetFieldMask(GetProperty("bIsABot")); + return SetBitfieldValue(bIsABotOffset, bIsABotFieldMask, NewValue); +} + +void APlayerState::OnRep_PlayerName() +{ + static auto OnRep_PlayerNameFn = FindObject("/Script/Engine.PlayerState.OnRep_PlayerName"); + this->ProcessEvent(OnRep_PlayerNameFn); } \ No newline at end of file diff --git a/Project Reboot 3.0/PlayerState.h b/Project Reboot 3.0/PlayerState.h index 1b1f3d7..e375359 100644 --- a/Project Reboot 3.0/PlayerState.h +++ b/Project Reboot 3.0/PlayerState.h @@ -9,4 +9,7 @@ class APlayerState : public AActor public: FString GetPlayerName(); int& GetPlayerID(); // for future me to deal with (this is a short on some versions). + bool IsBot(); + void SetIsBot(bool NewValue); + void OnRep_PlayerName(); }; \ No newline at end of file diff --git a/Project Reboot 3.0/Project Reboot 3.0.vcxproj b/Project Reboot 3.0/Project Reboot 3.0.vcxproj index ce5b571..68e65be 100644 --- a/Project Reboot 3.0/Project Reboot 3.0.vcxproj +++ b/Project Reboot 3.0/Project Reboot 3.0.vcxproj @@ -274,6 +274,7 @@ + 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 a33f410..b3f47f1 100644 --- a/Project Reboot 3.0/Project Reboot 3.0.vcxproj.filters +++ b/Project Reboot 3.0/Project Reboot 3.0.vcxproj.filters @@ -712,9 +712,6 @@ Engine\Plugins\Runtime\GameplayAbilities\Source\GameplayAbilities\Public - - Reboot\Public\GUI - FortniteGame\Source\FortniteGame\Public\Athena\Vehicle @@ -851,6 +848,12 @@ FortniteGame\Source\FortniteGame\Public\Items + + Reboot\Public + + + Reboot\Public + @@ -1051,9 +1054,6 @@ {74e42db4-bdac-4e42-bb7e-58f1ab17b738} - - {15a7e32e-0505-49cc-9f6a-89d3e5c865b5} - {c0586029-3b4a-48f9-8de9-5b48a972cb5e} diff --git a/Project Reboot 3.0/Transform.h b/Project Reboot 3.0/Transform.h index e6ae1ac..012d8c9 100644 --- a/Project Reboot 3.0/Transform.h +++ b/Project Reboot 3.0/Transform.h @@ -5,9 +5,9 @@ MS_ALIGN(16) struct FTransform { - FQuat Rotation; // 0x0000(0x0010) (Edit, BlueprintVisible, SaveGame, IsPlainOldData, NoDestructor, NativeAccessSpecifierPublic) - FVector Translation; // 0x0010(0x000C) (Edit, BlueprintVisible, ZeroConstructor, SaveGame, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + FQuat Rotation = FQuat(0, 0, 0, 0); // 0x0000(0x0010) (Edit, BlueprintVisible, SaveGame, IsPlainOldData, NoDestructor, NativeAccessSpecifierPublic) + FVector Translation = FVector(0, 0, 0); // 0x0010(0x000C) (Edit, BlueprintVisible, ZeroConstructor, SaveGame, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) unsigned char UnknownData00[0x4]; // 0x001C(0x0004) MISSED OFFSET - FVector Scale3D; // 0x0020(0x000C) (Edit, BlueprintVisible, ZeroConstructor, SaveGame, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + FVector Scale3D = FVector(0, 0, 0); // 0x0020(0x000C) (Edit, BlueprintVisible, ZeroConstructor, SaveGame, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) unsigned char UnknownData01[0x4]; // 0x002C(0x0004) MISSED OFFSET }; \ No newline at end of file diff --git a/Project Reboot 3.0/World.h b/Project Reboot 3.0/World.h index c0bcd52..ad484a5 100644 --- a/Project Reboot 3.0/World.h +++ b/Project Reboot 3.0/World.h @@ -19,12 +19,12 @@ public: struct FActorSpawnParameters { - FName Name; - UObject* Template; - UObject* Owner; - UObject** Instigator; - UObject* OverrideLevel; - ESpawnActorCollisionHandlingMethod SpawnCollisionHandlingOverride; + FName Name = FName(0); + UObject* Template = nullptr; + UObject* Owner = nullptr; + UObject** Instigator = nullptr; + UObject* OverrideLevel = nullptr; + ESpawnActorCollisionHandlingMethod SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::Undefined; uint16 bRemoteOwned : 1; uint16 bNoFail : 1; uint16 bDeferConstruction : 1; diff --git a/Project Reboot 3.0/bots.h b/Project Reboot 3.0/bots.h new file mode 100644 index 0000000..c4dfdd1 --- /dev/null +++ b/Project Reboot 3.0/bots.h @@ -0,0 +1,248 @@ +#pragma once + +#include "FortGameModeAthena.h" +#include "OnlineReplStructs.h" +#include "BuildingContainer.h" + +class PlayerBot +{ +public: + AFortPlayerControllerAthena* PlayerController = nullptr; + float NextJumpTime = 1.0f; + + void Initialize(FTransform SpawnTransform) + { + auto GameState = Cast(GetWorld()->GetGameState()); + auto GameMode = Cast(GetWorld()->GetGameMode()); + + static auto PawnClass = FindObject("/Game/Athena/PlayerPawn_Athena.PlayerPawn_Athena_C"); + + FActorSpawnParameters PawnSpawnParameters{}; + PawnSpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn; + + PlayerController = GetWorld()->SpawnActor(AFortPlayerControllerAthena::StaticClass()); + AFortPlayerPawnAthena* Pawn = GetWorld()->SpawnActor(PawnClass, SpawnTransform, PawnSpawnParameters); + AFortPlayerStateAthena* PlayerState = Cast(PlayerController->GetPlayerState()); + + if (!Pawn || !PlayerState) + return; + + static int CurrentBotNum = 1; + + auto BotNumWStr = std::to_wstring(CurrentBotNum++); + + FString NewName = (L"RebootBot" + BotNumWStr).c_str(); + + PlayerController->ServerChangeName(NewName); + PlayerState->OnRep_PlayerName(); + + PlayerState->GetTeamIndex() = GameMode->Athena_PickTeamHook(GameMode, 0, PlayerController); + + static auto SquadIdOffset = PlayerState->GetOffset("SquadId", false); + + if (SquadIdOffset != -1) + PlayerState->GetSquadId() = PlayerState->GetTeamIndex() - 2; + + PlayerState->SetIsBot(true); + + /* + + static auto FortRegisteredPlayerInfoClass = FindObject("/Script/FortniteGame.FortRegisteredPlayerInfo"); + static auto MyPlayerInfoOffset = PlayerController->GetOffset("MyPlayerInfo"); + PlayerController->Get(MyPlayerInfoOffset) = UGameplayStatics::SpawnObject(FortRegisteredPlayerInfoClass, PlayerController); + + if (!PlayerController->Get(MyPlayerInfoOffset)) + { + LOG_ERROR(LogBots, "Failed to spawn PlayerInfo!"); + + Pawn->K2_DestroyActor(); + PlayerController->K2_DestroyActor(); + return nullptr; + } + + auto& PlayerInfo = PlayerController->Get(MyPlayerInfoOffset); + + static auto UniqueIdOffset = PlayerState->GetOffset("UniqueId"); + static auto PlayerInfo_PlayerNameOffset = PlayerInfo->GetOffset("PlayerName"); + static auto PlayerIDOffset = PlayerInfo->GetOffset("PlayerID"); + PlayerInfo->GetPtr(PlayerIDOffset)->CopyFromAnotherUniqueId(PlayerState->GetPtr(UniqueIdOffset)); + PlayerInfo->Get(PlayerInfo_PlayerNameOffset) = PlayerState->GetPlayerName(); + + */ + + PlayerController->Possess(Pawn); + + Pawn->SetHealth(100); + Pawn->SetMaxHealth(100); + + FActorSpawnParameters WorldInventorySpawnParameters{}; + WorldInventorySpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn; + WorldInventorySpawnParameters.Owner = PlayerController; + + FTransform WorldInventorySpawnTransform{}; + + static auto FortInventoryClass = FindObject("/Script/FortniteGame.FortInventory"); // AFortInventory::StaticClass() + PlayerController->GetWorldInventory() = GetWorld()->SpawnActor(FortInventoryClass, WorldInventorySpawnTransform, WorldInventorySpawnParameters); + + if (!PlayerController->GetWorldInventory()) + { + LOG_ERROR(LogBots, "Failed to spawn WorldInventory!"); + + Pawn->K2_DestroyActor(); + PlayerController->K2_DestroyActor(); + return; + } + + PlayerController->GetWorldInventory()->GetInventoryType() = EFortInventoryType::World; + + static auto bHasInitializedWorldInventoryOffset = PlayerController->GetOffset("bHasInitializedWorldInventory"); + PlayerController->Get(bHasInitializedWorldInventoryOffset) = true; + + auto& StartingItems = GameMode->GetStartingItems(); + + auto PickaxeInstance = PlayerController->AddPickaxeToInventory(); + + for (int i = 0; i < StartingItems.Num(); i++) + { + auto& StartingItem = StartingItems.at(i); + + PlayerController->GetWorldInventory()->AddItem(StartingItem.GetItem(), nullptr, StartingItem.GetCount()); + } + + if (PickaxeInstance) + { + PlayerController->ServerExecuteInventoryItemHook(PlayerController, PickaxeInstance->GetItemEntry()->GetItemGuid()); + } + + PlayerController->GetWorldInventory()->Update(); + + /* static auto HeroType = FindObject(L"/Game/Athena/Heroes/HID_115_Athena_Commando_M_CarbideBlue.HID_115_Athena_Commando_M_CarbideBlue"); + + static auto HeroTypeOffset = PlayerState->GetOffset("HeroType"); + + if (HeroTypeOffset != -1) + PlayerState->Get(HeroTypeOffset) = HeroType; */ + + auto PlayerAbilitySet = GetPlayerAbilitySet(); + auto AbilitySystemComponent = PlayerState->GetAbilitySystemComponent(); + + if (PlayerAbilitySet) + { + PlayerAbilitySet->GiveToAbilitySystem(AbilitySystemComponent); + } + + PlayerController->GetCosmeticLoadout()->GetCharacter() = FindObject("/Game/Athena/Items/Cosmetics/Characters/CID_263_Athena_Commando_F_MadCommander.CID_263_Athena_Commando_F_MadCommander"); + Pawn->GetCosmeticLoadout()->GetCharacter() = PlayerController->GetCosmeticLoadout()->GetCharacter(); + + PlayerController->ApplyCosmeticLoadout(); + + GameState->GetPlayersLeft()++; + GameState->OnRep_PlayersLeft(); + + GameMode->GetAlivePlayers().Add(PlayerController); + } +}; + +static std::vector AllPlayerBotsToTick; + +namespace Bots +{ + static AFortPlayerControllerAthena* SpawnBot(FTransform SpawnTransform) + { + auto playerBot = PlayerBot(); + playerBot.Initialize(SpawnTransform); + AllPlayerBotsToTick.push_back(playerBot); + return playerBot.PlayerController; + } + + static void SpawnBotsAtPlayerStarts(int AmountOfBots) + { + return; + + auto GameState = Cast(GetWorld()->GetGameState()); + auto GameMode = Cast(GetWorld()->GetGameMode()); + + for (int i = 0; i < AmountOfBots; i++) + { + FTransform SpawnTransform{}; + SpawnTransform.Translation = FVector(1, 1, 10000); + SpawnTransform.Rotation = FQuat(); + SpawnTransform.Scale3D = FVector(1, 1, 1); + + auto NewBot = SpawnBot(SpawnTransform); + auto PlayerStart = GameMode->K2_FindPlayerStart(NewBot, NewBot->GetPlayerState()->GetPlayerName()); // i dont think this works + + if (!PlayerStart) + { + LOG_ERROR(LogBots, "Failed to find PlayerStart for bot!"); + NewBot->GetPawn()->K2_DestroyActor(); + NewBot->K2_DestroyActor(); + continue; + } + + NewBot->TeleportTo(PlayerStart->GetActorLocation(), FRotator()); + NewBot->SetCanBeDamaged(Fortnite_Version < 7); // idk lol for spawn island + } + } + + static void Tick() + { + auto GameState = Cast(GetWorld()->GetGameState()); + auto GameMode = Cast(GetWorld()->GetGameMode()); + + auto AllBuildingContainers = UGameplayStatics::GetAllActorsOfClass(GetWorld(), ABuildingContainer::StaticClass()); + + // for (int i = 0; i < GameMode->GetAlivePlayers().Num(); i++) + for (auto& PlayerBot : AllPlayerBotsToTick) + { + auto CurrentPlayer = PlayerBot.PlayerController; + + if (CurrentPlayer->IsActorBeingDestroyed()) + continue; + + auto CurrentPawn = CurrentPlayer->GetMyFortPawn(); + + auto CurrentPlayerState = Cast(CurrentPlayer->GetPlayerState()); + + if (!CurrentPlayerState || !CurrentPlayerState->IsBot()) + continue; + + if (GameState->GetGamePhase() == EAthenaGamePhase::Warmup) + { + /* if (!CurrentPlayer->IsPlayingEmote()) + { + static auto AthenaDanceItemDefinitionClass = FindObject("/Script/FortniteGame.AthenaDanceItemDefinition"); + auto RandomDanceID = GetRandomObjectOfClass(AthenaDanceItemDefinitionClass); + + CurrentPlayer->ServerPlayEmoteItemHook(CurrentPlayer, RandomDanceID); + } */ + } + + if (CurrentPlayerState->IsInAircraft() && !CurrentPlayerState->HasThankedBusDriver()) + { + static auto ServerThankBusDriverFn = FindObject("/Script/FortniteGame.FortPlayerControllerAthena.ServerThankBusDriver"); + CurrentPlayer->ProcessEvent(ServerThankBusDriverFn); + } + + if (CurrentPawn) + { + if (PlayerBot.NextJumpTime <= UGameplayStatics::GetTimeSeconds(GetWorld())) + { + static auto JumpFn = FindObject("/Script/Engine.Character.Jump"); + + CurrentPawn->ProcessEvent(JumpFn); + PlayerBot.NextJumpTime = UGameplayStatics::GetTimeSeconds(GetWorld()) + (rand() % 4 + 3); + } + } + + /* bool bShouldJumpFromBus = CurrentPlayerState->IsInAircraft(); // TODO (Milxnor) add a random percent thing + + if (bShouldJumpFromBus) + { + CurrentPlayer->ServerAttemptAircraftJumpHook(CurrentPlayer, FRotator()); + } */ + } + + AllBuildingContainers.Free(); + } +} \ No newline at end of file diff --git a/Project Reboot 3.0/commands.h b/Project Reboot 3.0/commands.h index 4af139b..3f4e3fe 100644 --- a/Project Reboot 3.0/commands.h +++ b/Project Reboot 3.0/commands.h @@ -7,6 +7,8 @@ #include "FortAthenaMutator_Barrier.h" #include "FortWeaponMeleeItemDefinition.h" #include "builder.h" +#include "FortLootPackage.h" +#include "bots.h" bool IsOperator(APlayerState* PlayerState, AFortPlayerController* PlayerController) { @@ -200,6 +202,25 @@ void ServerCheatHook(AFortPlayerControllerAthena* PlayerController, FString Msg) SendMessageToConsole(PlayerController, L"Granted item!"); } + else if (Command == "printsimulatelootdrops") + { + if (NumArgs < 1) + { + SendMessageToConsole(PlayerController, L"Please provide a LootTierGroup!"); + return; + } + + auto& lootTierGroup = Arguments[1]; + + auto LootDrops = PickLootDrops(UKismetStringLibrary::Conv_StringToName(std::wstring(lootTierGroup.begin(), lootTierGroup.end()).c_str()), true); + + for (int i = 0; i < LootDrops.size(); i++) + { + + } + + SendMessageToConsole(PlayerController, L"Printed!"); + } else if (Command == "setpickaxe") { if (NumArgs < 1) @@ -348,7 +369,12 @@ void ServerCheatHook(AFortPlayerControllerAthena* PlayerController, FString Msg) } auto Location = Pawn->GetActorLocation(); - AFortPickup::SpawnPickup(WID, Location, count); + + PickupCreateData CreateData; + CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(WID, count, -1); + CreateData.SpawnLocation = Location; + + AFortPickup::SpawnPickup(CreateData); } else if (Command == "listplayers") { @@ -547,6 +573,60 @@ void ServerCheatHook(AFortPlayerControllerAthena* PlayerController, FString Msg) SendMessageToConsole(PlayerController, L"Not a valid class!"); } } + else if (Command == "spawnbot") + { + auto Pawn = ReceivingController->GetPawn(); + + if (!Pawn) + { + SendMessageToConsole(PlayerController, L"No pawn to spawn bot at!"); + return; + } + + int Count = 1; + + if (Arguments.size() >= 2) + { + try { Count = std::stod(Arguments[1]); } + catch (...) {} + } + + constexpr int Max = 99; + + if (Count > Max) + { + SendMessageToConsole(PlayerController, (std::wstring(L"You went over the limit! Only spawning ") + std::to_wstring(Max) + L".").c_str()); + Count = Max; + } + + int AmountSpawned = 0; + + for (int i = 0; i < Count; i++) + { + FActorSpawnParameters SpawnParameters{}; + // SpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn; + + auto Loc = Pawn->GetActorLocation(); + Loc.Z += 1000; + + FTransform Transform; + Transform.Translation = Loc; + Transform.Scale3D = FVector(1, 1, 1); + + auto NewActor = Bots::SpawnBot(Transform); + + if (!NewActor) + { + SendMessageToConsole(PlayerController, L"Failed to spawn an actor!"); + } + else + { + AmountSpawned++; + } + } + + SendMessageToConsole(PlayerController, L"Summoned!"); + } else if (Command == "sethealth") { auto Pawn = ReceivingController->GetMyFortPawn(); diff --git a/Project Reboot 3.0/die.h b/Project Reboot 3.0/die.h index 44c6dbb..eaa1753 100644 --- a/Project Reboot 3.0/die.h +++ b/Project Reboot 3.0/die.h @@ -7,6 +7,7 @@ #include "KismetStringLibrary.h" #include "DataTableFunctionLibrary.h" #include "FortPlaysetItemDefinition.h" +#include "gui.h" static inline void (*SetZoneToIndexOriginal)(AFortGameModeAthena* GameModeAthena, int OverridePhaseMaybeIDFK); @@ -178,6 +179,11 @@ 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(); diff --git a/Project Reboot 3.0/dllmain.cpp b/Project Reboot 3.0/dllmain.cpp index ed71542..18f4f70 100644 --- a/Project Reboot 3.0/dllmain.cpp +++ b/Project Reboot 3.0/dllmain.cpp @@ -513,9 +513,6 @@ DWORD WINAPI Main(LPVOID) break; } } - - // Hooking::MinHook::Hook(FortPlayerControllerAthenaDefault, FindObject(L"/Script/FortniteGame.FortPlayerControllerGameplay.EndGhostMode"), - // AFortPlayerControllerAthena::EndGhostModeHook, (PVOID*)&AFortPlayerControllerAthena::EndGhostModeOriginal, false); } } diff --git a/Project Reboot 3.0/finder.h b/Project Reboot 3.0/finder.h index a54eec8..34e3824 100644 --- a/Project Reboot 3.0/finder.h +++ b/Project Reboot 3.0/finder.h @@ -627,7 +627,7 @@ static inline uint64 FindUpdateTrackedAttributesLea() // kill me static inline uint64 FindCombinePickupLea() // kill me { - return 0; + // return 0; /* uint64 OnRep_PickupLocationDataAddr = 0; // TODO (Idea: Find SetupCombinePickupDelegates from this). diff --git a/Project Reboot 3.0/gui.h b/Project Reboot 3.0/gui.h index 956b885..184588f 100644 --- a/Project Reboot 3.0/gui.h +++ b/Project Reboot 3.0/gui.h @@ -38,6 +38,7 @@ #include "FortWeaponItemDefinition.h" #include "events.h" #include "FortAthenaMutator_Heist.h" +#include "BGA.h" #define GAME_TAB 1 #define PLAYERS_TAB 2 @@ -64,6 +65,9 @@ extern inline float AutoBusStartSeconds = 60; extern inline int NumRequiredPlayersToStart = 2; extern inline bool bDebugPrintLooting = false; extern inline bool bDebugPrintSwapping = false; +extern inline bool bEnableBotTick = false; +extern inline bool bEnableCombinePickup = false; +extern inline int AmountOfBotsToSpawn = 0; // THE BASE CODE IS FROM IMGUI GITHUB @@ -279,6 +283,7 @@ static inline void StaticUI() #ifndef PROD ImGui::Checkbox("Log ProcessEvent", &Globals::bLogProcessEvent); + ImGui::InputInt("Amount of bots to spawn", &AmountOfBotsToSpawn); #endif ImGui::Checkbox("Infinite Ammo", &Globals::bInfiniteAmmo); @@ -470,6 +475,11 @@ static inline void MainUI() UKismetSystemLibrary::ExecuteConsoleCommand(GetWorld(), cmd, nullptr); } + if (ImGui::Button("Spawn BGAs")) + { + SpawnBGAs(); + } + /* if (ImGui::Button("New")) { @@ -897,6 +907,8 @@ static inline void MainUI() static std::string FunctionNameToDump; ImGui::Checkbox("Fill Vending Machines", &Globals::bFillVendingMachines); + ImGui::Checkbox("Enable Bot Tick", &bEnableBotTick); + ImGui::Checkbox("Enable Combine Pickup", &bEnableCombinePickup); ImGui::InputText("Class Name to mess with", &ClassNameToDump); ImGui::InputText("Function Name to mess with", &FunctionNameToDump); @@ -1000,8 +1012,9 @@ static inline void PregameUI() if (!bSwitchedInitialLevel) ImGui::SliderInt("Seconds until load into map", &SecondsUntilTravel, 1, 100); - - ImGui::InputText("Playlist", &PlaylistName); + + if (!Globals::bCreative) + ImGui::InputText("Playlist", &PlaylistName); } static inline DWORD WINAPI GuiThread(LPVOID) diff --git a/Project Reboot 3.0/log.h b/Project Reboot 3.0/log.h index ffad628..44176d2 100644 --- a/Project Reboot 3.0/log.h +++ b/Project Reboot 3.0/log.h @@ -81,6 +81,7 @@ inline void InitLogger() MakeLogger("LogReplication"); MakeLogger("LogMutator"); MakeLogger("LogVehicles"); + MakeLogger("LogBots"); MakeLogger("LogCosmetics"); } diff --git a/Project Reboot 3.0/reboot.h b/Project Reboot 3.0/reboot.h index 43efa10..18c5d27 100644 --- a/Project Reboot 3.0/reboot.h +++ b/Project Reboot 3.0/reboot.h @@ -240,6 +240,14 @@ inline std::vector GetAllObjectsOfClass(UClass* Class) return Objects; } +template +inline T* GetRandomObjectOfClass(UClass* Class) +{ + auto AllObjectsVec = GetAllObjectsOfClass(Class); + + return AllObjectsVec.size() > 0 ? AllObjectsVec.at(std::rand() % AllObjectsVec.size()) : nullptr; +} + inline void* FindPropertyStruct(const std::string& StructName, const std::string& MemberName, bool bWarnIfNotFound = true) { UObject* Struct = FindObject(StructName); @@ -377,9 +385,9 @@ static void CopyStruct(void* Dest, void* Src, size_t Size, UStruct* Struct = nul } template -static T* Alloc(size_t Size = sizeof(T), bool bUseRealloc = false) +static T* Alloc(size_t Size = sizeof(T), bool bUseFMemoryRealloc = false) { - return bUseRealloc ? (T*)FMemory::Realloc(0, Size, 0) : (T*)VirtualAlloc(0, Size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); + return bUseFMemoryRealloc ? (T*)FMemory::Realloc(0, Size, 0) : (T*)VirtualAlloc(0, Size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); } namespace MemberOffsets