From b64f5695515fc74d093e9e74a7d19a3f1fa7601a Mon Sep 17 00:00:00 2001 From: Milxnor Date: Mon, 8 May 2023 22:28:32 -0400 Subject: [PATCH] a bit proper vending machines like fully, performance --- Project Reboot 3.0/Array.h | 39 ++++- Project Reboot 3.0/BGA.h | 2 +- Project Reboot 3.0/BuildingContainer.cpp | 2 +- Project Reboot 3.0/FortAthenaSupplyDrop.cpp | 1 + Project Reboot 3.0/FortGameModeAthena.cpp | 4 +- Project Reboot 3.0/FortInventory.cpp | 9 +- Project Reboot 3.0/FortItem.cpp | 3 +- Project Reboot 3.0/FortItem.h | 10 +- Project Reboot 3.0/FortKismetLibrary.cpp | 6 +- Project Reboot 3.0/FortLootPackage.cpp | 78 ++-------- Project Reboot 3.0/FortLootPackage.h | 70 ++++++++- Project Reboot 3.0/FortPickup.cpp | 67 +++++++++ Project Reboot 3.0/FortPickup.h | 14 ++ Project Reboot 3.0/FortPlayerController.cpp | 71 +-------- Project Reboot 3.0/Project Reboot 3.0.vcxproj | 1 + .../Project Reboot 3.0.vcxproj.filters | 7 +- Project Reboot 3.0/addresses.cpp | 2 + Project Reboot 3.0/bots.h | 45 ++++-- Project Reboot 3.0/commands.h | 3 +- Project Reboot 3.0/inc.cpp | 20 +++ Project Reboot 3.0/inc.h | 25 +++- Project Reboot 3.0/vendingmachine.h | 141 +++++++++++------- 22 files changed, 399 insertions(+), 221 deletions(-) create mode 100644 Project Reboot 3.0/inc.cpp diff --git a/Project Reboot 3.0/Array.h b/Project Reboot 3.0/Array.h index 1e68ace..b5b1200 100644 --- a/Project Reboot 3.0/Array.h +++ b/Project Reboot 3.0/Array.h @@ -71,15 +71,31 @@ public: ArrayMax = v3; } - int AddUnitialized2(SIZE_T NumBytesPerElement = sizeof(InElementType)) + void RefitArray(SIZE_T NumBytesPerElement = sizeof(InElementType)) + { + auto newNum = ArrayNum; + + // newNum = FMemory::QuantizeSize(NumBytesPerElement * newNum, 0) >> 4 + + ArrayMax = newNum; + + if (Data || ArrayNum) + { + Data = false ? (InElementType*)VirtualAlloc(0, newNum * NumBytesPerElement, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE) : + (InElementType*)FMemory::Realloc(Data, newNum * NumBytesPerElement, 0); + } + } + + int AddUninitialized2(SIZE_T NumBytesPerElement = sizeof(InElementType)) { const int OldArrayNum = ArrayNum; ArrayNum = OldArrayNum + 1; - if (ArrayNum > ArrayMax) + if (OldArrayNum + 1 > ArrayMax) { - ResizeArray(ArrayNum, NumBytesPerElement); + RefitArray(NumBytesPerElement); + // ResizeArray(ArrayNum, NumBytesPerElement); } return OldArrayNum; @@ -87,7 +103,7 @@ public: void CopyFromArray(TArray& OtherArray, SIZE_T NumBytesPerElement = sizeof(InElementType)) { - if (!OtherArray.ArrayNum && !ArrayMax) + if (!OtherArray.ArrayNum && !ArrayMax) // so if the new array has nothing, and we currently have nothing allocated, then we can just return { ArrayMax = 0; return; @@ -235,7 +251,7 @@ public: ArrayMax = ArrayNum; // CalculateSlackGrow(/* ArrayNum */ OldNum, ArrayMax, Size); // AllocatorInstance.ResizeAllocation(OldNum, ArrayMax, sizeof(ElementType)); // LOG_INFO(LogMemory, "ArrayMax: {} Size: {}", ArrayMax, Size); - Data = (InElementType*)FMemory::Realloc(Data, ArrayMax * Size, 0); + Data = (InElementType*)FMemory::Realloc(Data, ArrayNum * Size, 0); } FORCEINLINE int32 AddUninitialized(int32 Count = 1, size_t Size = sizeof(InElementType)) @@ -308,10 +324,17 @@ public: void FreeGood(SizeType Size = sizeof(InElementType)) { - static void (*FreeOriginal)(void* Original) = decltype(FreeOriginal)(Addresses::Free); + if (true) + { + static void (*FreeOriginal)(void* Original) = decltype(FreeOriginal)(Addresses::Free); - if (FreeOriginal) - FreeOriginal(Data); + if (FreeOriginal) + FreeOriginal(Data); + } + else + { + VirtualFree(Data, 0, MEM_RELEASE); + } Data = nullptr; ArrayNum = 0; diff --git a/Project Reboot 3.0/BGA.h b/Project Reboot 3.0/BGA.h index a760702..23e09f3 100644 --- a/Project Reboot 3.0/BGA.h +++ b/Project Reboot 3.0/BGA.h @@ -43,7 +43,7 @@ static inline void SpawnBGAs() // hahah not "proper", there's a function that we static auto SpawnLootTierGroupOffset = BGAConsumableSpawner->GetOffset("SpawnLootTierGroup"); auto& SpawnLootTierGroup = BGAConsumableSpawner->Get(SpawnLootTierGroupOffset); - auto LootDrops = PickLootDrops(SpawnLootTierGroup, false); + auto LootDrops = PickLootDrops(SpawnLootTierGroup); for (int z = 0; z < LootDrops.size(); z++) { diff --git a/Project Reboot 3.0/BuildingContainer.cpp b/Project Reboot 3.0/BuildingContainer.cpp index 1ac59d4..53deb19 100644 --- a/Project Reboot 3.0/BuildingContainer.cpp +++ b/Project Reboot 3.0/BuildingContainer.cpp @@ -14,7 +14,7 @@ bool ABuildingContainer::SpawnLoot(AFortPawn* Pawn) // LOG_INFO(LogInteraction, "RedirectedLootTier: {}", RedirectedLootTier.ToString()); - auto LootDrops = PickLootDrops(RedirectedLootTier, bDebugPrintLooting); + auto LootDrops = PickLootDrops(RedirectedLootTier, -1, bDebugPrintLooting); // LOG_INFO(LogInteraction, "LootDrops.size(): {}", LootDrops.size()); diff --git a/Project Reboot 3.0/FortAthenaSupplyDrop.cpp b/Project Reboot 3.0/FortAthenaSupplyDrop.cpp index 73d2bd9..63abf29 100644 --- a/Project Reboot 3.0/FortAthenaSupplyDrop.cpp +++ b/Project Reboot 3.0/FortAthenaSupplyDrop.cpp @@ -79,6 +79,7 @@ AFortPickup* AFortAthenaSupplyDrop::SpawnPickupHook(UObject* Context, FFrame& St CreateData.SpawnLocation = Position; CreateData.PawnOwner = TriggeringPawn; CreateData.Source = EFortPickupSpawnSource::GetSupplyDropValue(); + CreateData.bShouldFreeItemEntryWhenDeconstructed = true; *Ret = AFortPickup::SpawnPickup(CreateData); return *Ret; diff --git a/Project Reboot 3.0/FortGameModeAthena.cpp b/Project Reboot 3.0/FortGameModeAthena.cpp index a9779bd..9c38f29 100644 --- a/Project Reboot 3.0/FortGameModeAthena.cpp +++ b/Project Reboot 3.0/FortGameModeAthena.cpp @@ -968,7 +968,7 @@ void AFortGameModeAthena::Athena_HandleStartingNewPlayerHook(AFortGameModeAthena auto Location = CurrentActor->GetActorLocation(); Location.Z += UpZ; - std::vector LootDrops = PickLootDrops(SpawnIslandTierGroup, bPrintWarmup); + std::vector LootDrops = PickLootDrops(SpawnIslandTierGroup, -1, bPrintWarmup); for (auto& LootDrop : LootDrops) { @@ -998,7 +998,7 @@ void AFortGameModeAthena::Athena_HandleStartingNewPlayerHook(AFortGameModeAthena auto Location = CurrentActor->GetActorLocation(); Location.Z += UpZ; - std::vector LootDrops = PickLootDrops(BRIslandTierGroup, bPrint); + std::vector LootDrops = PickLootDrops(BRIslandTierGroup, -1, bPrint); for (auto& LootDrop : LootDrops) { diff --git a/Project Reboot 3.0/FortInventory.cpp b/Project Reboot 3.0/FortInventory.cpp index 5b42df8..5817c21 100644 --- a/Project Reboot 3.0/FortInventory.cpp +++ b/Project Reboot 3.0/FortInventory.cpp @@ -115,6 +115,7 @@ std::pair, std::vector> AFortInventory::AddI CreateData.SpawnLocation = Pawn->GetActorLocation(); CreateData.PawnOwner = Cast(Pawn); CreateData.SourceType = EFortPickupSourceTypeFlag::GetPlayerValue(); + CreateData.bShouldFreeItemEntryWhenDeconstructed = true; AFortPickup::SpawnPickup(CreateData); return std::make_pair(NewItemInstances, ModifiedItemInstances); @@ -238,7 +239,13 @@ std::pair, std::vector> AFortInventory::AddI auto ItemEntry = FFortItemEntry::MakeItemEntry(ItemDefinition, Count, LoadedAmmo); auto Ret = AddItem(ItemEntry, bShouldUpdate, bShowItemToast); - // VirtualFree(ItemEntry); + + if (!bUseFMemoryRealloc) + { + FFortItemEntry::FreeItemEntry(ItemEntry); + VirtualFree(ItemEntry, 0, MEM_RELEASE); + } + return Ret; } diff --git a/Project Reboot 3.0/FortItem.cpp b/Project Reboot 3.0/FortItem.cpp index af55850..c2b34fa 100644 --- a/Project Reboot 3.0/FortItem.cpp +++ b/Project Reboot 3.0/FortItem.cpp @@ -14,7 +14,7 @@ void FFortItemEntry::SetStateValue(EFortItemEntryState StateType, int IntValue) } } - auto idx = GetStateValues().AddUnitialized2(FFortItemEntryStateValue::GetStructSize()); + auto idx = GetStateValues().AddUninitialized2(FFortItemEntryStateValue::GetStructSize()); // AddUninitialized? GetStateValues().AtPtr(idx, FFortItemEntryStateValue::GetStructSize())->GetIntValue() = IntValue; GetStateValues().AtPtr(idx, FFortItemEntryStateValue::GetStructSize())->GetStateType() = StateType; @@ -27,7 +27,6 @@ void FFortItemEntry::SetStateValue(EFortItemEntryState StateType, int IntValue) FFortItemEntry* FFortItemEntry::MakeItemEntry(UFortItemDefinition* ItemDefinition, int Count, int LoadedAmmo, float Durability) { - bool bUseFMemoryRealloc = false; // I don't think this works because sometimes we don't free it (oops). auto Entry = Alloc(GetStructSize(), bUseFMemoryRealloc); if (!Entry) diff --git a/Project Reboot 3.0/FortItem.h b/Project Reboot 3.0/FortItem.h index 0cf743a..718ea79 100644 --- a/Project Reboot 3.0/FortItem.h +++ b/Project Reboot 3.0/FortItem.h @@ -8,6 +8,8 @@ #include "reboot.h" +constexpr inline bool bUseFMemoryRealloc = false; // This is for allocating our own Item entries, I don't know why this doesn't work + enum class EFortItemEntryState : uint8_t // this changes but its fineee { NoneState = 0, @@ -32,7 +34,7 @@ struct FFortItemEntryStateValue { static UStruct* GetStruct() { - static auto Struct = FindObject("/Script/FortniteGame.FortItemEntryStateValue"); + static auto Struct = FindObject(L"/Script/FortniteGame.FortItemEntryStateValue"); return Struct; } @@ -161,10 +163,10 @@ struct FFortItemEntry : FFastArraySerializerItem if (GenericAttributeValuesOffset != -1) { - this->GetGenericAttributeValues().CopyFromArray(OtherItemEntry->GetGenericAttributeValues()); + // this->GetGenericAttributeValues().CopyFromArray(OtherItemEntry->GetGenericAttributeValues()); } - this->GetStateValues().CopyFromArray(OtherItemEntry->GetStateValues(), FFortItemEntryStateValue::GetStructSize()); + // this->GetStateValues().CopyFromArray(OtherItemEntry->GetStateValues(), FFortItemEntryStateValue::GetStructSize()); // broooooooooooooooooooo // should we do this? @@ -177,7 +179,7 @@ struct FFortItemEntry : FFastArraySerializerItem static UStruct* GetStruct() { - static auto Struct = FindObject("/Script/FortniteGame.FortItemEntry"); + static auto Struct = FindObject(L"/Script/FortniteGame.FortItemEntry"); return Struct; } diff --git a/Project Reboot 3.0/FortKismetLibrary.cpp b/Project Reboot 3.0/FortKismetLibrary.cpp index 08bbb4d..57603b3 100644 --- a/Project Reboot 3.0/FortKismetLibrary.cpp +++ b/Project Reboot 3.0/FortKismetLibrary.cpp @@ -140,6 +140,8 @@ void UFortKismetLibrary::SpawnItemVariantPickupInWorldHook(UObject* Context, FFr CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(ItemDefinition, ParamsPtr->GetNumberToSpawn(), -1); CreateData.SourceType = ParamsPtr->GetSourceType(); CreateData.Source = ParamsPtr->GetSource(); + CreateData.bShouldFreeItemEntryWhenDeconstructed = true; + auto Pickup = AFortPickup::SpawnPickup(CreateData); return SpawnItemVariantPickupInWorldOriginal(Context, Stack, Ret); @@ -228,6 +230,7 @@ void UFortKismetLibrary::CreateTossAmmoPickupForWeaponItemDefinitionAtLocationHo CreateData.SourceType = SourceTypeFlag; CreateData.Source = SpawnSource; CreateData.SpawnLocation = Location; + CreateData.bShouldFreeItemEntryWhenDeconstructed = true; auto AmmoPickup = AFortPickup::SpawnPickup(CreateData); @@ -511,6 +514,7 @@ AFortPickup* UFortKismetLibrary::K2_SpawnPickupInWorldWithClassHook(UObject* Con CreateData.OverrideClass = PickupClass; CreateData.bToss = bToss; CreateData.bRandomRotation = bRandomRotation; + CreateData.bShouldFreeItemEntryWhenDeconstructed = true; auto NewPickup = AFortPickup::SpawnPickup(CreateData); @@ -597,7 +601,7 @@ bool UFortKismetLibrary::PickLootDropsHook(UObject* Context, FFrame& Stack, bool LOG_INFO(LogDev, "Picking loot for {}.", TierGroupName.ComparisonIndex.Value ? TierGroupName.ToString() : "InvalidName"); - auto LootDrops = PickLootDrops(TierGroupName, true); + auto LootDrops = PickLootDrops(TierGroupName, -1, true); for (int i = 0; i < LootDrops.size(); i++) { diff --git a/Project Reboot 3.0/FortLootPackage.cpp b/Project Reboot 3.0/FortLootPackage.cpp index 2e9712c..6bb1324 100644 --- a/Project Reboot 3.0/FortLootPackage.cpp +++ b/Project Reboot 3.0/FortLootPackage.cpp @@ -7,10 +7,6 @@ #include "GameplayTagContainer.h" #include "FortGameModeAthena.h" -#include -#include -#include - struct FFortGameFeatureLootTableData { TSoftObjectPtr LootTierData; @@ -18,10 +14,6 @@ struct FFortGameFeatureLootTableData }; #ifdef EXPERIMENTAL_LOOTING -float RandomFloatForLoot(float AllWeightsSum) -{ - return (rand() * 0.000030518509) * AllWeightsSum; -} template void CollectDataTablesRows(std::vector DataTables, std::map* OutMap, std::function Check = []() { return true; }) @@ -59,54 +51,6 @@ void CollectDataTablesRows(std::vector DataTables, std::map -static T* PickWeightedElement(const std::map& Elements, std::function GetWeightFn, float TotalWeightParam = -1, bool bCheckIfWeightIsZero = false, int RandMultiplier = 1, FName* OutName = nullptr, bool bPrint = false) -{ - float TotalWeight = TotalWeightParam; - - if (TotalWeight == -1) - { - TotalWeight = std::accumulate(Elements.begin(), Elements.end(), 0.0f, [&](float acc, const std::pair& p) { - auto Weight = GetWeightFn(p.second); - - if (bPrint && Weight != 0) - { - LOG_INFO(LogLoot, "Adding weight: {}", Weight); - } - - return acc + Weight; - }); - } - - float RandomNumber = // UKismetMathLibrary::RandomFloatInRange(0, TotalWeight); - RandMultiplier * RandomFloatForLoot(TotalWeight); - - if (bPrint) - { - LOG_INFO(LogLoot, "RandomNumber: {} TotalWeight: {}", RandomNumber, TotalWeight); - } - - for (auto& Element : Elements) - { - float Weight = GetWeightFn(Element.second); - - if (bCheckIfWeightIsZero && Weight == 0) - continue; - - if (RandomNumber <= Weight) - { - if (OutName) - *OutName = Element.first; - - return Element.second; - } - - RandomNumber -= Weight; - } - - return nullptr; -} - int GetItemLevel(const FDataTableCategoryHandle& LootLevelData, int WorldLevel) { return 0; @@ -200,18 +144,20 @@ float GetAmountOfLootPackagesToDrop(FFortLootTierData* LootTierData, int Origina FFortLootTierData* PickLootTierData(const std::vector& LTDTables, FName LootTierGroup, int WorldLevel = 0, int ForcedLootTier = -1, FName* OutRowName = nullptr) // Fortnite returns the row name and then finds the tier data again, but I really don't see the point of this. { + // This like isn't right, at all. + float LootTier = ForcedLootTier; if (LootTier == -1) { - LootTier = 0; + // LootTier = 0; } else { // buncha code im too lazy to reverse } - LootTier = 1; // ONG PROPER + // IDIakuuyg8712u091fj120gvik // if (fabs(LootTier) <= 0.0000000099999999) // return 0; @@ -219,7 +165,7 @@ FFortLootTierData* PickLootTierData(const std::vector& LTDTables, F std::map TierGroupLTDs; CollectDataTablesRows(LTDTables, &TierGroupLTDs, [&](FName RowName, FFortLootTierData* TierData) -> bool { - if (LootTierGroup == TierData->GetTierGroup()) + if (LootTierGroup == TierData->GetTierGroup() && (LootTier == -1 ? true : LootTier == TierData->GetLootTier())) { return true; } @@ -227,9 +173,9 @@ FFortLootTierData* PickLootTierData(const std::vector& LTDTables, F return false; }); - FFortLootTierData* ChosenRowLootTierData = PickWeightedElement(TierGroupLTDs, - [](FFortLootTierData* LootTierData) -> float { return LootTierData->GetWeight(); }, -1, - true, LootTier, OutRowName); + FFortLootTierData* ChosenRowLootTierData = PickWeightedElement(TierGroupLTDs, + [](FFortLootTierData* LootTierData) -> float { return LootTierData->GetWeight(); }, RandomFloatForLoot, -1, + true, LootTier == -1 ? 1 : LootTier, OutRowName); if (!ChosenRowLootTierData) return nullptr; @@ -274,8 +220,8 @@ void PickLootDropsFromLootPackage(const std::vector& LPTables, cons } FName PickedPackageRowName; - FFortLootPackageData* PickedPackage = PickWeightedElement(LootPackageIDMap, - [](FFortLootPackageData* LootPackageData) -> float { return LootPackageData->GetWeight(); }, + FFortLootPackageData* PickedPackage = PickWeightedElement(LootPackageIDMap, + [](FFortLootPackageData* LootPackageData) -> float { return LootPackageData->GetWeight(); }, RandomFloatForLoot, -1, true, 1, &PickedPackageRowName, bPrint); if (!PickedPackage) @@ -377,7 +323,7 @@ void PickLootDropsFromLootPackage(const std::vector& LPTables, cons } } -std::vector PickLootDrops(FName TierGroupName, bool bPrint, int recursive) +std::vector PickLootDrops(FName TierGroupName, int ForcedLootTier, bool bPrint, int recursive) { std::vector LootDrops; @@ -659,7 +605,7 @@ std::vector PickLootDrops(FName TierGroupName, bool bPrint, int recurs } FName LootTierRowName; - auto ChosenRowLootTierData = PickLootTierData(LTDTables, TierGroupName, 0, -1, &LootTierRowName); + auto ChosenRowLootTierData = PickLootTierData(LTDTables, TierGroupName, 0, ForcedLootTier, &LootTierRowName); if (!ChosenRowLootTierData) { diff --git a/Project Reboot 3.0/FortLootPackage.h b/Project Reboot 3.0/FortLootPackage.h index e32aaff..6e0d8df 100644 --- a/Project Reboot 3.0/FortLootPackage.h +++ b/Project Reboot 3.0/FortLootPackage.h @@ -1,6 +1,9 @@ #pragma once #include +#include +#include +#include #include "Array.h" #include "FortWorldItemDefinition.h" @@ -70,6 +73,12 @@ public: return *(FName*)(__int64(this) + TierGroupOffset); } + int& GetLootTier() + { + static auto LootTierOffset = FindOffsetStruct("/Script/FortniteGame.FortLootTierData", "LootTier"); + return *(int*)(__int64(this) + LootTierOffset); + } + float& GetWeight() { static auto WeightOffset = FindOffsetStruct("/Script/FortniteGame.FortLootTierData", "Weight"); @@ -115,4 +124,63 @@ struct LootDrop } }; -std::vector PickLootDrops(FName TierGroupName, bool bPrint = false, int recursive = 0); \ No newline at end of file +static inline float RandomFloatForLoot(float AllWeightsSum) +{ + return (rand() * 0.000030518509) * AllWeightsSum; +} + +template +FORCEINLINE static ValueType PickWeightedElement(const std::map& Elements, + std::function GetWeightFn, + std::function RandomFloatGenerator = RandomFloatForLoot, + float TotalWeightParam = -1, bool bCheckIfWeightIsZero = false, int RandMultiplier = 1, KeyType* OutName = nullptr, bool bPrint = false, bool bKeepGoingUntilWeGetValue = false) +{ + float TotalWeight = TotalWeightParam; + + if (TotalWeight == -1) + { + TotalWeight = std::accumulate(Elements.begin(), Elements.end(), 0.0f, [&](float acc, const std::pair& p) { + auto Weight = GetWeightFn(p.second); + + if (bPrint && Weight != 0) + { + LOG_INFO(LogLoot, "Adding weight: {}", Weight); + } + + return acc + Weight; + }); + } + + float RandomNumber = // UKismetMathLibrary::RandomFloatInRange(0, TotalWeight); + RandMultiplier * RandomFloatGenerator(TotalWeight); + + if (bPrint) + { + LOG_INFO(LogLoot, "RandomNumber: {} TotalWeight: {}", RandomNumber, TotalWeight); + } + + for (auto& Element : Elements) + { + float Weight = GetWeightFn(Element.second); + + if (bCheckIfWeightIsZero && Weight == 0) + continue; + + if (RandomNumber <= Weight) + { + if (OutName) + *OutName = Element.first; + + return Element.second; + } + + RandomNumber -= Weight; + } + + if (bKeepGoingUntilWeGetValue) + return PickWeightedElement(Elements, GetWeightFn, RandomFloatGenerator, TotalWeightParam, bCheckIfWeightIsZero, RandMultiplier, OutName, bPrint, bKeepGoingUntilWeGetValue); + + return ValueType(); +} + +std::vector PickLootDrops(FName TierGroupName, int ForcedLootTier = -1, bool bPrint = false, int recursive = 0); \ No newline at end of file diff --git a/Project Reboot 3.0/FortPickup.cpp b/Project Reboot 3.0/FortPickup.cpp index 29fdd5b..d20aa05 100644 --- a/Project Reboot 3.0/FortPickup.cpp +++ b/Project Reboot 3.0/FortPickup.cpp @@ -78,6 +78,72 @@ AFortPickup* AFortPickup::SpawnPickup(PickupCreateData& PickupData) PrimaryPickupItemEntry->CopyFromAnotherItemEntry(PickupData.ItemEntry); } + if (false && PlayerState) + { + if (auto GadgetItemDefinition = Cast(PrimaryPickupItemEntry->GetItemDefinition())) + { + auto ASC = PlayerState->GetAbilitySystemComponent(); + + if (GadgetItemDefinition->GetTrackedAttributes().Num() > 0) + { + PrimaryPickupItemEntry->SetStateValue(EFortItemEntryState::GenericAttributeValueSet, 1); + } + + std::vector AttributeValueVector; + + for (int i = 0; i < GadgetItemDefinition->GetTrackedAttributes().Num(); i++) + { + auto& CurrentTrackedAttribute = GadgetItemDefinition->GetTrackedAttributes().at(i); + + // LOG_INFO(LogDev, "[{}] TrackedAttribute Attribute Property Name {}", i, GadgetItemDefinition->GetTrackedAttributes().at(i).GetAttributePropertyName()); + // LOG_INFO(LogDev, "[{}] TrackedAttribute Attribute Name {}", i, GadgetItemDefinition->GetTrackedAttributes().at(i).GetAttributeName()); + // LOG_INFO(LogDev, "[{}] TrackedAttribute Attribute Owner {}", i, GadgetItemDefinition->GetTrackedAttributes().at(i).AttributeOwner->GetPathName()); + + if (!ASC) + break; + + int CurrentAttributeValue = -1; + + for (int i = 0; i < ASC->GetSpawnedAttributes().Num(); i++) + { + auto CurrentSpawnedAttribute = ASC->GetSpawnedAttributes().at(i); + + if (CurrentSpawnedAttribute->IsA(CurrentTrackedAttribute.AttributeOwner)) + { + auto PropertyOffset = CurrentSpawnedAttribute->GetOffset(CurrentTrackedAttribute.GetAttributePropertyName()); + + if (PropertyOffset != -1) + { + CurrentAttributeValue = CurrentSpawnedAttribute->GetPtr(PropertyOffset)->GetCurrentValue(); + break; // hm + } + } + } + + // LOG_INFO(LogDev, "CurrentAttributeValue: {}", CurrentAttributeValue); + + if (CurrentAttributeValue != -1) // Found the attribute. + { + // im so smart + + AttributeValueVector.push_back(CurrentAttributeValue); + } + } + + for (int z = 0; z < PrimaryPickupItemEntry->GetGenericAttributeValues().Num(); z++) // First value must be the current value // dont ask me why fortnite keeps the old values in it too.. + { + AttributeValueVector.push_back(PrimaryPickupItemEntry->GetGenericAttributeValues().at(z)); + } + + PrimaryPickupItemEntry->GetGenericAttributeValues().Free(); + + for (auto& AttributeValue : AttributeValueVector) + { + // ReplicatedEntry->GetGenericAttributeValues().Add(AttributeValue); + } + } + } + static auto PickupSourceTypeFlagsOffset = Pickup->GetOffset("PickupSourceTypeFlags", false); if (PickupSourceTypeFlagsOffset != -1) @@ -209,6 +275,7 @@ void AFortPickup::CombinePickupHook(AFortPickup* Pickup) CreateData.PawnOwner = ItemOwner; CreateData.SourceType = EFortPickupSourceTypeFlag::GetPlayerValue(); CreateData.IgnoreCombineTarget = PickupToCombineInto; + CreateData.bShouldFreeItemEntryWhenDeconstructed = true; auto NewOverStackPickup = AFortPickup::SpawnPickup(CreateData); } diff --git a/Project Reboot 3.0/FortPickup.h b/Project Reboot 3.0/FortPickup.h index 3c1283d..2cb071b 100644 --- a/Project Reboot 3.0/FortPickup.h +++ b/Project Reboot 3.0/FortPickup.h @@ -83,6 +83,20 @@ struct PickupCreateData if (bShouldFreeItemEntryWhenDeconstructed) { // real + + FFortItemEntry::FreeItemEntry(ItemEntry); + + if (bUseFMemoryRealloc) + { + static void (*FreeOriginal)(void* Original) = decltype(FreeOriginal)(Addresses::Free); + + if (FreeOriginal) + FreeOriginal(ItemEntry); + } + else + { + VirtualFree(ItemEntry, 0, MEM_RELEASE); + } } } }; diff --git a/Project Reboot 3.0/FortPlayerController.cpp b/Project Reboot 3.0/FortPlayerController.cpp index b0c920b..2650e4b 100644 --- a/Project Reboot 3.0/FortPlayerController.cpp +++ b/Project Reboot 3.0/FortPlayerController.cpp @@ -112,7 +112,7 @@ void AFortPlayerController::DropAllItems(const std::vector continue; PickupCreateData CreateData; - CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(WorldItemDefinition, ItemEntry->GetCount(), ItemEntry->GetLoadedAmmo()); + CreateData.ItemEntry = ItemEntry; CreateData.SpawnLocation = Location; CreateData.SourceType = EFortPickupSourceTypeFlag::GetPlayerValue(); @@ -595,6 +595,7 @@ void AFortPlayerController::ServerAttemptInteractHook(UObject* Context, FFrame* CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(Entry->GetItemDefinition(), Entry->GetCount(), Entry->GetLoadedAmmo()); CreateData.SpawnLocation = LocationToSpawnLoot; CreateData.PawnOwner = PlayerController->GetMyFortPawn(); // hmm + CreateData.bShouldFreeItemEntryWhenDeconstructed = true; AFortPickup::SpawnPickup(CreateData); } @@ -977,72 +978,6 @@ void AFortPlayerController::ServerAttemptInventoryDropHook(AFortPlayerController if (!ItemDefinition->ShouldIgnoreRespawningOnDrop() && (DropBehaviorOffset != -1 ? ItemDefinition->GetDropBehavior() != EWorldItemDropBehavior::DestroyOnDrop : true)) { - if (false) - { - if (auto GadgetItemDefinition = Cast(ItemDefinition)) - { - auto PlayerState = Cast(PlayerController->GetPlayerState()); - auto ASC = PlayerState->GetAbilitySystemComponent(); - - if (GadgetItemDefinition->GetTrackedAttributes().Num() > 0) - { - ReplicatedEntry->SetStateValue(EFortItemEntryState::GenericAttributeValueSet, 1); - } - - std::vector AttributeValueVector; - - for (int i = 0; i < GadgetItemDefinition->GetTrackedAttributes().Num(); i++) - { - auto& CurrentTrackedAttribute = GadgetItemDefinition->GetTrackedAttributes().at(i); - - // LOG_INFO(LogDev, "[{}] TrackedAttribute Attribute Property Name {}", i, GadgetItemDefinition->GetTrackedAttributes().at(i).GetAttributePropertyName()); - // LOG_INFO(LogDev, "[{}] TrackedAttribute Attribute Name {}", i, GadgetItemDefinition->GetTrackedAttributes().at(i).GetAttributeName()); - // LOG_INFO(LogDev, "[{}] TrackedAttribute Attribute Owner {}", i, GadgetItemDefinition->GetTrackedAttributes().at(i).AttributeOwner->GetPathName()); - - auto AbilitySystemComponent = PlayerState->GetAbilitySystemComponent(); - - int CurrentAttributeValue = -1; - - for (int i = 0; i < AbilitySystemComponent->GetSpawnedAttributes().Num(); i++) - { - auto CurrentSpawnedAttribute = AbilitySystemComponent->GetSpawnedAttributes().at(i); - - if (CurrentSpawnedAttribute->IsA(CurrentTrackedAttribute.AttributeOwner)) - { - auto PropertyOffset = CurrentSpawnedAttribute->GetOffset(CurrentTrackedAttribute.GetAttributePropertyName()); - - if (PropertyOffset != -1) - { - CurrentAttributeValue = CurrentSpawnedAttribute->GetPtr(PropertyOffset)->GetCurrentValue(); - break; // hm - } - } - } - - // LOG_INFO(LogDev, "CurrentAttributeValue: {}", CurrentAttributeValue); - - if (CurrentAttributeValue != -1) // Found the attribute. - { - // im so smart - - AttributeValueVector.push_back(CurrentAttributeValue); - } - } - - for (int z = 0; z < ReplicatedEntry->GetGenericAttributeValues().Num(); z++) // First value must be the current value // dont ask me why fortnite keeps the old values in it too.. - { - AttributeValueVector.push_back(ReplicatedEntry->GetGenericAttributeValues().at(z)); - } - - ReplicatedEntry->GetGenericAttributeValues().Free(); - - for (auto& AttributeValue : AttributeValueVector) - { - ReplicatedEntry->GetGenericAttributeValues().Add(AttributeValue); - } - } - } - auto Pickup = AFortPickup::SpawnPickup(ReplicatedEntry, Pawn->GetActorLocation(), EFortPickupSourceTypeFlag::GetPlayerValue(), 0, Pawn, nullptr, true, Count); if (!Pickup) @@ -1414,7 +1349,7 @@ void AFortPlayerController::ClientOnPawnDiedHook(AFortPlayerController* PlayerCo continue; PickupCreateData CreateData; - CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(WorldItemDefinition, ItemEntry->GetCount(), ItemEntry->GetLoadedAmmo()); + CreateData.ItemEntry = ItemEntry; CreateData.SourceType = EFortPickupSourceTypeFlag::GetPlayerValue(); CreateData.Source = EFortPickupSpawnSource::GetPlayerEliminationValue(); CreateData.SpawnLocation = DeathLocation; diff --git a/Project Reboot 3.0/Project Reboot 3.0.vcxproj b/Project Reboot 3.0/Project Reboot 3.0.vcxproj index 68e65be..0b0bbb0 100644 --- a/Project Reboot 3.0/Project Reboot 3.0.vcxproj +++ b/Project Reboot 3.0/Project Reboot 3.0.vcxproj @@ -234,6 +234,7 @@ + diff --git a/Project Reboot 3.0/Project Reboot 3.0.vcxproj.filters b/Project Reboot 3.0/Project Reboot 3.0.vcxproj.filters index cd76b6c..79b3686 100644 --- a/Project Reboot 3.0/Project Reboot 3.0.vcxproj.filters +++ b/Project Reboot 3.0/Project Reboot 3.0.vcxproj.filters @@ -268,11 +268,13 @@ FortniteGame\Source\FortniteGame\Private\Athena\Modifiers + + Reboot\Private + - Engine\Source\Runtime\Core\Public\Containers @@ -854,6 +856,9 @@ FortniteGame\Source\FortniteGame\Public\Athena\Modifiers + + Reboot\Public + diff --git a/Project Reboot 3.0/addresses.cpp b/Project Reboot 3.0/addresses.cpp index f90b131..10efbc4 100644 --- a/Project Reboot 3.0/addresses.cpp +++ b/Project Reboot 3.0/addresses.cpp @@ -353,6 +353,8 @@ 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, "FreeEntry: 0x{:x}", FreeEntry - Base); + LOG_INFO(LogDev, "FreeArrayOfEntries: 0x{:x}", FreeArrayOfEntries - Base); LOG_INFO(LogDev, "UpdateTrackedAttributesLea: 0x{:x}", UpdateTrackedAttributesLea - Base); LOG_INFO(LogDev, "CombinePickupLea: 0x{:x}", CombinePickupLea - Base); LOG_INFO(LogDev, "CreateBuildingActorCallForDeco: 0x{:x}", CreateBuildingActorCallForDeco - Base); diff --git a/Project Reboot 3.0/bots.h b/Project Reboot 3.0/bots.h index e36d517..1fe93fa 100644 --- a/Project Reboot 3.0/bots.h +++ b/Project Reboot 3.0/bots.h @@ -15,13 +15,30 @@ public: auto GameState = Cast(GetWorld()->GetGameState()); auto GameMode = Cast(GetWorld()->GetGameMode()); -#if 0 - static auto PawnClass = FindObject("/Game/Athena/PlayerPawn_Athena.PlayerPawn_Athena_C"); - static auto ControllerClass = AFortPlayerControllerAthena::StaticClass(); -#else - static auto PawnClass = FindObject("/Game/Athena/AI/Phoebe/BP_PlayerPawn_Athena_Phoebe.BP_PlayerPawn_Athena_Phoebe_C"); - static auto ControllerClass = FindObject("/Game/Athena/AI/Phoebe/BP_PhoebePlayerController.BP_PhoebePlayerController_C"); -#endif + static UClass* PawnClass = nullptr; + static UClass* ControllerClass = nullptr; + + if (!PawnClass) + { + if (true) + PawnClass = FindObject("/Game/Athena/PlayerPawn_Athena.PlayerPawn_Athena_C"); + else + PawnClass = FindObject("/Game/Athena/AI/Phoebe/BP_PlayerPawn_Athena_Phoebe.BP_PlayerPawn_Athena_Phoebe_C"); + } + + if (!ControllerClass) + { + if (true) + ControllerClass = AFortPlayerControllerAthena::StaticClass(); + else + ControllerClass = FindObject("/Game/Athena/AI/Phoebe/BP_PhoebePlayerController.BP_PhoebePlayerController_C"); + } + + if (!ControllerClass || !PawnClass) + { + LOG_ERROR(LogBots, "Failed to find a class for the bots!"); + return; + } static auto FortAthenaAIBotControllerClass = FindObject("/Script/FortniteGame.FortAthenaAIBotController"); @@ -135,14 +152,12 @@ public: FortPlayerController->Get(bHasInitializedWorldInventoryOffset) = true; } - if (false) + // if (false) { if (Inventory) { auto& StartingItems = GameMode->GetStartingItems(); - UFortItem* PickaxeInstance = nullptr; // PlayerController->AddPickaxeToInventory(); - for (int i = 0; i < StartingItems.Num(); i++) { auto& StartingItem = StartingItems.at(i); @@ -150,9 +165,15 @@ public: (*Inventory)->AddItem(StartingItem.GetItem(), nullptr, StartingItem.GetCount()); } - if (PickaxeInstance) + if (auto FortPlayerController = Cast(Controller)) { - // PlayerController->ServerExecuteInventoryItemHook(PlayerController, PickaxeInstance->GetItemEntry()->GetItemGuid()); + UFortItem* PickaxeInstance = FortPlayerController->AddPickaxeToInventory(); + + if (PickaxeInstance) + { + FortPlayerController->ServerExecuteInventoryItemHook(FortPlayerController, PickaxeInstance->GetItemEntry()->GetItemGuid()); + } + } (*Inventory)->Update(); diff --git a/Project Reboot 3.0/commands.h b/Project Reboot 3.0/commands.h index 2202513..5988b03 100644 --- a/Project Reboot 3.0/commands.h +++ b/Project Reboot 3.0/commands.h @@ -212,7 +212,7 @@ void ServerCheatHook(AFortPlayerControllerAthena* PlayerController, FString Msg) auto& lootTierGroup = Arguments[1]; - auto LootDrops = PickLootDrops(UKismetStringLibrary::Conv_StringToName(std::wstring(lootTierGroup.begin(), lootTierGroup.end()).c_str()), true); + auto LootDrops = PickLootDrops(UKismetStringLibrary::Conv_StringToName(std::wstring(lootTierGroup.begin(), lootTierGroup.end()).c_str()), -1, true); for (int i = 0; i < LootDrops.size(); i++) { @@ -442,6 +442,7 @@ void ServerCheatHook(AFortPlayerControllerAthena* PlayerController, FString Msg) PickupCreateData CreateData; CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(WID, count, -1); CreateData.SpawnLocation = Location; + CreateData.bShouldFreeItemEntryWhenDeconstructed = true; AFortPickup::SpawnPickup(CreateData); } diff --git a/Project Reboot 3.0/inc.cpp b/Project Reboot 3.0/inc.cpp new file mode 100644 index 0000000..ab9041d --- /dev/null +++ b/Project Reboot 3.0/inc.cpp @@ -0,0 +1,20 @@ +#include "inc.h" + +#include "Array.h" + +/* + +void* InstancedAllocator::Allocate(AllocatorType type, size_t Size) +{ + switch (type) + { + case AllocatorType::VIRTUALALLOC: + return VirtualAlloc(0, Size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); + case AllocatorType::FMEMORY: + return FMemory::Realloc(0, Size, 0); + } + + return nullptr; +} + +*/ \ No newline at end of file diff --git a/Project Reboot 3.0/inc.h b/Project Reboot 3.0/inc.h index 5844254..bf8418b 100644 --- a/Project Reboot 3.0/inc.h +++ b/Project Reboot 3.0/inc.h @@ -55,4 +55,27 @@ inline bool AreVehicleWeaponsEnabled() inline bool IsRestartingSupported() { return Engine_Version >= 419 && Engine_Version < 424; -} \ No newline at end of file +} + +/* + +enum class AllocatorType +{ + VIRTUALALLOC, + FMEMORY +}; + +class InstancedAllocator +{ +public: + AllocatorType allocatorType; + + static void* Allocate(AllocatorType type, size_t Size); + + void* Allocate(size_t Size) + { + return Allocate(allocatorType, Size); + } +}; + +*/ \ No newline at end of file diff --git a/Project Reboot 3.0/vendingmachine.h b/Project Reboot 3.0/vendingmachine.h index 948ecec..8ed30f6 100644 --- a/Project Reboot 3.0/vendingmachine.h +++ b/Project Reboot 3.0/vendingmachine.h @@ -5,6 +5,7 @@ #include "GameplayStatics.h" #include "FortLootPackage.h" #include "GameplayAbilityTypes.h" +#include "KismetMathLibrary.h" using ABuildingItemCollectorActor = ABuildingGameplayActor; @@ -12,7 +13,7 @@ struct FCollectorUnitInfo { static std::string GetStructName() { - static std::string StructName = FindObject("/Script/FortniteGame.CollectorUnitInfo") ? "/Script/FortniteGame.CollectorUnitInfo" : "/Script/FortniteGame.ColletorUnitInfo"; // nice one fortnite + static std::string StructName = FindObject(L"/Script/FortniteGame.CollectorUnitInfo") ? "/Script/FortniteGame.CollectorUnitInfo" : "/Script/FortniteGame.ColletorUnitInfo"; // nice one fortnite return StructName; } @@ -52,16 +53,9 @@ struct FCollectorUnitInfo } }; -static inline void FillItemCollector(ABuildingItemCollectorActor* ItemCollector, FName& LootTierGroup, bool bUseInstanceLootValueOverrides, bool bEnsureRarity = false, int recursive = 0) +static inline UCurveTable* GetGameData() { - if (recursive >= 10) - return; - - auto GameModeAthena = (AFortGameModeAthena*)GetWorld()->GetGameMode(); - auto GameState = Cast(GameModeAthena->GetGameState()); - - static auto ItemCollectionsOffset = ItemCollector->GetOffset("ItemCollections"); - auto& ItemCollections = ItemCollector->Get>(ItemCollectionsOffset); + auto GameState = Cast(GetWorld()->GetGameState()); UCurveTable* FortGameData = nullptr; @@ -74,7 +68,23 @@ static inline void FillItemCollector(ABuildingItemCollectorActor* ItemCollector, } if (!FortGameData) - FortGameData = FindObject("/Game/Athena/Balance/AthenaGameData.AthenaGameData"); // uhm so theres one without athena and on newer versions that has it so idk + FortGameData = FindObject(L"/Game/Athena/Balance/DataTables/AthenaGameData.AthenaGameData"); // uhm so theres one without athena and on newer versions that has it so idk // after i wrote this cokmment idk what i meant + + return FortGameData; +} + +static inline void FillItemCollector(ABuildingItemCollectorActor* ItemCollector, FName& LootTierGroup, bool bUseInstanceLootValueOverrides, int LootTier, int recursive = 0) +{ + if (recursive >= 10) + return; + + auto GameModeAthena = (AFortGameModeAthena*)GetWorld()->GetGameMode(); + auto GameState = Cast(GameModeAthena->GetGameState()); + + static auto ItemCollectionsOffset = ItemCollector->GetOffset("ItemCollections"); + auto& ItemCollections = ItemCollector->Get>(ItemCollectionsOffset); + + UCurveTable* FortGameData = GetGameData(); auto WoodName = UKismetStringLibrary::Conv_StringToName(L"Default.VendingMachine.Cost.Wood"); auto StoneName = UKismetStringLibrary::Conv_StringToName(L"Default.VendingMachine.Cost.Stone"); @@ -83,8 +93,6 @@ static inline void FillItemCollector(ABuildingItemCollectorActor* ItemCollector, static auto StoneItemData = FindObject("/Game/Items/ResourcePickups/StoneItemData.StoneItemData"); static auto MetalItemData = FindObject("/Game/Items/ResourcePickups/MetalItemData.MetalItemData"); - uint8_t RarityToUse = 69; - // TODO: Pull prices from datatables. bool bLowerPrices = Fortnite_Version >= 5.20; @@ -116,18 +124,7 @@ static inline void FillItemCollector(ABuildingItemCollectorActor* ItemCollector, constexpr bool bPrint = false; - std::vector LootDrops = PickLootDrops(LootTierGroup, bPrint); - - int tries = 0; - - while (LootDrops.size() == 0) - { - tries++; - LootDrops = PickLootDrops(LootTierGroup, bPrint); - - if (tries >= 10) - break; - } + std::vector LootDrops = PickLootDrops(LootTierGroup, LootTier, bPrint); if (LootDrops.size() == 0) continue; @@ -139,20 +136,9 @@ static inline void FillItemCollector(ABuildingItemCollectorActor* ItemCollector, if (!WorldItemDefinition) continue; - if (!IsPrimaryQuickbar(WorldItemDefinition)) + if (!IsPrimaryQuickbar(WorldItemDefinition)) // i dont think we need this check continue; - if (bEnsureRarity) - { - static auto RarityOffset = WorldItemDefinition->GetOffset("Rarity"); - - if (RarityToUse == 69) - RarityToUse = WorldItemDefinition->Get(RarityOffset); - - if (WorldItemDefinition->Get(RarityOffset) != RarityToUse) - continue; - } - bool bItemAlreadyInCollector = false; for (int ItemCollectorIt2 = 0; ItemCollectorIt2 < ItemCollections.Num(); ItemCollectorIt2++) @@ -196,11 +182,11 @@ static inline void FillItemCollector(ABuildingItemCollectorActor* ItemCollector, ItemCollection->GetInputCount()->GetCurve().CurveTable = bShouldBeNullTable ? nullptr : FortGameData; // scuffed idc ItemCollection->GetInputCount()->GetCurve().RowName = bShouldBeNullTable ? FName(0) : WoodName; // Scuffed idc - ItemCollection->GetInputCount()->GetValue() = RarityToUse == 0 ? CommonPrice - : RarityToUse == 1 ? UncommonPrice - : RarityToUse == 2 ? RarePrice - : RarityToUse == 3 ? EpicPrice - : RarityToUse == 4 ? LegendaryPrice + ItemCollection->GetInputCount()->GetValue() = LootTier == 0 ? CommonPrice + : LootTier == 1 ? UncommonPrice + : LootTier == 2 ? RarePrice + : LootTier == 3 ? EpicPrice + : LootTier == 4 ? LegendaryPrice : -1; } @@ -209,12 +195,12 @@ static inline void FillItemCollector(ABuildingItemCollectorActor* ItemCollector, if (bUseInstanceLootValueOverridesOffset != -1) ItemCollector->Get(bUseInstanceLootValueOverridesOffset) = bUseInstanceLootValueOverrides; - LOG_INFO(LogDev, "RarityToUse: {}", (int)RarityToUse); + // LOG_INFO(LogDev, "LootTier: {}", LootTier); static auto StartingGoalLevelOffset = ItemCollector->GetOffset("StartingGoalLevel"); if (StartingGoalLevelOffset != -1) - ItemCollector->Get(StartingGoalLevelOffset) = (int)RarityToUse; + ItemCollector->Get(StartingGoalLevelOffset) = LootTier; static auto VendingMachineClass = FindObject("/Game/Athena/Items/Gameplay/VendingMachine/B_Athena_VendingMachine.B_Athena_VendingMachine_C"); @@ -223,17 +209,17 @@ static inline void FillItemCollector(ABuildingItemCollectorActor* ItemCollector, static auto OverrideVendingMachineRarityOffset = ItemCollector->GetOffset("OverrideVendingMachineRarity", false); if (OverrideVendingMachineRarityOffset != -1) - ItemCollector->Get(OverrideVendingMachineRarityOffset) = RarityToUse; + ItemCollector->Get(OverrideVendingMachineRarityOffset) = LootTier; static auto OverrideGoalOffset = ItemCollector->GetOffset("OverrideGoal", false); if (OverrideGoalOffset != -1) { - ItemCollector->Get(OverrideGoalOffset) = RarityToUse == 0 ? CommonPrice - : RarityToUse == 1 ? UncommonPrice - : RarityToUse == 2 ? RarePrice - : RarityToUse == 3 ? EpicPrice - : RarityToUse == 4 ? LegendaryPrice + ItemCollector->Get(OverrideGoalOffset) = LootTier == 0 ? CommonPrice + : LootTier == 1 ? UncommonPrice + : LootTier == 2 ? RarePrice + : LootTier == 3 ? EpicPrice + : LootTier == 4 ? LegendaryPrice : -1; } } @@ -246,6 +232,28 @@ static inline void FillVendingMachines() auto OverrideLootTierGroup = UKismetStringLibrary::Conv_StringToName(L"Loot_AthenaVending"); // ItemCollector->GetLootTierGroupOverride(); + std::map ThingAndWeights; // Bro IDK WHat to name it! + + auto RarityWeightsName = UKismetStringLibrary::Conv_StringToName(L"Default.VendingMachine.RarityWeights"); + + auto FortGameData = GetGameData(); + + float WeightSum = 0; + + for (int i = 0; i < 6; i++) + { + auto Weight = UDataTableFunctionLibrary::EvaluateCurveTableRow(FortGameData, RarityWeightsName, i); + ThingAndWeights[i] = Weight; + WeightSum += Weight; + } + + for (int i = 0; i < ThingAndWeights.size(); i++) + { + LOG_INFO(LogDev, "[{}] bruh: {}", i, ThingAndWeights.at(i)); + } + + std::map PickedRarities; + for (int i = 0; i < AllVendingMachines.Num(); i++) { auto VendingMachine = (ABuildingItemCollectorActor*)AllVendingMachines.at(i); @@ -253,8 +261,39 @@ static inline void FillVendingMachines() if (!VendingMachine) continue; - FillItemCollector(VendingMachine, OverrideLootTierGroup, true, true); + auto randomFloatGenerator = [&](float Max) -> float { return UKismetMathLibrary::RandomFloatInRange(0, Max); }; + + int Out; + PickWeightedElement(ThingAndWeights, [&](float Weight) -> float { return Weight; }, randomFloatGenerator, WeightSum, false, 1, &Out, false, true); + + PickedRarities[Out]++; + + if (Out == 0) + { + VendingMachine->K2_DestroyActor(); + continue; + } + + FillItemCollector(VendingMachine, OverrideLootTierGroup, Out - 1, true, true); } + auto AllVendingMachinesNum = AllVendingMachines.Num(); + AllVendingMachines.Free(); + + bool bPrintDebug = true; + + if (bPrintDebug) + { + LOG_INFO(LogGame, "Destroyed {}/{} vending machines.", PickedRarities[0], AllVendingMachinesNum); + LOG_INFO(LogGame, "Filled {}/{} vending machines with common items.", PickedRarities[1], AllVendingMachinesNum); + LOG_INFO(LogGame, "Filled {}/{} vending machines with uncommon items.", PickedRarities[2], AllVendingMachinesNum); + LOG_INFO(LogGame, "Filled {}/{} vending machines with rare items.", PickedRarities[3], AllVendingMachinesNum); + LOG_INFO(LogGame, "Filled {}/{} vending machines with epic items.", PickedRarities[4], AllVendingMachinesNum); + LOG_INFO(LogGame, "Filled {}/{} vending machines with legendary items.", PickedRarities[5], AllVendingMachinesNum); + } + else + { + LOG_INFO(LogGame, "Filled {} vending machines!", AllVendingMachinesNum); + } } \ No newline at end of file