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;
}
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<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;
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;

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");
auto& SpawnLootTierGroup = BGAConsumableSpawner->Get<FName>(SpawnLootTierGroupOffset);
auto LootDrops = PickLootDrops(SpawnLootTierGroup, false);
auto LootDrops = PickLootDrops(SpawnLootTierGroup);
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());
auto LootDrops = PickLootDrops(RedirectedLootTier, bDebugPrintLooting);
auto LootDrops = PickLootDrops(RedirectedLootTier, -1, bDebugPrintLooting);
// LOG_INFO(LogInteraction, "LootDrops.size(): {}", LootDrops.size());

View File

@@ -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;

View File

@@ -968,7 +968,7 @@ void AFortGameModeAthena::Athena_HandleStartingNewPlayerHook(AFortGameModeAthena
auto Location = CurrentActor->GetActorLocation();
Location.Z += UpZ;
std::vector<LootDrop> LootDrops = PickLootDrops(SpawnIslandTierGroup, bPrintWarmup);
std::vector<LootDrop> 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<LootDrop> LootDrops = PickLootDrops(BRIslandTierGroup, bPrint);
std::vector<LootDrop> LootDrops = PickLootDrops(BRIslandTierGroup, -1, bPrint);
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.PawnOwner = Cast<AFortPawn>(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<UFortItem*>, std::vector<UFortItem*>> 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;
}

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())->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<FFortItemEntry>(GetStructSize(), bUseFMemoryRealloc);
if (!Entry)

View File

@@ -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<UStruct>("/Script/FortniteGame.FortItemEntryStateValue");
static auto Struct = FindObject<UStruct>(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<UStruct>("/Script/FortniteGame.FortItemEntry");
static auto Struct = FindObject<UStruct>(L"/Script/FortniteGame.FortItemEntry");
return Struct;
}

View File

@@ -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++)
{

View File

@@ -7,10 +7,6 @@
#include "GameplayTagContainer.h"
#include "FortGameModeAthena.h"
#include <random>
#include <map>
#include <numeric>
struct FFortGameFeatureLootTableData
{
TSoftObjectPtr<UDataTable> LootTierData;
@@ -18,10 +14,6 @@ struct FFortGameFeatureLootTableData
};
#ifdef EXPERIMENTAL_LOOTING
float RandomFloatForLoot(float AllWeightsSum)
{
return (rand() * 0.000030518509) * AllWeightsSum;
}
template <typename RowStructType = uint8>
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)
{
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.
{
// 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<UDataTable*>& LTDTables, F
std::map<FName, FFortLootTierData*> TierGroupLTDs;
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;
}
@@ -227,9 +173,9 @@ FFortLootTierData* PickLootTierData(const std::vector<UDataTable*>& LTDTables, F
return false;
});
FFortLootTierData* ChosenRowLootTierData = PickWeightedElement<FFortLootTierData>(TierGroupLTDs,
[](FFortLootTierData* LootTierData) -> float { return LootTierData->GetWeight(); }, -1,
true, LootTier, OutRowName);
FFortLootTierData* ChosenRowLootTierData = PickWeightedElement<FName, FFortLootTierData*>(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<UDataTable*>& LPTables, cons
}
FName PickedPackageRowName;
FFortLootPackageData* PickedPackage = PickWeightedElement<FFortLootPackageData>(LootPackageIDMap,
[](FFortLootPackageData* LootPackageData) -> float { return LootPackageData->GetWeight(); },
FFortLootPackageData* PickedPackage = PickWeightedElement<FName, FFortLootPackageData*>(LootPackageIDMap,
[](FFortLootPackageData* LootPackageData) -> float { return LootPackageData->GetWeight(); }, RandomFloatForLoot,
-1, true, 1, &PickedPackageRowName, bPrint);
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;
@@ -659,7 +605,7 @@ std::vector<LootDrop> 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)
{

View File

@@ -1,6 +1,9 @@
#pragma once
#include <vector>
#include <random>
#include <map>
#include <numeric>
#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<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);
}
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);
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);
}

View File

@@ -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);
}
}
}
};

View File

