proper vending machines like fully, performance
This commit is contained in:
Milxnor
2023-05-08 22:28:32 -04:00
parent d5c95ac978
commit b64f569551
22 changed files with 399 additions and 221 deletions

View File

@@ -71,15 +71,31 @@ public:
ArrayMax = v3; 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; const int OldArrayNum = ArrayNum;
ArrayNum = OldArrayNum + 1; ArrayNum = OldArrayNum + 1;
if (ArrayNum > ArrayMax) if (OldArrayNum + 1 > ArrayMax)
{ {
ResizeArray(ArrayNum, NumBytesPerElement); RefitArray(NumBytesPerElement);
// ResizeArray(ArrayNum, NumBytesPerElement);
} }
return OldArrayNum; return OldArrayNum;
@@ -87,7 +103,7 @@ public:
void CopyFromArray(TArray<InElementType>& OtherArray, SIZE_T NumBytesPerElement = sizeof(InElementType)) void CopyFromArray(TArray<InElementType>& 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; ArrayMax = 0;
return; return;
@@ -235,7 +251,7 @@ public:
ArrayMax = ArrayNum; // CalculateSlackGrow(/* ArrayNum */ OldNum, ArrayMax, Size); ArrayMax = ArrayNum; // CalculateSlackGrow(/* ArrayNum */ OldNum, ArrayMax, Size);
// AllocatorInstance.ResizeAllocation(OldNum, ArrayMax, sizeof(ElementType)); // AllocatorInstance.ResizeAllocation(OldNum, ArrayMax, sizeof(ElementType));
// LOG_INFO(LogMemory, "ArrayMax: {} Size: {}", ArrayMax, Size); // 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)) FORCEINLINE int32 AddUninitialized(int32 Count = 1, size_t Size = sizeof(InElementType))
@@ -308,10 +324,17 @@ public:
void FreeGood(SizeType Size = sizeof(InElementType)) 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) if (FreeOriginal)
FreeOriginal(Data); FreeOriginal(Data);
}
else
{
VirtualFree(Data, 0, MEM_RELEASE);
}
Data = nullptr; Data = nullptr;
ArrayNum = 0; ArrayNum = 0;

View File

