From 02717f33f3114ac85a463d3666674cd001a45c73 Mon Sep 17 00:00:00 2001 From: Milxnor Date: Sun, 30 Apr 2023 22:12:03 -0400 Subject: [PATCH] a medium amount fix some playlist starter loot, cleanup some code, fix death bugs on 1.8 and 1.7.2, fix reloading not taking items on 1.8 and 1.7.2, fix looting on s9, fix some s15 & s16 builds, fix bug with higher version looting --- Project Reboot 3.0/BGA.h | 22 +- Project Reboot 3.0/BuildingContainer.cpp | 26 ++ Project Reboot 3.0/BuildingContainer.h | 3 + Project Reboot 3.0/DataTable.h | 7 + .../FortAthenaMutator_LoadoutSwap.h | 8 + Project Reboot 3.0/FortAthenaMutator_TDM.h | 15 + Project Reboot 3.0/FortItem.h | 2 + Project Reboot 3.0/FortLootPackage.cpp | 15 +- Project Reboot 3.0/FortPlayerController.cpp | 362 ++++++++++-------- Project Reboot 3.0/FortPlayerController.h | 2 +- .../FortPlayerControllerAthena.cpp | 57 ++- Project Reboot 3.0/FortPlaylist.h | 42 ++ Project Reboot 3.0/GameModeBase.cpp | 33 +- Project Reboot 3.0/GameplayStatics.cpp | 37 ++ Project Reboot 3.0/GameplayStatics.h | 3 + Project Reboot 3.0/Project Reboot 3.0.vcxproj | 3 + .../Project Reboot 3.0.vcxproj.filters | 9 + Project Reboot 3.0/addresses.cpp | 4 - Project Reboot 3.0/addresses.h | 1 - Project Reboot 3.0/die.h | 3 +- Project Reboot 3.0/dllmain.cpp | 22 +- Project Reboot 3.0/finder.h | 17 +- Project Reboot 3.0/gui.h | 13 + Project Reboot 3.0/inc.h | 2 +- vendor/memcury.h | 9 +- 25 files changed, 477 insertions(+), 240 deletions(-) create mode 100644 Project Reboot 3.0/BuildingContainer.cpp create mode 100644 Project Reboot 3.0/FortAthenaMutator_LoadoutSwap.h create mode 100644 Project Reboot 3.0/FortAthenaMutator_TDM.h diff --git a/Project Reboot 3.0/BGA.h b/Project Reboot 3.0/BGA.h index 9397251..fab858c 100644 --- a/Project Reboot 3.0/BGA.h +++ b/Project Reboot 3.0/BGA.h @@ -24,6 +24,11 @@ void SpawnBGAs() // hahah not "proper", there's a function that we can hook and auto BGAConsumableSpawner = AllBGAConsumableSpawners.at(i); auto SpawnLocation = BGAConsumableSpawner->GetActorLocation(); + FTransform SpawnTransform{}; + SpawnTransform.Translation = SpawnLocation; + SpawnTransform.Scale3D = FVector{ 1, 1, 1 }; + SpawnTransform.Rotation = FQuat(); + if (FBuildingGameplayActorSpawnDetails::GetStruct()) { // todo handle? @@ -33,6 +38,7 @@ void SpawnBGAs() // hahah not "proper", there's a function that we can hook and else { // SpawnLocation.Z += 100; + // SpawnLocation.Z -= 50; // proper frfr } static auto SpawnLootTierGroupOffset = BGAConsumableSpawner->GetOffset("SpawnLootTierGroup"); @@ -45,7 +51,7 @@ void SpawnBGAs() // hahah not "proper", there's a function that we can hook and static auto ConsumableClassOffset = LootDrop.ItemDefinition->GetOffset("ConsumableClass"); auto ConsumableClassSoft = LootDrop.ItemDefinition->GetPtr>(ConsumableClassOffset); - static auto BlueprintGeneratedClassClass = FindObject("/Script/Engine.BlueprintGeneratedClass"); + static auto BlueprintGeneratedClassClass = FindObject(L"/Script/Engine.BlueprintGeneratedClass"); auto StrongConsumableClass = ConsumableClassSoft->Get(BlueprintGeneratedClassClass, true); if (!StrongConsumableClass) @@ -54,12 +60,20 @@ void SpawnBGAs() // hahah not "proper", there's a function that we can hook and continue; } - auto ConsumableActor = GetWorld()->SpawnActor(StrongConsumableClass, SpawnLocation); + bool bDeferConstruction = false; // hm? + + FActorSpawnParameters SpawnParameters{}; + // SpawnParameters.ObjectFlags = RF_Transactional; // idk fortnite does this i think + SpawnParameters.bDeferConstruction = bDeferConstruction; + + auto ConsumableActor = GetWorld()->SpawnActor(StrongConsumableClass, SpawnTransform, SpawnParameters); if (ConsumableActor) { - // BeginDeferredActorSpawnFromClass ?? - // ConsumableActor->InitializeBuildingActor(nullptr, nullptr, true); // idk UFortKismetLibrary::SpawnBuildingGameplayActor does this + if (bDeferConstruction) + UGameplayStatics::FinishSpawningActor(ConsumableActor, SpawnTransform); // what + + ConsumableActor->InitializeBuildingActor(nullptr, nullptr, true); // idk UFortKismetLibrary::SpawnBuildingGameplayActor does this } } } diff --git a/Project Reboot 3.0/BuildingContainer.cpp b/Project Reboot 3.0/BuildingContainer.cpp new file mode 100644 index 0000000..f267a0d --- /dev/null +++ b/Project Reboot 3.0/BuildingContainer.cpp @@ -0,0 +1,26 @@ +#include "BuildingContainer.h" +#include "FortPickup.h" +#include "FortLootPackage.h" +#include "FortGameModeAthena.h" + +bool ABuildingContainer::SpawnLoot(AFortPawn* Pawn) +{ + 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)); + + // LOG_INFO(LogInteraction, "RedirectedLootTier: {}", RedirectedLootTier.ToString()); + + auto LootDrops = PickLootDrops(RedirectedLootTier, true); + + // LOG_INFO(LogInteraction, "LootDrops.size(): {}", LootDrops.size()); + + for (int i = 0; i < LootDrops.size(); i++) + { + auto& lootDrop = LootDrops.at(i); + AFortPickup::SpawnPickup(lootDrop.ItemDefinition, LocationToSpawnLoot, lootDrop.Count, EFortPickupSourceTypeFlag::Container, EFortPickupSpawnSource::Unset, lootDrop.LoadedAmmo); + } + + return true; +} \ No newline at end of file diff --git a/Project Reboot 3.0/BuildingContainer.h b/Project Reboot 3.0/BuildingContainer.h index 141175e..444c95b 100644 --- a/Project Reboot 3.0/BuildingContainer.h +++ b/Project Reboot 3.0/BuildingContainer.h @@ -1,6 +1,7 @@ #pragma once #include "BuildingSMActor.h" +#include "FortPawn.h" class ABuildingContainer : public ABuildingSMActor { @@ -12,6 +13,8 @@ public: return this->ReadBitfieldValue(bDestroyContainerOnSearchOffset, bDestroyContainerOnSearchFieldMask); } + bool SpawnLoot(AFortPawn* Pawn); + static UClass* StaticClass() { static auto Class = FindObject("/Script/FortniteGame.BuildingContainer"); diff --git a/Project Reboot 3.0/DataTable.h b/Project Reboot 3.0/DataTable.h index 02019bb..796418f 100644 --- a/Project Reboot 3.0/DataTable.h +++ b/Project Reboot 3.0/DataTable.h @@ -27,3 +27,10 @@ struct FDataTableRowHandle UDataTable* DataTable; // 0x0000(0x0008) (Edit, BlueprintVisible, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) FName RowName; // 0x0008(0x0008) (Edit, BlueprintVisible, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) }; + +template +struct RowNameAndRowData +{ + FName RowName; + StructType* RowData; +}; \ No newline at end of file diff --git a/Project Reboot 3.0/FortAthenaMutator_LoadoutSwap.h b/Project Reboot 3.0/FortAthenaMutator_LoadoutSwap.h new file mode 100644 index 0000000..d798076 --- /dev/null +++ b/Project Reboot 3.0/FortAthenaMutator_LoadoutSwap.h @@ -0,0 +1,8 @@ +#pragma once + +#include "FortAthenaMutator.h" + +class AFortAthenaMutator_LoadoutSwap : public AFortAthenaMutator +{ +public: +}; \ No newline at end of file diff --git a/Project Reboot 3.0/FortAthenaMutator_TDM.h b/Project Reboot 3.0/FortAthenaMutator_TDM.h new file mode 100644 index 0000000..dde86fd --- /dev/null +++ b/Project Reboot 3.0/FortAthenaMutator_TDM.h @@ -0,0 +1,15 @@ +#pragma once + +#include "FortAthenaMutator.h" + +#include "reboot.h" + +class AFortAthenaMutator_TDM : public AFortAthenaMutator +{ +public: + static UClass* StaticClass() + { + static auto Class = FindObject("/Script/FortniteGame.FortAthenaMutator_TDM"); + return Class; + } +}; \ No newline at end of file diff --git a/Project Reboot 3.0/FortItem.h b/Project Reboot 3.0/FortItem.h index 54b4589..bd17b51 100644 --- a/Project Reboot 3.0/FortItem.h +++ b/Project Reboot 3.0/FortItem.h @@ -103,6 +103,8 @@ struct FFortItemEntry : FFastArraySerializerItem void CopyFromAnotherItemEntry(FFortItemEntry* OtherItemEntry, bool bCopyGuid = false) { + // We can use FortItemEntryStruct->CopyScriptStruct + FGuid OldGuid = this->GetItemGuid(); if (false) diff --git a/Project Reboot 3.0/FortLootPackage.cpp b/Project Reboot 3.0/FortLootPackage.cpp index 0857482..1f8d143 100644 --- a/Project Reboot 3.0/FortLootPackage.cpp +++ b/Project Reboot 3.0/FortLootPackage.cpp @@ -74,9 +74,8 @@ static FFortLootPackageData* GetLootPackage(std::vector& struct FFortGameFeatureLootTableData { -public: - TSoftObjectPtr LootTierData; // 0x0(0x28)(Edit, UObjectWrapper, HasGetValueTypeHash, NativeAccessSpecifierPublic) - TSoftObjectPtr LootPackageData; // 0x28(0x28)(Edit, UObjectWrapper, HasGetValueTypeHash, NativeAccessSpecifierPublic) + TSoftObjectPtr LootTierData; + TSoftObjectPtr LootPackageData; }; std::vector PickLootDrops(FName TierGroupName, bool bPrint, int recursive) @@ -203,7 +202,7 @@ std::vector PickLootDrops(FName TierGroupName, bool bPrint, int recurs if (ptr) { - if (bOverrideIsComposite) + /* if (bOverrideIsComposite) { static auto ParentTablesOffset = ptr->GetOffset("ParentTables"); @@ -218,7 +217,7 @@ std::vector PickLootDrops(FName TierGroupName, bool bPrint, int recurs LPTables.push_back(ParentTable); } } - } + } */ LPTables.push_back(ptr); } @@ -257,7 +256,7 @@ std::vector PickLootDrops(FName TierGroupName, bool bPrint, int recurs if (ptr) { - if (bOverrideIsComposite) + /* if (bOverrideIsComposite) { static auto ParentTablesOffset = ptr->GetOffset("ParentTables"); @@ -272,7 +271,7 @@ std::vector PickLootDrops(FName TierGroupName, bool bPrint, int recurs LTDTables.push_back(ParentTable); } } - } + } */ LTDTables.push_back(ptr); } @@ -312,7 +311,7 @@ std::vector PickLootDrops(FName TierGroupName, bool bPrint, int recurs } } - if (Fortnite_Version <= 6) // ahhh + if (Fortnite_Version <= 6 || std::floor(Fortnite_Version) == 9) // ahhh { LTDTables.clear(); LPTables.clear(); diff --git a/Project Reboot 3.0/FortPlayerController.cpp b/Project Reboot 3.0/FortPlayerController.cpp index 9bef356..ed01a86 100644 --- a/Project Reboot 3.0/FortPlayerController.cpp +++ b/Project Reboot 3.0/FortPlayerController.cpp @@ -22,6 +22,8 @@ #include "vendingmachine.h" #include "KismetSystemLibrary.h" #include "gui.h" +#include "FortAthenaMutator_InventoryOverride.h" +#include "FortAthenaMutator_TDM.h" void AFortPlayerController::ClientReportDamagedResourceBuilding(ABuildingSMActor* BuildingSMActor, EFortResourceType PotentialResourceType, int PotentialResourceCount, bool bDestroyed, bool bJustHitWeakspot) { @@ -416,22 +418,7 @@ void AFortPlayerController::ServerAttemptInteractHook(UObject* Context, FFrame* static auto OnRep_bAlreadySearchedFn = FindObject(L"/Script/FortniteGame.BuildingContainer.OnRep_bAlreadySearched"); BuildingContainer->ProcessEvent(OnRep_bAlreadySearchedFn); - static auto SearchLootTierGroupOffset = BuildingContainer->GetOffset("SearchLootTierGroup"); - auto RedirectedLootTier = Cast(GetWorld()->GetGameMode(), false)->RedirectLootTier(BuildingContainer->Get(SearchLootTierGroupOffset)); - - LOG_INFO(LogInteraction, "RedirectedLootTier: {}", RedirectedLootTier.ToString()); - - auto LootDrops = PickLootDrops(RedirectedLootTier, true); - - LOG_INFO(LogInteraction, "LootDrops.size(): {}", LootDrops.size()); - - for (int i = 0; i < LootDrops.size(); i++) - { - auto& lootDrop = LootDrops.at(i); - AFortPickup::SpawnPickup(lootDrop.ItemDefinition, LocationToSpawnLoot, lootDrop.Count, EFortPickupSourceTypeFlag::Container, EFortPickupSpawnSource::Unset, lootDrop.LoadedAmmo - // , (AFortPawn*)PlayerController->GetPawn() // should we put this here? - ); - } + BuildingContainer->SpawnLoot(PlayerController->GetMyFortPawn()); // if (BuildingContainer->ShouldDestroyOnSearch()) // BuildingContainer->K2_DestroyActor(); @@ -1135,188 +1122,231 @@ void AFortPlayerController::ClientOnPawnDiedHook(AFortPlayerController* PlayerCo static auto FallDamageEnumValue = 1; - auto DeathInfo = (void*)(__int64(DeadPlayerState) + MemberOffsets::FortPlayerStateAthena::DeathInfo); // Alloc(DeathInfoStructSize); - RtlSecureZeroMemory(DeathInfo, DeathInfoStructSize); + uint8_t DeathCause = 0; - auto/*&*/ Tags = MemberOffsets::FortPlayerPawn::CorrectTags == 0 ? FGameplayTagContainer() - : DeadPawn->Get(MemberOffsets::FortPlayerPawn::CorrectTags); - // *(FGameplayTagContainer*)(__int64(DeathReport) + MemberOffsets::DeathReport::Tags); - - // LOG_INFO(LogDev, "Tags: {}", Tags.ToStringSimple(true)); - - auto DeathCause = ToDeathCause(Tags, false, DeadPawn); // DeadPawn->IsDBNO() ?? - - LOG_INFO(LogDev, "DeathCause: {}", (int)DeathCause); - - *(bool*)(__int64(DeathInfo) + MemberOffsets::DeathInfo::bDBNO) = DeadPawn->IsDBNO(); - *(uint8*)(__int64(DeathInfo) + MemberOffsets::DeathInfo::DeathCause) = DeathCause; - *(AActor**)(__int64(DeathInfo) + MemberOffsets::DeathInfo::FinisherOrDowner) = KillerPlayerState ? KillerPlayerState : DeadPlayerState; - - if (MemberOffsets::DeathInfo::DeathLocation != -1) - *(FVector*)(__int64(DeathInfo) + MemberOffsets::DeathInfo::DeathLocation) = DeathLocation; - - if (MemberOffsets::DeathInfo::DeathTags != -1) - *(FGameplayTagContainer*)(__int64(DeathInfo) + MemberOffsets::DeathInfo::DeathTags) = Tags; - - if (MemberOffsets::DeathInfo::bInitialized != -1) - *(bool*)(__int64(DeathInfo) + MemberOffsets::DeathInfo::bInitialized) = true; - - if (DeathCause == FallDamageEnumValue) + if (Fortnite_Version > 1.8 || Fortnite_Version == 1.11) { - if (MemberOffsets::FortPlayerPawnAthena::LastFallDistance != -1) - *(float*)(__int64(DeathInfo) + MemberOffsets::DeathInfo::Distance) = DeadPawn->Get(MemberOffsets::FortPlayerPawnAthena::LastFallDistance); + auto DeathInfo = (void*)(__int64(DeadPlayerState) + MemberOffsets::FortPlayerStateAthena::DeathInfo); // Alloc(DeathInfoStructSize); + RtlSecureZeroMemory(DeathInfo, DeathInfoStructSize); + + auto/*&*/ Tags = MemberOffsets::FortPlayerPawn::CorrectTags == 0 ? FGameplayTagContainer() + : DeadPawn->Get(MemberOffsets::FortPlayerPawn::CorrectTags); + // *(FGameplayTagContainer*)(__int64(DeathReport) + MemberOffsets::DeathReport::Tags); + + // LOG_INFO(LogDev, "Tags: {}", Tags.ToStringSimple(true)); + + DeathCause = ToDeathCause(Tags, false, DeadPawn); // DeadPawn->IsDBNO() ?? + + LOG_INFO(LogDev, "DeathCause: {}", (int)DeathCause); + + *(bool*)(__int64(DeathInfo) + MemberOffsets::DeathInfo::bDBNO) = DeadPawn->IsDBNO(); + *(uint8*)(__int64(DeathInfo) + MemberOffsets::DeathInfo::DeathCause) = DeathCause; + *(AActor**)(__int64(DeathInfo) + MemberOffsets::DeathInfo::FinisherOrDowner) = KillerPlayerState ? KillerPlayerState : DeadPlayerState; + + if (MemberOffsets::DeathInfo::DeathLocation != -1) + *(FVector*)(__int64(DeathInfo) + MemberOffsets::DeathInfo::DeathLocation) = DeathLocation; + + if (MemberOffsets::DeathInfo::DeathTags != -1) + *(FGameplayTagContainer*)(__int64(DeathInfo) + MemberOffsets::DeathInfo::DeathTags) = Tags; + + if (MemberOffsets::DeathInfo::bInitialized != -1) + *(bool*)(__int64(DeathInfo) + MemberOffsets::DeathInfo::bInitialized) = true; + + if (DeathCause == FallDamageEnumValue) + { + if (MemberOffsets::FortPlayerPawnAthena::LastFallDistance != -1) + *(float*)(__int64(DeathInfo) + MemberOffsets::DeathInfo::Distance) = DeadPawn->Get(MemberOffsets::FortPlayerPawnAthena::LastFallDistance); + } + else + { + if (MemberOffsets::DeathInfo::Distance != -1) + *(float*)(__int64(DeathInfo) + MemberOffsets::DeathInfo::Distance) = KillerPawn ? KillerPawn->GetDistanceTo(DeadPawn) : 0; + } + + if (MemberOffsets::FortPlayerState::PawnDeathLocation != -1) + DeadPlayerState->Get(MemberOffsets::FortPlayerState::PawnDeathLocation) = DeathLocation; + + static auto OnRep_DeathInfoFn = FindObject(L"/Script/FortniteGame.FortPlayerStateAthena.OnRep_DeathInfo"); + + if (OnRep_DeathInfoFn) + { + DeadPlayerState->ProcessEvent(OnRep_DeathInfoFn); + } + + if (KillerPlayerState && KillerPlayerState != DeadPlayerState) + { + if (MemberOffsets::FortPlayerStateAthena::KillScore != -1) + KillerPlayerState->Get(MemberOffsets::FortPlayerStateAthena::KillScore)++; + + if (MemberOffsets::FortPlayerStateAthena::TeamKillScore != -1) + KillerPlayerState->Get(MemberOffsets::FortPlayerStateAthena::TeamKillScore)++; + + KillerPlayerState->ClientReportKill(DeadPlayerState); + + /* LoopMutators([&](AFortAthenaMutator* Mutator) { + if (auto TDM_Mutator = Cast(Mutator)) + { + struct + { + int EventId; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + int EventParam1; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + int EventParam2; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + int EventParam3; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + } AFortAthenaMutator_TDM_OnMutatorGameplayEvent_Params{ 1, 0, 0, 0 }; + + static auto TDM_OnMutatorGameplayEventFn = FindObject("/Script/FortniteGame.FortAthenaMutator_TDM.OnMutatorGameplayEvent"); + TDM_Mutator->ProcessEvent(TDM_OnMutatorGameplayEventFn, &AFortAthenaMutator_TDM_OnMutatorGameplayEvent_Params); + } + }); */ + + // KillerPlayerState->OnRep_Kills(); + } + + // LOG_INFO(LogDev, "Reported kill."); + + /* if (KillerPawn && KillerPawn != DeadPawn) + { + KillerPawn->SetHealth(100); + KillerPawn->SetShield(100); + } */ } - else - { - if (MemberOffsets::DeathInfo::Distance != -1) - *(float*)(__int64(DeathInfo) + MemberOffsets::DeathInfo::Distance) = KillerPawn ? KillerPawn->GetDistanceTo(DeadPawn) : 0; - } - - if (MemberOffsets::FortPlayerState::PawnDeathLocation != -1) - DeadPlayerState->Get(MemberOffsets::FortPlayerState::PawnDeathLocation) = DeathLocation; - - static auto OnRep_DeathInfoFn = FindObject(L"/Script/FortniteGame.FortPlayerStateAthena.OnRep_DeathInfo"); - - if (OnRep_DeathInfoFn) - { - DeadPlayerState->ProcessEvent(OnRep_DeathInfoFn); - } - - if (KillerPlayerState && KillerPlayerState != DeadPlayerState) - { - KillerPlayerState->Get(MemberOffsets::FortPlayerStateAthena::KillScore)++; - - if (MemberOffsets::FortPlayerStateAthena::TeamKillScore != -1) - KillerPlayerState->Get(MemberOffsets::FortPlayerStateAthena::TeamKillScore)++; - - KillerPlayerState->ClientReportKill(DeadPlayerState); - // KillerPlayerState->OnRep_Kills(); - } - - LOG_INFO(LogDev, "Reported kill."); - - /* if (KillerPawn && KillerPawn != DeadPawn) - { - KillerPawn->SetHealth(100); - KillerPawn->SetShield(100); - } */ bool bIsRespawningAllowed = GameState->IsRespawningAllowed(DeadPlayerState); if (!bIsRespawningAllowed) { - auto WorldInventory = PlayerController->GetWorldInventory(); + bool bDropInventory = true; - if (!WorldInventory) - return ClientOnPawnDiedOriginal(PlayerController, DeathReport); + LoopMutators([&](AFortAthenaMutator* Mutator) + { + if (auto FortAthenaMutator_InventoryOverride = Cast(Mutator)) + { + if (FortAthenaMutator_InventoryOverride->GetDropAllItemsOverride(DeadPlayerState->GetTeamIndex()) == EAthenaLootDropOverride::ForceKeep) + { + bDropInventory = false; + } + } + } + ); - auto& ItemInstances = WorldInventory->GetItemList().GetItemInstances(); - - std::vector> GuidAndCountsToRemove; - - for (int i = 0; i < ItemInstances.Num(); i++) + if (bDropInventory) { - auto ItemInstance = ItemInstances.at(i); + auto WorldInventory = PlayerController->GetWorldInventory(); - // LOG_INFO(LogDev, "[{}/{}] CurrentItemInstance {}", i, ItemInstances.Num(), __int64(ItemInstance)); + if (!WorldInventory) + return ClientOnPawnDiedOriginal(PlayerController, DeathReport); - if (!ItemInstance) - continue; + auto& ItemInstances = WorldInventory->GetItemList().GetItemInstances(); - auto ItemEntry = ItemInstance->GetItemEntry(); - auto WorldItemDefinition = Cast(ItemEntry->GetItemDefinition()); + std::vector> GuidAndCountsToRemove; - // LOG_INFO(LogDev, "[{}/{}] WorldItemDefinition {}", i, ItemInstances.Num(), WorldItemDefinition ? WorldItemDefinition->GetFullName() : "InvalidObject"); + for (int i = 0; i < ItemInstances.Num(); i++) + { + auto ItemInstance = ItemInstances.at(i); - if (!WorldItemDefinition) - continue; + // LOG_INFO(LogDev, "[{}/{}] CurrentItemInstance {}", i, ItemInstances.Num(), __int64(ItemInstance)); - auto ShouldBeDropped = WorldItemDefinition->CanBeDropped(); // WorldItemDefinition->ShouldDropOnDeath(); + if (!ItemInstance) + continue; - // LOG_INFO(LogDev, "[{}/{}] ShouldBeDropped {}", i, ItemInstances.Num(), ShouldBeDropped); + auto ItemEntry = ItemInstance->GetItemEntry(); + auto WorldItemDefinition = Cast(ItemEntry->GetItemDefinition()); - if (!ShouldBeDropped) - continue; + // LOG_INFO(LogDev, "[{}/{}] WorldItemDefinition {}", i, ItemInstances.Num(), WorldItemDefinition ? WorldItemDefinition->GetFullName() : "InvalidObject"); - AFortPickup::SpawnPickup(WorldItemDefinition, DeathLocation, ItemEntry->GetCount(), EFortPickupSourceTypeFlag::Player, EFortPickupSpawnSource::PlayerElimination, - ItemEntry->GetLoadedAmmo()); + if (!WorldItemDefinition) + continue; - GuidAndCountsToRemove.push_back({ ItemEntry->GetItemGuid(), ItemEntry->GetCount() }); - // WorldInventory->RemoveItem(ItemEntry->GetItemGuid(), nullptr, ItemEntry->GetCount()); + auto ShouldBeDropped = WorldItemDefinition->CanBeDropped(); // WorldItemDefinition->ShouldDropOnDeath(); + + // LOG_INFO(LogDev, "[{}/{}] ShouldBeDropped {}", i, ItemInstances.Num(), ShouldBeDropped); + + if (!ShouldBeDropped) + continue; + + AFortPickup::SpawnPickup(WorldItemDefinition, DeathLocation, ItemEntry->GetCount(), EFortPickupSourceTypeFlag::Player, EFortPickupSpawnSource::PlayerElimination, + ItemEntry->GetLoadedAmmo()); + + GuidAndCountsToRemove.push_back({ ItemEntry->GetItemGuid(), ItemEntry->GetCount() }); + // WorldInventory->RemoveItem(ItemEntry->GetItemGuid(), nullptr, ItemEntry->GetCount()); + } + + for (auto& Pair : GuidAndCountsToRemove) + { + WorldInventory->RemoveItem(Pair.first, nullptr, Pair.second, true); + } + + WorldInventory->Update(); } - for (auto& Pair : GuidAndCountsToRemove) - { - WorldInventory->RemoveItem(Pair.first, nullptr, Pair.second, true); - } - - WorldInventory->Update(); - auto GameMode = Cast(GetWorld()->GetGameMode()); if (!DeadPawn->IsDBNO()) { - static void (*RemoveFromAlivePlayers)(AFortGameModeAthena* GameMode, AFortPlayerController* PlayerController, APlayerState* PlayerState, APawn* FinisherPawn, - UFortWeaponItemDefinition* FinishingWeapon, uint8_t DeathCause, char a7) - = decltype(RemoveFromAlivePlayers)(Addresses::RemoveFromAlivePlayers); - - AActor* DamageCauser = *(AActor**)(__int64(DeathReport) + MemberOffsets::DeathReport::DamageCauser); - UFortWeaponItemDefinition* KillerWeaponDef = nullptr; - - static auto FortProjectileBaseClass = FindObject(L"/Script/FortniteGame.FortProjectileBase"); - LOG_INFO(LogDev, "FortProjectileBaseClass: {}", __int64(FortProjectileBaseClass)); - - if (DamageCauser) + if (Fortnite_Version > 1.8 || Fortnite_Version == 1.11) { - if (DamageCauser->IsA(FortProjectileBaseClass)) + static void (*RemoveFromAlivePlayers)(AFortGameModeAthena * GameMode, AFortPlayerController * PlayerController, APlayerState * PlayerState, APawn * FinisherPawn, + UFortWeaponItemDefinition * FinishingWeapon, uint8_t DeathCause, char a7) + = decltype(RemoveFromAlivePlayers)(Addresses::RemoveFromAlivePlayers); + + AActor* DamageCauser = *(AActor**)(__int64(DeathReport) + MemberOffsets::DeathReport::DamageCauser); + UFortWeaponItemDefinition* KillerWeaponDef = nullptr; + + static auto FortProjectileBaseClass = FindObject(L"/Script/FortniteGame.FortProjectileBase"); + LOG_INFO(LogDev, "FortProjectileBaseClass: {}", __int64(FortProjectileBaseClass)); + + if (DamageCauser) { - LOG_INFO(LogDev, "From a projectile!"); - auto Owner = Cast(DamageCauser->GetOwner()); - KillerWeaponDef = Owner->IsValidLowLevel() ? Owner->GetWeaponData() : nullptr; // I just added the IsValidLowLevel check because what if the weapon destroys? - } - if (auto Weapon = Cast(DamageCauser)) - { - LOG_INFO(LogDev, "From a weapon!"); - KillerWeaponDef = Weapon->GetWeaponData(); - } - } - - // LOG_INFO(LogDev, "KillerWeaponDef: {}", KillerWeaponDef ? KillerWeaponDef->GetFullName() : "InvalidObject"); - - RemoveFromAlivePlayers(GameMode, PlayerController, KillerPlayerState == DeadPlayerState ? nullptr : KillerPlayerState, KillerPawn, KillerWeaponDef, DeathCause, 0); - - LOG_INFO(LogDev, "Removed!"); - - if (Fortnite_Version < 6) // Spectating - { - static auto bAllowSpectateAfterDeathOffset = GameMode->GetOffset("bAllowSpectateAfterDeath"); - - bool bAllowSpectate = false; // GameMode->Get(bAllowSpectateAfterDeathOffset); - - LOG_INFO(LogDev, "bAllowSpectate: {}", bAllowSpectate); - - if (bAllowSpectate) - { - LOG_INFO(LogDev, "Starting Spectating!"); - - static auto PlayerToSpectateOnDeathOffset = PlayerController->GetOffset("PlayerToSpectateOnDeath"); - PlayerController->Get(PlayerToSpectateOnDeathOffset) = KillerPawn; - - PlayerControllersDead.push_back(PlayerController); - - /* if (numValidElements < PlayerControllersDead.size()) + if (DamageCauser->IsA(FortProjectileBaseClass)) { - PlayerControllersDead[numValidElements].store(PlayerController); - numValidElements.fetch_add(1); - } */ - - static bool bCreatedThread = false; - - if (!bCreatedThread) + LOG_INFO(LogDev, "From a projectile!"); + auto Owner = Cast(DamageCauser->GetOwner()); + KillerWeaponDef = Owner->IsValidLowLevel() ? Owner->GetWeaponData() : nullptr; // I just added the IsValidLowLevel check because what if the weapon destroys? + } + if (auto Weapon = Cast(DamageCauser)) { - bCreatedThread = true; + LOG_INFO(LogDev, "From a weapon!"); + KillerWeaponDef = Weapon->GetWeaponData(); + } + } - CreateThread(0, 0, SpectateThread, 0, 0, 0); + // LOG_INFO(LogDev, "KillerWeaponDef: {}", KillerWeaponDef ? KillerWeaponDef->GetFullName() : "InvalidObject"); + + RemoveFromAlivePlayers(GameMode, PlayerController, KillerPlayerState == DeadPlayerState ? nullptr : KillerPlayerState, KillerPawn, KillerWeaponDef, DeathCause, 0); + + LOG_INFO(LogDev, "Removed!"); + + if (Fortnite_Version < 6) // Spectating + { + static auto bAllowSpectateAfterDeathOffset = GameMode->GetOffset("bAllowSpectateAfterDeath"); + + bool bAllowSpectate = false; // GameMode->Get(bAllowSpectateAfterDeathOffset); + + LOG_INFO(LogDev, "bAllowSpectate: {}", bAllowSpectate); + + if (bAllowSpectate) + { + LOG_INFO(LogDev, "Starting Spectating!"); + + static auto PlayerToSpectateOnDeathOffset = PlayerController->GetOffset("PlayerToSpectateOnDeath"); + PlayerController->Get(PlayerToSpectateOnDeathOffset) = KillerPawn; + + PlayerControllersDead.push_back(PlayerController); + + /* if (numValidElements < PlayerControllersDead.size()) + { + PlayerControllersDead[numValidElements].store(PlayerController); + numValidElements.fetch_add(1); + } */ + + static bool bCreatedThread = false; + + if (!bCreatedThread) + { + bCreatedThread = true; + + CreateThread(0, 0, SpectateThread, 0, 0, 0); + } } } } diff --git a/Project Reboot 3.0/FortPlayerController.h b/Project Reboot 3.0/FortPlayerController.h index 5d8faf0..27f349d 100644 --- a/Project Reboot 3.0/FortPlayerController.h +++ b/Project Reboot 3.0/FortPlayerController.h @@ -95,7 +95,7 @@ public: bool HasTryPickupSwap() { - static auto bTryPickupSwapOffset = GetOffset("bTryPickupSwap"); + static auto bTryPickupSwapOffset = GetOffset("bTryPickupSwap", false); return bTryPickupSwapOffset != -1; } diff --git a/Project Reboot 3.0/FortPlayerControllerAthena.cpp b/Project Reboot 3.0/FortPlayerControllerAthena.cpp index 10fe242..821bd89 100644 --- a/Project Reboot 3.0/FortPlayerControllerAthena.cpp +++ b/Project Reboot 3.0/FortPlayerControllerAthena.cpp @@ -8,6 +8,7 @@ #include "hooking.h" #include "FortAthenaMutator_GiveItemsAtGamePhaseStep.h" #include "DataTableFunctionLibrary.h" +#include "FortAthenaMutator_InventoryOverride.h" void AFortPlayerControllerAthena::StartGhostModeHook(UObject* Context, FFrame* Stack, void* Ret) { @@ -135,20 +136,15 @@ void AFortPlayerControllerAthena::EnterAircraftHook(UObject* PC, AActor* Aircraf std::vector> FunctionsToCall; - for (int i = 0; i < AllMutators.Num(); i++) - { - auto Mutator = (AFortAthenaMutator*)AllMutators.at(i); - - LOG_INFO(LogDev, "[{}] Mutator: {}", i, Mutator->GetFullName()); - - FunctionsToCall.push_back(std::make_pair(Mutator, Mutator->FindFunction("OnGamePhaseStepChanged"))); + LoopMutators([&](AFortAthenaMutator* Mutator) { FunctionsToCall.push_back(std::make_pair(Mutator, Mutator->FindFunction("OnGamePhaseStepChanged"))); }); + auto HandleGiveItemsAtGamePhaseStepMutator = [&](AFortAthenaMutator* Mutator) { if (auto GiveItemsAtGamePhaseStepMutator = Cast(Mutator)) { auto PhaseToGive = GiveItemsAtGamePhaseStepMutator->GetPhaseToGiveItems(); auto& ItemsToGive = GiveItemsAtGamePhaseStepMutator->GetItemsToGive(); - LOG_INFO(LogDev, "[{}] PhaseToGiveItems: {} ItemsToGive.Num(): {}", i, (int)PhaseToGive, ItemsToGive.Num()); + // LOG_INFO(LogDev, "[{}] PhaseToGiveItems: {} ItemsToGive.Num(): {}", i, (int)PhaseToGive, ItemsToGive.Num()); if (PhaseToGive <= 5) // Flying or lower { @@ -166,27 +162,54 @@ void AFortPlayerControllerAthena::EnterAircraftHook(UObject* PC, AActor* Aircraf Out2 = UDataTableFunctionLibrary::EvaluateCurveTableRow(ItemToGive->GetNumberToGive().GetCurve().CurveTable, ItemToGive->GetNumberToGive().GetCurve().RowName, 0.f); } - LOG_INFO(LogDev, "[{}] [{}] Out2: {} ItemToGive.ItemToDrop: {}", i, j, Out2, ItemToGive->GetItemToDrop()->IsValidLowLevel() ? ItemToGive->GetItemToDrop()->GetFullName() : "BadRead"); + LOG_INFO(LogDev, "[{}] Out2: {} ItemToGive.ItemToDrop: {}", j, Out2, ItemToGive->GetItemToDrop()->IsValidLowLevel() ? ItemToGive->GetItemToDrop()->GetFullName() : "BadRead"); - if (!Out2) + if (!Out2) // ? continue; WorldInventory->AddItem(ItemToGive->GetItemToDrop(), nullptr, Out2); } } } - /* else if (auto GGMutator = Cast(Mutator)) + }; + + LoopMutators(HandleGiveItemsAtGamePhaseStepMutator); + + /* if (auto GGMutator = Cast(Mutator)) + { + auto& WeaponEntries = GGMutator->GetWeaponEntries(); + + LOG_INFO(LogDev, "[{}] WeaponEntries.Num(): {}", i, WeaponEntries.Num()); + + for (int j = 0; j < WeaponEntries.Num(); j++) { - auto& WeaponEntries = GGMutator->GetWeaponEntries(); + WorldInventory->AddItem(WeaponEntries.at(j).Weapon, nullptr, 1); + } + } */ - LOG_INFO(LogDev, "[{}] WeaponEntries.Num(): {}", i, WeaponEntries.Num()); + auto PlayerStateAthena = Cast(PlayerController->GetPlayerState()); - for (int j = 0; j < WeaponEntries.Num(); j++) + auto AddInventoryOverrideTeamLoadouts = [&](AFortAthenaMutator* Mutator) + { + if (auto InventoryOverride = Cast(Mutator)) + { + auto TeamIndex = PlayerStateAthena->GetTeamIndex(); + auto LoadoutTeam = InventoryOverride->GetLoadoutTeamForTeamIndex(TeamIndex); + + if (LoadoutTeam.UpdateOverrideType == EAthenaInventorySpawnOverride::AircraftPhaseOnly) { - WorldInventory->AddItem(WeaponEntries.at(j).Weapon, nullptr, 1); + auto LoadoutContainer = InventoryOverride->GetLoadoutContainerForTeamIndex(TeamIndex); + + for (int i = 0; i < LoadoutContainer.Loadout.Num(); i++) + { + auto& ItemAndCount = LoadoutContainer.Loadout.at(i); + WorldInventory->AddItem(ItemAndCount.GetItem(), nullptr, ItemAndCount.GetCount()); + } } - } */ - } + } + }; + + LoopMutators(AddInventoryOverrideTeamLoadouts); static int LastNum1 = 3125; diff --git a/Project Reboot 3.0/FortPlaylist.h b/Project Reboot 3.0/FortPlaylist.h index f7016b3..55f05aa 100644 --- a/Project Reboot 3.0/FortPlaylist.h +++ b/Project Reboot 3.0/FortPlaylist.h @@ -8,6 +8,7 @@ #include "GameplayTagContainer.h" #include "BuildingActor.h" #include "FortPlayerPawnAthena.h" +#include "GameplayAbilityTypes.h" struct FGameplayTagRequirements { @@ -236,6 +237,41 @@ public: } }; + +struct FAthenaScoreData +{ + +}; + +struct FWinConditionScoreData +{ + static UStruct* GetStruct() + { + static auto Struct = FindObject("/Script/FortniteGame.WinConditionScoreData"); + return Struct; + } + + static int GetStructSize() { return GetStruct()->GetPropertiesSize(); } + + FScalableFloat* GetGoalScore() + { + static auto GoalScoreOffset = FindOffsetStruct("/Script/FortniteGame.WinConditionScoreData", "GoalScore"); + return (FScalableFloat*)(__int64(this) + GoalScoreOffset); + } + + FScalableFloat* GetBigScoreThreshold() + { + static auto BigScoreThresholdOffset = FindOffsetStruct("/Script/FortniteGame.WinConditionScoreData", "BigScoreThreshold"); + return (FScalableFloat*)(__int64(this) + BigScoreThresholdOffset); + } + + TArray& GetScoreDataList() + { + static auto ScoreDataListOffset = FindOffsetStruct("/Script/FortniteGame.WinConditionScoreData", "ScoreDataList"); + return *(TArray*)(__int64(this) + ScoreDataListOffset); + } +}; + class UFortPlaylist : public UObject { public: @@ -245,6 +281,12 @@ public: return this->Get>>(ModifierListOffset); } + FWinConditionScoreData* GetScoringData() + { + static auto ScoringDataOffset = GetOffset("ScoringData"); + return GetPtr(ScoringDataOffset); + } + void ApplyModifiersToActor(AActor* Actor) { if (!Actor) diff --git a/Project Reboot 3.0/GameModeBase.cpp b/Project Reboot 3.0/GameModeBase.cpp index 83a7d28..8e7e46d 100644 --- a/Project Reboot 3.0/GameModeBase.cpp +++ b/Project Reboot 3.0/GameModeBase.cpp @@ -107,20 +107,16 @@ APawn* AGameModeBase::SpawnDefaultPawnForHook(AGameModeBase* GameMode, AControll auto PickaxeDefinition = CosmeticLoadoutPickaxe ? CosmeticLoadoutPickaxe->Get(WeaponDefinitionOffset) : FindObject(L"/Game/Athena/Items/Weapons/WID_Harvest_Pickaxe_Athena_C_T01.WID_Harvest_Pickaxe_Athena_C_T01"); - static UFortItemDefinition* EditToolItemDefinition = FindObject(L"/Game/Items/Weapons/BuildingTools/EditTool.EditTool"); - static UFortItemDefinition* BuildingItemData_Wall = FindObject(L"/Game/Items/Weapons/BuildingTools/BuildingItemData_Wall.BuildingItemData_Wall"); - static UFortItemDefinition* BuildingItemData_Floor = FindObject(L"/Game/Items/Weapons/BuildingTools/BuildingItemData_Floor.BuildingItemData_Floor"); - static UFortItemDefinition* BuildingItemData_Stair_W = FindObject(L"/Game/Items/Weapons/BuildingTools/BuildingItemData_Stair_W.BuildingItemData_Stair_W"); - static UFortItemDefinition* BuildingItemData_RoofS = FindObject(L"/Game/Items/Weapons/BuildingTools/BuildingItemData_RoofS.BuildingItemData_RoofS"); - static UFortItemDefinition* WoodItemData = FindObject(L"/Game/Items/ResourcePickups/WoodItemData.WoodItemData"); - static UFortItemDefinition* DamageTrap = FindObject(L"/Game/Athena/Items/Traps/TID_ContextTrap_Athena.TID_ContextTrap_Athena"); + auto& StartingItems = ((AFortGameModeAthena*)GameMode)->GetStartingItems(); WorldInventory->AddItem(PickaxeDefinition, nullptr); - WorldInventory->AddItem(EditToolItemDefinition, nullptr); - WorldInventory->AddItem(BuildingItemData_Wall, nullptr); - WorldInventory->AddItem(BuildingItemData_Floor, nullptr); - WorldInventory->AddItem(BuildingItemData_Stair_W, nullptr); - WorldInventory->AddItem(BuildingItemData_RoofS, nullptr); + + for (int i = 0; i < StartingItems.Num(); i++) + { + auto& StartingItem = StartingItems.at(i); + + WorldInventory->AddItem(StartingItem.GetItem(), nullptr, StartingItem.GetCount()); + } /* if (Globals::bLateGame) { @@ -142,12 +138,17 @@ APawn* AGameModeBase::SpawnDefaultPawnForHook(AGameModeBase* GameMode, AControll if (auto InventoryOverride = Cast(Mutator)) { auto TeamIndex = PlayerStateAthena->GetTeamIndex(); - auto LoadoutContainer = InventoryOverride->GetLoadoutContainerForTeamIndex(TeamIndex); + auto LoadoutTeam = InventoryOverride->GetLoadoutTeamForTeamIndex(TeamIndex); - for (int i = 0; i < LoadoutContainer.Loadout.Num(); i++) + if (LoadoutTeam.UpdateOverrideType == EAthenaInventorySpawnOverride::Always) { - auto& ItemAndCount = LoadoutContainer.Loadout.at(i); - WorldInventory->AddItem(ItemAndCount.GetItem(), nullptr, ItemAndCount.GetCount()); + auto LoadoutContainer = InventoryOverride->GetLoadoutContainerForTeamIndex(TeamIndex); + + for (int i = 0; i < LoadoutContainer.Loadout.Num(); i++) + { + auto& ItemAndCount = LoadoutContainer.Loadout.at(i); + WorldInventory->AddItem(ItemAndCount.GetItem(), nullptr, ItemAndCount.GetCount()); + } } } }; diff --git a/Project Reboot 3.0/GameplayStatics.cpp b/Project Reboot 3.0/GameplayStatics.cpp index 0d0fb8c..7d7e217 100644 --- a/Project Reboot 3.0/GameplayStatics.cpp +++ b/Project Reboot 3.0/GameplayStatics.cpp @@ -74,6 +74,43 @@ void UGameplayStatics::RemovePlayer(APlayerController* Player, bool bDestroyPawn defaultObj->ProcessEvent(fn, &UGameplayStatics_RemovePlayer_Params); } +AActor* UGameplayStatics::BeginDeferredActorSpawnFromClass(const UObject* WorldContextObject, UClass* ActorClass, const FTransform& SpawnTransform, ESpawnActorCollisionHandlingMethod CollisionHandlingOverride, AActor* Owner) +{ + static auto fn = FindObject("/Script/Engine.GameplayStatics.BeginDeferredActorSpawnFromClass"); + + struct + { + const UObject* WorldContextObject; // (ConstParm, Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + UClass* ActorClass; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, UObjectWrapper, HasGetValueTypeHash, NativeAccessSpecifierPublic) + FTransform SpawnTransform; // (ConstParm, Parm, OutParm, ReferenceParm, IsPlainOldData, NoDestructor, NativeAccessSpecifierPublic) + ESpawnActorCollisionHandlingMethod CollisionHandlingOverride; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + AActor* Owner; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + AActor* ReturnValue; // (Parm, OutParm, ZeroConstructor, ReturnParm, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + } UGameplayStatics_BeginDeferredActorSpawnFromClass_Params{ WorldContextObject, ActorClass, SpawnTransform, CollisionHandlingOverride, Owner }; + + static auto defaultObj = StaticClass(); + defaultObj->ProcessEvent(fn, &UGameplayStatics_BeginDeferredActorSpawnFromClass_Params); + + return UGameplayStatics_BeginDeferredActorSpawnFromClass_Params.ReturnValue; +} + +AActor* UGameplayStatics::FinishSpawningActor(AActor* Actor, const FTransform& SpawnTransform) +{ + static auto FinishSpawningActorFn = FindObject("/Script/Engine.GameplayStatics.FinishSpawningActor"); + + struct + { + AActor* Actor; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + FTransform SpawnTransform; // (ConstParm, Parm, OutParm, ReferenceParm, IsPlainOldData, NoDestructor, NativeAccessSpecifierPublic) + AActor* ReturnValue; // (Parm, OutParm, ZeroConstructor, ReturnParm, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + } UGameplayStatics_FinishSpawningActor_Params{ Actor, SpawnTransform }; + + static auto defaultObj = StaticClass(); + defaultObj->ProcessEvent(FinishSpawningActorFn, &UGameplayStatics_FinishSpawningActor_Params); + + return UGameplayStatics_FinishSpawningActor_Params.ReturnValue; +} + void UGameplayStatics::LoadStreamLevel(UObject* WorldContextObject, FName LevelName, bool bMakeVisibleAfterLoad, bool bShouldBlockOnLoad, const FLatentActionInfo& LatentInfo) { static auto LoadStreamLevelFn = FindObject("/Script/Engine.GameplayStatics.LoadStreamLevel"); diff --git a/Project Reboot 3.0/GameplayStatics.h b/Project Reboot 3.0/GameplayStatics.h index 2867eb9..f335c7a 100644 --- a/Project Reboot 3.0/GameplayStatics.h +++ b/Project Reboot 3.0/GameplayStatics.h @@ -4,6 +4,7 @@ #include "Array.h" #include "Actor.h" #include "LatentActionManager.h" +#include "EngineTypes.h" class UGameplayStatics : public UObject { @@ -22,6 +23,8 @@ public: // static void OpenLevel(UObject* WorldContextObject, FName LevelName, bool bAbsolute, const FString& Options); static void RemovePlayer(class APlayerController* Player, bool bDestroyPawn); + static AActor* FinishSpawningActor(AActor* Actor, const FTransform& SpawnTransform); + static AActor* BeginDeferredActorSpawnFromClass(const UObject* WorldContextObject, UClass* ActorClass, const FTransform& SpawnTransform, ESpawnActorCollisionHandlingMethod CollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::Undefined, AActor* Owner = nullptr); static void LoadStreamLevel(UObject* WorldContextObject, FName LevelName, bool bMakeVisibleAfterLoad, bool bShouldBlockOnLoad, const FLatentActionInfo& LatentInfo); static void UnloadStreamLevel(UObject* WorldContextObject, FName LevelName, const FLatentActionInfo& LatentInfo, bool bShouldBlockOnUnload); diff --git a/Project Reboot 3.0/Project Reboot 3.0.vcxproj b/Project Reboot 3.0/Project Reboot 3.0.vcxproj index 52fb3af..c05373d 100644 --- a/Project Reboot 3.0/Project Reboot 3.0.vcxproj +++ b/Project Reboot 3.0/Project Reboot 3.0.vcxproj @@ -178,6 +178,7 @@ + @@ -313,6 +314,8 @@ + + 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 b29bc1f..7982d95 100644 --- a/Project Reboot 3.0/Project Reboot 3.0.vcxproj.filters +++ b/Project Reboot 3.0/Project Reboot 3.0.vcxproj.filters @@ -262,6 +262,9 @@ FortniteGame\Source\FortniteGame\Private\Vehicles + + FortniteGame\Source\FortniteGame\Private\Building + @@ -832,6 +835,12 @@ FortniteGame\Source\FortniteGame\Public\Athena\Vehicle + + FortniteGame\Source\FortniteGame\Public\Mutators + + + FortniteGame\Source\FortniteGame\Public\Mutators + diff --git a/Project Reboot 3.0/addresses.cpp b/Project Reboot 3.0/addresses.cpp index c0b6491..15fde66 100644 --- a/Project Reboot 3.0/addresses.cpp +++ b/Project Reboot 3.0/addresses.cpp @@ -279,9 +279,6 @@ void Addresses::FindAll() LOG_INFO(LogDev, "Finding FreeArrayOfEntries"); Addresses::FreeArrayOfEntries = FindFreeArrayOfEntries(); - LOG_INFO(LogDev, "Finding ApplyHomebaseEffectsOnPlayerSetup"); - Addresses::FreeArrayOfEntries = FindApplyHomebaseEffectsOnPlayerSetup(); - LOG_INFO(LogDev, "Finished finding!"); } @@ -344,7 +341,6 @@ void Addresses::Print() LOG_INFO(LogDev, "EnterAircraft: 0x{:x}", EnterAircraft - Base); LOG_INFO(LogDev, "SetTimer: 0x{:x}", SetTimer - Base); LOG_INFO(LogDev, "PickupInitialize: 0x{:x}", PickupInitialize - Base); - LOG_INFO(LogDev, "ApplyHomebaseEffectsOnPlayerSetup: 0x{:x}", ApplyHomebaseEffectsOnPlayerSetup - Base); } void Offsets::FindAll() diff --git a/Project Reboot 3.0/addresses.h b/Project Reboot 3.0/addresses.h index 6036b11..8023a01 100644 --- a/Project Reboot 3.0/addresses.h +++ b/Project Reboot 3.0/addresses.h @@ -65,7 +65,6 @@ namespace Addresses extern inline uint64 PickupInitialize = 0; extern inline uint64 FreeEntry = 0; extern inline uint64 FreeArrayOfEntries = 0; - extern inline uint64 ApplyHomebaseEffectsOnPlayerSetup = 0; void SetupVersion(); // Finds Engine Version void FindAll(); diff --git a/Project Reboot 3.0/die.h b/Project Reboot 3.0/die.h index d710abd..48d6623 100644 --- a/Project Reboot 3.0/die.h +++ b/Project Reboot 3.0/die.h @@ -314,7 +314,8 @@ void ProcessEventHook(UObject* Object, UFunction* Function, void* Parameters) !strstr(FunctionFullName.c_str(), "Primitive_Structure_AmbAudioComponent") && !strstr(FunctionName.c_str(), "ServerTriggerCombatEvent") && !strstr(FunctionName.c_str(), "SpinCubeTimeline__UpdateFunc") && - !strstr(ObjectName.c_str(), "FortPhysicsObjectComponent")) + !strstr(ObjectName.c_str(), "FortPhysicsObjectComponent") && + !strstr(FunctionName.c_str(), "GetTextValue")) { LOG_INFO(LogDev, "Function called: {} with {}", FunctionFullName, ObjectName); } diff --git a/Project Reboot 3.0/dllmain.cpp b/Project Reboot 3.0/dllmain.cpp index b43528d..bee399f 100644 --- a/Project Reboot 3.0/dllmain.cpp +++ b/Project Reboot 3.0/dllmain.cpp @@ -720,7 +720,7 @@ DWORD WINAPI Main(LPVOID) uint64 ServerRemoveInventoryItemFunctionCallBeginFunctionAddr = 0; - if (Engine_Version >= 419) // Dude idk why but its getting the second ref kms + // if (Engine_Version >= 419) { std::vector ServerRemoveInventoryItemCallFunctionStarts = Engine_Version == 416 ? std::vector{ 0x44, 0x88, 0x4C } @@ -729,14 +729,13 @@ DWORD WINAPI Main(LPVOID) : std::vector{ 0x48, 0x89, 0x5C }; auto ServerRemoveInventoryItemCallFunctionCall = FindFunctionCall(L"ServerRemoveInventoryItem", ServerRemoveInventoryItemCallFunctionStarts); - auto ServerRemoveInventoryItemFunctionCallRef = Memcury::Scanner::FindPointerRef((PVOID)ServerRemoveInventoryItemCallFunctionCall, true); + auto ServerRemoveInventoryItemFunctionCallRef = Memcury::Scanner::FindPointerRef((PVOID)ServerRemoveInventoryItemCallFunctionCall, 0, true); LOG_INFO(LogDev, "ServerRemoveInventoryItemFunctionCallRef: 0x{:x}", ServerRemoveInventoryItemFunctionCallRef.Get() - __int64(GetModuleHandleW(0))); - uint64 ServerRemoveInventoryItemFunctionCallBeginFunctionAddr = 0; - for (int i = 0; i < 400; i++) { + // LOG_INFO(LogDev, "[{}] Bugha: 0x{:x}", i, (int)(*(uint8_t*)ServerRemoveInventoryItemFunctionCallRef.Get() - i)); if (*(uint8_t*)(uint8_t*)(ServerRemoveInventoryItemFunctionCallRef.Get() - i) == 0x48 && *(uint8_t*)(uint8_t*)(ServerRemoveInventoryItemFunctionCallRef.Get() - i + 1) == 0x89 && *(uint8_t*)(uint8_t*)(ServerRemoveInventoryItemFunctionCallRef.Get() - i + 2) == 0x5C) { ServerRemoveInventoryItemFunctionCallBeginFunctionAddr = ServerRemoveInventoryItemFunctionCallRef.Get() - i; @@ -750,10 +749,6 @@ DWORD WINAPI Main(LPVOID) } } } - else - { - - } Hooking::MinHook::Hook(Memcury::Scanner(ServerRemoveInventoryItemFunctionCallBeginFunctionAddr).GetAs(), UFortInventoryInterface::RemoveInventoryItemHook); @@ -767,11 +762,12 @@ DWORD WINAPI Main(LPVOID) AddVehicleHook(); - if (Fortnite_Version > 1.8 || Fortnite_Version == 1.11) + // if (Fortnite_Version > 1.8 || Fortnite_Version == 1.11) { + auto ClientOnPawnDiedCallAddr = FindFunctionCall(L"ClientOnPawnDied", Engine_Version == 416 ? std::vector{ 0x48, 0x89, 0x54 } : std::vector{ 0x48, 0x89, 0x5C }); LOG_INFO(LogDev, "ahh!"); - LOG_INFO(LogDev, "Test: 0x{:x}", FindFunctionCall(L"ClientOnPawnDied") - __int64(GetModuleHandleW(0))); - Hooking::MinHook::Hook((PVOID)FindFunctionCall(L"ClientOnPawnDied"), AFortPlayerController::ClientOnPawnDiedHook, (PVOID*)&AFortPlayerController::ClientOnPawnDiedOriginal); + LOG_INFO(LogDev, "ClientOnPawnDiedCallAddr: 0x{:x}", ClientOnPawnDiedCallAddr - __int64(GetModuleHandleW(0))); + Hooking::MinHook::Hook((PVOID)ClientOnPawnDiedCallAddr, AFortPlayerController::ClientOnPawnDiedHook, (PVOID*)&AFortPlayerController::ClientOnPawnDiedOriginal); } LOG_INFO(LogDev, "PredictionKeySize: 0x{:x} {}", PredictionKeySize, PredictionKeySize); @@ -793,8 +789,8 @@ DWORD WINAPI Main(LPVOID) MemberOffsets::FortPlayerPawnAthena::LastFallDistance = FindOffsetStruct("/Script/FortniteGame.FortPlayerPawnAthena", "LastFallDistance", false); MemberOffsets::FortPlayerStateAthena::DeathInfo = FindOffsetStruct("/Script/FortniteGame.FortPlayerStateAthena", "DeathInfo"); - MemberOffsets::FortPlayerStateAthena::KillScore = FindOffsetStruct("/Script/FortniteGame.FortPlayerStateAthena", "KillScore"); - MemberOffsets::FortPlayerStateAthena::TeamKillScore = FindOffsetStruct("/Script/FortniteGame.FortPlayerStateAthena", "TeamKillScore"); + MemberOffsets::FortPlayerStateAthena::KillScore = FindOffsetStruct("/Script/FortniteGame.FortPlayerStateAthena", "KillScore", false); + MemberOffsets::FortPlayerStateAthena::TeamKillScore = FindOffsetStruct("/Script/FortniteGame.FortPlayerStateAthena", "TeamKillScore", false); MemberOffsets::DeathInfo::bDBNO = FindOffsetStruct("/Script/FortniteGame.DeathInfo", "bDBNO"); MemberOffsets::DeathInfo::DeathCause = FindOffsetStruct("/Script/FortniteGame.DeathInfo", "DeathCause"); diff --git a/Project Reboot 3.0/finder.h b/Project Reboot 3.0/finder.h index e1645f2..1a43155 100644 --- a/Project Reboot 3.0/finder.h +++ b/Project Reboot 3.0/finder.h @@ -414,11 +414,6 @@ static inline uint64 FindIsNetRelevantForOffset() return 0; } -static inline uint64 FindApplyHomebaseEffectsOnPlayerSetup() -{ - return 0; -} - static inline uint64 FindActorChannelClose() { auto StringRef = Memcury::Scanner::FindStringRef(L"UActorChannel::Close: ChIndex: %d, Actor: %s"); @@ -1450,7 +1445,14 @@ static inline uint64 FindCanActivateAbility() static inline uint64 FindGiveAbilityAndActivateOnce() { if (Engine_Version == 426) - return Memcury::Scanner::FindPattern("48 89 5C 24 ? 48 89 74 24 ? 57 48 83 EC 40 49 8B 40 10 49 8B D8 48 8B FA 48 8B F1").Get(); + { + auto sig1 = Memcury::Scanner::FindPattern("48 89 5C 24 ? 48 89 74 24 ? 57 48 83 EC 40 49 8B 40 10 49 8B D8 48 8B FA 48 8B F1", false).Get(); + + if (!sig1) + sig1 = Memcury::Scanner::FindPattern("48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 48 83 EC 40 49 8B 40 10 49").Get(); // 15.50 + + return sig1; + } auto Addrr = Memcury::Scanner::FindStringRef(L"GiveAbilityAndActivateOnce called on ability %s on the client, not allowed!", true, 0, Engine_Version >= 500).Get(); @@ -1602,6 +1604,9 @@ static inline uint64 FindClearAbility() { auto GiveAbilityAndActivateOnce = FindGiveAbilityAndActivateOnce(); + if (!GiveAbilityAndActivateOnce) + return 0; + return Memcury::Scanner(GiveAbilityAndActivateOnce).ScanFor({ 0xE8 }, true, 4).RelativeOffset(1).Get(); if (Engine_Version == 416) diff --git a/Project Reboot 3.0/gui.h b/Project Reboot 3.0/gui.h index 407989f..76976f3 100644 --- a/Project Reboot 3.0/gui.h +++ b/Project Reboot 3.0/gui.h @@ -843,9 +843,12 @@ static inline void MainUI() else if (Tab == DEVELOPER_TAB) { static std::string ClassNameToDump; + static std::string FunctionNameToDump; ImGui::InputText("Class Name to mess with", &ClassNameToDump); + ImGui::InputText("Function Name to mess with", &FunctionNameToDump); + if (ImGui::Button("Print Class VFT")) { auto Class = FindObject(ClassNameToDump); @@ -861,6 +864,16 @@ static inline void MainUI() } } + if (ImGui::Button("Print Function Exec Addy")) + { + auto Function = FindObject(FunctionNameToDump); + + if (Function) + { + LOG_INFO(LogDev, "{} Exec: 0x{:x}", Function->GetName(), __int64(Function->GetFunc()) - __int64(GetModuleHandleW(0))); + } + } + /* if (ImGui::Button("Load BGA Class (and spawn so no GC)")) { static auto BGAClass = FindObject("/Script/Engine.BlueprintGeneratedClass"); diff --git a/Project Reboot 3.0/inc.h b/Project Reboot 3.0/inc.h index 982d984..cf097a8 100644 --- a/Project Reboot 3.0/inc.h +++ b/Project Reboot 3.0/inc.h @@ -54,5 +54,5 @@ inline bool AreVehicleWeaponsEnabled() inline bool IsRestartingSupported() { - return Engine_Version < 424; + return Engine_Version >= 419 && Engine_Version < 424; } \ No newline at end of file diff --git a/vendor/memcury.h b/vendor/memcury.h index b54286d..2b3cce9 100644 --- a/vendor/memcury.h +++ b/vendor/memcury.h @@ -777,6 +777,8 @@ { add = PE::Address(&scanBytes[i]); + // LOG_INFO(LogDev, "2add: 0x{:x}", add.Get() - __int64(GetModuleHandleW(0))); + if (bUseFirstResult) return Scanner(add); @@ -791,6 +793,8 @@ { add = PE::Address(&scanBytes[i]); + // LOG_INFO(LogDev, "1add: 0x{:x}", add.Get() - __int64(GetModuleHandleW(0))); + if (bUseFirstResult) return Scanner(add); @@ -847,7 +851,8 @@ { if constexpr (!bIsPtr) { - typedef T::value_type char_type; + // typedef T::value_type char_type; + using char_type = std::decay_t>; auto lea = stringAdd.GetAs(); @@ -1404,7 +1409,7 @@ } // Finds a string ref, then goes searches xref of the function that it's in and returns that address. - inline uintptr_t FindFunctionCall(const wchar_t* Name, const std::vector& Bytes = { 0x48, 0x89, 0x5C }, int skip = 0) // credit ender & me + inline uintptr_t FindFunctionCall(const wchar_t* Name, const std::vector& Bytes = std::vector{ 0x48, 0x89, 0x5C }, int skip = 0) // credit ender & me { auto FunctionPtr = Memcury::Scanner::FindStringRef(Name, true, skip).ScanFor({ 0x48, 0x8D, 0x0D }).RelativeOffset(3).GetAs();