@@ -112,7 +112,7 @@ void AFortPlayerController::DropAllItems(const std::vector<UFortItemDefinition*>
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<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);
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;

View File

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

View File

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

View File

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

View File

@@ -15,13 +15,30 @@ public:
auto GameState = Cast<AFortGameStateAthena>(GetWorld()->GetGameState());
auto GameMode = Cast<AFortGameModeAthena>(GetWorld()->GetGameMode());
#if 0
static auto PawnClass = FindObject<UClass>("/Game/Athena/PlayerPawn_Athena.PlayerPawn_Athena_C");
static auto ControllerClass = AFortPlayerControllerAthena::StaticClass();
#else
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");
#endif
static UClass* PawnClass = nullptr;
static UClass* ControllerClass = nullptr;
if (!PawnClass)
{
if (true)
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");
@@ -135,14 +152,12 @@ public:
FortPlayerController->Get<bool>(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<AFortPlayerController>(Controller))
{
// PlayerController->ServerExecuteInventoryItemHook(PlayerController, PickaxeInstance->GetItemEntry()->GetItemGuid());
UFortItem* PickaxeInstance = FortPlayerController->AddPickaxeToInventory();
if (PickaxeInstance)
{
FortPlayerController->ServerExecuteInventoryItemHook(FortPlayerController, PickaxeInstance->GetItemEntry()->GetItemGuid());
}
}
(*Inventory)->Update();

View File

@@ -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);
}

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

@@ -55,4 +55,27 @@ inline bool AreVehicleWeaponsEnabled()
inline bool IsRestartingSupported()
{
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 "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<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;
}
@@ -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<AFortGameStateAthena>(GameModeAthena->GetGameState());
static auto ItemCollectionsOffset = ItemCollector->GetOffset("ItemCollections");
auto& ItemCollections = ItemCollector->Get<TArray<FCollectorUnitInfo>>(ItemCollectionsOffset);
auto GameState = Cast<AFortGameStateAthena>(GetWorld()->GetGameState());
UCurveTable* FortGameData = nullptr;
@@ -74,7 +68,23 @@ static inline void FillItemCollector(ABuildingItemCollectorActor* ItemCollector,
}
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 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 MetalItemData = FindObject<UFortResourceItemDefinition>("/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<LootDrop> LootDrops = PickLootDrops(LootTierGroup, bPrint);
int tries = 0;
while (LootDrops.size() == 0)
{
tries++;
LootDrops = PickLootDrops(LootTierGroup, bPrint);
if (tries >= 10)
break;
}
std::vector<LootDrop> 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<uint8_t>(RarityOffset);
if (WorldItemDefinition->Get<uint8_t>(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<bool>(bUseInstanceLootValueOverridesOffset) = bUseInstanceLootValueOverrides;
LOG_INFO(LogDev, "RarityToUse: {}", (int)RarityToUse);
// LOG_INFO(LogDev, "LootTier: {}", LootTier);
static auto StartingGoalLevelOffset = ItemCollector->GetOffset("StartingGoalLevel");
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");
@@ -223,17 +209,17 @@ static inline void FillItemCollector(ABuildingItemCollectorActor* ItemCollector,
static auto OverrideVendingMachineRarityOffset = ItemCollector->GetOffset("OverrideVendingMachineRarity", false);
if (OverrideVendingMachineRarityOffset != -1)
ItemCollector->Get<uint8_t>(OverrideVendingMachineRarityOffset) = RarityToUse;
ItemCollector->Get<uint8_t>(OverrideVendingMachineRarityOffset) = LootTier;
static auto OverrideGoalOffset = ItemCollector->GetOffset("OverrideGoal", false);
if (OverrideGoalOffset != -1)
{
ItemCollector->Get<int32>(OverrideGoalOffset) = RarityToUse == 0 ? CommonPrice
: RarityToUse == 1 ? UncommonPrice
: RarityToUse == 2 ? RarePrice
: RarityToUse == 3 ? EpicPrice
: RarityToUse == 4 ? LegendaryPrice
ItemCollector->Get<int32>(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<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++)
{
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<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();
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);
}
}