@@ -43,7 +43,7 @@ static inline void SpawnBGAs() // hahah not "proper", there's a function that we
static auto SpawnLootTierGroupOffset = BGAConsumableSpawner->GetOffset("SpawnLootTierGroup"); static auto SpawnLootTierGroupOffset = BGAConsumableSpawner->GetOffset("SpawnLootTierGroup");
auto& SpawnLootTierGroup = BGAConsumableSpawner->Get<FName>(SpawnLootTierGroupOffset); auto& SpawnLootTierGroup = BGAConsumableSpawner->Get<FName>(SpawnLootTierGroupOffset);
auto LootDrops = PickLootDrops(SpawnLootTierGroup, false); auto LootDrops = PickLootDrops(SpawnLootTierGroup);
for (int z = 0; z < LootDrops.size(); z++) for (int z = 0; z < LootDrops.size(); z++)
{ {

View File

@@ -14,7 +14,7 @@ bool ABuildingContainer::SpawnLoot(AFortPawn* Pawn)
// LOG_INFO(LogInteraction, "RedirectedLootTier: {}", RedirectedLootTier.ToString()); // LOG_INFO(LogInteraction, "RedirectedLootTier: {}", RedirectedLootTier.ToString());
auto LootDrops = PickLootDrops(RedirectedLootTier, bDebugPrintLooting); auto LootDrops = PickLootDrops(RedirectedLootTier, -1, bDebugPrintLooting);
// LOG_INFO(LogInteraction, "LootDrops.size(): {}", LootDrops.size()); // LOG_INFO(LogInteraction, "LootDrops.size(): {}", LootDrops.size());

View File

@@ -79,6 +79,7 @@ AFortPickup* AFortAthenaSupplyDrop::SpawnPickupHook(UObject* Context, FFrame& St
CreateData.SpawnLocation = Position; CreateData.SpawnLocation = Position;
CreateData.PawnOwner = TriggeringPawn; CreateData.PawnOwner = TriggeringPawn;
CreateData.Source = EFortPickupSpawnSource::GetSupplyDropValue(); CreateData.Source = EFortPickupSpawnSource::GetSupplyDropValue();
CreateData.bShouldFreeItemEntryWhenDeconstructed = true;
*Ret = AFortPickup::SpawnPickup(CreateData); *Ret = AFortPickup::SpawnPickup(CreateData);
return *Ret; return *Ret;

View File

@@ -968,7 +968,7 @@ void AFortGameModeAthena::Athena_HandleStartingNewPlayerHook(AFortGameModeAthena
auto Location = CurrentActor->GetActorLocation(); auto Location = CurrentActor->GetActorLocation();
Location.Z += UpZ; Location.Z += UpZ;
std::vector<LootDrop> LootDrops = PickLootDrops(SpawnIslandTierGroup, bPrintWarmup); std::vector<LootDrop> LootDrops = PickLootDrops(SpawnIslandTierGroup, -1, bPrintWarmup);
for (auto& LootDrop : LootDrops) for (auto& LootDrop : LootDrops)
{ {
@@ -998,7 +998,7 @@ void AFortGameModeAthena::Athena_HandleStartingNewPlayerHook(AFortGameModeAthena
auto Location = CurrentActor->GetActorLocation(); auto Location = CurrentActor->GetActorLocation();
Location.Z += UpZ; Location.Z += UpZ;
std::vector<LootDrop> LootDrops = PickLootDrops(BRIslandTierGroup, bPrint); std::vector<LootDrop> LootDrops = PickLootDrops(BRIslandTierGroup, -1, bPrint);
for (auto& LootDrop : LootDrops) for (auto& LootDrop : LootDrops)
{ {

View File

@@ -115,6 +115,7 @@ std::pair<std::vector<UFortItem*>, std::vector<UFortItem*>> AFortInventory::AddI
CreateData.SpawnLocation = Pawn->GetActorLocation(); CreateData.SpawnLocation = Pawn->GetActorLocation();
CreateData.PawnOwner = Cast<AFortPawn>(Pawn); CreateData.PawnOwner = Cast<AFortPawn>(Pawn);
CreateData.SourceType = EFortPickupSourceTypeFlag::GetPlayerValue(); CreateData.SourceType = EFortPickupSourceTypeFlag::GetPlayerValue();
CreateData.bShouldFreeItemEntryWhenDeconstructed = true;
AFortPickup::SpawnPickup(CreateData); AFortPickup::SpawnPickup(CreateData);
return std::make_pair(NewItemInstances, ModifiedItemInstances); return std::make_pair(NewItemInstances, ModifiedItemInstances);
@@ -238,7 +239,13 @@ std::pair<std::vector<UFortItem*>, std::vector<UFortItem*>> AFortInventory::AddI
auto ItemEntry = FFortItemEntry::MakeItemEntry(ItemDefinition, Count, LoadedAmmo); auto ItemEntry = FFortItemEntry::MakeItemEntry(ItemDefinition, Count, LoadedAmmo);
auto Ret = AddItem(ItemEntry, bShouldUpdate, bShowItemToast); auto Ret = AddItem(ItemEntry, bShouldUpdate, bShowItemToast);
// VirtualFree(ItemEntry);
if (!bUseFMemoryRealloc)
{
FFortItemEntry::FreeItemEntry(ItemEntry);
VirtualFree(ItemEntry, 0, MEM_RELEASE);
}
return Ret; return Ret;
} }

View File

@@ -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())->GetIntValue() = IntValue;
GetStateValues().AtPtr(idx, FFortItemEntryStateValue::GetStructSize())->GetStateType() = StateType; 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) 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<FFortItemEntry>(GetStructSize(), bUseFMemoryRealloc); auto Entry = Alloc<FFortItemEntry>(GetStructSize(), bUseFMemoryRealloc);
if (!Entry) if (!Entry)

View File

@@ -8,6 +8,8 @@
#include "reboot.h" #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 enum class EFortItemEntryState : uint8_t // this changes but its fineee
{ {
NoneState = 0, NoneState = 0,
@@ -32,7 +34,7 @@ struct FFortItemEntryStateValue
{ {
static UStruct* GetStruct() static UStruct* GetStruct()
{ {
static auto Struct = FindObject<UStruct>("/Script/FortniteGame.FortItemEntryStateValue"); static auto Struct = FindObject<UStruct>(L"/Script/FortniteGame.FortItemEntryStateValue");
return Struct; return Struct;
} }
@@ -161,10 +163,10 @@ struct FFortItemEntry : FFastArraySerializerItem
if (GenericAttributeValuesOffset != -1) 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? // should we do this?
@@ -177,7 +179,7 @@ struct FFortItemEntry : FFastArraySerializerItem
static UStruct* GetStruct() static UStruct* GetStruct()
{ {
static auto Struct = FindObject<UStruct>("/Script/FortniteGame.FortItemEntry"); static auto Struct = FindObject<UStruct>(L"/Script/FortniteGame.FortItemEntry");
return Struct; return Struct;
} }

View File

@@ -140,6 +140,8 @@ void UFortKismetLibrary::SpawnItemVariantPickupInWorldHook(UObject* Context, FFr
CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(ItemDefinition, ParamsPtr->GetNumberToSpawn(), -1); CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(ItemDefinition, ParamsPtr->GetNumberToSpawn(), -1);
CreateData.SourceType = ParamsPtr->GetSourceType(); CreateData.SourceType = ParamsPtr->GetSourceType();
CreateData.Source = ParamsPtr->GetSource(); CreateData.Source = ParamsPtr->GetSource();
CreateData.bShouldFreeItemEntryWhenDeconstructed = true;
auto Pickup = AFortPickup::SpawnPickup(CreateData); auto Pickup = AFortPickup::SpawnPickup(CreateData);
return SpawnItemVariantPickupInWorldOriginal(Context, Stack, Ret); return SpawnItemVariantPickupInWorldOriginal(Context, Stack, Ret);
@@ -228,6 +230,7 @@ void UFortKismetLibrary::CreateTossAmmoPickupForWeaponItemDefinitionAtLocationHo
CreateData.SourceType = SourceTypeFlag; CreateData.SourceType = SourceTypeFlag;
CreateData.Source = SpawnSource; CreateData.Source = SpawnSource;
CreateData.SpawnLocation = Location; CreateData.SpawnLocation = Location;
CreateData.bShouldFreeItemEntryWhenDeconstructed = true;
auto AmmoPickup = AFortPickup::SpawnPickup(CreateData); auto AmmoPickup = AFortPickup::SpawnPickup(CreateData);
@@ -511,6 +514,7 @@ AFortPickup* UFortKismetLibrary::K2_SpawnPickupInWorldWithClassHook(UObject* Con
CreateData.OverrideClass = PickupClass; CreateData.OverrideClass = PickupClass;
CreateData.bToss = bToss; CreateData.bToss = bToss;
CreateData.bRandomRotation = bRandomRotation; CreateData.bRandomRotation = bRandomRotation;
CreateData.bShouldFreeItemEntryWhenDeconstructed = true;
auto NewPickup = AFortPickup::SpawnPickup(CreateData); 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"); 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++) for (int i = 0; i < LootDrops.size(); i++)
{ {

View File

@@ -7,10 +7,6 @@
#include "GameplayTagContainer.h" #include "GameplayTagContainer.h"
#include "FortGameModeAthena.h" #include "FortGameModeAthena.h"
#include <random>
#include <map>
#include <numeric>
struct FFortGameFeatureLootTableData struct FFortGameFeatureLootTableData
{ {
TSoftObjectPtr<UDataTable> LootTierData; TSoftObjectPtr<UDataTable> LootTierData;
@@ -18,10 +14,6 @@ struct FFortGameFeatureLootTableData
}; };
#ifdef EXPERIMENTAL_LOOTING #ifdef EXPERIMENTAL_LOOTING
float RandomFloatForLoot(float AllWeightsSum)
{
return (rand() * 0.000030518509) * AllWeightsSum;
}
template <typename RowStructType = uint8> template <typename RowStructType = uint8>
void CollectDataTablesRows(std::vector<UDataTable*> DataTables, std::map<FName, RowStructType*>* OutMap, std::function<bool(FName, RowStructType*)> Check = []() { return true; }) void CollectDataTablesRows(std::vector<UDataTable*> DataTables, std::map<FName, RowStructType*>* OutMap, std::function<bool(FName, RowStructType*)> Check = []() { return true; })
@@ -59,54 +51,6 @@ void CollectDataTablesRows(std::vector<UDataTable*> DataTables, std::map<FName,
} }
} }
template <typename T>
static T* PickWeightedElement(const std::map<FName, T*>& Elements, std::function<float(T*)> 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<FName, T*>& 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) int GetItemLevel(const FDataTableCategoryHandle& LootLevelData, int WorldLevel)
{ {
return 0; return 0;
@@ -200,18 +144,20 @@ float GetAmountOfLootPackagesToDrop(FFortLootTierData* LootTierData, int Origina
FFortLootTierData* PickLootTierData(const std::vector<UDataTable*>& 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. FFortLootTierData* PickLootTierData(const std::vector<UDataTable*>& 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; float LootTier = ForcedLootTier;
if (LootTier == -1) if (LootTier == -1)
{ {
LootTier = 0; // LootTier = 0;
} }
else else
{ {
// buncha code im too lazy to reverse // buncha code im too lazy to reverse
} }
LootTier = 1; // ONG PROPER // IDIakuuyg8712u091fj120gvik
// if (fabs(LootTier) <= 0.0000000099999999) // if (fabs(LootTier) <= 0.0000000099999999)
// return 0; // return 0;
@@ -219,7 +165,7 @@ FFortLootTierData* PickLootTierData(const std::vector<UDataTable*>& LTDTables, F
std::map<FName, FFortLootTierData*> TierGroupLTDs; std::map<FName, FFortLootTierData*> TierGroupLTDs;
CollectDataTablesRows<FFortLootTierData>(LTDTables, &TierGroupLTDs, [&](FName RowName, FFortLootTierData* TierData) -> bool { CollectDataTablesRows<FFortLootTierData>(LTDTables, &TierGroupLTDs, [&](FName RowName, FFortLootTierData* TierData) -> bool {
if (LootTierGroup == TierData->GetTierGroup()) if (LootTierGroup == TierData->GetTierGroup() && (LootTier == -1 ? true : LootTier == TierData->GetLootTier()))
{ {
return true; return true;
} }
@@ -227,9 +173,9 @@ FFortLootTierData* PickLootTierData(const std::vector<UDataTable*>& LTDTables, F
return false; return false;
}); });
FFortLootTierData* ChosenRowLootTierData = PickWeightedElement<FFortLootTierData>(TierGroupLTDs, FFortLootTierData* ChosenRowLootTierData = PickWeightedElement<FName, FFortLootTierData*>(TierGroupLTDs,
[](FFortLootTierData* LootTierData) -> float { return LootTierData->GetWeight(); }, -1, [](FFortLootTierData* LootTierData) -> float { return LootTierData->GetWeight(); }, RandomFloatForLoot, -1,
true, LootTier, OutRowName); true, LootTier == -1 ? 1 : LootTier, OutRowName);
if (!ChosenRowLootTierData) if (!ChosenRowLootTierData)
return nullptr; return nullptr;
@@ -274,8 +220,8 @@ void PickLootDropsFromLootPackage(const std::vector<UDataTable*>& LPTables, cons
} }
FName PickedPackageRowName; FName PickedPackageRowName;
FFortLootPackageData* PickedPackage = PickWeightedElement<FFortLootPackageData>(LootPackageIDMap, FFortLootPackageData* PickedPackage = PickWeightedElement<FName, FFortLootPackageData*>(LootPackageIDMap,
[](FFortLootPackageData* LootPackageData) -> float { return LootPackageData->GetWeight(); }, [](FFortLootPackageData* LootPackageData) -> float { return LootPackageData->GetWeight(); }, RandomFloatForLoot,
-1, true, 1, &PickedPackageRowName, bPrint); -1, true, 1, &PickedPackageRowName, bPrint);
if (!PickedPackage) if (!PickedPackage)
@@ -377,7 +323,7 @@ void PickLootDropsFromLootPackage(const std::vector<UDataTable*>& LPTables, cons
} }
} }
std::vector<LootDrop> PickLootDrops(FName TierGroupName, bool bPrint, int recursive) std::vector<LootDrop> PickLootDrops(FName TierGroupName, int ForcedLootTier, bool bPrint, int recursive)
{ {
std::vector<LootDrop> LootDrops; std::vector<LootDrop> LootDrops;
@@ -659,7 +605,7 @@ std::vector<LootDrop> PickLootDrops(FName TierGroupName, bool bPrint, int recurs
} }
FName LootTierRowName; FName LootTierRowName;
auto ChosenRowLootTierData = PickLootTierData(LTDTables, TierGroupName, 0, -1, &LootTierRowName); auto ChosenRowLootTierData = PickLootTierData(LTDTables, TierGroupName, 0, ForcedLootTier, &LootTierRowName);
if (!ChosenRowLootTierData) if (!ChosenRowLootTierData)
{ {

View File

@@ -1,6 +1,9 @@
#pragma once #pragma once
#include <vector> #include <vector>
#include <random>
#include <map>
#include <numeric>
#include "Array.h" #include "Array.h"
#include "FortWorldItemDefinition.h" #include "FortWorldItemDefinition.h"
@@ -70,6 +73,12 @@ public:
return *(FName*)(__int64(this) + TierGroupOffset); return *(FName*)(__int64(this) + TierGroupOffset);
} }
int& GetLootTier()
{
static auto LootTierOffset = FindOffsetStruct("/Script/FortniteGame.FortLootTierData", "LootTier");
return *(int*)(__int64(this) + LootTierOffset);
}
float& GetWeight() float& GetWeight()
{ {
static auto WeightOffset = FindOffsetStruct("/Script/FortniteGame.FortLootTierData", "Weight"); static auto WeightOffset = FindOffsetStruct("/Script/FortniteGame.FortLootTierData", "Weight");
@@ -115,4 +124,63 @@ struct LootDrop
} }
}; };
std::vector<LootDrop> PickLootDrops(FName TierGroupName, bool bPrint = false, int recursive = 0); static inline float RandomFloatForLoot(float AllWeightsSum)
{
return (rand() * 0.000030518509) * AllWeightsSum;
}
template <typename KeyType, typename ValueType>
FORCEINLINE static ValueType PickWeightedElement(const std::map<KeyType, ValueType>& Elements,
std::function<float(ValueType)> GetWeightFn,
std::function<float(float)> 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<KeyType, ValueType>& 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<KeyType, ValueType>(Elements, GetWeightFn, RandomFloatGenerator, TotalWeightParam, bCheckIfWeightIsZero, RandMultiplier, OutName, bPrint, bKeepGoingUntilWeGetValue);
return ValueType();
}
std::vector<LootDrop> PickLootDrops(FName TierGroupName, int ForcedLootTier = -1, bool bPrint = false, int recursive = 0);

View File

@@ -78,6 +78,72 @@ AFortPickup* AFortPickup::SpawnPickup(PickupCreateData& PickupData)
PrimaryPickupItemEntry->CopyFromAnotherItemEntry(PickupData.ItemEntry); PrimaryPickupItemEntry->CopyFromAnotherItemEntry(PickupData.ItemEntry);
} }
if (false && PlayerState)
{
if (auto GadgetItemDefinition = Cast<UFortGadgetItemDefinition>(PrimaryPickupItemEntry->GetItemDefinition()))
{
auto ASC = PlayerState->GetAbilitySystemComponent();
if (GadgetItemDefinition->GetTrackedAttributes().Num() > 0)
{
PrimaryPickupItemEntry->SetStateValue(EFortItemEntryState::GenericAttributeValueSet, 1);
}
std::vector<float> 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<FFortGameplayAttributeData>(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); static auto PickupSourceTypeFlagsOffset = Pickup->GetOffset("PickupSourceTypeFlags", false);
if (PickupSourceTypeFlagsOffset != -1) if (PickupSourceTypeFlagsOffset != -1)
@@ -209,6 +275,7 @@ void AFortPickup::CombinePickupHook(AFortPickup* Pickup)
CreateData.PawnOwner = ItemOwner; CreateData.PawnOwner = ItemOwner;
CreateData.SourceType = EFortPickupSourceTypeFlag::GetPlayerValue(); CreateData.SourceType = EFortPickupSourceTypeFlag::GetPlayerValue();
CreateData.IgnoreCombineTarget = PickupToCombineInto; CreateData.IgnoreCombineTarget = PickupToCombineInto;
CreateData.bShouldFreeItemEntryWhenDeconstructed = true;
auto NewOverStackPickup = AFortPickup::SpawnPickup(CreateData); auto NewOverStackPickup = AFortPickup::SpawnPickup(CreateData);
} }

View File

@@ -83,6 +83,20 @@ struct PickupCreateData
if (bShouldFreeItemEntryWhenDeconstructed) if (bShouldFreeItemEntryWhenDeconstructed)
{ {
// real // 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);
}
} }
} }
}; };

View File

@@ -112,7 +112,7 @@ void AFortPlayerController::DropAllItems(const std::vector<UFortItemDefinition*>
continue; continue;
PickupCreateData CreateData; PickupCreateData CreateData;
CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(WorldItemDefinition, ItemEntry->GetCount(), ItemEntry->GetLoadedAmmo()); CreateData.ItemEntry = ItemEntry;
CreateData.SpawnLocation = Location; CreateData.SpawnLocation = Location;
CreateData.SourceType = EFortPickupSourceTypeFlag::GetPlayerValue(); 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.ItemEntry = FFortItemEntry::MakeItemEntry(Entry->GetItemDefinition(), Entry->GetCount(), Entry->GetLoadedAmmo());
CreateData.SpawnLocation = LocationToSpawnLoot; CreateData.SpawnLocation = LocationToSpawnLoot;
CreateData.PawnOwner = PlayerController->GetMyFortPawn(); // hmm CreateData.PawnOwner = PlayerController->GetMyFortPawn(); // hmm
CreateData.bShouldFreeItemEntryWhenDeconstructed = true;
AFortPickup::SpawnPickup(CreateData); AFortPickup::SpawnPickup(CreateData);
} }
@@ -977,72 +978,6 @@ void AFortPlayerController::ServerAttemptInventoryDropHook(AFortPlayerController
if (!ItemDefinition->ShouldIgnoreRespawningOnDrop() && (DropBehaviorOffset != -1 ? ItemDefinition->GetDropBehavior() != EWorldItemDropBehavior::DestroyOnDrop : true)) if (!ItemDefinition->ShouldIgnoreRespawningOnDrop() && (DropBehaviorOffset != -1 ? ItemDefinition->GetDropBehavior() != EWorldItemDropBehavior::DestroyOnDrop : true))
{ {
if (false)
{
if (auto GadgetItemDefinition = Cast<UFortGadgetItemDefinition>(ItemDefinition))
{
auto PlayerState = Cast<AFortPlayerState>(PlayerController->GetPlayerState());
auto ASC = PlayerState->GetAbilitySystemComponent();
if (GadgetItemDefinition->GetTrackedAttributes().Num() > 0)
{
ReplicatedEntry->SetStateValue(EFortItemEntryState::GenericAttributeValueSet, 1);
}
std::vector<float> 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<FFortGameplayAttributeData>(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); auto Pickup = AFortPickup::SpawnPickup(ReplicatedEntry, Pawn->GetActorLocation(), EFortPickupSourceTypeFlag::GetPlayerValue(), 0, Pawn, nullptr, true, Count);
if (!Pickup) if (!Pickup)
@@ -1414,7 +1349,7 @@ void AFortPlayerController::ClientOnPawnDiedHook(AFortPlayerController* PlayerCo
continue; continue;
PickupCreateData CreateData; PickupCreateData CreateData;
CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(WorldItemDefinition, ItemEntry->GetCount(), ItemEntry->GetLoadedAmmo()); CreateData.ItemEntry = ItemEntry;
CreateData.SourceType = EFortPickupSourceTypeFlag::GetPlayerValue(); CreateData.SourceType = EFortPickupSourceTypeFlag::GetPlayerValue();
CreateData.Source = EFortPickupSpawnSource::GetPlayerEliminationValue(); CreateData.Source = EFortPickupSpawnSource::GetPlayerEliminationValue();
CreateData.SpawnLocation = DeathLocation; CreateData.SpawnLocation = DeathLocation;

View File

@@ -234,6 +234,7 @@
<ClCompile Include="GameplayStatics.cpp" /> <ClCompile Include="GameplayStatics.cpp" />
<ClCompile Include="GameState.cpp" /> <ClCompile Include="GameState.cpp" />
<ClCompile Include="GenericPlatformMath.cpp" /> <ClCompile Include="GenericPlatformMath.cpp" />
<ClCompile Include="inc.cpp" />
<ClCompile Include="InventoryManagementLibrary.cpp" /> <ClCompile Include="InventoryManagementLibrary.cpp" />
<ClCompile Include="KismetMathLibrary.cpp" /> <ClCompile Include="KismetMathLibrary.cpp" />
<ClCompile Include="KismetStringLibrary.cpp" /> <ClCompile Include="KismetStringLibrary.cpp" />

View File

@@ -268,11 +268,13 @@
<ClCompile Include="FortAthenaMutator_Disco.cpp"> <ClCompile Include="FortAthenaMutator_Disco.cpp">
<Filter>FortniteGame\Source\FortniteGame\Private\Athena\Modifiers</Filter> <Filter>FortniteGame\Source\FortniteGame\Private\Athena\Modifiers</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="inc.cpp">
<Filter>Reboot\Private</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="log.h" /> <ClInclude Include="log.h" />
<ClInclude Include="finder.h" /> <ClInclude Include="finder.h" />
<ClInclude Include="inc.h" />
<ClInclude Include="Array.h"> <ClInclude Include="Array.h">
<Filter>Engine\Source\Runtime\Core\Public\Containers</Filter> <Filter>Engine\Source\Runtime\Core\Public\Containers</Filter>
</ClInclude> </ClInclude>
@@ -854,6 +856,9 @@
<ClInclude Include="FortAthenaMutator_LoadoutSwap.h"> <ClInclude Include="FortAthenaMutator_LoadoutSwap.h">
<Filter>FortniteGame\Source\FortniteGame\Public\Athena\Modifiers</Filter> <Filter>FortniteGame\Source\FortniteGame\Public\Athena\Modifiers</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="inc.h">
<Filter>Reboot\Public</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Filter Include="Engine"> <Filter Include="Engine">

View File

@@ -353,6 +353,8 @@ void Addresses::Print()
LOG_INFO(LogDev, "EnterAircraft: 0x{:x}", EnterAircraft - Base); LOG_INFO(LogDev, "EnterAircraft: 0x{:x}", EnterAircraft - Base);
LOG_INFO(LogDev, "SetTimer: 0x{:x}", SetTimer - Base); LOG_INFO(LogDev, "SetTimer: 0x{:x}", SetTimer - Base);
LOG_INFO(LogDev, "PickupInitialize: 0x{:x}", PickupInitialize - 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, "UpdateTrackedAttributesLea: 0x{:x}", UpdateTrackedAttributesLea - Base);
LOG_INFO(LogDev, "CombinePickupLea: 0x{:x}", CombinePickupLea - Base); LOG_INFO(LogDev, "CombinePickupLea: 0x{:x}", CombinePickupLea - Base);
LOG_INFO(LogDev, "CreateBuildingActorCallForDeco: 0x{:x}", CreateBuildingActorCallForDeco - Base); LOG_INFO(LogDev, "CreateBuildingActorCallForDeco: 0x{:x}", CreateBuildingActorCallForDeco - Base);

View File

@@ -15,13 +15,30 @@ public:
auto GameState = Cast<AFortGameStateAthena>(GetWorld()->GetGameState()); auto GameState = Cast<AFortGameStateAthena>(GetWorld()->GetGameState());
auto GameMode = Cast<AFortGameModeAthena>(GetWorld()->GetGameMode()); auto GameMode = Cast<AFortGameModeAthena>(GetWorld()->GetGameMode());
#if 0 static UClass* PawnClass = nullptr;
static auto PawnClass = FindObject<UClass>("/Game/Athena/PlayerPawn_Athena.PlayerPawn_Athena_C"); static UClass* ControllerClass = nullptr;
static auto ControllerClass = AFortPlayerControllerAthena::StaticClass();
#else if (!PawnClass)
static auto PawnClass = FindObject<UClass>("/Game/Athena/AI/Phoebe/BP_PlayerPawn_Athena_Phoebe.BP_PlayerPawn_Athena_Phoebe_C"); {
static auto ControllerClass = FindObject<UClass>("/Game/Athena/AI/Phoebe/BP_PhoebePlayerController.BP_PhoebePlayerController_C"); if (true)
#endif PawnClass = FindObject<UClass>("/Game/Athena/PlayerPawn_Athena.PlayerPawn_Athena_C");
else
PawnClass = FindObject<UClass>("/Game/Athena/AI/Phoebe/BP_PlayerPawn_Athena_Phoebe.BP_PlayerPawn_Athena_Phoebe_C");
}
if (!ControllerClass)
{
if (true)
ControllerClass = AFortPlayerControllerAthena::StaticClass();
else
ControllerClass = FindObject<UClass>("/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<UClass>("/Script/FortniteGame.FortAthenaAIBotController"); static auto FortAthenaAIBotControllerClass = FindObject<UClass>("/Script/FortniteGame.FortAthenaAIBotController");
@@ -135,14 +152,12 @@ public:
FortPlayerController->Get<bool>(bHasInitializedWorldInventoryOffset) = true; FortPlayerController->Get<bool>(bHasInitializedWorldInventoryOffset) = true;
} }
if (false) // if (false)
{ {
if (Inventory) if (Inventory)
{ {
auto& StartingItems = GameMode->GetStartingItems(); auto& StartingItems = GameMode->GetStartingItems();
UFortItem* PickaxeInstance = nullptr; // PlayerController->AddPickaxeToInventory();
for (int i = 0; i < StartingItems.Num(); i++) for (int i = 0; i < StartingItems.Num(); i++)
{ {
auto& StartingItem = StartingItems.at(i); auto& StartingItem = StartingItems.at(i);
@@ -150,9 +165,15 @@ public:
(*Inventory)->AddItem(StartingItem.GetItem(), nullptr, StartingItem.GetCount()); (*Inventory)->AddItem(StartingItem.GetItem(), nullptr, StartingItem.GetCount());
} }
if (PickaxeInstance) if (auto FortPlayerController = Cast<AFortPlayerController>(Controller))
{ {
// PlayerController->ServerExecuteInventoryItemHook(PlayerController, PickaxeInstance->GetItemEntry()->GetItemGuid()); UFortItem* PickaxeInstance = FortPlayerController->AddPickaxeToInventory();
if (PickaxeInstance)
{
FortPlayerController->ServerExecuteInventoryItemHook(FortPlayerController, PickaxeInstance->GetItemEntry()->GetItemGuid());
}
} }
(*Inventory)->Update(); (*Inventory)->Update();

View File

@@ -212,7 +212,7 @@ void ServerCheatHook(AFortPlayerControllerAthena* PlayerController, FString Msg)
auto& lootTierGroup = Arguments[1]; 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++) for (int i = 0; i < LootDrops.size(); i++)
{ {
@@ -442,6 +442,7 @@ void ServerCheatHook(AFortPlayerControllerAthena* PlayerController, FString Msg)
PickupCreateData CreateData; PickupCreateData CreateData;
CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(WID, count, -1); CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(WID, count, -1);
CreateData.SpawnLocation = Location; CreateData.SpawnLocation = Location;
CreateData.bShouldFreeItemEntryWhenDeconstructed = true;
AFortPickup::SpawnPickup(CreateData); AFortPickup::SpawnPickup(CreateData);
} }

View File

@@ -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;
}
*/

View File

@@ -56,3 +56,26 @@ inline bool IsRestartingSupported()
{ {
return Engine_Version >= 419 && Engine_Version < 424; return Engine_Version >= 419 && Engine_Version < 424;
} }
/*
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);
}
};
*/

View File

@@ -5,6 +5,7 @@
#include "GameplayStatics.h" #include "GameplayStatics.h"
#include "FortLootPackage.h" #include "FortLootPackage.h"
#include "GameplayAbilityTypes.h" #include "GameplayAbilityTypes.h"
#include "KismetMathLibrary.h"
using ABuildingItemCollectorActor = ABuildingGameplayActor; using ABuildingItemCollectorActor = ABuildingGameplayActor;
@@ -12,7 +13,7 @@ struct FCollectorUnitInfo
{ {
static std::string GetStructName() static std::string GetStructName()
{ {
static std::string StructName = FindObject<UStruct>("/Script/FortniteGame.CollectorUnitInfo") ? "/Script/FortniteGame.CollectorUnitInfo" : "/Script/FortniteGame.ColletorUnitInfo"; // nice one fortnite static std::string StructName = FindObject<UStruct>(L"/Script/FortniteGame.CollectorUnitInfo") ? "/Script/FortniteGame.CollectorUnitInfo" : "/Script/FortniteGame.ColletorUnitInfo"; // nice one fortnite
return StructName; 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) auto GameState = Cast<AFortGameStateAthena>(GetWorld()->GetGameState());
return;
auto GameModeAthena = (AFortGameModeAthena*)GetWorld()->GetGameMode();
auto GameState = Cast<AFortGameStateAthena>(GameModeAthena->GetGameState());
static auto ItemCollectionsOffset = ItemCollector->GetOffset("ItemCollections");
auto& ItemCollections = ItemCollector->Get<TArray<FCollectorUnitInfo>>(ItemCollectionsOffset);
UCurveTable* FortGameData = nullptr; UCurveTable* FortGameData = nullptr;
@@ -74,7 +68,23 @@ static inline void FillItemCollector(ABuildingItemCollectorActor* ItemCollector,
} }
if (!FortGameData) if (!FortGameData)
FortGameData = FindObject<UCurveTable>("/Game/Athena/Balance/AthenaGameData.AthenaGameData"); // uhm so theres one without athena and on newer versions that has it so idk FortGameData = FindObject<UCurveTable>(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<AFortGameStateAthena>(GameModeAthena->GetGameState());
static auto ItemCollectionsOffset = ItemCollector->GetOffset("ItemCollections");
auto& ItemCollections = ItemCollector->Get<TArray<FCollectorUnitInfo>>(ItemCollectionsOffset);
UCurveTable* FortGameData = GetGameData();
auto WoodName = UKismetStringLibrary::Conv_StringToName(L"Default.VendingMachine.Cost.Wood"); auto WoodName = UKismetStringLibrary::Conv_StringToName(L"Default.VendingMachine.Cost.Wood");
auto StoneName = UKismetStringLibrary::Conv_StringToName(L"Default.VendingMachine.Cost.Stone"); auto StoneName = UKismetStringLibrary::Conv_StringToName(L"Default.VendingMachine.Cost.Stone");
@@ -83,8 +93,6 @@ static inline void FillItemCollector(ABuildingItemCollectorActor* ItemCollector,
static auto StoneItemData = FindObject<UFortResourceItemDefinition>("/Game/Items/ResourcePickups/StoneItemData.StoneItemData"); static auto StoneItemData = FindObject<UFortResourceItemDefinition>("/Game/Items/ResourcePickups/StoneItemData.StoneItemData");
static auto MetalItemData = FindObject<UFortResourceItemDefinition>("/Game/Items/ResourcePickups/MetalItemData.MetalItemData"); static auto MetalItemData = FindObject<UFortResourceItemDefinition>("/Game/Items/ResourcePickups/MetalItemData.MetalItemData");
uint8_t RarityToUse = 69;
// TODO: Pull prices from datatables. // TODO: Pull prices from datatables.
bool bLowerPrices = Fortnite_Version >= 5.20; bool bLowerPrices = Fortnite_Version >= 5.20;
@@ -116,18 +124,7 @@ static inline void FillItemCollector(ABuildingItemCollectorActor* ItemCollector,
constexpr bool bPrint = false; constexpr bool bPrint = false;
std::vector<LootDrop> LootDrops = PickLootDrops(LootTierGroup, bPrint); std::vector<LootDrop> LootDrops = PickLootDrops(LootTierGroup, LootTier, bPrint);
int tries = 0;
while (LootDrops.size() == 0)
{
tries++;
LootDrops = PickLootDrops(LootTierGroup, bPrint);
if (tries >= 10)
break;
}
if (LootDrops.size() == 0) if (LootDrops.size() == 0)
continue; continue;
@@ -139,20 +136,9 @@ static inline void FillItemCollector(ABuildingItemCollectorActor* ItemCollector,
if (!WorldItemDefinition) if (!WorldItemDefinition)
continue; continue;
if (!IsPrimaryQuickbar(WorldItemDefinition)) if (!IsPrimaryQuickbar(WorldItemDefinition)) // i dont think we need this check
continue; continue;
if (bEnsureRarity)
{
static auto RarityOffset = WorldItemDefinition->GetOffset("Rarity");
if (RarityToUse == 69)
RarityToUse = WorldItemDefinition->Get<uint8_t>(RarityOffset);
if (WorldItemDefinition->Get<uint8_t>(RarityOffset) != RarityToUse)
continue;
}
bool bItemAlreadyInCollector = false; bool bItemAlreadyInCollector = false;
for (int ItemCollectorIt2 = 0; ItemCollectorIt2 < ItemCollections.Num(); ItemCollectorIt2++) 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().CurveTable = bShouldBeNullTable ? nullptr : FortGameData; // scuffed idc
ItemCollection->GetInputCount()->GetCurve().RowName = bShouldBeNullTable ? FName(0) : WoodName; // Scuffed idc ItemCollection->GetInputCount()->GetCurve().RowName = bShouldBeNullTable ? FName(0) : WoodName; // Scuffed idc
ItemCollection->GetInputCount()->GetValue() = RarityToUse == 0 ? CommonPrice ItemCollection->GetInputCount()->GetValue() = LootTier == 0 ? CommonPrice
: RarityToUse == 1 ? UncommonPrice : LootTier == 1 ? UncommonPrice
: RarityToUse == 2 ? RarePrice : LootTier == 2 ? RarePrice
: RarityToUse == 3 ? EpicPrice : LootTier == 3 ? EpicPrice
: RarityToUse == 4 ? LegendaryPrice : LootTier == 4 ? LegendaryPrice
: -1; : -1;
} }
@@ -209,12 +195,12 @@ static inline void FillItemCollector(ABuildingItemCollectorActor* ItemCollector,
if (bUseInstanceLootValueOverridesOffset != -1) if (bUseInstanceLootValueOverridesOffset != -1)
ItemCollector->Get<bool>(bUseInstanceLootValueOverridesOffset) = bUseInstanceLootValueOverrides; ItemCollector->Get<bool>(bUseInstanceLootValueOverridesOffset) = bUseInstanceLootValueOverrides;
LOG_INFO(LogDev, "RarityToUse: {}", (int)RarityToUse); // LOG_INFO(LogDev, "LootTier: {}", LootTier);
static auto StartingGoalLevelOffset = ItemCollector->GetOffset("StartingGoalLevel"); static auto StartingGoalLevelOffset = ItemCollector->GetOffset("StartingGoalLevel");
if (StartingGoalLevelOffset != -1) if (StartingGoalLevelOffset != -1)
ItemCollector->Get<int32>(StartingGoalLevelOffset) = (int)RarityToUse; ItemCollector->Get<int32>(StartingGoalLevelOffset) = LootTier;
static auto VendingMachineClass = FindObject<UClass>("/Game/Athena/Items/Gameplay/VendingMachine/B_Athena_VendingMachine.B_Athena_VendingMachine_C"); static auto VendingMachineClass = FindObject<UClass>("/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); static auto OverrideVendingMachineRarityOffset = ItemCollector->GetOffset("OverrideVendingMachineRarity", false);
if (OverrideVendingMachineRarityOffset != -1) if (OverrideVendingMachineRarityOffset != -1)
ItemCollector->Get<uint8_t>(OverrideVendingMachineRarityOffset) = RarityToUse; ItemCollector->Get<uint8_t>(OverrideVendingMachineRarityOffset) = LootTier;
static auto OverrideGoalOffset = ItemCollector->GetOffset("OverrideGoal", false); static auto OverrideGoalOffset = ItemCollector->GetOffset("OverrideGoal", false);
if (OverrideGoalOffset != -1) if (OverrideGoalOffset != -1)
{ {
ItemCollector->Get<int32>(OverrideGoalOffset) = RarityToUse == 0 ? CommonPrice ItemCollector->Get<int32>(OverrideGoalOffset) = LootTier == 0 ? CommonPrice
: RarityToUse == 1 ? UncommonPrice : LootTier == 1 ? UncommonPrice
: RarityToUse == 2 ? RarePrice : LootTier == 2 ? RarePrice
: RarityToUse == 3 ? EpicPrice : LootTier == 3 ? EpicPrice
: RarityToUse == 4 ? LegendaryPrice : LootTier == 4 ? LegendaryPrice
: -1; : -1;
} }
} }
@@ -246,6 +232,28 @@ static inline void FillVendingMachines()
auto OverrideLootTierGroup = UKismetStringLibrary::Conv_StringToName(L"Loot_AthenaVending"); // ItemCollector->GetLootTierGroupOverride(); auto OverrideLootTierGroup = UKismetStringLibrary::Conv_StringToName(L"Loot_AthenaVending"); // ItemCollector->GetLootTierGroupOverride();
std::map<int, float> 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<int, int> PickedRarities;
for (int i = 0; i < AllVendingMachines.Num(); i++) for (int i = 0; i < AllVendingMachines.Num(); i++)
{ {
auto VendingMachine = (ABuildingItemCollectorActor*)AllVendingMachines.at(i); auto VendingMachine = (ABuildingItemCollectorActor*)AllVendingMachines.at(i);
@@ -253,8 +261,39 @@ static inline void FillVendingMachines()
if (!VendingMachine) if (!VendingMachine)
continue; continue;
FillItemCollector(VendingMachine, OverrideLootTierGroup, true, true); auto randomFloatGenerator = [&](float Max) -> float { return UKismetMathLibrary::RandomFloatInRange(0, Max); };
int Out;
PickWeightedElement<int, float>(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(); 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);
}
} }