level showing up on items now, fix s19, improve performance, fix big issue on s5
This commit is contained in:
Milxnor
2023-05-21 00:38:59 -04:00
parent 33433ea9de
commit a2d621560a
37 changed files with 600 additions and 168 deletions

View File

@@ -37,6 +37,8 @@ public:
inline InElementType& at(int i, size_t Size = sizeof(InElementType)) const { return *(InElementType*)(__int64(Data) + (static_cast<long long>(Size) * i)); }
inline InElementType* AtPtr(int i, size_t Size = sizeof(InElementType)) const { return (InElementType*)(__int64(Data) + (static_cast<long long>(Size) * i)); }
bool IsValidIndex(int i) { return i > 0 && i < ArrayNum; }
ElementAllocatorType& GetData() const { return Data; }
ElementAllocatorType& GetData() { return Data; }

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);
auto LootDrops = PickLootDrops(SpawnLootTierGroup, GameState->GetWorldLevel());
for (int z = 0; z < LootDrops.size(); z++)
{
@@ -63,11 +63,7 @@ static inline void SpawnBGAs() // hahah not "proper", there's a function that we
bool bDeferConstruction = true; // hm?
FActorSpawnParameters SpawnParameters{};
// SpawnParameters.ObjectFlags = RF_Transactional; // idk fortnite does this i think // i think its acutally suppsoed to be |= RF_Transient
SpawnParameters.bDeferConstruction = bDeferConstruction;
auto ConsumableActor = GetWorld()->SpawnActor<ABuildingGameplayActor>(StrongConsumableClass, SpawnTransform, SpawnParameters);
auto ConsumableActor = GetWorld()->SpawnActor<ABuildingGameplayActor>(StrongConsumableClass, SpawnTransform, CreateSpawnParameters(ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn, bDeferConstruction));
if (ConsumableActor)
{

View File

@@ -14,7 +14,9 @@ bool ABuildingContainer::SpawnLoot(AFortPawn* Pawn)
// LOG_INFO(LogInteraction, "RedirectedLootTier: {}", RedirectedLootTier.ToString());
auto LootDrops = PickLootDrops(RedirectedLootTier, -1, bDebugPrintLooting);
auto GameState = Cast<AFortGameStateAthena>(GetWorld()->GetGameState());
auto LootDrops = PickLootDrops(RedirectedLootTier, GameState->GetWorldLevel(), -1, bDebugPrintLooting);
// LOG_INFO(LogInteraction, "LootDrops.size(): {}", LootDrops.size());
@@ -25,7 +27,7 @@ bool ABuildingContainer::SpawnLoot(AFortPawn* Pawn)
PickupCreateData CreateData;
CreateData.bToss = true;
// CreateData.PawnOwner = Pawn;
CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(lootDrop->GetItemDefinition(), lootDrop->GetCount(), lootDrop->GetLoadedAmmo());
CreateData.ItemEntry = lootDrop.ItemEntry;
CreateData.SpawnLocation = LocationToSpawnLoot;
CreateData.SourceType = EFortPickupSourceTypeFlag::GetContainerValue();
CreateData.bRandomRotation = true;

View File

@@ -8,6 +8,12 @@ public:
AActor* GetViewTarget();
void Possess(class APawn* Pawn);
FName& GetStateName()
{
static auto StateNameOffset = GetOffset("StateName");
return Get<FName>(StateNameOffset);
}
class APawn*& GetPawn()
{
static auto PawnOffset = this->GetOffset("Pawn");

View File

@@ -1,9 +1,15 @@
#pragma once
#include "Object.h"
#include "reboot.h"
#include "Map.h"
struct FTableRowBase
{
unsigned char UnknownData00[0x8]; // this is actually structural padding
};
class UDataTable : public UObject
{
public:
@@ -17,7 +23,7 @@ public:
static UClass* StaticClass()
{
static auto Class = FindObject<UClass>("/Script/Engine.DataTable");
static auto Class = FindObject<UClass>(L"/Script/Engine.DataTable");
return Class;
}
};

View File

@@ -63,11 +63,8 @@ void AFortAthenaMapInfo::SpawnLlamas()
InitialSpawnTransform.Rotation = RandomYawRotator.Quaternion();
InitialSpawnTransform.Scale3D = FVector(1, 1, 1);
FActorSpawnParameters SpawnParameters{};
SpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
SpawnParameters.bDeferConstruction = true;
auto LlamaStart = GetWorld()->SpawnActor<AFortAthenaSupplyDrop>(GetLlamaClass(), InitialSpawnTransform, SpawnParameters);
auto LlamaStart = GetWorld()->SpawnActor<AFortAthenaSupplyDrop>(GetLlamaClass(), InitialSpawnTransform,
CreateSpawnParameters(ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn, true));
// LOG_INFO(LogDev, "LlamaStart: {}", __int64(LlamaStart));

View File

@@ -1,8 +1,9 @@
#include "FortAthenaSupplyDrop.h"
#include "FortGameStateAthena.h"
FVector AFortAthenaSupplyDrop::FindGroundLocationAt(FVector InLocation)
{
static auto FindGroundLocationAtFn = FindObject<UFunction>("/Script/FortniteGame.FortAthenaSupplyDrop.FindGroundLocationAt");
static auto FindGroundLocationAtFn = FindObject<UFunction>(L"/Script/FortniteGame.FortAthenaSupplyDrop.FindGroundLocationAt");
struct
{
@@ -44,12 +45,15 @@ AFortPickup* AFortAthenaSupplyDrop::SpawnGameModePickupHook(UObject* Context, FF
LOG_INFO(LogDev, "Spawning GameModePickup with ItemDefinition: {}", ItemDefinition->GetFullName());
auto GameState = Cast<AFortGameStateAthena>(GetWorld()->GetGameState());
PickupCreateData CreateData;
CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(ItemDefinition, NumberToSpawn, -1);
CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(ItemDefinition, NumberToSpawn, -1, MAX_DURABILITY, ItemDefinition->GetFinalLevel(GameState->GetWorldLevel()));
CreateData.SpawnLocation = Position;
CreateData.PawnOwner = TriggeringPawn;
CreateData.Source = EFortPickupSpawnSource::GetSupplyDropValue();
CreateData.OverrideClass = PickupClass;
CreateData.bShouldFreeItemEntryWhenDeconstructed = true;
*Ret = AFortPickup::SpawnPickup(CreateData);
return *Ret;
@@ -74,8 +78,10 @@ AFortPickup* AFortAthenaSupplyDrop::SpawnPickupHook(UObject* Context, FFrame& St
if (!ItemDefinition)
return nullptr;
auto GameState = Cast<AFortGameStateAthena>(GetWorld()->GetGameState());
PickupCreateData CreateData;
CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(ItemDefinition, NumberToSpawn, -1);
CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(ItemDefinition, NumberToSpawn, -1, MAX_DURABILITY, ItemDefinition->GetFinalLevel(GameState->GetWorldLevel()));
CreateData.SpawnLocation = Position;
CreateData.PawnOwner = TriggeringPawn;
CreateData.Source = EFortPickupSpawnSource::GetSupplyDropValue();

View File

@@ -652,6 +652,8 @@ bool AFortGameModeAthena::Athena_ReadyToStartMatchHook(AFortGameModeAthena* Game
GetWorld()->Listen();
LOG_INFO(LogNet, "WorldLevel {}", GameState->GetWorldLevel());
if (auto TeamsArrayContainer = GameState->GetTeamsArrayContainer())
{
TeamsArrayContainer->TeamIndexesArray.Free();
@@ -889,6 +891,8 @@ int AFortGameModeAthena::Athena_PickTeamHook(AFortGameModeAthena* GameMode, uint
bShouldSpreadTeams = bIsLargeTeamGame;
}
// bShouldSpreadTeams = true;
static int CurrentTeamMembers = 0; // bad
static int Current = DefaultFirstTeam;
static int NextTeamIndex = DefaultFirstTeam;
@@ -986,11 +990,14 @@ int AFortGameModeAthena::Athena_PickTeamHook(AFortGameModeAthena* GameMode, uint
{
if (auto TeamsArrayContainer = GameState->GetTeamsArrayContainer())
{
auto& TeamArray = TeamsArrayContainer->TeamsArray.at(NextTeamIndex);
TArray<TWeakObjectPtr<AFortPlayerStateAthena>>* TeamArray = TeamsArrayContainer->TeamsArray.IsValidIndex(NextTeamIndex) ? TeamsArrayContainer->TeamsArray.AtPtr(NextTeamIndex) : nullptr;
LOG_INFO(LogDev, "TeamsArrayContainer->TeamsArray.Num(): {}", TeamsArrayContainer->TeamsArray.Num());
LOG_INFO(LogDev, "TeamArray.Num(): {}", TeamArray.Num());
TeamArray.Add(WeakPlayerState);
if (TeamArray)
{
LOG_INFO(LogDev, "TeamArray.Num(): {}", TeamArray->Num());
TeamArray->Add(WeakPlayerState);
}
}
}
@@ -1130,13 +1137,13 @@ void AFortGameModeAthena::Athena_HandleStartingNewPlayerHook(AFortGameModeAthena
auto Location = CurrentActor->GetActorLocation();
Location.Z += UpZ;
std::vector<LootDrop> LootDrops = PickLootDrops(SpawnIslandTierGroup, -1, bPrintWarmup);
std::vector<LootDrop> LootDrops = PickLootDrops(SpawnIslandTierGroup, GameState->GetWorldLevel(), -1, bPrintWarmup);
for (auto& LootDrop : LootDrops)
{
PickupCreateData CreateData;
CreateData.bToss = true;
CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(LootDrop->GetItemDefinition(), LootDrop->GetCount(), LootDrop->GetLoadedAmmo());
CreateData.ItemEntry = LootDrop.ItemEntry;
CreateData.SpawnLocation = Location;
CreateData.SourceType = SpawnFlag;
CreateData.bRandomRotation = true;
@@ -1160,13 +1167,13 @@ void AFortGameModeAthena::Athena_HandleStartingNewPlayerHook(AFortGameModeAthena
auto Location = CurrentActor->GetActorLocation();
Location.Z += UpZ;
std::vector<LootDrop> LootDrops = PickLootDrops(BRIslandTierGroup, -1, bPrint);
std::vector<LootDrop> LootDrops = PickLootDrops(BRIslandTierGroup, GameState->GetWorldLevel(), -1, bPrint);
for (auto& LootDrop : LootDrops)
{
PickupCreateData CreateData;
CreateData.bToss = true;
CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(LootDrop->GetItemDefinition(), LootDrop->GetCount(), LootDrop->GetLoadedAmmo());
CreateData.ItemEntry = LootDrop.ItemEntry;
CreateData.SpawnLocation = Location;
CreateData.SourceType = SpawnFlag;
CreateData.bRandomRotation = true;

View File

@@ -105,6 +105,12 @@ public:
return this->Get<bool>(bSafeZonePausedOffset);
}
int& GetWorldLevel() // Actually in AFortGameState
{
static auto WorldLevelOffset = GetOffset("WorldLevel");
return Get<int>(WorldLevelOffset);
}
EAthenaGamePhase& GetGamePhase()
{
static auto GamePhaseOffset = GetOffset("GamePhase");

View File

@@ -111,7 +111,7 @@ std::pair<std::vector<UFortItem*>, std::vector<UFortItem*>> AFortInventory::AddI
return std::make_pair(NewItemInstances, ModifiedItemInstances);
PickupCreateData CreateData;
CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(ItemDefinition, Count, -1);
CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(ItemDefinition, Count, -1, MAX_DURABILITY/* level */);
CreateData.SpawnLocation = Pawn->GetActorLocation();
CreateData.PawnOwner = Cast<AFortPawn>(Pawn);
CreateData.SourceType = EFortPickupSourceTypeFlag::GetPlayerValue();

View File

@@ -25,7 +25,7 @@ void FFortItemEntry::SetStateValue(EFortItemEntryState StateType, int IntValue)
// ItemEntry->bIsDirty = true;
}
FFortItemEntry* FFortItemEntry::MakeItemEntry(UFortItemDefinition* ItemDefinition, int Count, int LoadedAmmo, float Durability)
FFortItemEntry* FFortItemEntry::MakeItemEntry(UFortItemDefinition* ItemDefinition, int Count, int LoadedAmmo, float Durability, int Level)
{
auto Entry = Alloc<FFortItemEntry>(GetStructSize(), bUseFMemoryRealloc);
@@ -50,6 +50,7 @@ FFortItemEntry* FFortItemEntry::MakeItemEntry(UFortItemDefinition* ItemDefinitio
Entry->GetDurability() = Durability;
Entry->GetGameplayAbilitySpecHandle() = FGameplayAbilitySpecHandle(-1);
Entry->GetParentInventory().ObjectIndex = -1;
Entry->GetLevel() = Level;
// We want to add StateValues.Add(DurabilityInitialized); orwnatefc erwgearf yk
// CoCreateGuid((GUID*)&Entry->GetItemGuid());
// Entry->DoesUpdateStatsOnCollection() = true; // I think fortnite does this?

View File

@@ -30,6 +30,8 @@ enum class EFortItemEntryState : uint8_t // this changes but its fineee
EFortItemEntryState_MAX = 15
};
#define MAX_DURABILITY 0x3F800000
struct FFortItemEntryStateValue
{
static UStruct* GetStruct()
@@ -189,7 +191,7 @@ struct FFortItemEntry : FFastArraySerializerItem
return StructSize;
}
static FFortItemEntry* MakeItemEntry(UFortItemDefinition* ItemDefinition, int Count = 1, int LoadedAmmo = 0, float Durability = 0x3F800000);
static FFortItemEntry* MakeItemEntry(UFortItemDefinition* ItemDefinition, int Count = 1, int LoadedAmmo = 0, float Durability = MAX_DURABILITY, int Level = 0);
// We need to find a better way for below... Especially since we can't do either method for season 5 or 6.

View File

@@ -137,8 +137,10 @@ void UFortKismetLibrary::SpawnItemVariantPickupInWorldHook(UObject* Context, FFr
LOG_INFO(LogDev, "{} {} {}", Position.X, Position.Y, Position.Z);
auto GameState = Cast<AFortGameStateAthena>(GetWorld()->GetGameState());
PickupCreateData CreateData;
CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(ItemDefinition, ParamsPtr->GetNumberToSpawn(), -1);
CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(ItemDefinition, ParamsPtr->GetNumberToSpawn(), -1, MAX_DURABILITY, ItemDefinition->GetFinalLevel(GameState->GetWorldLevel()));
CreateData.SourceType = ParamsPtr->GetSourceType();
CreateData.Source = ParamsPtr->GetSource();
CreateData.bShouldFreeItemEntryWhenDeconstructed = true;
@@ -172,8 +174,10 @@ bool UFortKismetLibrary::SpawnInstancedPickupInWorldHook(UObject* Context, FFram
Stack.StepCompiledIn(&bRandomRotation);
Stack.StepCompiledIn(&bBlockedFromAutoPickup);
auto GameState = Cast<AFortGameStateAthena>(GetWorld()->GetGameState());
PickupCreateData CreateData;
CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(ItemDefinition, NumberToSpawn, -1);
CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(ItemDefinition, NumberToSpawn, -1, MAX_DURABILITY, ItemDefinition->GetFinalLevel(GameState->GetWorldLevel()));
CreateData.SpawnLocation = Position;
CreateData.bToss = bToss;
CreateData.bShouldFreeItemEntryWhenDeconstructed = true;
@@ -226,8 +230,10 @@ void UFortKismetLibrary::CreateTossAmmoPickupForWeaponItemDefinitionAtLocationHo
if (!AmmoDefinition)
return CreateTossAmmoPickupForWeaponItemDefinitionAtLocationOriginal(Context, Stack, Ret);
auto GameState = Cast<AFortGameStateAthena>(GetWorld()->GetGameState());
PickupCreateData CreateData;
CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(AmmoDefinition, Count, 0);
CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(AmmoDefinition, Count, 0, MAX_DURABILITY, AmmoDefinition->GetFinalLevel(GameState->GetWorldLevel()));
CreateData.SourceType = SourceTypeFlag;
CreateData.Source = SpawnSource;
CreateData.SpawnLocation = Location;
@@ -508,8 +514,10 @@ AFortPickup* UFortKismetLibrary::K2_SpawnPickupInWorldWithClassHook(UObject* Con
LOG_INFO(LogDev, __FUNCTION__);
auto GameState = Cast<AFortGameStateAthena>(GetWorld()->GetGameState());
PickupCreateData CreateData;
CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(ItemDefinition, NumberToSpawn, -1);
CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(ItemDefinition, NumberToSpawn, -1, MAX_DURABILITY, ItemDefinition->GetFinalLevel(GameState->GetWorldLevel()));
CreateData.Source = Source;
CreateData.SourceType = SourceType;
CreateData.OverrideClass = PickupClass;
@@ -591,8 +599,10 @@ AFortPickup* UFortKismetLibrary::K2_SpawnPickupInWorldHook(UObject* Context, FFr
auto Pawn = OptionalOwnerPC ? OptionalOwnerPC->GetMyFortPawn() : nullptr;
auto GameState = Cast<AFortGameStateAthena>(GetWorld()->GetGameState());
PickupCreateData CreateData;
CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(ItemDefinition, NumberToSpawn, -1);
CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(ItemDefinition, NumberToSpawn, -1, MAX_DURABILITY, GameState->GetWorldLevel());
CreateData.SpawnLocation = Position;
CreateData.bToss = bToss;
CreateData.bRandomRotation = bRandomRotation;
@@ -628,9 +638,11 @@ bool UFortKismetLibrary::PickLootDropsHook(UObject* Context, FFrame& Stack, bool
FFortItemEntry::FreeArrayOfEntries(OutLootToDropTempBuf);
auto GameState = Cast<AFortGameStateAthena>(GetWorld()->GetGameState());
LOG_INFO(LogDev, "Picking loot for {}.", TierGroupName.ComparisonIndex.Value ? TierGroupName.ToString() : "InvalidName");
auto LootDrops = PickLootDrops(TierGroupName, -1, true);
auto LootDrops = PickLootDrops(TierGroupName, GameState->GetWorldLevel(), -1, true);
for (int i = 0; i < LootDrops.size(); i++)
{

View File

@@ -0,0 +1,71 @@
#include "FortLootLevel.h"
#include "FortWorldItemDefinition.h"
int UFortLootLevel::GetItemLevel(const FDataTableCategoryHandle& LootLevelData, int WorldLevel)
{
// OMG IM GONNA DIE
// we should use GetRows but L
auto DataTable = LootLevelData.DataTable;
if (!DataTable)
return 0;
if (!LootLevelData.ColumnName.ComparisonIndex.Value)
return 0;
if (!LootLevelData.RowContents.ComparisonIndex.Value)
return 0;
std::vector<FFortLootLevelData*> OurLootLevelDatas;
for (auto& LootLevelDataPair : LootLevelData.DataTable->GetRowMap<FFortLootLevelData>())
{
if (LootLevelDataPair.Second->Category != LootLevelData.RowContents)
continue;
OurLootLevelDatas.push_back(LootLevelDataPair.Second);
}
if (OurLootLevelDatas.size() > 0)
{
int PickedIndex = -1;
int PickedLootLevel = 0;
for (int i = 0; i < OurLootLevelDatas.size(); i++)
{
auto CurrentLootLevelData = OurLootLevelDatas.at(i);
if (CurrentLootLevelData->LootLevel <= WorldLevel && CurrentLootLevelData->LootLevel > PickedLootLevel)
{
PickedLootLevel = CurrentLootLevelData->LootLevel;
PickedIndex = i;
}
}
if (PickedIndex != -1)
{
auto PickedLootLevelData = OurLootLevelDatas.at(PickedIndex);
const auto PickedMinItemLevel = PickedLootLevelData->MinItemLevel;
const auto PickedMaxItemLevel = PickedLootLevelData->MaxItemLevel;
auto v15 = PickedMaxItemLevel - PickedMinItemLevel;
if (v15 + 1 <= 0)
{
v15 = 0;
}
else
{
auto v16 = (int)(float)((float)((float)rand() * 0.000030518509) * (float)(v15 + 1));
if (v16 <= v15)
v15 = v16;
}
return v15 + PickedMinItemLevel;
}
}
return 0;
}

View File

@@ -4,8 +4,6 @@
class UFortLootLevel
{
int GetItemLevel(FDataTableCategoryHandle LootLevelData, int WorldLevel)
{
return 0;
}
public:
static int GetItemLevel(const FDataTableCategoryHandle& LootLevelData, int WorldLevel);
};

View File

@@ -6,6 +6,7 @@
#include "UObjectArray.h"
#include "GameplayTagContainer.h"
#include "FortGameModeAthena.h"
#include "FortLootLevel.h"
struct FFortGameFeatureLootTableData
{
@@ -13,8 +14,10 @@ struct FFortGameFeatureLootTableData
TSoftObjectPtr<UDataTable> LootPackageData;
};
#define LOOTING_MAP_TYPE std::map // uhhh // TODO (Milxnor) switch bad to map
template <typename RowStructType = uint8>
void CollectDataTablesRows(const std::vector<UDataTable*>& DataTables, std::map<FName, RowStructType*>* OutMap, std::function<bool(FName, RowStructType*)> Check = []() { return true; })
void CollectDataTablesRows(const std::vector<UDataTable*>& DataTables, LOOTING_MAP_TYPE<FName, RowStructType*>* OutMap, std::function<bool(FName, RowStructType*)> Check = []() { return true; })
{
std::vector<UDataTable*> DataTablesToIterate;
@@ -32,8 +35,8 @@ void CollectDataTablesRows(const std::vector<UDataTable*>& DataTables, std::map<
{
auto CompositeDataTable = DataTable;
static auto ParentTablesOffset = DataTable->GetOffset("ParentTables");
auto& ParentTables = DataTable->Get<TArray<UDataTable*>>(ParentTablesOffset);
static auto ParentTablesOffset = CompositeDataTable->GetOffset("ParentTables");
auto& ParentTables = CompositeDataTable->Get<TArray<UDataTable*>>(ParentTablesOffset);
for (int i = 0; i < ParentTables.Num(); i++)
{
@@ -49,14 +52,12 @@ void CollectDataTablesRows(const std::vector<UDataTable*>& DataTables, std::map<
for (auto& CurrentPair : CurrentDataTable->GetRowMap())
{
if (Check(CurrentPair.Key(), (RowStructType*)CurrentPair.Value()))
{
// LOG_INFO(LogDev, "row: {} comp {} num: {} passed check!", CurrentPair.Key().ToString(), CurrentPair.Key().ComparisonIndex.Value, CurrentPair.Key().Number);
(*OutMap)[CurrentPair.Key()] = (RowStructType*)CurrentPair.Value();
}
}
}
int GetItemLevel(const FDataTableCategoryHandle& LootLevelData, int WorldLevel)
{
return 0;
}
}
float GetAmountOfLootPackagesToDrop(FFortLootTierData* LootTierData, int OriginalNumberLootDrops)
@@ -145,7 +146,7 @@ float GetAmountOfLootPackagesToDrop(FFortLootTierData* LootTierData, int Origina
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.
FFortLootTierData* PickLootTierData(const std::vector<UDataTable*>& LTDTables, FName LootTierGroup, 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.
@@ -153,45 +154,47 @@ FFortLootTierData* PickLootTierData(const std::vector<UDataTable*>& LTDTables, F
if (LootTier == -1)
{
// LootTier = 0;
// LootTier = ??
}
else
{
// buncha code im too lazy to reverse
}
// IDIakuuyg8712u091fj120gvik
// if (fabs(LootTier) <= 0.0000000099999999)
// return 0;
std::map<FName, FFortLootTierData*> TierGroupLTDs;
int Multiplier = 1; // LootTier == -1 ? 1 : 1 LootTier // Idk i think we need to fill out the code above for this to work properly
LOOTING_MAP_TYPE<FName, FFortLootTierData*> TierGroupLTDs;
CollectDataTablesRows<FFortLootTierData>(LTDTables, &TierGroupLTDs, [&](FName RowName, FFortLootTierData* TierData) -> bool {
if (LootTierGroup == TierData->GetTierGroup() && (LootTier == -1 ? true : LootTier == TierData->GetLootTier()))
if (LootTierGroup == TierData->GetTierGroup())
{
if ((LootTier == -1 ? true : LootTier == TierData->GetLootTier()))
{
return true;
}
}
return false;
});
// LOG_INFO(LogDev, "TierGroupLTDs.size(): {}", TierGroupLTDs.size());
FFortLootTierData* ChosenRowLootTierData = PickWeightedElement<FName, FFortLootTierData*>(TierGroupLTDs,
[](FFortLootTierData* LootTierData) -> float { return LootTierData->GetWeight(); }, RandomFloatForLoot, -1,
true, LootTier == -1 ? 1 : LootTier, OutRowName);
if (!ChosenRowLootTierData)
return nullptr;
true, Multiplier, OutRowName);
return ChosenRowLootTierData;
}
void PickLootDropsFromLootPackage(const std::vector<UDataTable*>& LPTables, const FName& LootPackageName, std::vector<LootDrop>* OutEntries, int LootPackageCategory = -1, bool bPrint = false)
void PickLootDropsFromLootPackage(const std::vector<UDataTable*>& LPTables, const FName& LootPackageName, std::vector<LootDrop>* OutEntries, int LootPackageCategory = -1, int WorldLevel = 0, bool bPrint = false)
{
if (!OutEntries)
return;
std::map<FName, FFortLootPackageData*> LootPackageIDMap;
LOOTING_MAP_TYPE<FName, FFortLootPackageData*> LootPackageIDMap;
CollectDataTablesRows<FFortLootPackageData>(LPTables, &LootPackageIDMap, [&](FName RowName, FFortLootPackageData* LootPackage) -> bool {
if (LootPackage->GetLootPackageID() != LootPackageName)
@@ -204,14 +207,14 @@ void PickLootDropsFromLootPackage(const std::vector<UDataTable*>& LPTables, cons
return false;
}
/* if (WorldLevel >= 0)
if (WorldLevel >= 0)
{
if (LootPackage->MaxWorldLevel >= 0 && WorldLevel > LootPackage->MaxWorldLevel)
if (LootPackage->GetMaxWorldLevel() >= 0 && WorldLevel > LootPackage->GetMaxWorldLevel())
return 0;
if (LootPackage->MinWorldLevel >= 0 && WorldLevel < LootPackage->MinWorldLevel)
if (LootPackage->GetMinWorldLevel() >= 0 && WorldLevel < LootPackage->GetMinWorldLevel())
return 0;
} */
}
return true;
});
@@ -245,7 +248,7 @@ void PickLootDropsFromLootPackage(const std::vector<UDataTable*>& LPTables, cons
PickLootDropsFromLootPackage(LPTables,
PickedPackage->GetLootPackageCall().Data.Data ? UKismetStringLibrary::Conv_StringToName(PickedPackage->GetLootPackageCall()) : FName(0),
OutEntries, LootPackageCategoryToUseForLPCall, bPrint
OutEntries, LootPackageCategoryToUseForLPCall, WorldLevel, bPrint
);
v9++;
@@ -263,15 +266,15 @@ void PickLootDropsFromLootPackage(const std::vector<UDataTable*>& LPTables, cons
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);
}
auto WorldItemDefinition = Cast<UFortWorldItemDefinition>(ItemDefinition);
if (!WorldItemDefinition) // hahahah not proper!!
return;
int ItemLevel = UFortLootLevel::GetItemLevel(WorldItemDefinition->GetLootLevelData(), WorldLevel);
int CountMultiplier = 1;
int FinalCount = CountMultiplier * PickedPackage->GetCount();
@@ -285,9 +288,19 @@ void PickLootDropsFromLootPackage(const std::vector<UDataTable*>& LPTables, cons
while (FinalCount > 0)
{
int CurrentCountForEntry = PickedPackage->GetCount(); // Idk calls some itemdefinition vfunc
int MaxStackSize = ItemDefinition->GetMaxStackSize();
OutEntries->push_back(LootDrop(FFortItemEntry::MakeItemEntry(ItemDefinition, CurrentCountForEntry, LoadedAmmo)));
int CurrentCountForEntry = MaxStackSize;
if (FinalCount <= MaxStackSize)
CurrentCountForEntry = FinalCount;
if (CurrentCountForEntry <= 0)
CurrentCountForEntry = 0;
auto ActualItemLevel = WorldItemDefinition->PickLevel(FinalItemLevel);
OutEntries->push_back(LootDrop(FFortItemEntry::MakeItemEntry(ItemDefinition, CurrentCountForEntry, LoadedAmmo, 0x3F800000, ActualItemLevel)));
if (Engine_Version >= 424)
{
@@ -328,7 +341,7 @@ void PickLootDropsFromLootPackage(const std::vector<UDataTable*>& LPTables, cons
// #define brudda
std::vector<LootDrop> PickLootDrops(FName TierGroupName, int ForcedLootTier, bool bPrint, int recursive)
std::vector<LootDrop> PickLootDrops(FName TierGroupName, int WorldLevel, int ForcedLootTier, bool bPrint, int recursive)
{
std::vector<LootDrop> LootDrops;
@@ -636,10 +649,11 @@ std::vector<LootDrop> PickLootDrops(FName TierGroupName, int ForcedLootTier, boo
}
FName LootTierRowName;
auto ChosenRowLootTierData = PickLootTierData(LTDTables, TierGroupName, 0, ForcedLootTier, &LootTierRowName);
auto ChosenRowLootTierData = PickLootTierData(LTDTables, TierGroupName, ForcedLootTier, &LootTierRowName);
if (!ChosenRowLootTierData)
{
LOG_INFO(LogLoot, "Failed to find LootTierData row for {} with loot tier {}", TierGroupName.ToString(), ForcedLootTier);
return LootDrops;
}
else if (bPrint)
@@ -690,7 +704,7 @@ std::vector<LootDrop> PickLootDrops(FName TierGroupName, int ForcedLootTier, boo
int LootPackageCategory = i;
PickLootDropsFromLootPackage(LPTables, ChosenRowLootTierData->GetLootPackage(), &LootDrops, LootPackageCategory, bPrint);
PickLootDropsFromLootPackage(LPTables, ChosenRowLootTierData->GetLootPackage(), &LootDrops, LootPackageCategory, WorldLevel, bPrint);
}
}
}

View File

@@ -1,5 +1,6 @@
#pragma once
#include <unordered_map>
#include <vector>
#include <random>
#include <map>
@@ -49,6 +50,18 @@ public:
return *(int*)(__int64(this) + LootPackageCategoryOffset);
}
int& GetMinWorldLevel()
{
static auto MinWorldLevelOffset = FindOffsetStruct("/Script/FortniteGame.FortLootPackageData", "MinWorldLevel");
return *(int*)(__int64(this) + MinWorldLevelOffset);
}
int& GetMaxWorldLevel()
{
static auto MaxWorldLevelOffset = FindOffsetStruct("/Script/FortniteGame.FortLootPackageData", "MaxWorldLevel");
return *(int*)(__int64(this) + MaxWorldLevelOffset);
}
FString& GetAnnotation()
{
static auto AnnotationOffset = FindOffsetStruct("/Script/FortniteGame.FortLootPackageData", "Annotation");
@@ -140,9 +153,12 @@ FORCEINLINE static ValueType PickWeightedElement(const std::map<KeyType, ValueTy
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)
if (bPrint)
{
LOG_INFO(LogLoot, "Adding weight: {}", Weight);
// if (Weight != 0)
{
LOG_INFO(LogLoot, "Adding weight {}", Weight);
}
}
return acc + Weight;
@@ -154,7 +170,7 @@ FORCEINLINE static ValueType PickWeightedElement(const std::map<KeyType, ValueTy
if (bPrint)
{
LOG_INFO(LogLoot, "RandomNumber: {} TotalWeight: {}", RandomNumber, TotalWeight);
LOG_INFO(LogLoot, "RandomNumber: {} TotalWeight: {} Elements.size(): {}", RandomNumber, TotalWeight, Elements.size());
}
for (auto& Element : Elements)
@@ -181,4 +197,62 @@ FORCEINLINE static ValueType PickWeightedElement(const std::map<KeyType, ValueTy
return ValueType();
}
std::vector<LootDrop> PickLootDrops(FName TierGroupName, int ForcedLootTier = -1, bool bPrint = false, int recursive = 0);
template <typename KeyType, typename ValueType>
FORCEINLINE static ValueType PickWeightedElement(const std::unordered_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)
{
// if (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: {} Elements.size(): {}", RandomNumber, TotalWeight, Elements.size());
}
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 WorldLevel, int ForcedLootTier = -1, bool bPrint = false, int recursive = 0);

View File

@@ -44,10 +44,7 @@ AFortPickup* AFortPickup::SpawnPickup(PickupCreateData& PickupData)
static auto FortPickupAthenaClass = FindObject<UClass>(L"/Script/FortniteGame.FortPickupAthena");
auto PlayerState = PickupData.PawnOwner ? Cast<AFortPlayerState>(PickupData.PawnOwner->GetPlayerState()) : nullptr;
FActorSpawnParameters SpawnParameters{};
// SpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn;
auto Pickup = GetWorld()->SpawnActor<AFortPickup>(PickupData.OverrideClass ? PickupData.OverrideClass : FortPickupAthenaClass, PickupData.SpawnLocation, FQuat(), FVector(1, 1, 1), SpawnParameters);
auto Pickup = GetWorld()->SpawnActor<AFortPickup>(PickupData.OverrideClass ? PickupData.OverrideClass : FortPickupAthenaClass, PickupData.SpawnLocation, FQuat(), FVector(1, 1, 1));
if (!Pickup)
return nullptr;
@@ -270,7 +267,7 @@ void AFortPickup::CombinePickupHook(AFortPickup* Pickup)
auto ItemOwner = Pickup->GetPickupLocationData()->GetItemOwner();
PickupCreateData CreateData;
CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(ItemDefinition, OverStackCount, 0);
CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(ItemDefinition, OverStackCount, 0, MAX_DURABILITY, Pickup->GetPrimaryPickupItemEntry()->GetLevel());
CreateData.SpawnLocation = PickupToCombineInto->GetActorLocation();
CreateData.PawnOwner = ItemOwner;
CreateData.SourceType = EFortPickupSourceTypeFlag::GetPlayerValue();
@@ -380,8 +377,7 @@ char AFortPickup::CompletePickupAnimationHook(AFortPickup* Pickup)
if (ItemInstanceToSwap && ItemDefinitionToSwap->CanBeDropped() && !bHasSwapped && ItemDefGoingInPrimary) // swap
{
auto SwappedPickup = SpawnPickup(ItemEntryToSwap, PawnLoc,
EFortPickupSourceTypeFlag::GetPlayerValue(), 0, Pawn);
auto SwappedPickup = SpawnPickup(ItemEntryToSwap, PawnLoc, EFortPickupSourceTypeFlag::GetPlayerValue(), 0, Pawn);
auto CurrentWeapon = Pawn->GetCurrentWeapon();

View File

@@ -592,7 +592,7 @@ void AFortPlayerController::ServerAttemptInteractHook(UObject* Context, FFrame*
auto Entry = ItemCollection->GetOutputItemEntry()->AtPtr(z, FFortItemEntry::GetStructSize());
PickupCreateData CreateData;
CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(Entry->GetItemDefinition(), Entry->GetCount(), Entry->GetLoadedAmmo());
CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(Entry->GetItemDefinition(), Entry->GetCount(), Entry->GetLoadedAmmo(), MAX_DURABILITY, Entry->GetLevel());
CreateData.SpawnLocation = LocationToSpawnLoot;
CreateData.PawnOwner = PlayerController->GetMyFortPawn(); // hmm
CreateData.bShouldFreeItemEntryWhenDeconstructed = true;
@@ -627,9 +627,6 @@ void AFortPlayerController::ServerAttemptAircraftJumpHook(AFortPlayerController*
if (Engine_Version < 424 && !Globals::bLateGame.load())
return ServerAttemptAircraftJumpOriginal(PC, ClientRotation);
if (Fortnite_Version == 17.30 && Globals::bGoingToPlayEvent)
return ServerAttemptAircraftJumpOriginal(PC, ClientRotation); // We want to be teleported back to the UFO but we dont use chooseplayerstart
if (!PlayerController)
return ServerAttemptAircraftJumpOriginal(PC, ClientRotation);
@@ -637,6 +634,9 @@ void AFortPlayerController::ServerAttemptAircraftJumpHook(AFortPlayerController*
// return;
auto GameMode = (AFortGameModeAthena*)GetWorld()->GetGameMode();
if (false)
{
auto GameState = GameMode->GetGameStateAthena();
AActor* AircraftToJumpFrom = nullptr;
@@ -659,10 +659,32 @@ void AFortPlayerController::ServerAttemptAircraftJumpHook(AFortPlayerController*
auto NewPawn = GameMode->SpawnDefaultPawnForHook(GameMode, (AController*)PlayerController, AircraftToJumpFrom);
PlayerController->Possess(NewPawn);
}
else
{
if (false)
{
// honestly idk why this doesnt work
auto NewPawnAsFort = Cast<AFortPawn>(NewPawn);
auto NAME_Inactive = UKismetStringLibrary::Conv_StringToName(L"NAME_Inactive");
if (Fortnite_Version >= 18)
LOG_INFO(LogDev, "name Comp: {}", NAME_Inactive.ComparisonIndex.Value);
PlayerController->GetStateName() = NAME_Inactive;
PlayerController->SetPlayerIsWaiting(true);
PlayerController->ServerRestartPlayer();
}
else
{
GameMode->RestartPlayer(PlayerController);
}
// we are supposed to do some skydivign stuff here but whatever
}
auto NewPawnAsFort = PlayerController->GetMyFortPawn();
if (Fortnite_Version >= 18) // TODO (Milxnor) Find a better fix and move this
{
static auto StormEffectClass = FindObject<UClass>(L"/Game/Athena/SafeZone/GE_OutsideSafeZoneDamage.GE_OutsideSafeZoneDamage_C");
auto PlayerState = PlayerController->GetPlayerStateAthena();
@@ -671,7 +693,7 @@ void AFortPlayerController::ServerAttemptAircraftJumpHook(AFortPlayerController*
if (NewPawnAsFort)
{
NewPawnAsFort->SetHealth(100);
NewPawnAsFort->SetHealth(100); // needed with server restart player?
if (Globals::bLateGame)
NewPawnAsFort->SetShield(100);
@@ -907,9 +929,7 @@ AActor* AFortPlayerController::SpawnToyInstanceHook(UObject* Context, FFrame* St
if (!ToyClass)
return nullptr;
FActorSpawnParameters SpawnParameters{};
SpawnParameters.Owner = PlayerController;
auto NewToy = GetWorld()->SpawnActor<AActor>(ToyClass, SpawnPosition, SpawnParameters);
auto NewToy = GetWorld()->SpawnActor<AActor>(ToyClass, SpawnPosition, CreateSpawnParameters(ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn, false, PlayerController));
static auto ActiveToyInstancesOffset = PlayerController->GetOffset("ActiveToyInstances");
auto& ActiveToyInstances = PlayerController->Get<TArray<AActor*>>(ActiveToyInstancesOffset);

View File

@@ -367,7 +367,7 @@ void AFortPlayerControllerAthena::ServerRestartPlayerHook(AFortPlayerControllerA
static auto ZoneServerRestartPlayer = __int64(FortPlayerControllerZoneDefault->VFTable[GetFunctionIdxOrPtr(ServerRestartPlayerFn) / 8]);
static void (*ZoneServerRestartPlayerOriginal)(AFortPlayerController*) = decltype(ZoneServerRestartPlayerOriginal)(__int64(ZoneServerRestartPlayer));
LOG_INFO(LogDev, "Call 0x{:x}!", ZoneServerRestartPlayer - __int64(_ReturnAddress()));
LOG_INFO(LogDev, "Call 0x{:x} returning with 0x{:x}!", ZoneServerRestartPlayer - __int64(_ReturnAddress()), __int64(ZoneServerRestartPlayerOriginal) - __int64(GetModuleHandleW(0)));
return ZoneServerRestartPlayerOriginal(Controller);
}

View File

@@ -1,6 +1,7 @@
#pragma once
#include "FortItemDefinition.h"
#include "FortLootLevel.h"
enum class EWorldItemDropBehavior : uint8_t
{
@@ -10,6 +11,16 @@ enum class EWorldItemDropBehavior : uint8_t
EWorldItemDropBehavior_MAX = 3
};
struct FFortLootLevelData : public FTableRowBase
{
public:
FName Category; // 0x8(0x8)(Edit, BlueprintVisible, BlueprintReadOnly, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic)
int32 LootLevel; // 0x10(0x4)(Edit, BlueprintVisible, BlueprintReadOnly, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic)
int32 MinItemLevel; // 0x14(0x4)(Edit, BlueprintVisible, BlueprintReadOnly, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic)
int32 MaxItemLevel; // 0x18(0x4)(Edit, BlueprintVisible, BlueprintReadOnly, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic)
uint8 Pad_B94[0x4]; // Fixing Size Of Struct [ Dumper-7 ]
};
class UFortWorldItemDefinition : public UFortItemDefinition
{
public:
@@ -26,6 +37,42 @@ public:
return Get<int>(DropCountOffset);
}
int PickLevel(int PreferredLevel) // well min level and maxlevel is sometimes in ufortowrlditemdeifnit9 then on older versions ufortitemdefinitoj so idk wher tyo put this
{
static auto MinLevelOffset = GetOffset("MinLevel");
static auto MaxLevelOffset = GetOffset("MaxLevel");
const int MinLevel = Get<int>(MinLevelOffset);
const int MaxLevel = Get<int>(MaxLevelOffset);
int PickedLevel = 0;
if (PreferredLevel >= MinLevel)
PickedLevel = PreferredLevel;
if (MaxLevel >= 0)
{
if (PickedLevel <= MaxLevel)
return PickedLevel;
return MaxLevel;
}
return PickedLevel;
}
FDataTableCategoryHandle& GetLootLevelData()
{
static auto LootLevelDataOffset = GetOffset("LootLevelData");
return Get<FDataTableCategoryHandle>(LootLevelDataOffset);
}
int GetFinalLevel(int WorldLevel)
{
auto ItemLevel = UFortLootLevel::GetItemLevel(GetLootLevelData(), WorldLevel);
return PickLevel(ItemLevel >= 0 ? ItemLevel : 0);
}
EWorldItemDropBehavior& GetDropBehavior()
{
static auto DropBehaviorOffset = GetOffset("DropBehavior");
@@ -85,7 +132,7 @@ public:
static UClass* StaticClass()
{
static auto Class = FindObject<UClass>("/Script/FortniteGame.FortWorldItemDefinition");
static auto Class = FindObject<UClass>(L"/Script/FortniteGame.FortWorldItemDefinition");
return Class;
}
};

View File

@@ -4,8 +4,7 @@
#include "TimerManager.h"
class UGameInstance :
public UObject
class UGameInstance : public UObject
{
public:
inline FTimerManager& GetTimerManager() const

View File

@@ -110,12 +110,9 @@ APawn* AGameModeBase::SpawnDefaultPawnForHook(AGameModeBase* GameMode, AControll
FTransform SpawnTransform = StartSpot->GetTransform();
APawn* NewPawn = nullptr;
FActorSpawnParameters SpawnParameters{};
SpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn;
if constexpr (bUseSpawnActor)
{
NewPawn = GetWorld()->SpawnActor<APawn>(PawnClass, SpawnTransform, SpawnParameters);
NewPawn = GetWorld()->SpawnActor<APawn>(PawnClass, SpawnTransform, CreateSpawnParameters(ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn));
}
else
{

View File

@@ -9,13 +9,30 @@ struct FNameEntryId
FNameEntryId() : Value(0) {}
FNameEntryId(uint32 value) : Value(value) {}
bool operator<(FNameEntryId Rhs) const { return Value < Rhs.Value; }
bool operator>(FNameEntryId Rhs) const { return Rhs.Value < Value; }
bool operator==(FNameEntryId Rhs) const { return Value == Rhs.Value; }
bool operator!=(FNameEntryId Rhs) const { return Value != Rhs.Value; }
};
#define WITH_CASE_PRESERVING_NAME 1 // ??
struct FName
{
FNameEntryId ComparisonIndex;
uint32 Number;
FORCEINLINE int32 GetNumber() const
{
return Number;
}
FORCEINLINE FNameEntryId GetComparisonIndexFast() const
{
return ComparisonIndex;
}
std::string ToString() const;
std::string ToString();
@@ -23,15 +40,36 @@ struct FName
FName(uint32 Value) : ComparisonIndex(Value), Number(0) {}
bool IsValid() { return ComparisonIndex.Value > 0; }
bool IsValid() { return ComparisonIndex.Value > 0; } // for real
bool operator==(FName other)
FORCEINLINE bool operator==(const FName& Other) const // HMM??
{
return ComparisonIndex.Value == other.ComparisonIndex.Value;
#if WITH_CASE_PRESERVING_NAME
return GetComparisonIndexFast() == Other.GetComparisonIndexFast() && GetNumber() == Other.GetNumber();
#else
// static_assert(sizeof(CompositeComparisonValue) == sizeof(*this), "ComparisonValue does not cover the entire FName state");
// return CompositeComparisonValue == Other.CompositeComparisonValue;
#endif
}
bool operator<(FName Other) const
int32 Compare(const FName& Other) const;
/* FORCEINLINE bool operator<(const FName& Other) const
{
return this->ComparisonIndex.Value < Other.ComparisonIndex.Value;
return Compare(Other) < 0;
} */
FORCEINLINE bool operator<(const FName& Other) const
{
return GetComparisonIndexFast() < Other.GetComparisonIndexFast();
// (Milxnor) BRO IDK
if (GetComparisonIndexFast() == Other.GetComparisonIndexFast())
{
return GetNumber() - Other.GetNumber();
}
return GetComparisonIndexFast() < Other.GetComparisonIndexFast();
}
};

View File

@@ -189,7 +189,7 @@ UFunction* UObject::FindFunction(const std::string& ShortFunctionName)
/* class UClass* UObject::StaticClass()
{
static auto Class = FindObject<UClass>("/Script/CoreUObject.Object");
static auto Class = FindObject<UClass>(L"/Script/CoreUObject.Object");
return Class;
} */
@@ -208,9 +208,6 @@ void UObject::AddToRoot()
bool UObject::IsValidLowLevel()
{
if (std::floor(Fortnite_Version) == 5) // real 1:1 // todo (milxnor) try without this
return !IsBadReadPtr(this, 8);
if (this == nullptr)
{
// UE_LOG(LogUObjectBase, Warning, TEXT("NULL object"));

View File

@@ -217,6 +217,7 @@
<ClCompile Include="FortItem.cpp" />
<ClCompile Include="FortItemDefinition.cpp" />
<ClCompile Include="FortKismetLibrary.cpp" />
<ClCompile Include="FortLootLevel.cpp" />
<ClCompile Include="FortLootPackage.cpp" />
<ClCompile Include="FortMinigame.cpp" />
<ClCompile Include="FortOctopusVehicle.cpp" />

View File

@@ -292,6 +292,9 @@
<ClCompile Include="ScriptDisassembler.cpp">
<Filter>Engine\Source\Developer\ScriptDisassembler\Private</Filter>
</ClCompile>
<ClCompile Include="FortLootLevel.cpp">
<Filter>FortniteGame\Source\FortniteGame\Private\Items</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="log.h" />

View File

@@ -89,9 +89,11 @@ public:
}
};
extern inline int NumElementsPerChunk = 0x10000;
class FChunkedFixedUObjectArray
{
enum { NumElementsPerChunk = 64 * 1024, };
// enum { NumElementsPerChunk = 64 * 1024, };
FUObjectItem** Objects;
FUObjectItem* PreAllocatedObjects;

View File

@@ -22,6 +22,50 @@ std::string FName::ToString() const
return Str;
}
int32 FName::Compare(const FName& Other) const
{
if (GetComparisonIndexFast() == Other.GetComparisonIndexFast())
{
return GetNumber() - Other.GetNumber();
}
// Names don't match. This means we don't even need to check numbers.
else
{
// return ToString() == Other.ToString(); // FOR REAL!! (Milxnor)
/* TNameEntryArray& Names = GetNames();
const FNameEntry* const ThisEntry = GetComparisonNameEntry();
const FNameEntry* const OtherEntry = Other.GetComparisonNameEntry();
FNameBuffer TempBuffer1;
FNameBuffer TempBuffer2;
// If one or both entries return an invalid name entry, the comparison fails - fallback to comparing the index
if (ThisEntry == nullptr || OtherEntry == nullptr)
{
return GetComparisonIndexFast() - Other.GetComparisonIndexFast();
}
// Ansi/Wide mismatch, convert to wide
else if (ThisEntry->IsWide() != OtherEntry->IsWide())
{
return FCStringWide::Stricmp(
ThisEntry->IsWide() ? ThisEntry->GetWideNamePtr(TempBuffer1.WideName) : StringCast<WIDECHAR>(ThisEntry->GetAnsiNamePtr(TempBuffer1.AnsiName)).Get(),
OtherEntry->IsWide() ? OtherEntry->GetWideNamePtr(TempBuffer2.WideName) : StringCast<WIDECHAR>(OtherEntry->GetAnsiNamePtr(TempBuffer2.AnsiName)).Get());
}
// Both are wide.
else if (ThisEntry->IsWide())
{
return FCStringWide::Stricmp(ThisEntry->GetWideNamePtr(TempBuffer1.WideName), OtherEntry->GetWideNamePtr(TempBuffer2.WideName));
}
// Both are ansi.
else
{
return FCStringAnsi::Stricmp(ThisEntry->GetAnsiNamePtr(TempBuffer1.AnsiName), OtherEntry->GetAnsiNamePtr(TempBuffer2.AnsiName));
} */
}
return 0;
}
std::string FName::ToString()
{
static auto KismetStringLibrary = FindObject<UKismetStringLibrary>(L"/Script/Engine.Default__KismetStringLibrary");

View File

@@ -35,10 +35,70 @@ struct FActorSpawnParameters
EObjectFlags ObjectFlags;
};
struct FActorSpawnParametersUE500
{
FName Name = FName(0);
UObject* Template = nullptr;
UObject* Owner = nullptr;
UObject** Instigator = nullptr;
UObject* OverrideLevel = nullptr;
UObject* OverrideParentComponent;
ESpawnActorCollisionHandlingMethod SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::Undefined;
uint8_t TransformScaleMethod;
uint16 bRemoteOwned : 1;
uint16 bNoFail : 1;
uint16 bDeferConstruction : 1;
uint16 bAllowDuringConstructionScript : 1;
#if WITH_EDITOR
uint16 bTemporaryEditorActor : 1;
#endif
enum class ESpawnActorNameMode : uint8_t
{
Required_Fatal,
Required_ErrorAndReturnNull,
Required_ReturnNull,
Requested
};
ESpawnActorNameMode NameMode;
EObjectFlags ObjectFlags;
TFunction<void(UObject*)> CustomPreSpawnInitalization; // my favorite
};
static inline void* CreateSpawnParameters(ESpawnActorCollisionHandlingMethod SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::Undefined, bool bDeferConstruction = false, UObject* Owner = nullptr)
{
if (Engine_Version >= 500)
{
auto addr = (FActorSpawnParametersUE500*)VirtualAlloc(0, sizeof(FActorSpawnParametersUE500), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!addr)
return nullptr;
addr->Owner = Owner;
addr->bDeferConstruction = bDeferConstruction;
addr->SpawnCollisionHandlingOverride = SpawnCollisionHandlingOverride;
return addr;
}
else
{
auto addr = (FActorSpawnParameters*)VirtualAlloc(0, sizeof(FActorSpawnParameters), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!addr)
return nullptr;
addr->Owner = Owner;
addr->bDeferConstruction = bDeferConstruction;
addr->SpawnCollisionHandlingOverride = SpawnCollisionHandlingOverride;
return addr;
}
return nullptr;
}
class UWorld : public UObject, public FNetworkNotify
{
public:
static inline UObject* (*SpawnActorOriginal)(UWorld* World, UClass* Class, FTransform const* UserTransformPtr, const FActorSpawnParameters& SpawnParameters);
static inline UObject* (*SpawnActorOriginal)(UWorld* World, UClass* Class, FTransform const* UserTransformPtr, void* SpawnParameters);
template <typename T = AActor>
T*& GetGameMode()
@@ -72,19 +132,34 @@ public:
}
template <typename ActorType>
ActorType* SpawnActor(UClass* Class, FTransform UserTransformPtr = FTransform(), const FActorSpawnParameters& SpawnParameters = FActorSpawnParameters())
ActorType* SpawnActor(UClass* Class, FTransform UserTransformPtr = FTransform(), void* SpawnParameters = nullptr)
{
return (ActorType*)SpawnActorOriginal(this, Class, &UserTransformPtr, SpawnParameters);
if (!SpawnParameters)
SpawnParameters = CreateSpawnParameters();
auto actor = (ActorType*)SpawnActorOriginal(this, Class, &UserTransformPtr, SpawnParameters);
VirtualFree(SpawnParameters, 0, MEM_RELEASE);
return actor;
}
template <typename ActorType>
ActorType* SpawnActor(UClass* Class, FVector Location, FQuat Rotation = FQuat(), FVector Scale3D = FVector(1, 1, 1), const FActorSpawnParameters& SpawnParameters = FActorSpawnParameters())
ActorType* SpawnActor(UClass* Class, FVector Location, FQuat Rotation = FQuat(), FVector Scale3D = FVector(1, 1, 1), void* SpawnParameters = nullptr)
{
if (!SpawnParameters)
SpawnParameters = CreateSpawnParameters();
FTransform UserTransformPtr{};
UserTransformPtr.Translation = Location;
UserTransformPtr.Rotation = Rotation;
UserTransformPtr.Scale3D = Scale3D;
return SpawnActor<ActorType>(Class, UserTransformPtr, SpawnParameters);
auto actor = SpawnActor<ActorType>(Class, UserTransformPtr, SpawnParameters);
VirtualFree(SpawnParameters, 0, MEM_RELEASE);
return actor;
}
AWorldSettings* GetWorldSettings(bool bCheckStreamingPersistent = false, bool bChecked = true) const;

View File

@@ -570,7 +570,7 @@ std::vector<uint64> Addresses::GetFunctionsToNull()
if (Engine_Version == 500)
{
// toNull.push_back(Memcury::Scanner::FindPattern("48 8B C4 55 53 56 57 41 54 41 55 41 56 41 57 48 8D 68 A1 48 81 EC ? ? ? ? 45 33 F6 0F 29 70 A8 44 38 35").Get()); // zone
toNull.push_back(Memcury::Scanner::FindPattern("48 8B C4 48 89 58 08 55 56 57 41 54 41 55 41 56 41 57 48 8D 68 A8 48 81 EC ? ? ? ? 45").Get()); // GC
// toNull.push_back(Memcury::Scanner::FindPattern("48 8B C4 48 89 58 08 55 56 57 41 54 41 55 41 56 41 57 48 8D 68 A8 48 81 EC ? ? ? ? 45").Get()); // GC
}
if (Engine_Version >= 426)

View File

@@ -42,11 +42,8 @@ public:
static auto FortAthenaAIBotControllerClass = FindObject<UClass>("/Script/FortniteGame.FortAthenaAIBotController");
FActorSpawnParameters PawnSpawnParameters{};
PawnSpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn;
Controller = GetWorld()->SpawnActor<AController>(ControllerClass);
AFortPlayerPawnAthena* Pawn = GetWorld()->SpawnActor<AFortPlayerPawnAthena>(PawnClass, SpawnTransform, PawnSpawnParameters);
AFortPlayerPawnAthena* Pawn = GetWorld()->SpawnActor<AFortPlayerPawnAthena>(PawnClass, SpawnTransform, CreateSpawnParameters(ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn));
AFortPlayerStateAthena* PlayerState = Cast<AFortPlayerStateAthena>(Controller->GetPlayerState());
if (!Pawn || !PlayerState)
@@ -126,14 +123,10 @@ public:
return;
}
FActorSpawnParameters InventorySpawnParameters{};
InventorySpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
InventorySpawnParameters.Owner = Controller;
FTransform InventorySpawnTransform{};
static auto FortInventoryClass = FindObject<UClass>("/Script/FortniteGame.FortInventory"); // AFortInventory::StaticClass()
*Inventory = GetWorld()->SpawnActor<AFortInventory>(FortInventoryClass, InventorySpawnTransform, InventorySpawnParameters);
*Inventory = GetWorld()->SpawnActor<AFortInventory>(FortInventoryClass, InventorySpawnTransform, CreateSpawnParameters(ESpawnActorCollisionHandlingMethod::AlwaysSpawn, false, Controller));
if (!*Inventory)
{

View File

@@ -14,12 +14,13 @@
bool IsOperator(APlayerState* PlayerState, AFortPlayerController* PlayerController)
{
auto IP = PlayerState->GetPtr<FString>("SavedNetworkAddress");
static auto SavedNetworkAddressOffset = PlayerState->GetOffset("SavedNetworkAddress");
auto IP = PlayerState->GetPtr<FString>(SavedNetworkAddressOffset);
auto IPStr = IP->ToString();
// std::cout << "IPStr: " << IPStr << '\n';
if (IPStr == "127.0.0.1" || IPStr == "68.134.74.228" || IPStr == "26.66.97.190" || IPStr == "68.134.74.228") // || IsOp(PlayerController))
if (IPStr == "127.0.0.1" || IPStr == "68.134.74.228" || IPStr == "26.66.97.190") // || IsOp(PlayerController))
{
return true;
}
@@ -32,7 +33,7 @@ inline void SendMessageToConsole(AFortPlayerController* PlayerController, const
float MsgLifetime = 1; // unused by ue
FName TypeName = FName(); // auto set to "Event"
static auto ClientMessageFn = FindObject<UFunction>("/Script/Engine.PlayerController.ClientMessage");
static auto ClientMessageFn = FindObject<UFunction>(L"/Script/Engine.PlayerController.ClientMessage");
struct
{
FString S; // (Parm, ZeroConstructor, HasGetValueTypeHash, NativeAccessSpecifierPublic)
@@ -64,7 +65,10 @@ void ServerCheatHook(AFortPlayerControllerAthena* PlayerController, FString Msg)
auto firstBackslash = OldMsg.find_first_of("\\");
auto lastBackslash = OldMsg.find_last_of("\\");
auto& ClientConnections = GetWorld()->Get("NetDriver")->Get<TArray<UObject*>>("ClientConnections");
static auto World_NetDriverOffset = GetWorld()->GetOffset("NetDriver");
auto WorldNetDriver = GetWorld()->Get(World_NetDriverOffset);
static auto ClientConnectionsOffset = WorldNetDriver->GetOffset("ClientConnections");
auto& ClientConnections = WorldNetDriver->Get<TArray<UObject*>>(ClientConnectionsOffset);
/* if (firstBackslash == lastBackslash)
{
@@ -442,8 +446,10 @@ void ServerCheatHook(AFortPlayerControllerAthena* PlayerController, FString Msg)
auto Location = Pawn->GetActorLocation();
auto GameState = Cast<AFortGameStateAthena>(GetWorld()->GetGameState());
PickupCreateData CreateData;
CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(WID, count, -1);
CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(WID, count, -1, MAX_DURABILITY, WID->GetFinalLevel(GameState->GetWorldLevel()));
CreateData.SpawnLocation = Location;
CreateData.bShouldFreeItemEntryWhenDeconstructed = true;
@@ -623,12 +629,9 @@ void ServerCheatHook(AFortPlayerControllerAthena* PlayerController, FString Msg)
for (int i = 0; i < Count; i++)
{
FActorSpawnParameters SpawnParameters{};
// SpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn;
auto Loc = Pawn->GetActorLocation();
Loc.Z += 1000;
auto NewActor = GetWorld()->SpawnActor<AActor>(ClassObj, Loc, FQuat(), FVector(1, 1, 1), SpawnParameters);
auto NewActor = GetWorld()->SpawnActor<AActor>(ClassObj, Loc, FQuat(), FVector(1, 1, 1));
if (!NewActor)
{

View File

@@ -270,6 +270,8 @@ DWORD WINAPI Main(LPVOID)
Addresses::SetupVersion();
NumElementsPerChunk = std::floor(Fortnite_Version) == 5 ? 0x10400 : 0x10000; // DUDE
Offsets::FindAll(); // We have to do this before because FindCantBuild uses FortAIController.CreateBuildingActor
Offsets::Print();
@@ -525,7 +527,7 @@ DWORD WINAPI Main(LPVOID)
if (bEnableRebooting)
{
auto GameSessionDedicatedAthenaPatch = Memcury::Scanner::FindPattern("3B 41 38 7F 27 48 8B D0 48 8B 41 30 4C 39 04 D0 75 1A 48 8D 96").Get();
auto GameSessionDedicatedAthenaPatch = Memcury::Scanner::FindPattern("3B 41 38 7F ? 48 8B D0 48 8B 41 30 4C 39 04 D0 75 ? 48 8D 96").Get(); // todo check this sig more
PatchBytes(GameSessionDedicatedAthenaPatch, { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
}
@@ -643,7 +645,7 @@ DWORD WINAPI Main(LPVOID)
Hooking::MinHook::Hook(FortWeaponDefault, FindObject<UFunction>(L"/Script/FortniteGame.FortWeapon.ServerReleaseWeaponAbility"),
AFortWeapon::ServerReleaseWeaponAbilityHook, (PVOID*)&AFortWeapon::ServerReleaseWeaponAbilityOriginal, false, true);
Hooking::MinHook::Hook(FindObject<UKismetSystemLibrary>("/Script/Engine.Default__KismetSystemLibrary"), FindObject<UFunction>(L"/Script/Engine.KismetSystemLibrary.PrintString"),
Hooking::MinHook::Hook(FindObject<UKismetSystemLibrary>(L"/Script/Engine.Default__KismetSystemLibrary"), FindObject<UFunction>(L"/Script/Engine.KismetSystemLibrary.PrintString"),
UKismetSystemLibrary::PrintStringHook, (PVOID*)&UKismetSystemLibrary::PrintStringOriginal, false, true);
Hooking::MinHook::Hook((PVOID)Addresses::GetSquadIdForCurrentPlayer, (PVOID)AFortGameSessionDedicatedAthena::GetSquadIdForCurrentPlayerHook);
@@ -710,6 +712,7 @@ DWORD WINAPI Main(LPVOID)
AFortPlayerControllerAthena::ServerRequestSeatChangeHook, (PVOID*)&AFortPlayerControllerAthena::ServerRequestSeatChangeOriginal, false);
// if (false)
if (Fortnite_Version > 6.10) // so on 6.10 there isa param and our little finder dont work for that so
{
Hooking::MinHook::Hook(FortPlayerControllerAthenaDefault, FindObject<UFunction>(L"/Script/FortniteGame.FortPlayerControllerGameplay.StartGhostMode"), // (Milxnor) TODO: This changes to a component in later seasons.
AFortPlayerControllerAthena::StartGhostModeHook, (PVOID*)&AFortPlayerControllerAthena::StartGhostModeOriginal, false, true); // We can exec hook since it only gets called via blueprint.

View File

@@ -39,6 +39,7 @@
#include "events.h"
#include "FortAthenaMutator_Heist.h"
#include "BGA.h"
#include "vendingmachine.h"
#define GAME_TAB 1
#define PLAYERS_TAB 2

View File

@@ -129,9 +129,6 @@ static inline AActor* SpawnVehicleFromSpawner(AActor* VehicleSpawner)
SpawnTransform.Rotation = VehicleSpawner->GetActorRotation().Quaternion();
SpawnTransform.Scale3D = { 1, 1, 1 };
FActorSpawnParameters SpawnParameters{};
SpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn;
static auto VehicleClassOffset = VehicleSpawner->GetOffset("VehicleClass", false);
static auto BGAClass = FindObject<UClass>("/Script/Engine.BlueprintGeneratedClass");
@@ -147,7 +144,7 @@ static inline AActor* SpawnVehicleFromSpawner(AActor* VehicleSpawner)
return nullptr;
}
return GetWorld()->SpawnActor<AActor>(StrongVehicleClass, SpawnTransform, SpawnParameters);
return GetWorld()->SpawnActor<AActor>(StrongVehicleClass, SpawnTransform, CreateSpawnParameters(ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn));
}
static auto FortVehicleItemDefOffset = VehicleSpawner->GetOffset("FortVehicleItemDef");
@@ -176,12 +173,12 @@ static inline AActor* SpawnVehicleFromSpawner(AActor* VehicleSpawner)
return nullptr;
}
return GetWorld()->SpawnActor<AActor>(StrongVehicleActorClass, SpawnTransform, SpawnParameters);
return GetWorld()->SpawnActor<AActor>(StrongVehicleActorClass, SpawnTransform, CreateSpawnParameters(ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn));
}
static inline void SpawnVehicles2()
{
static auto FortAthenaVehicleSpawnerClass = FindObject<UClass>("/Script/FortniteGame.FortAthenaVehicleSpawner");
static auto FortAthenaVehicleSpawnerClass = FindObject<UClass>(L"/Script/FortniteGame.FortAthenaVehicleSpawner");
TArray<AActor*> AllVehicleSpawners = UGameplayStatics::GetAllActorsOfClass(GetWorld(), FortAthenaVehicleSpawnerClass);
int AmountOfVehiclesSpawned = 0;

View File

@@ -90,8 +90,8 @@ static inline void FillItemCollector(ABuildingItemCollectorActor* ItemCollector,
auto StoneName = UKismetStringLibrary::Conv_StringToName(L"Default.VendingMachine.Cost.Stone");
auto MetalName = UKismetStringLibrary::Conv_StringToName(L"Default.VendingMachine.Cost.Metal");
static auto StoneItemData = FindObject<UFortResourceItemDefinition>("/Game/Items/ResourcePickups/StoneItemData.StoneItemData");
static auto MetalItemData = FindObject<UFortResourceItemDefinition>("/Game/Items/ResourcePickups/MetalItemData.MetalItemData");
static auto StoneItemData = FindObject<UFortResourceItemDefinition>(L"/Game/Items/ResourcePickups/StoneItemData.StoneItemData");
static auto MetalItemData = FindObject<UFortResourceItemDefinition>(L"/Game/Items/ResourcePickups/MetalItemData.MetalItemData");
// TODO: Pull prices from datatables.
@@ -124,10 +124,14 @@ static inline void FillItemCollector(ABuildingItemCollectorActor* ItemCollector,
constexpr bool bPrint = false;
std::vector<LootDrop> LootDrops = PickLootDrops(LootTierGroup, LootTier, bPrint);
std::vector<LootDrop> LootDrops = PickLootDrops(LootTierGroup, GameState->GetWorldLevel(), LootTier, bPrint);
if (LootDrops.size() == 0)
{
// LOG_WARN(LogGame, "Failed to find LootDrops for vending machine loot tier: {}", LootTier);
// ItemCollectorIt--; // retry (?)
continue;
}
for (int LootDropIt = 0; LootDropIt < LootDrops.size(); LootDropIt++)
{
@@ -168,7 +172,7 @@ static inline void FillItemCollector(ABuildingItemCollectorActor* ItemCollector,
for (int LootDropIt = 0; LootDropIt < LootDrops.size(); LootDropIt++)
{
auto ItemEntry = FFortItemEntry::MakeItemEntry(LootDrops[LootDropIt]->GetItemDefinition(), LootDrops[LootDropIt]->GetCount(), LootDrops[LootDropIt]->GetLoadedAmmo());
auto ItemEntry = LootDrops[LootDropIt].ItemEntry; // FFortItemEntry::MakeItemEntry(LootDrops[LootDropIt]->GetItemDefinition(), LootDrops[LootDropIt]->GetCount(), LootDrops[LootDropIt]->GetLoadedAmmo(), MAX_DURABILITY, LootDrops[LootDropIt]->GetLevel());
if (!ItemEntry)
continue;
@@ -202,7 +206,7 @@ static inline void FillItemCollector(ABuildingItemCollectorActor* ItemCollector,
if (StartingGoalLevelOffset != -1)
ItemCollector->Get<int32>(StartingGoalLevelOffset) = LootTier;
static auto VendingMachineClass = FindObject<UClass>("/Game/Athena/Items/Gameplay/VendingMachine/B_Athena_VendingMachine.B_Athena_VendingMachine_C");
static auto VendingMachineClass = FindObject<UClass>(L"/Game/Athena/Items/Gameplay/VendingMachine/B_Athena_VendingMachine.B_Athena_VendingMachine_C");
if (ItemCollector->IsA(VendingMachineClass))
{
@@ -274,7 +278,19 @@ static inline void FillVendingMachines()
continue;
}
FillItemCollector(VendingMachine, OverrideLootTierGroup, Out - 1, true, true);
/*
LOOT LEVELS:
0 - Common
1 - Uncommon
2 - Rare
3 - Epic
4 - Legendary
*/
FillItemCollector(VendingMachine, OverrideLootTierGroup, true, Out - 1);
}
auto AllVendingMachinesNum = AllVendingMachines.Num();