abundant update

complete looting rewrite, improve combining pickups, add debug printing logs, fix some agids, fix cheat summon, fix issue with vehicle spawning.
This commit is contained in:
Milxnor
2023-05-06 19:01:56 -04:00
parent a4ed589aab
commit 5e92f2e90b
31 changed files with 1113 additions and 201 deletions

View File

@@ -35,11 +35,6 @@ void SpawnBGAs() // hahah not "proper", there's a function that we can hook and
auto MapInfo = GameState->GetMapInfo();
}
else
{
// SpawnLocation.Z += 100;
// SpawnLocation.Z -= 50; // proper frfr
}
static auto SpawnLootTierGroupOffset = BGAConsumableSpawner->GetOffset("SpawnLootTierGroup");
auto& SpawnLootTierGroup = BGAConsumableSpawner->Get<FName>(SpawnLootTierGroupOffset);
@@ -48,8 +43,8 @@ void SpawnBGAs() // hahah not "proper", there's a function that we can hook and
for (auto& LootDrop : LootDrops)
{
static auto ConsumableClassOffset = LootDrop.ItemDefinition->GetOffset("ConsumableClass");
auto ConsumableClassSoft = LootDrop.ItemDefinition->GetPtr<TSoftObjectPtr<UClass>>(ConsumableClassOffset);
static auto ConsumableClassOffset = LootDrop->GetItemDefinition()->GetOffset("ConsumableClass");
auto ConsumableClassSoft = LootDrop->GetItemDefinition()->GetPtr<TSoftObjectPtr<UClass>>(ConsumableClassOffset);
static auto BlueprintGeneratedClassClass = FindObject<UClass>(L"/Script/Engine.BlueprintGeneratedClass");
auto StrongConsumableClass = ConsumableClassSoft->Get(BlueprintGeneratedClassClass, true);

View File

@@ -2,6 +2,7 @@
#include "FortPickup.h"
#include "FortLootPackage.h"
#include "FortGameModeAthena.h"
#include "gui.h"
bool ABuildingContainer::SpawnLoot(AFortPawn* Pawn)
{
@@ -12,14 +13,14 @@ bool ABuildingContainer::SpawnLoot(AFortPawn* Pawn)
// LOG_INFO(LogInteraction, "RedirectedLootTier: {}", RedirectedLootTier.ToString());
auto LootDrops = PickLootDrops(RedirectedLootTier, true);
auto LootDrops = PickLootDrops(RedirectedLootTier, bDebugPrintLooting);
// LOG_INFO(LogInteraction, "LootDrops.size(): {}", LootDrops.size());
for (int i = 0; i < LootDrops.size(); i++)
{
auto& lootDrop = LootDrops.at(i);
AFortPickup::SpawnPickup(lootDrop.ItemDefinition, LocationToSpawnLoot, lootDrop.Count, EFortPickupSourceTypeFlag::Container, EFortPickupSpawnSource::Unset, lootDrop.LoadedAmmo);
AFortPickup::SpawnPickup(lootDrop->GetItemDefinition(), LocationToSpawnLoot, lootDrop->GetCount(), EFortPickupSourceTypeFlag::Container, EFortPickupSpawnSource::Unset, lootDrop->GetLoadedAmmo());
}
return true;

View File

@@ -34,3 +34,10 @@ struct RowNameAndRowData
FName RowName;
StructType* RowData;
};
struct FDataTableCategoryHandle
{
UDataTable* DataTable; // 0x0000(0x0008) (Edit, BlueprintVisible, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic)
FName ColumnName; // 0x0008(0x0008) (Edit, BlueprintVisible, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic)
FName RowContents; // 0x0010(0x0008) (Edit, BlueprintVisible, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic)
};

View File

@@ -40,6 +40,7 @@ void AFortAthenaMapInfo::SpawnLlamas()
return;
}
int AmountOfLlamasSpawned = 0;
auto AmountOfLlamasToSpawn = CalcuateCurveMinAndMax(GetLlamaQuantityMin(), GetLlamaQuantityMax(), 1);
LOG_INFO(LogDev, "Attempting to spawn {} llamas.", AmountOfLlamasToSpawn);
@@ -67,7 +68,7 @@ void AFortAthenaMapInfo::SpawnLlamas()
auto LlamaStart = GetWorld()->SpawnActor<AFortAthenaSupplyDrop>(GetLlamaClass(), InitialSpawnTransform, SpawnParameters);
LOG_INFO(LogDev, "LlamaStart: {}", __int64(LlamaStart));
// LOG_INFO(LogDev, "LlamaStart: {}", __int64(LlamaStart));
if (!LlamaStart)
continue;
@@ -80,5 +81,8 @@ void AFortAthenaMapInfo::SpawnLlamas()
LOG_INFO(LogDev, "Spawning Llama at {} {} {}", GroundLocation.X, GroundLocation.Y, GroundLocation.Z);
UGameplayStatics::FinishSpawningActor(LlamaStart, FinalSpawnTransform);
AmountOfLlamasSpawned++;
}
LOG_INFO(LogGame, "Spawned {} llamas.", AmountOfLlamasSpawned);
}

View File

@@ -17,6 +17,15 @@ public:
return GetPawnAtSeat_Params.ReturnValue;
}
int FindSeatIndex(class AFortPlayerPawn* PlayerPawn)
{
static auto FindSeatIndexFn = FindObject<UFunction>("/Script/FortniteGame.FortAthenaVehicle.FindSeatIndex");
struct { AFortPlayerPawn* PlayerPawn; int ReturnValue; } AFortAthenaVehicle_FindSeatIndex_Params{ PlayerPawn };
this->ProcessEvent(FindSeatIndexFn, &AFortAthenaVehicle_FindSeatIndex_Params);
return AFortAthenaVehicle_FindSeatIndex_Params.ReturnValue;
}
UFortWeaponItemDefinition* GetVehicleWeaponForSeat(int SeatIdx);
static UClass* StaticClass()

View File

