diff --git a/Project Reboot 3.0/FortPlayerController.cpp b/Project Reboot 3.0/FortPlayerController.cpp index 2670daa..b2a3582 100644 --- a/Project Reboot 3.0/FortPlayerController.cpp +++ b/Project Reboot 3.0/FortPlayerController.cpp @@ -429,6 +429,9 @@ void AFortPlayerController::ServerAttemptInteractHook(UObject* Context, FFrame* static auto ReceivingActorOffset = FindOffsetStruct(StructName, "ReceivingActor"); auto ReceivingActor = *(AActor**)(__int64(Params) + ReceivingActorOffset); + static auto InteractionBeingAttemptedOffset = FindOffsetStruct(StructName, "InteractionBeingAttempted"); + auto InteractionBeingAttempted = *(EInteractionBeingAttempted*)(__int64(Params) + InteractionBeingAttemptedOffset); + // LOG_INFO(LogInteraction, "ReceivingActor: {}", __int64(ReceivingActor)); if (!ReceivingActor) @@ -549,83 +552,179 @@ void AFortPlayerController::ServerAttemptInteractHook(UObject* Context, FFrame* } else if (ReceivingActor->IsA(BuildingItemCollectorActorClass)) { - auto WorldInventory = PlayerController->GetWorldInventory(); - - if (!WorldInventory) - return ServerAttemptInteractOriginal(Context, Stack, Ret); - - auto ItemCollector = ReceivingActor; - static auto ActiveInputItemOffset = ItemCollector->GetOffset("ActiveInputItem"); - auto CurrentMaterial = ItemCollector->Get(ActiveInputItemOffset); // InteractType->OptionalObjectData - - if (!CurrentMaterial) - return ServerAttemptInteractOriginal(Context, Stack, Ret); - - int Index = 0; - - // this is a weird way of getting the current item collection we are on. - - static auto StoneItemData = FindObject(L"/Game/Items/ResourcePickups/StoneItemData.StoneItemData"); - static auto MetalItemData = FindObject(L"/Game/Items/ResourcePickups/MetalItemData.MetalItemData"); - - if (CurrentMaterial == StoneItemData) - Index = 1; - else if (CurrentMaterial == MetalItemData) - Index = 2; - - static auto ItemCollectionsOffset = ItemCollector->GetOffset("ItemCollections"); - auto& ItemCollections = ItemCollector->Get>(ItemCollectionsOffset); - - auto ItemCollection = ItemCollections.AtPtr(Index, FCollectorUnitInfo::GetPropertiesSize()); - - if (Fortnite_Version < 8.10) + if (Engine_Version >= 424 && Fortnite_Version < 15 && ReceivingActor->GetFullName().contains("Wumba")) { - auto Cost = ItemCollection->GetInputCount()->GetValue(); - - if (!CurrentMaterial) - return ServerAttemptInteractOriginal(Context, Stack, Ret); - - auto MatInstance = WorldInventory->FindItemInstance(CurrentMaterial); - - if (!MatInstance) - return ServerAttemptInteractOriginal(Context, Stack, Ret); - + bool bIsSidegrading = InteractionBeingAttempted == EInteractionBeingAttempted::SecondInteraction ? true : false; + + LOG_INFO(LogDev, "bIsSidegrading: {}", (bool)bIsSidegrading); + + struct FWeaponUpgradeItemRow + { + void* FTableRowBaseInheritance; + UFortWeaponItemDefinition* CurrentWeaponDef; // 0x8(0x8)(Edit, ZeroConstructor, DisableEditOnInstance, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + UFortWeaponItemDefinition* UpgradedWeaponDef; // 0x10(0x8)(Edit, ZeroConstructor, DisableEditOnInstance, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + EFortWeaponUpgradeCosts WoodCost; // 0x18(0x1)(Edit, ZeroConstructor, DisableEditOnInstance, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + EFortWeaponUpgradeCosts MetalCost; // 0x19(0x1)(Edit, ZeroConstructor, DisableEditOnInstance, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + EFortWeaponUpgradeCosts BrickCost; // 0x1A(0x1)(Edit, ZeroConstructor, DisableEditOnInstance, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + EFortWeaponUpgradeDirection Direction; + }; + + static auto WumbaDataTable = FindObject("/Game/Items/Datatables/AthenaWumbaData.AthenaWumbaData"); + + static auto LootPackagesRowMap = WumbaDataTable->GetRowMap(); + + auto Pawn = Cast(PlayerController->GetPawn()); + auto CurrentHeldWeapon = Pawn->GetCurrentWeapon(); + auto CurrentHeldWeaponDef = CurrentHeldWeapon->GetWeaponData(); + + auto Direction = bIsSidegrading ? EFortWeaponUpgradeDirection::Horizontal : EFortWeaponUpgradeDirection::Vertical; + + LOG_INFO(LogDev, "Direction: {}", (int)Direction); + + FWeaponUpgradeItemRow* FoundRow = nullptr; + + for (int i = 0; i < LootPackagesRowMap.Pairs.Elements.Data.Num(); i++) + { + auto& Pair = LootPackagesRowMap.Pairs.Elements.Data.at(i).ElementData.Value; + auto First = Pair.First; + auto Row = (FWeaponUpgradeItemRow*)Pair.Second; + + if (Row->CurrentWeaponDef == CurrentHeldWeaponDef && Row->Direction == Direction) + { + FoundRow = Row; + break; + } + } + + if (!FoundRow) + { + LOG_WARN(LogGame, "Failed to find row!"); + return; + } + + auto NewDefinition = FoundRow->UpgradedWeaponDef; + + LOG_INFO(LogDev, "UpgradedWeaponDef: {}", NewDefinition->GetFullName()); + + int WoodCost = (int)FoundRow->WoodCost * 50; + int StoneCost = (int)FoundRow->BrickCost * 50 - 400; + int MetalCost = (int)FoundRow->MetalCost * 50 - 200; + + if (bIsSidegrading) + { + WoodCost = 20; + StoneCost = 20; + MetalCost = 20; + } + + static auto WoodItemData = FindObject("/Game/Items/ResourcePickups/WoodItemData.WoodItemData"); + static auto StoneItemData = FindObject("/Game/Items/ResourcePickups/StoneItemData.StoneItemData"); + static auto MetalItemData = FindObject("/Game/Items/ResourcePickups/MetalItemData.MetalItemData"); + + auto WorldInventory = PlayerController->GetWorldInventory(); + + auto WoodInstance = WorldInventory->FindItemInstance(WoodItemData); + auto WoodCount = WoodInstance->GetItemEntry()->GetCount(); + + auto StoneInstance = WorldInventory->FindItemInstance(StoneItemData); + auto StoneCount = StoneInstance->GetItemEntry()->GetCount(); + + auto MetalInstance = WorldInventory->FindItemInstance(MetalItemData); + auto MetalCount = MetalInstance->GetItemEntry()->GetCount(); + bool bShouldUpdate = false; - - if (!WorldInventory->RemoveItem(MatInstance->GetItemEntry()->GetItemGuid(), &bShouldUpdate, Cost, true)) - return ServerAttemptInteractOriginal(Context, Stack, Ret); - + + WorldInventory->RemoveItem(WoodInstance->GetItemEntry()->GetItemGuid(), &bShouldUpdate, WoodCost); + WorldInventory->RemoveItem(StoneInstance->GetItemEntry()->GetItemGuid(), &bShouldUpdate, StoneCost); + WorldInventory->RemoveItem(MetalInstance->GetItemEntry()->GetItemGuid(), &bShouldUpdate, MetalCost); + + WorldInventory->RemoveItem(CurrentHeldWeapon->GetItemEntryGuid(), &bShouldUpdate, 1, true); + + WorldInventory->AddItem(NewDefinition, &bShouldUpdate); + if (bShouldUpdate) WorldInventory->Update(); } - - for (int z = 0; z < ItemCollection->GetOutputItemEntry()->Num(); z++) + else { - auto Entry = ItemCollection->GetOutputItemEntry()->AtPtr(z, FFortItemEntry::GetStructSize()); - - PickupCreateData CreateData; - CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(Entry->GetItemDefinition(), Entry->GetCount(), Entry->GetLoadedAmmo(), MAX_DURABILITY, Entry->GetLevel()); - CreateData.SpawnLocation = LocationToSpawnLoot; - CreateData.PawnOwner = PlayerController->GetMyFortPawn(); // hmm - CreateData.bShouldFreeItemEntryWhenDeconstructed = true; - - AFortPickup::SpawnPickup(CreateData); - } - - static auto bCurrentInteractionSuccessOffset = ItemCollector->GetOffset("bCurrentInteractionSuccess", false); - - if (bCurrentInteractionSuccessOffset != -1) - { - static auto bCurrentInteractionSuccessFieldMask = GetFieldMask(ItemCollector->GetProperty("bCurrentInteractionSuccess")); - ItemCollector->SetBitfieldValue(bCurrentInteractionSuccessOffset, bCurrentInteractionSuccessFieldMask, true); // idek if this is needed - } - - static auto DoVendDeath = FindObject(L"/Game/Athena/Items/Gameplay/VendingMachine/B_Athena_VendingMachine.B_Athena_VendingMachine_C.DoVendDeath"); - - if (DoVendDeath) - { - ItemCollector->ProcessEvent(DoVendDeath); - ItemCollector->K2_DestroyActor(); + auto WorldInventory = PlayerController->GetWorldInventory(); + + if (!WorldInventory) + return ServerAttemptInteractOriginal(Context, Stack, Ret); + + auto ItemCollector = ReceivingActor; + static auto ActiveInputItemOffset = ItemCollector->GetOffset("ActiveInputItem"); + auto CurrentMaterial = ItemCollector->Get(ActiveInputItemOffset); // InteractType->OptionalObjectData + + if (!CurrentMaterial) + return ServerAttemptInteractOriginal(Context, Stack, Ret); + + int Index = 0; + + // this is a weird way of getting the current item collection we are on. + + static auto StoneItemData = FindObject(L"/Game/Items/ResourcePickups/StoneItemData.StoneItemData"); + static auto MetalItemData = FindObject(L"/Game/Items/ResourcePickups/MetalItemData.MetalItemData"); + + if (CurrentMaterial == StoneItemData) + Index = 1; + else if (CurrentMaterial == MetalItemData) + Index = 2; + + static auto ItemCollectionsOffset = ItemCollector->GetOffset("ItemCollections"); + auto& ItemCollections = ItemCollector->Get>(ItemCollectionsOffset); + + auto ItemCollection = ItemCollections.AtPtr(Index, FCollectorUnitInfo::GetPropertiesSize()); + + if (Fortnite_Version < 8.10) + { + auto Cost = ItemCollection->GetInputCount()->GetValue(); + + if (!CurrentMaterial) + return ServerAttemptInteractOriginal(Context, Stack, Ret); + + auto MatInstance = WorldInventory->FindItemInstance(CurrentMaterial); + + if (!MatInstance) + return ServerAttemptInteractOriginal(Context, Stack, Ret); + + bool bShouldUpdate = false; + + if (!WorldInventory->RemoveItem(MatInstance->GetItemEntry()->GetItemGuid(), &bShouldUpdate, Cost, true)) + return ServerAttemptInteractOriginal(Context, Stack, Ret); + + if (bShouldUpdate) + WorldInventory->Update(); + } + + for (int z = 0; z < ItemCollection->GetOutputItemEntry()->Num(); z++) + { + auto Entry = ItemCollection->GetOutputItemEntry()->AtPtr(z, FFortItemEntry::GetStructSize()); + + PickupCreateData CreateData; + CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(Entry->GetItemDefinition(), Entry->GetCount(), Entry->GetLoadedAmmo(), MAX_DURABILITY, Entry->GetLevel()); + CreateData.SpawnLocation = LocationToSpawnLoot; + CreateData.PawnOwner = PlayerController->GetMyFortPawn(); // hmm + CreateData.bShouldFreeItemEntryWhenDeconstructed = true; + + AFortPickup::SpawnPickup(CreateData); + } + + static auto bCurrentInteractionSuccessOffset = ItemCollector->GetOffset("bCurrentInteractionSuccess", false); + + if (bCurrentInteractionSuccessOffset != -1) + { + static auto bCurrentInteractionSuccessFieldMask = GetFieldMask(ItemCollector->GetProperty("bCurrentInteractionSuccess")); + ItemCollector->SetBitfieldValue(bCurrentInteractionSuccessOffset, bCurrentInteractionSuccessFieldMask, true); // idek if this is needed + } + + static auto DoVendDeath = FindObject(L"/Game/Athena/Items/Gameplay/VendingMachine/B_Athena_VendingMachine.B_Athena_VendingMachine_C.DoVendDeath"); + + if (DoVendDeath) + { + ItemCollector->ProcessEvent(DoVendDeath); + ItemCollector->K2_DestroyActor(); + } } } @@ -1692,4 +1791,4 @@ void AFortPlayerController::ServerEndEditingBuildingActorHook(AFortPlayerControl EditTool->GetEditActor() = nullptr; EditTool->OnRep_EditActor(); } -} \ No newline at end of file +} diff --git a/Project Reboot 3.0/FortPlayerController.h b/Project Reboot 3.0/FortPlayerController.h index 9458e0c..bd7599c 100644 --- a/Project Reboot 3.0/FortPlayerController.h +++ b/Project Reboot 3.0/FortPlayerController.h @@ -40,6 +40,55 @@ struct FFortAthenaLoadout } }; +enum class EFortWeaponUpgradeCosts : uint8_t +{ + NotSet = 0, + WoodUncommon = 1, + WoodRare = 2, + WoodVeryRare = 3, + WoodSuperRare = 4, + MetalUncommon = 5, + MetalRare = 6, + MetalVeryRare = 7, + MetalSuperRare = 8, + BrickUncommon = 9, + BrickRare = 10, + BrickVeryRare = 11, + BrickSuperRare = 12, + HorizontalWoodCommon = 13, + HorizontalWoodUncommon = 14, + HorizontalWoodRare = 15, + HorizontalWoodVeryRare = 16, + HorizontalWoodSuperRare = 17, + HorizontalMetalCommon = 18, + HorizontalMetalUncommon = 19, + HorizontalMetalRare = 20, + HorizontalMetalVeryRare = 21, + HorizontalMetalSuperRare = 22, + HorizontalBrickCommon = 23, + HorizontalBrickUncommon = 24, + HorizontalBrickRare = 25, + HorizontalBrickVeryRare = 26, + HorizontalBrickSuperRare = 27, + EFortWeaponUpgradeCosts_MAX = 28, +}; + +enum class EFortWeaponUpgradeDirection : uint8 +{ + NotSet = 0, + Vertical = 1, + Horizontal = 2, + EFortWeaponUpgradeDirection_MAX = 3, +}; + +enum class EInteractionBeingAttempted : uint8 +{ + FirstInteraction = 0, + SecondInteraction = 1, + AllInteraction = 2, + EInteractionBeingAttempted_MAX = 3, +}; + class AFortPlayerController : public APlayerController { public: @@ -169,4 +218,4 @@ public: static auto Class = FindObject("/Script/FortniteGame.FortPlayerController"); return Class; } -}; \ No newline at end of file +};