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();