@@ -963,7 +963,7 @@ void AFortGameModeAthena::Athena_HandleStartingNewPlayerHook(AFortGameModeAthena
{
for (auto& LootDrop : LootDrops)
{
auto Pickup = AFortPickup::SpawnPickup(LootDrop.ItemDefinition, Location, LootDrop.Count, SpawnFlag, EFortPickupSpawnSource::Unset, LootDrop.LoadedAmmo);
auto Pickup = AFortPickup::SpawnPickup(LootDrop->GetItemDefinition(), Location, LootDrop->GetCount(), SpawnFlag, EFortPickupSpawnSource::Unset, LootDrop->GetLoadedAmmo());
}
}
}
@@ -996,7 +996,7 @@ void AFortGameModeAthena::Athena_HandleStartingNewPlayerHook(AFortGameModeAthena
{
for (auto& LootDrop : LootDrops)
{
auto Pickup = AFortPickup::SpawnPickup(LootDrop.ItemDefinition, Location, LootDrop.Count, SpawnFlag, EFortPickupSpawnSource::Unset, LootDrop.LoadedAmmo);
auto Pickup = AFortPickup::SpawnPickup(LootDrop->GetItemDefinition(), Location, LootDrop->GetCount(), SpawnFlag, EFortPickupSpawnSource::Unset, LootDrop->GetLoadedAmmo());
}
}
@@ -1013,9 +1013,9 @@ void AFortGameModeAthena::Athena_HandleStartingNewPlayerHook(AFortGameModeAthena
if (Engine_Version >= 423 && Fortnite_Version <= 12.61) // 423+ we need to spawn manually and vehicle sync doesn't work on >S13.
{
static int LastNum420 = 1;
static int LastNum420 = 114;
if (Globals::AmountOfListens != LastNum420)
if (LastNum420 != Globals::AmountOfListens)
{
LastNum420 = Globals::AmountOfListens;

View File

@@ -154,7 +154,7 @@ std::pair<std::vector<UFortItem*>, std::vector<UFortItem*>> AFortInventory::AddI
{
if (GadgetItemDefinition->ShouldDropAllItemsOnEquip()) // idk shouldnt this be auto?
{
FortPlayerController->DropAllItems({ GadgetItemDefinition });
FortPlayerController->DropAllItems({ GadgetItemDefinition }, false, false, Fortnite_Version < 7);
}
bool (*ApplyGadgetData)(UFortGadgetItemDefinition* a1, __int64 a2, UFortItem* a3, unsigned __int8 a4) = decltype(ApplyGadgetData)(Addresses::ApplyGadgetData);
@@ -165,17 +165,6 @@ std::pair<std::vector<UFortItem*>, std::vector<UFortItem*>> AFortInventory::AddI
bool DidApplyingGadgetSucceed = ApplyGadgetData(GadgetItemDefinition, Interface, NewItemInstance, idktbh);
LOG_INFO(LogDev, "DidApplyingGadgetSucceed: {}", DidApplyingGadgetSucceed);
bWasGadget = true;
if (Fortnite_Version < 7)
{
auto PickaxeInstance = GetPickaxeInstance();
if (PickaxeInstance)
{
// RemoveItem(PickaxeInstance->GetItemEntry()->GetItemGuid(), nullptr, PickaxeInstance->GetItemEntry()->GetCount(), true);
Update();
}
}
}
}
@@ -185,14 +174,6 @@ std::pair<std::vector<UFortItem*>, std::vector<UFortItem*>> AFortInventory::AddI
FortPlayerController->ServerExecuteInventoryItemHook(FortPlayerController, NewItemInstance->GetItemEntry()->GetItemGuid());
FortPlayerController->ClientEquipItem(NewItemInstance->GetItemEntry()->GetItemGuid(), true);
}
if (bWasGadget)
{
if (Fortnite_Version < 7)
{
// FortPlayerController->AddPickaxeToInventory();
}
}
}
else
{
@@ -357,9 +338,12 @@ bool AFortInventory::RemoveItem(const FGuid& ItemGuid, bool* bShouldUpdate, int
bWasGadget = true;
if (Fortnite_Version < 7)
if (bWasGadget)
{
// FortPlayerController->AddPickaxeToInventory();
if (Fortnite_Version < 7 && GadgetItemDefinition->ShouldDropAllItemsOnEquip())
{
FortPlayerController->AddPickaxeToInventory();
}
}
}
}

View File

@@ -1,7 +1,10 @@
#pragma once
#include <Windows.h>
#include "NetSerialization.h"
#include "Class.h"
#include "GameplayAbilitySpec.h"
#include "reboot.h"
@@ -101,6 +104,24 @@ struct FFortItemEntry : FFastArraySerializerItem
return *(int*)(__int64(this) + LoadedAmmoOffset);
}
float& GetDurability()
{
static auto DurabilityOffset = FindOffsetStruct("/Script/FortniteGame.FortItemEntry", "Durability");
return *(float*)(__int64(this) + DurabilityOffset);
}
FGameplayAbilitySpecHandle& GetGameplayAbilitySpecHandle()
{
static auto GameplayAbilitySpecHandleOffset = FindOffsetStruct("/Script/FortniteGame.FortItemEntry", "GameplayAbilitySpecHandle");
return *(FGameplayAbilitySpecHandle*)(__int64(this) + GameplayAbilitySpecHandleOffset);
}
TWeakObjectPtr<class AFortInventory>& GetParentInventory()
{
static auto ParentInventoryOffset = FindOffsetStruct("/Script/FortniteGame.FortItemEntry", "ParentInventory");
return *(TWeakObjectPtr<class AFortInventory>*)(__int64(this) + ParentInventoryOffset);
}
void CopyFromAnotherItemEntry(FFortItemEntry* OtherItemEntry, bool bCopyGuid = false)
{
// We can use FortItemEntryStruct->CopyScriptStruct
@@ -142,7 +163,7 @@ struct FFortItemEntry : FFastArraySerializerItem
return StructSize;
}
static FFortItemEntry* MakeItemEntry(UFortItemDefinition* ItemDefinition, int Count = 1, int LoadedAmmo = 0)
static FFortItemEntry* MakeItemEntry(UFortItemDefinition* ItemDefinition, int Count = 1, int LoadedAmmo = 0, float Durability = 0x3F800000)
{
auto Entry = // (FFortItemEntry*)FMemory::Realloc(0, GetStructSize(), 0);
Alloc<FFortItemEntry>(GetStructSize());
@@ -150,14 +171,18 @@ struct FFortItemEntry : FFastArraySerializerItem
if (!Entry)
return nullptr;
Entry->MostRecentArrayReplicationKey = -1;
Entry->MostRecentArrayReplicationKey = -1; // idk if we need to set this
Entry->ReplicationID = -1;
Entry->ReplicationKey = -1;
Entry->GetItemDefinition() = ItemDefinition;
Entry->GetCount() = Count;
Entry->GetLoadedAmmo() = LoadedAmmo;
// Entry->bUpdateStatsOnCollection = true; // Idk what this does but fortnite does it soo
Entry->GetDurability() = Durability;
Entry->GetGameplayAbilitySpecHandle() = FGameplayAbilitySpecHandle(-1);
Entry->GetParentInventory().ObjectIndex = -1;
// CoCreateGuid((GUID*)&Entry->GetItemGuid());
// Entry->bUpdateStatsOnCollection = true; // Idk what this does but fortnite does it i think
return Entry;
}

View File

@@ -35,6 +35,27 @@ UFortResourceItemDefinition* UFortKismetLibrary::K2_GetResourceItemDefinition(EF
return params.ret;
}
FVector UFortKismetLibrary::FindGroundLocationAt(UWorld* World, AActor* IgnoreActor, FVector InLocation, float TraceStartZ, float TraceEndZ, FName TraceName)
{
static auto FindGroundLocationAtFn = FindObject<UFunction>("/Script/FortniteGame.FortKismetLibrary.FindGroundLocationAt");
struct
{
UWorld* World; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic)
AActor* IgnoreActor; // (ConstParm, Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic)
FVector InLocation; // (ConstParm, Parm, OutParm, ZeroConstructor, ReferenceParm, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic)
float TraceStartZ; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic)
float TraceEndZ; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic)
FName TraceName; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic)
FVector ReturnValue; // (Parm, OutParm, ZeroConstructor, ReturnParm, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic)
} UFortKismetLibrary_FindGroundLocationAt_Params{ World, IgnoreActor, InLocation, TraceStartZ, TraceEndZ, TraceName };
static auto DefaultClass = StaticClass();
DefaultClass->ProcessEvent(FindGroundLocationAtFn, &UFortKismetLibrary_FindGroundLocationAt_Params);
return UFortKismetLibrary_FindGroundLocationAt_Params.ReturnValue;
}
void UFortKismetLibrary::ApplyCharacterCosmetics(UObject* WorldContextObject, const TArray<UObject*>& CharacterParts, UObject* PlayerState, bool* bSuccess)
{
static auto fn = FindObject<UFunction>("/Script/FortniteGame.FortKismetLibrary.ApplyCharacterCosmetics");
@@ -550,7 +571,7 @@ bool UFortKismetLibrary::PickLootDropsHook(UObject* Context, FFrame& Stack, bool
{
auto& LootDrop = LootDrops.at(i);
auto NewEntry = FFortItemEntry::MakeItemEntry(LootDrop.ItemDefinition, LootDrop.Count, LootDrop.LoadedAmmo);
auto NewEntry = FFortItemEntry::MakeItemEntry(LootDrop->GetItemDefinition(), LootDrop->GetCount(), LootDrop->GetLoadedAmmo());
OutLootToDrop.AddPtr(NewEntry, FFortItemEntry::GetStructSize());
}

View File

@@ -84,6 +84,7 @@ public:
static UFortResourceItemDefinition* K2_GetResourceItemDefinition(EFortResourceType ResourceType);
static void ApplyCharacterCosmetics(UObject* WorldContextObject, const TArray<UObject*>& CharacterParts, UObject* PlayerState, bool* bSuccess);
static FVector FindGroundLocationAt(UWorld* World, AActor* IgnoreActor, FVector InLocation, float TraceStartZ, float TraceEndZ, FName TraceName);
static void PickLootDropsWithNamedWeightsHook(UObject* Context, FFrame& Stack, void* Ret);
static void SpawnItemVariantPickupInWorldHook(UObject* Context, FFrame& Stack, void* Ret);

View File

@@ -0,0 +1,11 @@
#pragma once
#include "DataTable.h"
class UFortLootLevel
{
int GetItemLevel(FDataTableCategoryHandle LootLevelData, int WorldLevel)
{
return 0;
}
};

View File

@@ -8,6 +8,711 @@
#include "FortGameModeAthena.h"
#include <random>
#include <map>
#include <numeric>
struct FFortGameFeatureLootTableData
{
TSoftObjectPtr<UDataTable> LootTierData;
TSoftObjectPtr<UDataTable> LootPackageData;
};
#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; })
{
std::vector<UDataTable*> DataTablesToIterate;
static auto CompositeDataTableClass = FindObject<UClass>("/Script/Engine.CompositeDataTable");
for (auto DataTable : DataTables)
{
// if (auto CompositeDataTable = Cast<UCompositeDataTable>(DataTable))
if (DataTable->IsA(CompositeDataTableClass))
{
auto CompositeDataTable = DataTable;
static auto ParentTablesOffset = DataTable->GetOffset("ParentTables");
auto& ParentTables = DataTable->Get<TArray<UDataTable*>>(ParentTablesOffset);
for (int i = 0; i < ParentTables.Num(); i++)
{
DataTablesToIterate.push_back(ParentTables.at(i));
}
}
DataTablesToIterate.push_back(DataTable);
}
for (auto CurrentDataTable : DataTablesToIterate)
{
for (auto& CurrentPair : CurrentDataTable->GetRowMap())
{
if (Check(CurrentPair.Key(), (RowStructType*)CurrentPair.Value()))
(*OutMap)[CurrentPair.Key()] = (RowStructType*)CurrentPair.Value();
}
}
}
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)
{
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;
}
float GetAmountOfLootPackagesToDrop(FFortLootTierData* LootTierData, int OriginalNumberLootDrops)
{
if (LootTierData->GetLootPackageCategoryMinArray().Num() != LootTierData->GetLootPackageCategoryWeightArray().Num()
|| LootTierData->GetLootPackageCategoryMinArray().Num() != LootTierData->GetLootPackageCategoryMaxArray().Num()
)
return 0;
// return OriginalNumberLootDrops;
float MinimumLootDrops = 0;
if (LootTierData->GetLootPackageCategoryMinArray().Num() > 0)
{
for (int i = 0; i < LootTierData->GetLootPackageCategoryMinArray().Num(); i++)
{
// Fortnite does more here, we need to figure it out.
MinimumLootDrops += LootTierData->GetLootPackageCategoryMinArray().at(i);
}
}
if (MinimumLootDrops > OriginalNumberLootDrops)
{
LOG_INFO(LogLoot, "Requested {} loot drops but minimum drops is {} for loot package {}", OriginalNumberLootDrops, MinimumLootDrops, LootTierData->GetLootPackage().ToString());
// Fortnite doesn't return here?
}
int SumLootPackageCategoryWeightArray = 0;
if (LootTierData->GetLootPackageCategoryWeightArray().Num() > 0)
{
for (int i = 0; i < LootTierData->GetLootPackageCategoryWeightArray().Num(); i++)
{
// Fortnite does more here, we need to figure it out.
if (LootTierData->GetLootPackageCategoryWeightArray().at(i) > 0)
{
auto LootPackageCategoryMaxArrayIt = LootTierData->GetLootPackageCategoryMaxArray().at(i);
float IDK = 0; // TODO
if (LootPackageCategoryMaxArrayIt < 0 || IDK < LootPackageCategoryMaxArrayIt)
{
SumLootPackageCategoryWeightArray += LootTierData->GetLootPackageCategoryWeightArray().at(i);
}
}
}
}
// if (MinimumLootDrops < OriginalNumberLootDrops) // real commeneted one to one
{
// IDK
while (SumLootPackageCategoryWeightArray > 0)
{
// HONESTLY IDEK WHAT FORTNITE DOES HERE
float v29 = (float)rand() * 0.000030518509;
float v35 = (int)(float)((float)((float)((float)SumLootPackageCategoryWeightArray * v29)
+ (float)((float)SumLootPackageCategoryWeightArray * v29))
+ 0.5) >> 1;
// OutLootTierInfo->Hello++;
MinimumLootDrops++;
if (MinimumLootDrops >= OriginalNumberLootDrops)
return MinimumLootDrops;
SumLootPackageCategoryWeightArray--;
}
/* if (MinimumLootDrops < OriginalNumberLootDrops)
{
std::cout << std::format("Requested {} loot drops but maximum drops is {} for loot package {}\n", OriginalNumberLootDrops, MinimumLootDrops, LootTierData->LootPackage.ToString());
} */
}
return MinimumLootDrops;
}
/*struct UFortLootPackage
{
int CurrentIdx = 0;
std::vector<FFortItemEntry> ItemEntries;
}; */
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.
{
float LootTier = ForcedLootTier;
if (LootTier == -1)
{
LootTier = 0;
}
else
{
// buncha code im too lazy to reverse
}
LootTier = 1; // ONG PROPER
// if (fabs(LootTier) <= 0.0000000099999999)
// return 0;
std::map<FName, FFortLootTierData*> TierGroupLTDs;
CollectDataTablesRows<FFortLootTierData>(LTDTables, &TierGroupLTDs, [&](FName RowName, FFortLootTierData* TierData) -> bool {
if (LootTierGroup == TierData->GetTierGroup())
{
return true;
}
return false;
});
FFortLootTierData* ChosenRowLootTierData = PickWeightedElement<FFortLootTierData>(TierGroupLTDs,
[](FFortLootTierData* LootTierData) -> float { return LootTierData->GetWeight(); }, -1,
true, LootTier, OutRowName);
if (!ChosenRowLootTierData)
return nullptr;
return ChosenRowLootTierData;
}
void PickLootDropsFromLootPackage(const std::vector<UDataTable*>& LPTables, const FName& LootPackageName, std::vector<LootDrop>* OutEntries, int LootPackageCategory = -1, bool bPrint = false)
{
if (!OutEntries)
return;
std::map<FName, FFortLootPackageData*> LootPackageIDMap;
CollectDataTablesRows<FFortLootPackageData>(LPTables, &LootPackageIDMap, [&](FName RowName, FFortLootPackageData* LootPackage) -> bool {
if (LootPackage->GetLootPackageID() != LootPackageName)
{
return false;
}
if (LootPackageCategory != -1 && LootPackage->GetLootPackageCategory() != LootPackageCategory) // idk if proper
{
return false;
}
/* if (WorldLevel >= 0)
{
if (LootPackage->MaxWorldLevel >= 0 && WorldLevel > LootPackage->MaxWorldLevel)
return 0;
if (LootPackage->MinWorldLevel >= 0 && WorldLevel < LootPackage->MinWorldLevel)
return 0;
} */
return true;
});
if (LootPackageIDMap.size() == 0)
{
// std::cout << std::format("Loot Package {} has no valid weights.\n", LootPackageName.ToString());
return;
}
FName PickedPackageRowName;
FFortLootPackageData* PickedPackage = PickWeightedElement<FFortLootPackageData>(LootPackageIDMap,
[](FFortLootPackageData* LootPackageData) -> float { return LootPackageData->GetWeight(); },
-1, true, 1, &PickedPackageRowName, bPrint);
if (!PickedPackage)
return;
if (bPrint)
LOG_INFO(LogLoot, "PickLootDropsFromLootPackage selected package {} with loot package category {} from LootPackageIDMap of size: {}", PickedPackageRowName.ToString(), LootPackageCategory, LootPackageIDMap.size());
if (PickedPackage->GetLootPackageCall().Data.Num() > 1)
{
if (PickedPackage->GetCount() > 0)
{
int v9 = 0;
while (v9 < PickedPackage->GetCount())
{
int LootPackageCategoryToUseForLPCall = 0; // hmm
PickLootDropsFromLootPackage(LPTables,
PickedPackage->GetLootPackageCall().Data.Data ? UKismetStringLibrary::Conv_StringToName(PickedPackage->GetLootPackageCall()) : FName(0),
OutEntries, LootPackageCategoryToUseForLPCall, bPrint
);
v9++;
}
}
return;
}
auto ItemDefinition = PickedPackage->GetItemDefinition().Get(UFortItemDefinition::StaticClass(), true);
if (!ItemDefinition)
{
LOG_INFO(LogLoot, "Loot Package {} does not contain a LootPackageCall or ItemDefinition.", PickedPackage->GetLootPackageID().ToString());
return;
}
int ItemLevel = 0;
auto WeaponItemDefinition = Cast<UFortWeaponItemDefinition>(ItemDefinition);
int LoadedAmmo = WeaponItemDefinition ? WeaponItemDefinition->GetClipSize() : 0; // we shouldnt set loaded ammo here techinally
if (auto WorldItemDefinition = Cast<UFortWorldItemDefinition>(ItemDefinition))
{
ItemLevel = 0; // GetItemLevel(WorldItemDefinition->LootLevelData, 0);
}
int CountMultiplier = 1;
int FinalCount = CountMultiplier * PickedPackage->GetCount();
if (FinalCount > 0)
{
int FinalItemLevel = 0;
if (ItemLevel >= 0)
FinalItemLevel = ItemLevel;
while (FinalCount > 0)
{
int CurrentCountForEntry = PickedPackage->GetCount(); // Idk calls some itemdefinition vfunc
OutEntries->push_back(LootDrop(FFortItemEntry::MakeItemEntry(ItemDefinition, CurrentCountForEntry, LoadedAmmo)));
if (Engine_Version >= 424)
{
/*
Alright, so Fortnite literally doesn't reference the first loot package category for chests and floor loot (didnt check rest).
Usually the first loot package category in our case is ammo, so this is quite weird.
I have no clue how Fortnite would actually add the ammo.
Guess what, on the chapter 2 new loot tier groups, like FactionChests, they don't even have a package which has ammo as its loot package call.
*/
bool IsWeapon = PickedPackage->GetLootPackageID().ToString().contains(".Weapon.") && WeaponItemDefinition; // ONG?
if (IsWeapon)
{
auto AmmoData = WeaponItemDefinition->GetAmmoData();
int AmmoCount = AmmoData->GetDropCount(); // idk about this one
OutEntries->push_back(LootDrop(FFortItemEntry::MakeItemEntry(WeaponItemDefinition->GetAmmoData(), AmmoCount)));
}
}
FinalCount -= CurrentCountForEntry;
}
}
}
std::vector<LootDrop> PickLootDrops(FName TierGroupName, bool bPrint, int recursive)
{
std::vector<LootDrop> LootDrops;
if (recursive > 6)
return LootDrops;
auto GameState = ((AFortGameModeAthena*)GetWorld()->GetGameMode())->GetGameStateAthena();
static auto CurrentPlaylistDataOffset = GameState->GetOffset("CurrentPlaylistData", false);
static std::vector<UDataTable*> LTDTables;
static std::vector<UDataTable*> LPTables;
static auto CompositeDataTableClass = FindObject<UClass>(L"/Script/Engine.CompositeDataTable");
static int LastNum1 = 14915;
auto CurrentPlaylist = CurrentPlaylistDataOffset == -1 && Fortnite_Version < 6 ? nullptr : GameState->GetCurrentPlaylist();
if (LastNum1 != Globals::AmountOfListens)
{
LastNum1 = Globals::AmountOfListens;
LTDTables.clear();
LPTables.clear();
bool bFoundPlaylistTable = false;
if (CurrentPlaylist)
{
static auto LootTierDataOffset = CurrentPlaylist->GetOffset("LootTierData");
auto& LootTierDataSoft = CurrentPlaylist->Get<TSoftObjectPtr<UDataTable>>(LootTierDataOffset);
static auto LootPackagesOffset = CurrentPlaylist->GetOffset("LootPackages");
auto& LootPackagesSoft = CurrentPlaylist->Get<TSoftObjectPtr<UDataTable>>(LootPackagesOffset);
if (LootTierDataSoft.IsValid() && LootPackagesSoft.IsValid())
{
auto LootTierDataStr = LootTierDataSoft.SoftObjectPtr.ObjectID.AssetPathName.ToString();
auto LootPackagesStr = LootPackagesSoft.SoftObjectPtr.ObjectID.AssetPathName.ToString();
auto LootTierDataTableIsComposite = LootTierDataStr.contains("Composite");
auto LootPackageTableIsComposite = LootPackagesStr.contains("Composite");
auto StrongLootTierData = LootTierDataSoft.Get(LootTierDataTableIsComposite ? CompositeDataTableClass : UDataTable::StaticClass(), true);
auto StrongLootPackage = LootPackagesSoft.Get(LootPackageTableIsComposite ? CompositeDataTableClass : UDataTable::StaticClass(), true);
if (StrongLootTierData && StrongLootPackage)
{
LTDTables.push_back(StrongLootTierData);
LPTables.push_back(StrongLootPackage);
bFoundPlaylistTable = true;
}
}
}
if (!bFoundPlaylistTable)
{
LTDTables.push_back(LoadObject<UDataTable>(L"/Game/Items/Datatables/AthenaLootTierData_Client.AthenaLootTierData_Client"));
LPTables.push_back(LoadObject<UDataTable>(L"/Game/Items/Datatables/AthenaLootPackages_Client.AthenaLootPackages_Client"));
}
// LTDTables.push_back(LoadObject<UDataTable>(L"/Game/Athena/Playlists/Playground/AthenaLootTierData_Client.AthenaLootTierData_Client"));
// LPTables.push_back(LoadObject<UDataTable>(L"/Game/Athena/Playlists/Playground/AthenaLootPackages_Client.AthenaLootPackages_Client"));
static auto FortGameFeatureDataClass = FindObject<UClass>("/Script/FortniteGame.FortGameFeatureData");
if (FortGameFeatureDataClass)
{
for (int i = 0; i < ChunkedObjects->Num(); i++)
{
auto Object = ChunkedObjects->GetObjectByIndex(i);
if (!Object)
continue;
if (Object->IsA(FortGameFeatureDataClass))
{
auto GameFeatureData = Object;
static auto DefaultLootTableDataOffset = GameFeatureData->GetOffset("DefaultLootTableData");
if (DefaultLootTableDataOffset != -1)
{
auto DefaultLootTableData = GameFeatureData->GetPtr<FFortGameFeatureLootTableData>(DefaultLootTableDataOffset);
auto LootTierDataTableStr = DefaultLootTableData->LootTierData.SoftObjectPtr.ObjectID.AssetPathName.ToString();
auto LootTierDataTableIsComposite = LootTierDataTableStr.contains("Composite");
auto LootPackageTableStr = DefaultLootTableData->LootPackageData.SoftObjectPtr.ObjectID.AssetPathName.ToString();
auto LootPackageTableIsComposite = LootPackageTableStr.contains("Composite");
auto LootTierDataPtr = DefaultLootTableData->LootTierData.Get(LootTierDataTableIsComposite ? CompositeDataTableClass : UDataTable::StaticClass(), true);
auto LootPackagePtr = DefaultLootTableData->LootPackageData.Get(LootPackageTableIsComposite ? CompositeDataTableClass : UDataTable::StaticClass(), true);
if (LootPackagePtr)
{
LPTables.push_back(LootPackagePtr);
}
if (CurrentPlaylist)
{
static auto PlaylistOverrideLootTableDataOffset = GameFeatureData->GetOffset("PlaylistOverrideLootTableData");
auto& PlaylistOverrideLootTableData = GameFeatureData->Get<TMap<FGameplayTag, FFortGameFeatureLootTableData>>(PlaylistOverrideLootTableDataOffset);
static auto GameplayTagContainerOffset = CurrentPlaylist->GetOffset("GameplayTagContainer");
auto GameplayTagContainer = CurrentPlaylist->GetPtr<FGameplayTagContainer>(GameplayTagContainerOffset);
for (int i = 0; i < GameplayTagContainer->GameplayTags.Num(); i++)
{
auto& Tag = GameplayTagContainer->GameplayTags.At(i);
for (auto& Value : PlaylistOverrideLootTableData)
{
auto CurrentOverrideTag = Value.First;
if (Tag.TagName == CurrentOverrideTag.TagName)
{
auto OverrideLootPackageTableStr = Value.Second.LootPackageData.SoftObjectPtr.ObjectID.AssetPathName.ToString();
auto bOverrideIsComposite = OverrideLootPackageTableStr.contains("Composite");
auto ptr = Value.Second.LootPackageData.Get(bOverrideIsComposite ? CompositeDataTableClass : UDataTable::StaticClass(), true);
if (ptr)
{
/* if (bOverrideIsComposite)
{
static auto ParentTablesOffset = ptr->GetOffset("ParentTables");
auto ParentTables = ptr->GetPtr<TArray<UDataTable*>>(ParentTablesOffset);
for (int z = 0; z < ParentTables->size(); z++)
{
auto ParentTable = ParentTables->At(z);
if (ParentTable)
{
LPTables.push_back(ParentTable);
}
}
} */
LPTables.push_back(ptr);
}
}
}
}
}
if (LootTierDataPtr)
{
LTDTables.push_back(LootTierDataPtr);
}
if (CurrentPlaylist)
{
static auto PlaylistOverrideLootTableDataOffset = GameFeatureData->GetOffset("PlaylistOverrideLootTableData");
auto& PlaylistOverrideLootTableData = GameFeatureData->Get<TMap<FGameplayTag, FFortGameFeatureLootTableData>>(PlaylistOverrideLootTableDataOffset);
static auto GameplayTagContainerOffset = CurrentPlaylist->GetOffset("GameplayTagContainer");
auto GameplayTagContainer = CurrentPlaylist->GetPtr<FGameplayTagContainer>(GameplayTagContainerOffset);
for (int i = 0; i < GameplayTagContainer->GameplayTags.Num(); i++)
{
auto& Tag = GameplayTagContainer->GameplayTags.At(i);
for (auto& Value : PlaylistOverrideLootTableData)
{
auto CurrentOverrideTag = Value.First;
if (Tag.TagName == CurrentOverrideTag.TagName)
{
auto OverrideLootTierDataStr = Value.Second.LootTierData.SoftObjectPtr.ObjectID.AssetPathName.ToString();
auto bOverrideIsComposite = OverrideLootTierDataStr.contains("Composite");
auto ptr = Value.Second.LootTierData.Get(bOverrideIsComposite ? CompositeDataTableClass : UDataTable::StaticClass(), true);
if (ptr)
{
/* if (bOverrideIsComposite)
{
static auto ParentTablesOffset = ptr->GetOffset("ParentTables");
auto ParentTables = ptr->GetPtr<TArray<UDataTable*>>(ParentTablesOffset);
for (int z = 0; z < ParentTables->size(); z++)
{
auto ParentTable = ParentTables->At(z);
if (ParentTable)
{
LTDTables.push_back(ParentTable);
}
}
} */
LTDTables.push_back(ptr);
}
}
}
}
}
}
}
}
}
for (int i = 0; i < LTDTables.size(); i++)
{
auto& Table = LTDTables.at(i);
if (!Table->IsValidLowLevel())
{
continue;
}
Table->AddToRoot();
LOG_INFO(LogDev, "[{}] LTD {}", i, Table->GetFullName());
}
for (int i = 0; i < LPTables.size(); i++)
{
auto& Table = LPTables.at(i);
if (!Table->IsValidLowLevel())
{
continue;
}
Table->AddToRoot();
LOG_INFO(LogDev, "[{}] LP {}", i, Table->GetFullName());
}
}
if (Fortnite_Version <= 6 || std::floor(Fortnite_Version) == 9) // ahhh
{
LTDTables.clear();
LPTables.clear();
bool bFoundPlaylistTable = false;
if (CurrentPlaylist)
{
static auto LootTierDataOffset = CurrentPlaylist->GetOffset("LootTierData");
auto& LootTierDataSoft = CurrentPlaylist->Get<TSoftObjectPtr<UDataTable>>(LootTierDataOffset);
static auto LootPackagesOffset = CurrentPlaylist->GetOffset("LootPackages");
auto& LootPackagesSoft = CurrentPlaylist->Get<TSoftObjectPtr<UDataTable>>(LootPackagesOffset);
if (LootTierDataSoft.IsValid() && LootPackagesSoft.IsValid())
{
auto LootTierDataStr = LootTierDataSoft.SoftObjectPtr.ObjectID.AssetPathName.ToString();
auto LootPackagesStr = LootPackagesSoft.SoftObjectPtr.ObjectID.AssetPathName.ToString();
auto LootTierDataTableIsComposite = LootTierDataStr.contains("Composite");
auto LootPackageTableIsComposite = LootPackagesStr.contains("Composite");
auto StrongLootTierData = LootTierDataSoft.Get(LootTierDataTableIsComposite ? CompositeDataTableClass : UDataTable::StaticClass(), true);
auto StrongLootPackage = LootPackagesSoft.Get(LootPackageTableIsComposite ? CompositeDataTableClass : UDataTable::StaticClass(), true);
if (StrongLootTierData && StrongLootPackage)
{
LTDTables.push_back(StrongLootTierData);
LPTables.push_back(StrongLootPackage);
bFoundPlaylistTable = true;
}
}
}
if (!bFoundPlaylistTable)
{
LTDTables.push_back(LoadObject<UDataTable>(L"/Game/Items/Datatables/AthenaLootTierData_Client.AthenaLootTierData_Client"));
LPTables.push_back(LoadObject<UDataTable>(L"/Game/Items/Datatables/AthenaLootPackages_Client.AthenaLootPackages_Client"));
}
}
if (LTDTables.size() <= 0 || LPTables.size() <= 0)
{
LOG_WARN(LogLoot, "Empty tables! ({} {})", LTDTables.size(), LPTables.size());
return LootDrops;
}
FName LootTierRowName;
auto ChosenRowLootTierData = PickLootTierData(LTDTables, TierGroupName, 0, -1, &LootTierRowName);
if (!ChosenRowLootTierData)
{
return LootDrops;
}
else if (bPrint)
{
LOG_INFO(LogLoot, "Picked loot tier data row {}", LootTierRowName.ToString());
}
// auto ChosenLootPackageName = ChosenRowLootTierData->GetLootPackage().ToString();
// if (ChosenLootPackageName.contains(".Empty")) { return PickLootDropsNew(TierGroupName, bPrint, ++recursive); }
float NumLootPackageDrops = ChosenRowLootTierData->GetNumLootPackageDrops();
float NumberLootDrops = 0;
if (NumLootPackageDrops > 0)
{
if (NumLootPackageDrops < 1)
{
NumberLootDrops = 1;
}
else
{
NumberLootDrops = (int)(float)((float)(NumLootPackageDrops + NumLootPackageDrops) - 0.5) >> 1;
float v20 = NumLootPackageDrops - NumberLootDrops;
if (v20 > 0.0000099999997)
{
NumberLootDrops += v20 >= (rand() * 0.000030518509);
}
}
}
float AmountOfLootPackageDrops = GetAmountOfLootPackagesToDrop(ChosenRowLootTierData, NumberLootDrops);
LootDrops.reserve(AmountOfLootPackageDrops);
if (AmountOfLootPackageDrops > 0)
{
for (int i = 0; i < AmountOfLootPackageDrops; i++)
{
if (i >= ChosenRowLootTierData->GetLootPackageCategoryMinArray().Num())
break;
for (int j = 0; j < ChosenRowLootTierData->GetLootPackageCategoryMinArray().at(i); j++)
{
if (ChosenRowLootTierData->GetLootPackageCategoryMinArray().at(i) < 1)
break;
int LootPackageCategory = i;
PickLootDropsFromLootPackage(LPTables, ChosenRowLootTierData->GetLootPackage(), &LootDrops, LootPackageCategory, bPrint);
}
}
}
return LootDrops;
}
#else
float GetRandomFloatForLooting(float min, float max)
{
@@ -72,12 +777,6 @@ static FFortLootPackageData* GetLootPackage(std::vector<FFortLootPackageData*>&
return SelectedItem;
}
struct FFortGameFeatureLootTableData
{
TSoftObjectPtr<UDataTable> LootTierData;
TSoftObjectPtr<UDataTable> LootPackageData;
};
std::vector<LootDrop> PickLootDrops(FName TierGroupName, bool bPrint, int recursive)
{
std::vector<LootDrop> LootDrops;
@@ -644,13 +1343,9 @@ std::vector<LootDrop> PickLootDrops(FName TierGroupName, bool bPrint, int recurs
auto WeaponDef = Cast<UFortWeaponItemDefinition>(ItemDef);
LootDrop lootDrop{};
lootDrop.ItemDefinition = ItemDef;
lootDrop.LoadedAmmo = WeaponDef ? WeaponDef->GetClipSize() : 0;
lootDrop.Count = LootPackageCall->GetCount();
LootDrops.push_back(lootDrop);
LootDrops.push_back(LootDrop(FFortItemEntry::MakeItemEntry(ItemDef, LootPackageCall->GetCount(), WeaponDef ? WeaponDef->GetClipSize() : 0));
}
return LootDrops;
}
#endif

View File

@@ -5,13 +5,9 @@
#include "Array.h"
#include "FortWorldItemDefinition.h"
#include "SoftObjectPtr.h"
#include "FortItem.h"
struct LootDrop
{
UFortItemDefinition* ItemDefinition;
int Count;
int LoadedAmmo;
};
#define EXPERIMENTAL_LOOTING
struct FFortLootPackageData
{
@@ -46,6 +42,12 @@ public:
return *(int*)(__int64(this) + CountOffset);
}
int& GetLootPackageCategory()
{
static auto LootPackageCategoryOffset = FindOffsetStruct("/Script/FortniteGame.FortLootPackageData", "LootPackageCategory");
return *(int*)(__int64(this) + LootPackageCategoryOffset);
}
FString& GetAnnotation()
{
static auto AnnotationOffset = FindOffsetStruct("/Script/FortniteGame.FortLootPackageData", "Annotation");
@@ -99,4 +101,18 @@ public:
}
};
struct LootDrop
{
FFortItemEntry* ItemEntry;
FFortItemEntry* operator->() {
return ItemEntry;
}
~LootDrop()
{
}
};
std::vector<LootDrop> PickLootDrops(FName TierGroupName, bool bPrint = false, int recursive = 0);

View File

@@ -8,6 +8,7 @@
#include "FortPlayerController.h"
#include <memcury.h>
#include "GameplayStatics.h"
#include "gui.h"
void AFortPickup::TossPickup(FVector FinalLocation, AFortPawn* ItemOwner, int OverrideMaxStackCount, bool bToss, EFortPickupSourceTypeFlag InPickupSourceTypeFlags, EFortPickupSpawnSource InPickupSpawnSource)
{
@@ -30,7 +31,7 @@ void AFortPickup::SpawnMovementComponent()
AFortPickup* AFortPickup::SpawnPickup(FFortItemEntry* ItemEntry, FVector Location,
EFortPickupSourceTypeFlag PickupSource, EFortPickupSpawnSource SpawnSource,
class AFortPawn* Pawn, UClass* OverrideClass, bool bToss, int OverrideCount)
class AFortPawn* Pawn, UClass* OverrideClass, bool bToss, int OverrideCount, AFortPickup* IgnoreCombinePickup)
{
if (bToss)
{
@@ -85,14 +86,17 @@ AFortPickup* AFortPickup::SpawnPickup(FFortItemEntry* ItemEntry, FVector Locatio
{
auto OtherPickup = (AFortPickup*)OtherPickupActor;
if (OtherPickup->GetPickupLocationData()->GetCombineTarget())
if (OtherPickup == IgnoreCombinePickup || OtherPickup->GetPickupLocationData()->GetCombineTarget())
return false;
if (PrimaryPickupItemEntry->GetItemDefinition() == OtherPickup->GetPrimaryPickupItemEntry()->GetItemDefinition())
{
auto IncomingCount = OtherPickup->GetPrimaryPickupItemEntry()->GetCount();
// auto IncomingCount = OtherPickup->GetPrimaryPickupItemEntry()->GetCount();
if (PrimaryPickupItemEntry->GetCount() + IncomingCount > PrimaryPickupItemEntry->GetItemDefinition()->GetMaxStackSize())
// if (PrimaryPickupItemEntry->GetCount() + IncomingCount == PrimaryPickupItemEntry->GetItemDefinition()->GetMaxStackSize())
// return false;
if (OtherPickup->GetPrimaryPickupItemEntry()->GetCount() == PrimaryPickupItemEntry->GetItemDefinition()->GetMaxStackSize()) // Other pickup is already at the max size.
return false;
return true;
@@ -106,21 +110,29 @@ AFortPickup* AFortPickup::SpawnPickup(FFortItemEntry* ItemEntry, FVector Locatio
PickupLocationData->GetCombineTarget() = (AFortPickup*)Pickup->GetClosestActor(AFortPickup::StaticClass(), 4, CanCombineWithPickup);
}
// our little remake of tosspickup
Pickup->GetPickupLocationData()->GetLootFinalPosition() = Location;
Pickup->GetPickupLocationData()->GetLootInitialPosition() = Pickup->GetActorLocation();
Pickup->GetPickupLocationData()->GetFlyTime() = 1.4f; // not right really
Pickup->GetPickupLocationData()->GetItemOwner() = Pawn;
Pickup->GetPickupLocationData()->GetFinalTossRestLocation() = Pickup->GetActorLocation(); // ong ong proper
if (!PickupLocationData->GetCombineTarget()) // I don't think we should call TossPickup for every pickup.
if (!PickupLocationData->GetCombineTarget()) // I don't think we should call TossPickup for every pickup anyways.
{
Pickup->TossPickup(Location, Pawn, 0, bToss, PickupSource, SpawnSource);
}
else
{
auto ActorLocation = Pickup->GetActorLocation();
auto CurrentActorLocation = PickupLocationData->GetCombineTarget()->GetActorLocation();
int Dist = float(sqrtf(powf(CurrentActorLocation.X - ActorLocation.X, 2.0) + powf(CurrentActorLocation.Y - ActorLocation.Y, 2.0) + powf(CurrentActorLocation.Z - ActorLocation.Z, 2.0))) / 100.f;
// LOG_INFO(LogDev, "Distance: {}", Dist);
// our little remake of tosspickup
PickupLocationData->GetLootFinalPosition() = Location;
PickupLocationData->GetLootInitialPosition() = Pickup->GetActorLocation();
PickupLocationData->GetFlyTime() = 1.f / Dist; // Higher the dist quicker it should be. // not right
PickupLocationData->GetItemOwner() = Pawn;
PickupLocationData->GetFinalTossRestLocation() = PickupLocationData->GetCombineTarget()->GetActorLocation(); // Pickup->GetActorLocation() // ong ong proper
Pickup->OnRep_PickupLocationData();
Pickup->ForceNetUpdate();
}
if (PickupSource == EFortPickupSourceTypeFlag::Container) // crashes if we do this then tosspickup
@@ -142,7 +154,7 @@ AFortPickup* AFortPickup::SpawnPickup(FFortItemEntry* ItemEntry, FVector Locatio
}
AFortPickup* AFortPickup::SpawnPickup(UFortItemDefinition* ItemDef, FVector Location, int Count, EFortPickupSourceTypeFlag PickupSource, EFortPickupSpawnSource SpawnSource,
int LoadedAmmo, AFortPawn* Pawn, UClass* OverrideClass, bool bToss)
int LoadedAmmo, AFortPawn* Pawn, UClass* OverrideClass, bool bToss, AFortPickup* IgnoreCombinePickup)
{
if (LoadedAmmo == -1)
{
@@ -153,7 +165,7 @@ AFortPickup* AFortPickup::SpawnPickup(UFortItemDefinition* ItemDef, FVector Loca
}
auto ItemEntry = FFortItemEntry::MakeItemEntry(ItemDef, Count, LoadedAmmo);
auto Pickup = SpawnPickup(ItemEntry, Location, PickupSource, SpawnSource, Pawn, OverrideClass, bToss);
auto Pickup = SpawnPickup(ItemEntry, Location, PickupSource, SpawnSource, Pawn, OverrideClass, bToss, -1, IgnoreCombinePickup);
// VirtualFree(ItemEntry);
return Pickup;
}
@@ -164,11 +176,30 @@ void AFortPickup::CombinePickupHook(AFortPickup* Pickup)
auto PickupToCombineInto = (AFortPickup*)Pickup->GetPickupLocationData()->GetCombineTarget();
if (!PickupToCombineInto->IsActorBeingDestroyed())
{
// TODO Add more checks
if (PickupToCombineInto->IsActorBeingDestroyed())
return;
PickupToCombineInto->GetPrimaryPickupItemEntry()->GetCount() += Pickup->GetPrimaryPickupItemEntry()->GetCount();
const int IncomingCount = Pickup->GetPrimaryPickupItemEntry()->GetCount();
const int OriginalCount = PickupToCombineInto->GetPrimaryPickupItemEntry()->GetCount();
// add more checks?
auto ItemDefinition = PickupToCombineInto->GetPrimaryPickupItemEntry()->GetItemDefinition();
int CountToAdd = IncomingCount;
if (OriginalCount + CountToAdd > ItemDefinition->GetMaxStackSize())
{
const int OverStackCount = OriginalCount + CountToAdd - ItemDefinition->GetMaxStackSize();
CountToAdd = ItemDefinition->GetMaxStackSize() - OriginalCount;
auto ItemOwner = Pickup->GetPickupLocationData()->GetItemOwner();
auto NewOverStackPickup = AFortPickup::SpawnPickup(ItemDefinition, PickupToCombineInto->GetActorLocation(), OverStackCount,
EFortPickupSourceTypeFlag::Player, EFortPickupSpawnSource::Unset, -1, ItemOwner, nullptr, false, PickupToCombineInto);
}
PickupToCombineInto->GetPrimaryPickupItemEntry()->GetCount() += CountToAdd;
PickupToCombineInto->OnRep_PrimaryPickupItemEntry();
PickupToCombineInto->ForceNetUpdate();
@@ -176,15 +207,9 @@ void AFortPickup::CombinePickupHook(AFortPickup* Pickup)
Pickup->K2_DestroyActor();
}
}
char AFortPickup::CompletePickupAnimationHook(AFortPickup* Pickup)
{
constexpr bool bTestPrinting = false; // we could just use our own logger but eh
if constexpr (bTestPrinting)
LOG_INFO(LogDev, "CompletePickupAnimationHook!");
auto Pawn = Cast<AFortPlayerPawn>(Pickup->GetPickupLocationData()->GetPickupTarget());
if (!Pawn)
@@ -234,7 +259,7 @@ char AFortPickup::CompletePickupAnimationHook(AFortPickup* Pickup)
std::vector<std::pair<FFortItemEntry*, FFortItemEntry*>> PairsToMarkDirty; // vector of sets or something so no duplicates??
if constexpr (bTestPrinting)
if (bDebugPrintSwapping)
LOG_INFO(LogDev, "Start cpyCount: {}", cpyCount);
bool bWasHoldingSameItemWhenSwap = false;
@@ -300,7 +325,7 @@ char AFortPickup::CompletePickupAnimationHook(AFortPickup* Pickup)
bHasSwapped = true;
if constexpr (bTestPrinting)
if (bDebugPrintSwapping)
LOG_INFO(LogDev, "[{}] Swapping: {}", i, ItemDefinitionToSwap->GetFullName());
// bForceDontAddItem = true;
@@ -311,7 +336,7 @@ char AFortPickup::CompletePickupAnimationHook(AFortPickup* Pickup)
if (CurrentItemEntry->GetItemDefinition() == PickupItemDefinition)
{
if constexpr (bTestPrinting)
if (bDebugPrintSwapping)
LOG_INFO(LogDev, "[{}] Found stack of item!", i);
if (CurrentItemEntry->GetCount() < PickupItemDefinition->GetMaxStackSize())
@@ -327,7 +352,7 @@ char AFortPickup::CompletePickupAnimationHook(AFortPickup* Pickup)
bEverStacked = true;
if constexpr (bTestPrinting)
if (bDebugPrintSwapping)
LOG_INFO(LogDev, "[{}] We are stacking {}.", i, AmountToStack);
// if (cpyCount > 0)
@@ -339,7 +364,7 @@ char AFortPickup::CompletePickupAnimationHook(AFortPickup* Pickup)
if ((bIsInventoryFull || bForceOverflow) && cpyCount > 0) // overflow
{
if constexpr (bTestPrinting)
if (bDebugPrintSwapping)
LOG_INFO(LogDev, "[{}] Overflow", i);
UFortWorldItemDefinition* ItemDefinitionToSpawn = PickupItemDefinition;
@@ -359,7 +384,7 @@ char AFortPickup::CompletePickupAnimationHook(AFortPickup* Pickup)
if (cpyCount > 0 && !bIsInventoryFull && !bForceDontAddItem)
{
if constexpr (bTestPrinting)
if (bDebugPrintSwapping)
LOG_INFO(LogDev, "Attempting to add to inventory.");
if (bDoesStackExist ? PickupItemDefinition->DoesAllowMultipleStacks() : true)
@@ -375,7 +400,7 @@ char AFortPickup::CompletePickupAnimationHook(AFortPickup* Pickup)
else
cpyCount -= NewItemCount;
if constexpr (bTestPrinting)
if (bDebugPrintSwapping)
LOG_INFO(LogDev, "Added item with count {} to inventory.", NewItemCount);
if (bHasSwapped && NewSwappedItem == FGuid(-1, -1, -1, -1))

View File

@@ -120,11 +120,11 @@ public:
static AFortPickup* SpawnPickup(FFortItemEntry* ItemEntry, FVector Location,
EFortPickupSourceTypeFlag PickupSource = EFortPickupSourceTypeFlag::Other, EFortPickupSpawnSource SpawnSource = EFortPickupSpawnSource::Unset,
class AFortPawn* Pawn = nullptr, UClass* OverrideClass = nullptr, bool bToss = true, int OverrideCount = -1);
class AFortPawn* Pawn = nullptr, UClass* OverrideClass = nullptr, bool bToss = true, int OverrideCount = -1, AFortPickup* IgnoreCombinePickup = nullptr);
static AFortPickup* SpawnPickup(class UFortItemDefinition* ItemDef, FVector Location, int Count,
EFortPickupSourceTypeFlag PickupSource = EFortPickupSourceTypeFlag::Other, EFortPickupSpawnSource SpawnSource = EFortPickupSpawnSource::Unset,
int LoadedAmmo = -1, class AFortPawn* Pawn = nullptr, UClass* OverrideClass = nullptr, bool bToss = true);
int LoadedAmmo = -1, class AFortPawn* Pawn = nullptr, UClass* OverrideClass = nullptr, bool bToss = true, AFortPickup* IgnoreCombinePickup = nullptr);
static void CombinePickupHook(AFortPickup* Pickup);
static char CompletePickupAnimationHook(AFortPickup* Pickup);

View File

@@ -61,7 +61,7 @@ bool AFortPlayerController::DoesBuildFree()
return ReadBitfieldValue(bBuildFreeOffset, bBuildFreeFieldMask);
}
void AFortPlayerController::DropAllItems(const std::vector<UFortItemDefinition*>& IgnoreItemDefs, bool bIgnoreSecondaryQuickbar, bool bRemoveIfNotDroppable)
void AFortPlayerController::DropAllItems(const std::vector<UFortItemDefinition*>& IgnoreItemDefs, bool bIgnoreSecondaryQuickbar, bool bRemoveIfNotDroppable, bool RemovePickaxe)
{
auto Pawn = this->GetMyFortPawn();
@@ -78,6 +78,8 @@ void AFortPlayerController::DropAllItems(const std::vector<UFortItemDefinition*>
std::vector<std::pair<FGuid, int>> GuidAndCountsToRemove;
auto PickaxeInstance = WorldInventory->GetPickaxeInstance();
for (int i = 0; i < ItemInstances.Num(); i++)
{
auto ItemInstance = ItemInstances.at(i);
@@ -86,6 +88,13 @@ void AFortPlayerController::DropAllItems(const std::vector<UFortItemDefinition*>
continue;
auto ItemEntry = ItemInstance->GetItemEntry();
if (RemovePickaxe && ItemInstance == PickaxeInstance)
{
GuidAndCountsToRemove.push_back({ ItemEntry->GetItemGuid(), ItemEntry->GetCount() });
continue;
}
auto WorldItemDefinition = Cast<UFortWorldItemDefinition>(ItemEntry->GetItemDefinition());
if (!WorldItemDefinition || std::find(IgnoreItemDefs.begin(), IgnoreItemDefs.end(), WorldItemDefinition) != IgnoreItemDefs.end())
@@ -482,16 +491,42 @@ void AFortPlayerController::ServerAttemptInteractHook(UObject* Context, FFrame*
auto VehicleWeapon = Pawn->EquipWeaponDefinition(VehicleWeaponDefinition, NewVehicleInstance->GetItemEntry()->GetItemGuid());
// PlayerController->ServerExecuteInventoryItemHook(PlayerController, newitem->GetItemEntry()->GetItemGuid());
/* if (WeaponComponent)
/* static auto GetSeatWeaponComponentFn = FindObject<UFunction>("/Script/FortniteGame.FortAthenaVehicle.GetSeatWeaponComponent");
if (GetSeatWeaponComponentFn)
{
struct { int SeatIndex; UObject* ReturnValue; } AFortAthenaVehicle_GetSeatWeaponComponent_Params{};
Vehicle->ProcessEvent(GetSeatWeaponComponentFn, &AFortAthenaVehicle_GetSeatWeaponComponent_Params);
UObject* WeaponComponent = AFortAthenaVehicle_GetSeatWeaponComponent_Params.ReturnValue;
if (!WeaponComponent)
return;
static auto WeaponSeatDefinitionStructSize = FindObject<UClass>("/Script/FortniteGame.WeaponSeatDefinition")->GetPropertiesSize();
static auto VehicleWeaponOffset = FindOffsetStruct("/Script/FortniteGame.WeaponSeatDefinition", "VehicleWeapon");
static auto SeatIndexOffset = FindOffsetStruct("/Script/FortniteGame.WeaponSeatDefinition", "SeatIndex");
static auto WeaponSeatDefinitionsOffset = WeaponComponent->GetOffset("WeaponSeatDefinitions");
auto& WeaponSeatDefinitions = WeaponComponent->Get<TArray<__int64>>(WeaponSeatDefinitionsOffset);
for (int i = 0; i < WeaponSeatDefinitions.Num(); i++)
{
auto WeaponSeat = WeaponSeatDefinitions.AtPtr(i, WeaponSeatDefinitionStructSize);
if (*(int*)(__int64(WeaponSeat) + SeatIndexOffset) != Vehicle->FindSeatIndex(Pawn))
continue;
auto VehicleGrantedWeaponItem = (TWeakObjectPtr<UFortItem>*)(__int64(WeaponSeat) + 0x20);
VehicleGrantedWeaponItem->ObjectIndex = NewVehicleInstance->InternalIndex;
VehicleGrantedWeaponItem->ObjectSerialNumber = GetItemByIndex(NewVehicleInstance->InternalIndex)->SerialNumber;
static auto bWeaponEquippedOffset = WeaponComponent->GetOffset("bWeaponEquipped");
WeaponComponent->Get<bool>(bWeaponEquippedOffset) = true;
static auto CachedWeaponOffset = WeaponComponent->GetOffset("CachedWeapon");
WeaponComponent->Get<AFortWeapon*>(CachedWeaponOffset) = VehicleWeapon;
static auto CachedWeaponDefOffset = WeaponComponent->GetOffset("CachedWeaponDef");
WeaponComponent->Get<UFortWeaponItemDefinition*>(CachedWeaponDefOffset) = VehicleWeaponDefinition;
break;
}
} */
return;

View File

@@ -87,7 +87,7 @@ public:
return CosmeticLoadout;
}
void AddPickaxeToInventory()
UFortItem* AddPickaxeToInventory()
{
auto CosmeticLoadout = GetCosmeticLoadout();
auto CosmeticLoadoutPickaxe = CosmeticLoadout ? CosmeticLoadout->GetPickaxe() : nullptr;
@@ -100,10 +100,12 @@ public:
auto WorldInventory = GetWorldInventory();
if (!WorldInventory || WorldInventory->GetPickaxeInstance())
return;
return nullptr;
WorldInventory->AddItem(PickaxeDefinition, nullptr);
auto NewAndModifiedInstances = WorldInventory->AddItem(PickaxeDefinition, nullptr);
WorldInventory->Update();
return NewAndModifiedInstances.first.size() > 0 ? NewAndModifiedInstances.first[0] : nullptr;
}
bool& ShouldTryPickupSwap()
@@ -121,7 +123,7 @@ public:
void ClientEquipItem(const FGuid& ItemGuid, bool bForceExecution);
bool DoesBuildFree();
void DropAllItems(const std::vector<UFortItemDefinition*>& IgnoreItemDefs, bool bIgnoreSecondaryQuickbar = false, bool bRemoveIfNotDroppable = false);
void DropAllItems(const std::vector<UFortItemDefinition*>& IgnoreItemDefs, bool bIgnoreSecondaryQuickbar = false, bool bRemoveIfNotDroppable = false, bool RemovePickaxe = false);
void ApplyCosmeticLoadout();
static void ServerLoadingScreenDroppedHook(UObject* Context, FFrame* Stack, void* Ret);

View File

@@ -44,6 +44,13 @@ void AFortPlayerControllerAthena::StartGhostModeHook(UObject* Context, FFrame* S
if (!WorldInventory)
return StartGhostModeOriginal(Context, Stack, Ret);
auto PickaxeInstance = WorldInventory->GetPickaxeInstance();
if (PickaxeInstance)
{
WorldInventory->RemoveItem(PickaxeInstance->GetItemEntry()->GetItemGuid(), nullptr, PickaxeInstance->GetItemEntry()->GetCount(), true);
}
bool bShouldUpdate = false;
auto NewAndModifiedInstances = WorldInventory->AddItem(ItemProvidingGhostMode, &bShouldUpdate, 1);
auto GhostModeItemInstance = NewAndModifiedInstances.first[0];
@@ -51,7 +58,7 @@ void AFortPlayerControllerAthena::StartGhostModeHook(UObject* Context, FFrame* S
if (!GhostModeItemInstance)
return StartGhostModeOriginal(Context, Stack, Ret);
if (bShouldUpdate)
// if (bShouldUpdate)
WorldInventory->Update();
PlayerController->ServerExecuteInventoryItemHook(PlayerController, GhostModeItemInstance->GetItemEntry()->GetItemGuid());
@@ -95,12 +102,20 @@ void AFortPlayerControllerAthena::EndGhostModeHook(AFortPlayerControllerAthena*
if (!GhostModeItemInstance)
return EndGhostModeOriginal(PlayerController);
auto PickaxeInstance = PlayerController->AddPickaxeToInventory();
WorldInventory->Update();
if (PickaxeInstance)
{
PlayerController->ClientEquipItem(PickaxeInstance->GetItemEntry()->GetItemGuid(), true);
}
bool bShouldUpdate = false;
int Count = GhostModeItemInstance->GetItemEntry()->GetCount(); // 1
bool bForceRemoval = true; // false
WorldInventory->RemoveItem(GhostModeItemInstance->GetItemEntry()->GetItemGuid(), &bShouldUpdate, Count, bForceRemoval);
if (bShouldUpdate)
// if (bShouldUpdate)
WorldInventory->Update();
return EndGhostModeOriginal(PlayerController);

View File

@@ -140,17 +140,7 @@ UFortWeaponItemDefinition* AFortPlayerPawn::GetVehicleWeaponDefinition(AFortAthe
if (!Vehicle)
return nullptr;
static auto FindSeatIndexFn = FindObject<UFunction>("/Script/FortniteGame.FortAthenaVehicle.FindSeatIndex");
/* auto Vehicle = GetVehicle();
if (!Vehicle)
return nullptr; */
struct { AFortPlayerPawn* PlayerPawn; int ReturnValue; } AFortAthenaVehicle_FindSeatIndex_Params{ this };
Vehicle->ProcessEvent(FindSeatIndexFn, &AFortAthenaVehicle_FindSeatIndex_Params);
auto SeatIndex = AFortAthenaVehicle_FindSeatIndex_Params.ReturnValue;
return Vehicle->GetVehicleWeaponForSeat(SeatIndex);
return Vehicle->GetVehicleWeaponForSeat(Vehicle->FindSeatIndex(this));
}
void AFortPlayerPawn::UnEquipVehicleWeaponDefinition(UFortWeaponItemDefinition* VehicleWeaponDefinition)

View File

@@ -38,8 +38,8 @@ int UFortWeaponItemDefinition::GetClipSize()
UFortWorldItemDefinition* UFortWeaponItemDefinition::GetAmmoData()
{
static auto AmmoDataOffset = GetOffset("AmmoData");
auto AmmoData = Get<TSoftObjectPtr<UFortWorldItemDefinition>>(AmmoDataOffset);
return AmmoData.Get();
auto AmmoData = GetPtr<TSoftObjectPtr<UFortWorldItemDefinition>>(AmmoDataOffset);
return AmmoData->Get();
}
UClass* UFortWeaponItemDefinition::StaticClass()

View File

@@ -20,6 +20,12 @@ public:
return ReadBitfieldValue(bCanBeDroppedOffset, bCanBeDroppedFieldMask);
}
int& GetDropCount()
{
static auto DropCountOffset = GetOffset("DropCount");
return Get<int>(DropCountOffset);
}
EWorldItemDropBehavior& GetDropBehavior()
{
static auto DropBehaviorOffset = GetOffset("DropBehavior");

View File

@@ -29,4 +29,9 @@ struct FName
{
return ComparisonIndex.Value == other.ComparisonIndex.Value;
}
bool operator<(FName Other) const
{
return this->ComparisonIndex.Value < Other.ComparisonIndex.Value;
}
};

View File

@@ -335,6 +335,7 @@
<ClInclude Include="FortItem.h" />
<ClInclude Include="FortItemDefinition.h" />
<ClInclude Include="FortKismetLibrary.h" />
<ClInclude Include="FortLootLevel.h" />
<ClInclude Include="FortLootPackage.h" />
<ClInclude Include="FortMinigame.h" />
<ClInclude Include="FortMountedCannon.h" />

View File

@@ -694,9 +694,6 @@
<ClInclude Include="ReversePredicate.h">
<Filter>Engine\Source\Runtime\Core\Public\Templates</Filter>
</ClInclude>
<ClInclude Include="UnrealTypeTraits.h">
<Filter>Engine\Source\Runtime\Core\Public\Templates</Filter>
</ClInclude>
<ClInclude Include="IsEnum.h">
<Filter>Engine\Source\Runtime\Core\Public\Templates</Filter>
</ClInclude>
@@ -848,6 +845,12 @@
<ClInclude Include="Vector2D.h">
<Filter>Engine\Source\Runtime\Core\Public\Math</Filter>
</ClInclude>
<ClInclude Include="UnrealTypeTraits.h">
<Filter>Engine\Source\Runtime\Core\Public\Templates</Filter>
</ClInclude>
<ClInclude Include="FortLootLevel.h">
<Filter>FortniteGame\Source\FortniteGame\Public\Items</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="Engine">

View File

@@ -490,7 +490,7 @@ void ServerCheatHook(AFortPlayerControllerAthena* PlayerController, FString Msg)
return;
}
auto Pawn = ReceivingController->GetMyFortPawn();
auto Pawn = ReceivingController->GetPawn();
if (!Pawn)
{
@@ -519,11 +519,25 @@ void ServerCheatHook(AFortPlayerControllerAthena* PlayerController, FString Msg)
if (ClassObj)
{
int AmountSpawned = 0;
for (int i = 0; i < Count; i++)
{
FActorSpawnParameters SpawnParameters{};
// SpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn;
auto Loc = Pawn->GetActorLocation();
// Loc.Z += 1000;
GetWorld()->SpawnActor<AActor>(ClassObj, Loc, FQuat());
Loc.Z += 1000;
auto NewActor = GetWorld()->SpawnActor<AActor>(ClassObj, Loc, FQuat(), FVector(1, 1, 1), SpawnParameters);
if (!NewActor)
{
SendMessageToConsole(PlayerController, L"Failed to spawn an actor!");
}
else
{
AmountSpawned++;
}
}
SendMessageToConsole(PlayerController, L"Summoned!");

View File

@@ -627,12 +627,26 @@ static inline uint64 FindUpdateTrackedAttributesLea() // kill me
static inline uint64 FindCombinePickupLea() // kill me
{
return 0;
/* uint64 OnRep_PickupLocationDataAddr = 0; // TODO (Idea: Find SetupCombinePickupDelegates from this).
if (!OnRep_PickupLocationDataAddr)
return 0; */
uint64 SetupCombinePickupDelegatesAddr = Memcury::Scanner::FindPattern("48 89 AC 24 ? ? ? ? 48 89 B4 24 ? ? ? ? 48 89 BC 24 ? ? ? ? 0F 29 B4 24 ? ? ? ? 75").Get(); // Haha so funny thing, this isn't actually the start its the middle because it's in function chunks yay!
uint64 SetupCombinePickupDelegatesAddr = 0;
bool bShouldCheckSafety = true;
if (Engine_Version <= 420)
{
SetupCombinePickupDelegatesAddr = Memcury::Scanner::FindPattern("49 89 73 10 49 89 7B 18 4D 89 73 20 4D 89 7B E8 41 0F 29 73 ? 75").Get(); // found on 4.1
bShouldCheckSafety = false; // it's like "corrupted" and not just return
}
else if (Engine_Version >= 421)
{
SetupCombinePickupDelegatesAddr = Memcury::Scanner::FindPattern("48 89 AC 24 ? ? ? ? 48 89 B4 24 ? ? ? ? 48 89 BC 24 ? ? ? ? 0F 29 B4 24 ? ? ? ? 75").Get(); // Haha so funny thing, this isn't actually the start its the middle because it's in function chunks yay!
}
if (!SetupCombinePickupDelegatesAddr)
return 0;
@@ -644,7 +658,7 @@ static inline uint64 FindCombinePickupLea() // kill me
{
auto loadAddress = Memcury::Scanner(SetupCombinePickupDelegatesAddr + i).RelativeOffset(3).Get();
if (IsNullSub(loadAddress)) // Safety
if (!bShouldCheckSafety || IsNullSub(loadAddress))
return SetupCombinePickupDelegatesAddr + i;
}
}

View File

@@ -48,8 +48,9 @@
#define DUMP_TAB 7
#define UNBAN_TAB 8
#define DEVELOPER_TAB 9
#define SETTINGS_TAB 10
#define CREDITS_TAB 11
#define DEBUGLOG_TAB 10
#define SETTINGS_TAB 11
#define CREDITS_TAB 12
#define MAIN_PLAYERTAB 1
#define INVENTORY_PLAYERTAB 2
@@ -61,6 +62,8 @@ extern inline bool bSwitchedInitialLevel = false;
extern inline bool bIsInAutoRestart = false;
extern inline float AutoBusStartSeconds = 60;
extern inline int NumRequiredPlayersToStart = 2;
extern inline bool bDebugPrintLooting = false;
extern inline bool bDebugPrintSwapping = false;
// THE BASE CODE IS FROM IMGUI GITHUB
@@ -376,6 +379,14 @@ static inline void MainTabs()
bInformationTab = false;
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Debug Logs"))
{
Tab = DEBUGLOG_TAB;
PlayerTab = -1;
bInformationTab = false;
ImGui::EndTabItem();
}
#endif
if (false && ImGui::BeginTabItem(("Credits")))
@@ -954,6 +965,11 @@ static inline void MainUI()
}
*/
}
else if (Tab == DEBUGLOG_TAB)
{
ImGui::Checkbox("Looting Debug Log", &bDebugPrintLooting);
ImGui::Checkbox("Swapping Debug Log", &bDebugPrintSwapping);
}
else if (Tab == SETTINGS_TAB)
{
// ImGui::Checkbox("Use custom lootpool (from Win64/lootpool.txt)", &Defines::bCustomLootpool);

View File

@@ -49,7 +49,7 @@ struct PlaceholderBitfield
inline bool AreVehicleWeaponsEnabled()
{
return Fortnite_Version < 9;
return Fortnite_Version > 6;
}
inline bool IsRestartingSupported()

View File

@@ -184,11 +184,22 @@ static inline void SpawnVehicles2()
static auto FortAthenaVehicleSpawnerClass = FindObject<UClass>("/Script/FortniteGame.FortAthenaVehicleSpawner");
TArray<AActor*> AllVehicleSpawners = UGameplayStatics::GetAllActorsOfClass(GetWorld(), FortAthenaVehicleSpawnerClass);
int AmountOfVehiclesSpawned = 0;
for (int i = 0; i < AllVehicleSpawners.Num(); i++)
{
auto VehicleSpawner = AllVehicleSpawners.at(i);
auto Vehicle = SpawnVehicleFromSpawner(VehicleSpawner);
if (Vehicle)
{
AmountOfVehiclesSpawned++;
}
}
auto AllVehicleSpawnersNum = AllVehicleSpawners.Num();
AllVehicleSpawners.Free();
LOG_INFO(LogGame, "Spawned {}/{} vehicles.", AmountOfVehiclesSpawned, AllVehicleSpawnersNum);
}

View File

@@ -134,7 +134,7 @@ static inline void FillItemCollector(ABuildingItemCollectorActor* ItemCollector,
for (int LootDropIt = 0; LootDropIt < LootDrops.size(); LootDropIt++)
{
auto WorldItemDefinition = Cast<UFortWorldItemDefinition>(LootDrops[LootDropIt].ItemDefinition);
UFortWorldItemDefinition* WorldItemDefinition = Cast<UFortWorldItemDefinition>(LootDrops[LootDropIt]->GetItemDefinition());
if (!WorldItemDefinition)
continue;
@@ -182,7 +182,7 @@ static inline void FillItemCollector(ABuildingItemCollectorActor* ItemCollector,
for (int LootDropIt = 0; LootDropIt < LootDrops.size(); LootDropIt++)
{
auto ItemEntry = FFortItemEntry::MakeItemEntry(LootDrops[LootDropIt].ItemDefinition, LootDrops[LootDropIt].Count, LootDrops[LootDropIt].LoadedAmmo);
auto ItemEntry = FFortItemEntry::MakeItemEntry(LootDrops[LootDropIt]->GetItemDefinition(), LootDrops[LootDropIt]->GetCount(), LootDrops[LootDropIt]->GetLoadedAmmo());
if (!ItemEntry)
continue;

8
vendor/memcury.h vendored
View File

@@ -1431,4 +1431,10 @@
return PtrRef.ScanFor(Bytes, false).Get();
}
inline bool IsNullSub(uint64 Addr) { return *(uint8_t*)(Addr) == 0xC3 || *(uint8_t*)(Addr) == 0xC2; }
inline bool IsNullSub(uint64 Addr)
{
// if (*(uint8_t*)(Addr) == 0xEB && *(uint8_t*)(Addr + 1) == 0xF7) // positive sp value has been detected, the output may be wrong!
// return true;
return *(uint8_t*)(Addr) == 0xC3 || *(uint8_t*)(Addr) == 0xC2;
}