a good update

Added a very useful debugging tool, made looting even more proper
This commit is contained in:
Milxnor
2023-05-09 22:37:04 -04:00
parent b64f569551
commit 3fb5c4671d
34 changed files with 612 additions and 169 deletions

View File

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

View File

@@ -7,6 +7,8 @@
bool ABuildingContainer::SpawnLoot(AFortPawn* Pawn) bool ABuildingContainer::SpawnLoot(AFortPawn* Pawn)
{ {
auto GameMode = Cast<AFortGameModeAthena>(GetWorld()->GetGameMode()); auto GameMode = Cast<AFortGameModeAthena>(GetWorld()->GetGameMode());
auto GameState = Cast<AFortGameStateAthena>(GetWorld()->GetGameState());
FVector LocationToSpawnLoot = this->GetActorLocation() + this->GetActorRightVector() * 70.f + FVector{ 0, 0, 50 }; FVector LocationToSpawnLoot = this->GetActorLocation() + this->GetActorRightVector() * 70.f + FVector{ 0, 0, 50 };
static auto SearchLootTierGroupOffset = this->GetOffset("SearchLootTierGroup"); static auto SearchLootTierGroupOffset = this->GetOffset("SearchLootTierGroup");
@@ -14,18 +16,16 @@ bool ABuildingContainer::SpawnLoot(AFortPawn* Pawn)
// LOG_INFO(LogInteraction, "RedirectedLootTier: {}", RedirectedLootTier.ToString()); // LOG_INFO(LogInteraction, "RedirectedLootTier: {}", RedirectedLootTier.ToString());
auto LootDrops = PickLootDrops(RedirectedLootTier, -1, bDebugPrintLooting); auto LootDrops = PickLootDrops(RedirectedLootTier, GameState->GetWorldLevel(), -1, bDebugPrintLooting);
// LOG_INFO(LogInteraction, "LootDrops.size(): {}", LootDrops.size()); // LOG_INFO(LogInteraction, "LootDrops.size(): {}", LootDrops.size());
for (int i = 0; i < LootDrops.size(); i++) for (auto& LootDrop : LootDrops)
{ {
auto& lootDrop = LootDrops.at(i);
PickupCreateData CreateData{}; PickupCreateData CreateData{};
CreateData.bToss = true; CreateData.bToss = true;
// CreateData.PawnOwner = Pawn; // CreateData.PawnOwner = Pawn;
CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(lootDrop->GetItemDefinition(), lootDrop->GetCount(), lootDrop->GetLoadedAmmo()); CreateData.ItemEntry = LootDrop.ItemEntry;
CreateData.SpawnLocation = LocationToSpawnLoot; CreateData.SpawnLocation = LocationToSpawnLoot;
CreateData.SourceType = EFortPickupSourceTypeFlag::GetContainerValue(); CreateData.SourceType = EFortPickupSourceTypeFlag::GetContainerValue();
CreateData.bRandomRotation = true; CreateData.bRandomRotation = true;
@@ -34,5 +34,17 @@ bool ABuildingContainer::SpawnLoot(AFortPawn* Pawn)
auto NewPickup = AFortPickup::SpawnPickup(CreateData); auto NewPickup = AFortPickup::SpawnPickup(CreateData);
} }
static auto SearchAnimationCountOffset = FindOffsetStruct("/Script/FortniteGame.FortSearchBounceData", "SearchAnimationCount");
static auto SearchBounceDataOffset = this->GetOffset("SearchBounceData");
auto SearchBounceData = this->GetPtr<void>(SearchBounceDataOffset);
(*(int*)(__int64(SearchBounceData) + SearchAnimationCountOffset))++;
static auto OnRep_bAlreadySearchedFn = FindObject<UFunction>(L"/Script/FortniteGame.BuildingContainer.OnRep_bAlreadySearched");
this->ProcessEvent(OnRep_bAlreadySearchedFn);
// Now there is some function called here but idk what it is, it calls OnLoot though.
return true; return true;
} }

View File

@@ -1,9 +1,15 @@
#pragma once #pragma once
#include "Object.h" #include "Object.h"
#include "reboot.h"
#include "Map.h" #include "Map.h"
struct FTableRowBase
{
unsigned char UnknownData00[0x8]; // this is actually structural padding
};
class UDataTable : public UObject class UDataTable : public UObject
{ {
public: public:
@@ -40,4 +46,63 @@ struct FDataTableCategoryHandle
UDataTable* DataTable; // 0x0000(0x0008) (Edit, BlueprintVisible, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) UDataTable* DataTable; // 0x0000(0x0008) (Edit, BlueprintVisible, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic)
FName ColumnName; // 0x0008(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) FName RowContents; // 0x0010(0x0008) (Edit, BlueprintVisible, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic)
template <class T>
void GetRows(std::vector<T*>& OutRows, const FString& ContextString) const
{
OutRows.clear();
if (DataTable == nullptr)
{
if (RowContents.ComparisonIndex.Value != 0)
{
// UE_LOG(LogDataTable, Warning, TEXT("FDataTableCategoryHandle::FindRow : No DataTable for row %s (%s)."), *RowContents.ToString(), *ContextString);
}
return;
}
if (ColumnName.ComparisonIndex.Value == 0)
{
if (RowContents.ComparisonIndex.Value != 0)
{
// UE_LOG(LogDataTable, Warning, TEXT("FDataTableCategoryHandle::FindRow : No Column selected for row %s (%s)."), *RowContents.ToString(), *ContextString);
}
return;
}
return;
// unreal trippin
/*
// Find the property that matches the desired column (ColumnName)
UProperty* Property = DataTable->FindTableProperty(ColumnName);
if (Property == nullptr)
{
return;
}
// check each row to see if the value in the Property element is the one we're looking for (RowContents). If it is, add the row to OutRows
FString RowContentsAsString = RowContents.ToString();
for (auto RowIt = DataTable->RowMap.CreateConstIterator(); RowIt; ++RowIt)
{
uint8* RowData = RowIt.Value();
FString PropertyValue(TEXT(""));
Property->ExportText_InContainer(0, PropertyValue, RowData, RowData, nullptr, PPF_None);
if (RowContentsAsString == PropertyValue)
{
OutRows.Add((T*)RowData);
}
}
*/
return;
}
}; };

View File

@@ -6,18 +6,49 @@
#include "FortWorldItemDefinition.h" #include "FortWorldItemDefinition.h"
#include "FortInventory.h" #include "FortInventory.h"
enum class ERespawnRequirements : uint8_t
{
RespawnOnly = 0,
NoRespawnOnly = 1,
Both = 2,
ERespawnRequirements_MAX = 3
};
struct FItemsToDropOnDeath struct FItemsToDropOnDeath
{ {
UFortWorldItemDefinition* ItemToDrop; // 0x0000(0x0008) (Edit, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) static UStruct* GetStruct()
FScalableFloat NumberToDrop; // 0x0008(0x0020) (Edit, NativeAccessSpecifierPublic) {
static auto Struct = FindObject<UStruct>("/Script/FortniteGame.ItemsToDropOnDeath");
return Struct;
}
static int GetStructSize() { return GetStruct()->GetPropertiesSize(); }
UFortWorldItemDefinition*& GetItemToDrop()
{
static auto ItemToDropOffset = FindOffsetStruct("/Script/FortniteGame.ItemsToDropOnDeath", "ItemToDrop");
return *(UFortWorldItemDefinition**)(__int64(this) + ItemToDropOffset);
}
FScalableFloat* GetNumberToDrop()
{
static auto NumberToDropOffset = FindOffsetStruct("/Script/FortniteGame.ItemsToDropOnDeath", "NumberToDrop");
return (FScalableFloat*)(__int64(this) + NumberToDropOffset);
}
}; };
class AFortAthenaMutator_ItemDropOnDeath : public AFortAthenaMutator class AFortAthenaMutator_ItemDropOnDeath : public AFortAthenaMutator
{ {
public: public:
ERespawnRequirements/*&*/ GetRespawnRequirements()
{
static auto RespawnRequirementsOffset = GetOffset("RespawnRequirements");
return Get<ERespawnRequirements>(RespawnRequirementsOffset);
}
TArray<FItemsToDropOnDeath>& GetItemsToDrop() TArray<FItemsToDropOnDeath>& GetItemsToDrop()
{ {
static auto ItemsToDropOffset = GetOffset("ItemsToDrop"); static auto ItemsToDropOffset = GetOffset("ItemsToDrop");
return Get<TArray<FItemsToDropOnDeath>>(ItemsToDropoOffset); return Get<TArray<FItemsToDropOnDeath>>(ItemsToDropOffset);
} }
}; };

View File

@@ -1,6 +1,6 @@
#include "FortGameMode.h" #include "FortGameMode.h"
void AFortGameMode::SetCurrentPlaylistName(UObject* Playlist) // Techinally it takes in a fname void AFortGameMode::SetCurrentPlaylistName(UFortPlaylist* Playlist) // Techinally it takes in a fname
{ {
if (!Playlist) if (!Playlist)
{ {
@@ -9,11 +9,10 @@ void AFortGameMode::SetCurrentPlaylistName(UObject* Playlist) // Techinally it t
} }
static auto PlaylistNameOffset = Playlist->GetOffset("PlaylistName"); static auto PlaylistNameOffset = Playlist->GetOffset("PlaylistName");
static auto PlaylistIdOffset = Playlist->GetOffset("PlaylistId");
static auto CurrentPlaylistNameOffset = GetOffset("CurrentPlaylistName"); static auto CurrentPlaylistNameOffset = GetOffset("CurrentPlaylistName");
static auto CurrentPlaylistIdOffset = GetOffset("CurrentPlaylistId"); static auto CurrentPlaylistIdOffset = GetOffset("CurrentPlaylistId");
Get<FName>(CurrentPlaylistNameOffset) = Playlist->Get<FName>(PlaylistNameOffset); Get<FName>(CurrentPlaylistNameOffset) = Playlist->Get<FName>(PlaylistNameOffset);
Get<int>(CurrentPlaylistIdOffset) = Playlist->Get<int>(PlaylistIdOffset); Get<int>(CurrentPlaylistIdOffset) = Playlist->GetPlaylistId();
} }

View File

@@ -1,9 +1,10 @@
#pragma once #pragma once
#include "GameMode.h" #include "GameMode.h"
#include "FortPlaylist.h"
class AFortGameMode : public AGameMode class AFortGameMode : public AGameMode
{ {
public: public:
void SetCurrentPlaylistName(UObject* Playlist); // Techinally it takes in a fname void SetCurrentPlaylistName(UFortPlaylist* Playlist); // Techinally it takes in a fname
}; };

View File

@@ -161,21 +161,12 @@ bool AFortGameModeAthena::Athena_ReadyToStartMatchHook(AFortGameModeAthena* Game
(*(int*)(__int64(CurrentPlaylistInfo) + PlaylistReplicationKeyOffset))++; (*(int*)(__int64(CurrentPlaylistInfo) + PlaylistReplicationKeyOffset))++;
CurrentPlaylistInfo->MarkArrayDirty(); CurrentPlaylistInfo->MarkArrayDirty();
auto aeuh = *(UObject**)(__int64(CurrentPlaylistInfo) + BasePlaylistOffset); auto currentBasePlaylist = *(UFortPlaylist**)(__int64(CurrentPlaylistInfo) + BasePlaylistOffset);
if (aeuh) if (currentBasePlaylist)
{ {
GameMode->SetCurrentPlaylistName(aeuh); GameMode->SetCurrentPlaylistName(currentBasePlaylist);
GameState->SetPlaylistId(currentBasePlaylist);
/* if (Fortnite_Version >= 13)
{
static auto LastSafeZoneIndexOffset = aeuh->GetOffset("LastSafeZoneIndex");
if (LastSafeZoneIndexOffset != -1)
{
*(int*)(__int64(aeuh) + LastSafeZoneIndexOffset) = 0;
}
} */
} }
} }
else else
@@ -183,7 +174,15 @@ bool AFortGameModeAthena::Athena_ReadyToStartMatchHook(AFortGameModeAthena* Game
static auto CurrentPlaylistDataOffset = GameState->GetOffset("CurrentPlaylistData", false); static auto CurrentPlaylistDataOffset = GameState->GetOffset("CurrentPlaylistData", false);
if (CurrentPlaylistDataOffset != -1) if (CurrentPlaylistDataOffset != -1)
{
GameState->Get(CurrentPlaylistDataOffset) = Playlist; GameState->Get(CurrentPlaylistDataOffset) = Playlist;
if (GameState->Get(CurrentPlaylistDataOffset))
{
GameMode->SetCurrentPlaylistName(GameState->Get<UFortPlaylist*>(CurrentPlaylistDataOffset));
GameState->SetPlaylistId(GameState->Get<UFortPlaylist*>(CurrentPlaylistDataOffset));
}
}
} }
if (bOnRep) if (bOnRep)
@@ -550,13 +549,23 @@ bool AFortGameModeAthena::Athena_ReadyToStartMatchHook(AFortGameModeAthena* Game
LastNum3 = AmountOfRestarts; LastNum3 = AmountOfRestarts;
++Globals::AmountOfListens; ++Globals::AmountOfListens;
LOG_INFO(LogNet, "Attempting to listen!"); // LOG_INFO(LogNet, "Attempting to listen!");
GetWorld()->Listen(); GetWorld()->Listen();
LOG_INFO(LogDev, "WorldLevel: {}", GameState->GetWorldLevel());
SetupAIDirector(); SetupAIDirector();
SetupServerBotManager(); SetupServerBotManager();
bool bPrintCommonObjectPaths = true;
if (bPrintCommonObjectPaths)
{
LOG_INFO(LogGame, "GameState PathName: {}", GetWorld()->GetGameState()->GetPathName());
LOG_INFO(LogGame, "GameMode PathName: {}", GetWorld()->GetGameMode()->GetPathName());
}
if (AmountOfBotsToSpawn != 0) if (AmountOfBotsToSpawn != 0)
{ {
Bots::SpawnBotsAtPlayerStarts(AmountOfBotsToSpawn); Bots::SpawnBotsAtPlayerStarts(AmountOfBotsToSpawn);
@@ -968,13 +977,13 @@ void AFortGameModeAthena::Athena_HandleStartingNewPlayerHook(AFortGameModeAthena
auto Location = CurrentActor->GetActorLocation(); auto Location = CurrentActor->GetActorLocation();
Location.Z += UpZ; Location.Z += UpZ;
std::vector<LootDrop> LootDrops = PickLootDrops(SpawnIslandTierGroup, -1, bPrintWarmup); std::vector<LootDrop> LootDrops = PickLootDrops(SpawnIslandTierGroup, GameState->GetWorldLevel(), -1, bPrintWarmup);
for (auto& LootDrop : LootDrops) for (auto& LootDrop : LootDrops)
{ {
PickupCreateData CreateData; PickupCreateData CreateData;
CreateData.bToss = true; CreateData.bToss = true;
CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(LootDrop->GetItemDefinition(), LootDrop->GetCount(), LootDrop->GetLoadedAmmo()); CreateData.ItemEntry = LootDrop.ItemEntry;
CreateData.SpawnLocation = Location; CreateData.SpawnLocation = Location;
CreateData.SourceType = SpawnFlag; CreateData.SourceType = SpawnFlag;
CreateData.bRandomRotation = true; CreateData.bRandomRotation = true;
@@ -998,13 +1007,13 @@ void AFortGameModeAthena::Athena_HandleStartingNewPlayerHook(AFortGameModeAthena
auto Location = CurrentActor->GetActorLocation(); auto Location = CurrentActor->GetActorLocation();
Location.Z += UpZ; Location.Z += UpZ;
std::vector<LootDrop> LootDrops = PickLootDrops(BRIslandTierGroup, -1, bPrint); std::vector<LootDrop> LootDrops = PickLootDrops(BRIslandTierGroup, GameState->GetWorldLevel(), -1, bPrint);
for (auto& LootDrop : LootDrops) for (auto& LootDrop : LootDrops)
{ {
PickupCreateData CreateData; PickupCreateData CreateData;
CreateData.bToss = true; CreateData.bToss = true;
CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(LootDrop->GetItemDefinition(), LootDrop->GetCount(), LootDrop->GetLoadedAmmo()); CreateData.ItemEntry = LootDrop.ItemEntry;
CreateData.SpawnLocation = Location; CreateData.SpawnLocation = Location;
CreateData.SourceType = SpawnFlag; CreateData.SourceType = SpawnFlag;
CreateData.bRandomRotation = true; CreateData.bRandomRotation = true;

View File

@@ -81,7 +81,7 @@ static void SetFoundationTransform(AActor* BuildingFoundation, const FTransform&
static inline UFortAbilitySet* GetPlayerAbilitySet() static inline UFortAbilitySet* GetPlayerAbilitySet()
{ {
// There are some variables that contain this but it changes through versions soo.. // There are some variables that contain this but it changes through versions soo.. // GenericPlayerAbilitySet and PlayerAbilitySetBR
static auto GameplayAbilitySet = (UFortAbilitySet*)(Fortnite_Version >= 8.30 static auto GameplayAbilitySet = (UFortAbilitySet*)(Fortnite_Version >= 8.30
? LoadObject(L"/Game/Abilities/Player/Generic/Traits/DefaultPlayer/GAS_AthenaPlayer.GAS_AthenaPlayer", UFortAbilitySet::StaticClass()) ? LoadObject(L"/Game/Abilities/Player/Generic/Traits/DefaultPlayer/GAS_AthenaPlayer.GAS_AthenaPlayer", UFortAbilitySet::StaticClass())

View File

@@ -80,6 +80,12 @@ UFortPlaylist*& AFortGameStateAthena::GetCurrentPlaylist()
return *(UFortPlaylist**)(__int64(CurrentPlaylistInfo) + BasePlaylistOffset); return *(UFortPlaylist**)(__int64(CurrentPlaylistInfo) + BasePlaylistOffset);
} }
void AFortGameStateAthena::SetPlaylistId(UFortPlaylist* Playlist)
{
static auto CurrentPlaylistIdOffset = GetOffset("CurrentPlaylistId");
this->Get<int>(CurrentPlaylistIdOffset) = Playlist->GetPlaylistId();
}
int AFortGameStateAthena::GetAircraftIndex(AFortPlayerState* PlayerState) int AFortGameStateAthena::GetAircraftIndex(AFortPlayerState* PlayerState)
{ {
// The function has a string in it but we can just remake lol // The function has a string in it but we can just remake lol

View File

@@ -68,6 +68,12 @@ public:
return Get<EAthenaGamePhase>(GamePhaseOffset); return Get<EAthenaGamePhase>(GamePhaseOffset);
} }
int& GetWorldLevel() // Actually in AFortGameState
{
static auto WorldLevelOffset = GetOffset("WorldLevel");
return Get<int>(WorldLevelOffset);
}
UBuildingStructuralSupportSystem* GetStructuralSupportSystem() // actually in FortGameModeZone UBuildingStructuralSupportSystem* GetStructuralSupportSystem() // actually in FortGameModeZone
{ {
static auto StructuralSupportSystemOffset = GetOffset("StructuralSupportSystem"); static auto StructuralSupportSystemOffset = GetOffset("StructuralSupportSystem");
@@ -99,6 +105,7 @@ public:
// void AddPlayerStateToGameMemberInfo(class AFortPlayerStateAthena* PlayerState); // void AddPlayerStateToGameMemberInfo(class AFortPlayerStateAthena* PlayerState);
void SetPlaylistId(UFortPlaylist* Playlist);
int GetAircraftIndex(AFortPlayerState* PlayerState); int GetAircraftIndex(AFortPlayerState* PlayerState);
bool IsRespawningAllowed(AFortPlayerState* PlayerState); // actually in zone bool IsRespawningAllowed(AFortPlayerState* PlayerState); // actually in zone
bool IsPlayerBuildableClass(UClass* Class); bool IsPlayerBuildableClass(UClass* Class);

View File

@@ -25,7 +25,7 @@ void FFortItemEntry::SetStateValue(EFortItemEntryState StateType, int IntValue)
// ItemEntry->bIsDirty = true; // 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); auto Entry = Alloc<FFortItemEntry>(GetStructSize(), bUseFMemoryRealloc);
@@ -40,7 +40,7 @@ FFortItemEntry* FFortItemEntry::MakeItemEntry(UFortItemDefinition* ItemDefinitio
LoadedAmmo = 0; LoadedAmmo = 0;
} }
Entry->MostRecentArrayReplicationKey = -1; // idk if we need to set this Entry->MostRecentArrayReplicationKey = -1; // idk if we need to set this one
Entry->ReplicationID = -1; Entry->ReplicationID = -1;
Entry->ReplicationKey = -1; Entry->ReplicationKey = -1;
@@ -50,6 +50,7 @@ FFortItemEntry* FFortItemEntry::MakeItemEntry(UFortItemDefinition* ItemDefinitio
Entry->GetDurability() = Durability; Entry->GetDurability() = Durability;
Entry->GetGameplayAbilitySpecHandle() = FGameplayAbilitySpecHandle(-1); Entry->GetGameplayAbilitySpecHandle() = FGameplayAbilitySpecHandle(-1);
Entry->GetParentInventory().ObjectIndex = -1; Entry->GetParentInventory().ObjectIndex = -1;
Entry->GetLevel() = Level;
// We want to add StateValues.Add(DurabilityInitialized); orwnatefc erwgearf yk // We want to add StateValues.Add(DurabilityInitialized); orwnatefc erwgearf yk
// CoCreateGuid((GUID*)&Entry->GetItemGuid()); // CoCreateGuid((GUID*)&Entry->GetItemGuid());
// Entry->DoesUpdateStatsOnCollection() = true; // I think fortnite does this? // Entry->DoesUpdateStatsOnCollection() = true; // I think fortnite does this?

View File

@@ -143,18 +143,12 @@ struct FFortItemEntry : FFastArraySerializerItem
FGuid OldGuid = this->GetItemGuid(); FGuid OldGuid = this->GetItemGuid();
if (false) this->GetCount() = OtherItemEntry->GetCount();
{ this->GetItemDefinition() = OtherItemEntry->GetItemDefinition();
CopyStruct(this, OtherItemEntry, FFortItemEntry::GetStructSize(), FFortItemEntry::GetStruct()); this->GetDurability() = OtherItemEntry->GetDurability();
} this->GetLevel() = OtherItemEntry->GetLevel();
else this->GetLoadedAmmo() = OtherItemEntry->GetLoadedAmmo();
{ this->GetItemGuid() = OtherItemEntry->GetItemGuid();
this->GetItemDefinition() = OtherItemEntry->GetItemDefinition();
this->GetCount() = OtherItemEntry->GetCount();
this->GetLoadedAmmo() = OtherItemEntry->GetLoadedAmmo();
this->GetItemGuid() = OtherItemEntry->GetItemGuid();
this->GetLevel() = OtherItemEntry->GetLevel();
}
if (!bCopyGuid) if (!bCopyGuid)
this->GetItemGuid() = OldGuid; this->GetItemGuid() = OldGuid;
@@ -189,7 +183,7 @@ struct FFortItemEntry : FFastArraySerializerItem
return StructSize; 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 = 0x3F800000, 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. // We need to find a better way for below... Especially since we can't do either method for season 5 or 6.

View File

@@ -3,6 +3,7 @@
#include "FortPickup.h" #include "FortPickup.h"
#include "FortLootPackage.h" #include "FortLootPackage.h"
#include "AbilitySystemComponent.h" #include "AbilitySystemComponent.h"
#include "FortGameStateAthena.h"
UFortResourceItemDefinition* UFortKismetLibrary::K2_GetResourceItemDefinition(EFortResourceType ResourceType) UFortResourceItemDefinition* UFortKismetLibrary::K2_GetResourceItemDefinition(EFortResourceType ResourceType)
{ {
@@ -601,13 +602,15 @@ bool UFortKismetLibrary::PickLootDropsHook(UObject* Context, FFrame& Stack, bool
LOG_INFO(LogDev, "Picking loot for {}.", TierGroupName.ComparisonIndex.Value ? TierGroupName.ToString() : "InvalidName"); LOG_INFO(LogDev, "Picking loot for {}.", TierGroupName.ComparisonIndex.Value ? TierGroupName.ToString() : "InvalidName");
auto LootDrops = PickLootDrops(TierGroupName, -1, true); auto GameState = Cast<AFortGameStateAthena>(GetWorld()->GetGameState());
auto LootDrops = PickLootDrops(TierGroupName, GameState->GetWorldLevel(), -1, true);
for (int i = 0; i < LootDrops.size(); i++) for (int i = 0; i < LootDrops.size(); i++)
{ {
auto& LootDrop = LootDrops.at(i); auto& LootDrop = LootDrops.at(i);
auto NewEntry = FFortItemEntry::MakeItemEntry(LootDrop->GetItemDefinition(), LootDrop->GetCount(), LootDrop->GetLoadedAmmo()); auto NewEntry = LootDrop.ItemEntry;
OutLootToDrop.AddPtr(NewEntry, FFortItemEntry::GetStructSize()); OutLootToDrop.AddPtr(NewEntry, FFortItemEntry::GetStructSize());
} }

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 class UFortLootLevel
{ {
int GetItemLevel(FDataTableCategoryHandle LootLevelData, int WorldLevel) public:
{ static int GetItemLevel(const FDataTableCategoryHandle& LootLevelData, int WorldLevel);
return 0;
}
}; };

View File

@@ -6,6 +6,7 @@
#include "UObjectArray.h" #include "UObjectArray.h"
#include "GameplayTagContainer.h" #include "GameplayTagContainer.h"
#include "FortGameModeAthena.h" #include "FortGameModeAthena.h"
#include "FortLootLevel.h"
struct FFortGameFeatureLootTableData struct FFortGameFeatureLootTableData
{ {
@@ -51,11 +52,6 @@ void CollectDataTablesRows(std::vector<UDataTable*> DataTables, std::map<FName,
} }
} }
int GetItemLevel(const FDataTableCategoryHandle& LootLevelData, int WorldLevel)
{
return 0;
}
float GetAmountOfLootPackagesToDrop(FFortLootTierData* LootTierData, int OriginalNumberLootDrops) float GetAmountOfLootPackagesToDrop(FFortLootTierData* LootTierData, int OriginalNumberLootDrops)
{ {
if (LootTierData->GetLootPackageCategoryMinArray().Num() != LootTierData->GetLootPackageCategoryWeightArray().Num() if (LootTierData->GetLootPackageCategoryMinArray().Num() != LootTierData->GetLootPackageCategoryWeightArray().Num()
@@ -183,7 +179,7 @@ FFortLootTierData* PickLootTierData(const std::vector<UDataTable*>& LTDTables, F
return ChosenRowLootTierData; 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) if (!OutEntries)
return; return;
@@ -201,14 +197,16 @@ void PickLootDropsFromLootPackage(const std::vector<UDataTable*>& LPTables, cons
return false; return false;
} }
/* if (WorldLevel >= 0) // todo add required tag?
if (WorldLevel >= 0)
{ {
if (LootPackage->MaxWorldLevel >= 0 && WorldLevel > LootPackage->MaxWorldLevel) if (LootPackage->GetMaxWorldLevel() >= 0 && WorldLevel > LootPackage->GetMaxWorldLevel())
return 0; return 0;
if (LootPackage->MinWorldLevel >= 0 && WorldLevel < LootPackage->MinWorldLevel) if (LootPackage->GetMinWorldLevel() >= 0 && WorldLevel < LootPackage->GetMinWorldLevel())
return 0; return 0;
} */ }
return true; return true;
}); });
@@ -242,7 +240,7 @@ void PickLootDropsFromLootPackage(const std::vector<UDataTable*>& LPTables, cons
PickLootDropsFromLootPackage(LPTables, PickLootDropsFromLootPackage(LPTables,
PickedPackage->GetLootPackageCall().Data.Data ? UKismetStringLibrary::Conv_StringToName(PickedPackage->GetLootPackageCall()) : FName(0), PickedPackage->GetLootPackageCall().Data.Data ? UKismetStringLibrary::Conv_StringToName(PickedPackage->GetLootPackageCall()) : FName(0),
OutEntries, LootPackageCategoryToUseForLPCall, bPrint OutEntries, LootPackageCategoryToUseForLPCall, WorldLevel, bPrint
); );
v9++; v9++;
@@ -260,15 +258,15 @@ void PickLootDropsFromLootPackage(const std::vector<UDataTable*>& LPTables, cons
return; return;
} }
int ItemLevel = 0;
auto WeaponItemDefinition = Cast<UFortWeaponItemDefinition>(ItemDefinition); auto WeaponItemDefinition = Cast<UFortWeaponItemDefinition>(ItemDefinition);
int LoadedAmmo = WeaponItemDefinition ? WeaponItemDefinition->GetClipSize() : 0; // we shouldnt set loaded ammo here techinally int LoadedAmmo = WeaponItemDefinition ? WeaponItemDefinition->GetClipSize() : 0; // we shouldnt set loaded ammo here techinally
if (auto WorldItemDefinition = Cast<UFortWorldItemDefinition>(ItemDefinition)) auto WorldItemDefinition = Cast<UFortWorldItemDefinition>(ItemDefinition);
{
ItemLevel = 0; // GetItemLevel(WorldItemDefinition->LootLevelData, 0); if (!WorldItemDefinition) // hahahah not proper!!
} return;
int ItemLevel = UFortLootLevel::GetItemLevel(WorldItemDefinition->GetLootLevelData(), WorldLevel);
int CountMultiplier = 1; int CountMultiplier = 1;
int FinalCount = CountMultiplier * PickedPackage->GetCount(); int FinalCount = CountMultiplier * PickedPackage->GetCount();
@@ -282,15 +280,30 @@ void PickLootDropsFromLootPackage(const std::vector<UDataTable*>& LPTables, cons
while (FinalCount > 0) 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 (bPrint)
{
LOG_INFO(LogDev, "ActualItemLevel: {} FinalItemLevel: {} ItemLevel: {}", ActualItemLevel, FinalItemLevel, ItemLevel);
} */
if (Engine_Version >= 424) if (Engine_Version >= 424)
{ {
/* /*
Alright, so Fortnite literally doesn't reference the first loot package category for chests and floor loot (didnt check rest). Alright, so Fortnite literally doesn't reference the first loot package category for chests and floor loot on chapter two and above (didnt check rest).
Usually the first loot package category in our case is ammo, so this is quite weird. 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. I have no clue how Fortnite would actually add the ammo.
@@ -306,7 +319,7 @@ void PickLootDropsFromLootPackage(const std::vector<UDataTable*>& LPTables, cons
if (AmmoData) if (AmmoData)
{ {
int AmmoCount = AmmoData->GetDropCount(); // idk about this one int AmmoCount = AmmoData->GetDropCount(); // uhh???
OutEntries->push_back(LootDrop(FFortItemEntry::MakeItemEntry(AmmoData, AmmoCount))); OutEntries->push_back(LootDrop(FFortItemEntry::MakeItemEntry(AmmoData, AmmoCount)));
} }
@@ -323,7 +336,7 @@ void PickLootDropsFromLootPackage(const std::vector<UDataTable*>& LPTables, cons
} }
} }
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; std::vector<LootDrop> LootDrops;
@@ -659,7 +672,7 @@ std::vector<LootDrop> PickLootDrops(FName TierGroupName, int ForcedLootTier, boo
int LootPackageCategory = i; int LootPackageCategory = i;
PickLootDropsFromLootPackage(LPTables, ChosenRowLootTierData->GetLootPackage(), &LootDrops, LootPackageCategory, bPrint); PickLootDropsFromLootPackage(LPTables, ChosenRowLootTierData->GetLootPackage(), &LootDrops, LootPackageCategory, WorldLevel, bPrint);
} }
} }
} }

View File

@@ -45,6 +45,18 @@ public:
return *(int*)(__int64(this) + CountOffset); return *(int*)(__int64(this) + CountOffset);
} }
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);
}
int& GetLootPackageCategory() int& GetLootPackageCategory()
{ {
static auto LootPackageCategoryOffset = FindOffsetStruct("/Script/FortniteGame.FortLootPackageData", "LootPackageCategory"); static auto LootPackageCategoryOffset = FindOffsetStruct("/Script/FortniteGame.FortLootPackageData", "LootPackageCategory");
@@ -183,4 +195,4 @@ FORCEINLINE static ValueType PickWeightedElement(const std::map<KeyType, ValueTy
return ValueType(); return ValueType();
} }
std::vector<LootDrop> PickLootDrops(FName TierGroupName, int ForcedLootTier = -1, bool bPrint = false, int recursive = 0); std::vector<LootDrop> PickLootDrops(FName TierGroupName, int WorldLevel, int ForcedLootTier = -1, bool bPrint = false, int recursive = 0);

View File

@@ -34,7 +34,7 @@ AFortPickup* AFortPickup::SpawnPickup(PickupCreateData& PickupData)
if (PickupData.Source == -1) if (PickupData.Source == -1)
PickupData.Source = 0; PickupData.Source = 0;
if (PickupData.SourceType == -1) if (PickupData.SourceType == -1)
PickupData.SourceType = -1; PickupData.SourceType = 0;
/* if (PickupData.bToss) /* if (PickupData.bToss)
{ {

View File

@@ -430,26 +430,18 @@ void AFortPlayerController::ServerAttemptInteractHook(UObject* Context, FFrame*
FVector LocationToSpawnLoot = ReceivingActor->GetActorLocation() + ReceivingActor->GetActorRightVector() * 70.f + FVector{ 0, 0, 50 }; FVector LocationToSpawnLoot = ReceivingActor->GetActorLocation() + ReceivingActor->GetActorRightVector() * 70.f + FVector{ 0, 0, 50 };
static auto FortAthenaVehicleClass = FindObject<UClass>(L"/Script/FortniteGame.FortAthenaVehicle"); static auto FortAthenaVehicleClass = FindObject<UClass>(L"/Script/FortniteGame.FortAthenaVehicle");
static auto SearchAnimationCountOffset = FindOffsetStruct("/Script/FortniteGame.FortSearchBounceData", "SearchAnimationCount");
if (auto BuildingContainer = Cast<ABuildingContainer>(ReceivingActor)) if (auto BuildingContainer = Cast<ABuildingContainer>(ReceivingActor))
{ {
static auto bAlreadySearchedOffset = BuildingContainer->GetOffset("bAlreadySearched"); static auto bAlreadySearchedOffset = BuildingContainer->GetOffset("bAlreadySearched");
static auto SearchBounceDataOffset = BuildingContainer->GetOffset("SearchBounceData");
static auto bAlreadySearchedFieldMask = GetFieldMask(BuildingContainer->GetProperty("bAlreadySearched")); static auto bAlreadySearchedFieldMask = GetFieldMask(BuildingContainer->GetProperty("bAlreadySearched"));
auto SearchBounceData = BuildingContainer->GetPtr<void>(SearchBounceDataOffset);
if (BuildingContainer->ReadBitfieldValue(bAlreadySearchedOffset, bAlreadySearchedFieldMask)) if (BuildingContainer->ReadBitfieldValue(bAlreadySearchedOffset, bAlreadySearchedFieldMask))
return; return;
// LOG_INFO(LogInteraction, "bAlreadySearchedFieldMask: {}", bAlreadySearchedFieldMask); // LOG_INFO(LogInteraction, "bAlreadySearchedFieldMask: {}", bAlreadySearchedFieldMask);
BuildingContainer->SetBitfieldValue(bAlreadySearchedOffset, bAlreadySearchedFieldMask, true); BuildingContainer->SetBitfieldValue(bAlreadySearchedOffset, bAlreadySearchedFieldMask, true);
(*(int*)(__int64(SearchBounceData) + SearchAnimationCountOffset))++;
static auto OnRep_bAlreadySearchedFn = FindObject<UFunction>(L"/Script/FortniteGame.BuildingContainer.OnRep_bAlreadySearched");
BuildingContainer->ProcessEvent(OnRep_bAlreadySearchedFn);
BuildingContainer->SpawnLoot(PlayerController->GetMyFortPawn()); BuildingContainer->SpawnLoot(PlayerController->GetMyFortPawn());

View File

@@ -259,7 +259,7 @@ void AFortPlayerPawn::ServerHandlePickupHook(AFortPlayerPawn* Pawn, AFortPickup*
static auto bPickedUpOffset = Pickup->GetOffset("bPickedUp"); static auto bPickedUpOffset = Pickup->GetOffset("bPickedUp");
LOG_INFO(LogDev, "InFlyTime: {}", InFlyTime); // LOG_INFO(LogDev, "InFlyTime: {}", InFlyTime);
if (Pickup->Get<bool>(bPickedUpOffset)) if (Pickup->Get<bool>(bPickedUpOffset))
{ {

View File

@@ -9,6 +9,7 @@
#include "BuildingActor.h" #include "BuildingActor.h"
#include "FortPlayerPawnAthena.h" #include "FortPlayerPawnAthena.h"
#include "GameplayAbilityTypes.h" #include "GameplayAbilityTypes.h"
#include "FortPlayerState.h"
struct FGameplayTagRequirements struct FGameplayTagRequirements
{ {
@@ -275,6 +276,12 @@ struct FWinConditionScoreData
class UFortPlaylist : public UObject class UFortPlaylist : public UObject
{ {
public: public:
int& GetPlaylistId()
{
static auto PlaylistIdOffset = GetOffset("PlaylistId");
return Get<int>(PlaylistIdOffset);
}
TArray<TSoftObjectPtr<UFortGameplayModifierItemDefinition>>& GetModifierList() TArray<TSoftObjectPtr<UFortGameplayModifierItemDefinition>>& GetModifierList()
{ {
static auto ModifierListOffset = this->GetOffset("ModifierList"); static auto ModifierListOffset = this->GetOffset("ModifierList");

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include "FortItemDefinition.h" #include "FortItemDefinition.h"
#include "DataTable.h"
enum class EWorldItemDropBehavior : uint8_t enum class EWorldItemDropBehavior : uint8_t
{ {
@@ -10,6 +11,16 @@ enum class EWorldItemDropBehavior : uint8_t
EWorldItemDropBehavior_MAX = 3 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 class UFortWorldItemDefinition : public UFortItemDefinition
{ {
public: public:
@@ -20,6 +31,35 @@ public:
return ReadBitfieldValue(bCanBeDroppedOffset, bCanBeDroppedFieldMask); return ReadBitfieldValue(bCanBeDroppedOffset, bCanBeDroppedFieldMask);
} }
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& GetDropCount() int& GetDropCount()
{ {
static auto DropCountOffset = GetOffset("DropCount"); static auto DropCountOffset = GetOffset("DropCount");

View File

@@ -214,6 +214,7 @@
<ClCompile Include="FortItem.cpp" /> <ClCompile Include="FortItem.cpp" />
<ClCompile Include="FortItemDefinition.cpp" /> <ClCompile Include="FortItemDefinition.cpp" />
<ClCompile Include="FortKismetLibrary.cpp" /> <ClCompile Include="FortKismetLibrary.cpp" />
<ClCompile Include="FortLootLevel.cpp" />
<ClCompile Include="FortLootPackage.cpp" /> <ClCompile Include="FortLootPackage.cpp" />
<ClCompile Include="FortMinigame.cpp" /> <ClCompile Include="FortMinigame.cpp" />
<ClCompile Include="FortOctopusVehicle.cpp" /> <ClCompile Include="FortOctopusVehicle.cpp" />
@@ -287,6 +288,7 @@
<ClInclude Include="Channel.h" /> <ClInclude Include="Channel.h" />
<ClInclude Include="CheatManager.h" /> <ClInclude Include="CheatManager.h" />
<ClInclude Include="Class.h" /> <ClInclude Include="Class.h" />
<ClInclude Include="objectviewer.h" />
<ClInclude Include="commands.h" /> <ClInclude Include="commands.h" />
<ClInclude Include="ContainerAllocationPolicies.h" /> <ClInclude Include="ContainerAllocationPolicies.h" />
<ClInclude Include="Controller.h" /> <ClInclude Include="Controller.h" />

View File

@@ -271,6 +271,9 @@
<ClCompile Include="inc.cpp"> <ClCompile Include="inc.cpp">
<Filter>Reboot\Private</Filter> <Filter>Reboot\Private</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="FortLootLevel.cpp">
<Filter>FortniteGame\Source\FortniteGame\Private\Items</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="log.h" /> <ClInclude Include="log.h" />
@@ -859,6 +862,9 @@
<ClInclude Include="inc.h"> <ClInclude Include="inc.h">
<Filter>Reboot\Public</Filter> <Filter>Reboot\Public</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="objectviewer.h">
<Filter>Reboot\Public</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Filter Include="Engine"> <Filter Include="Engine">

View File

@@ -85,7 +85,7 @@ void UWorld::Listen()
*(UNetDriver**)(__int64(LevelCollections.AtPtr(0, LevelCollectionSize)) + 0x10) = NewNetDriver; *(UNetDriver**)(__int64(LevelCollections.AtPtr(0, LevelCollectionSize)) + 0x10) = NewNetDriver;
*(UNetDriver**)(__int64(LevelCollections.AtPtr(1, LevelCollectionSize)) + 0x10) = NewNetDriver; *(UNetDriver**)(__int64(LevelCollections.AtPtr(1, LevelCollectionSize)) + 0x10) = NewNetDriver;
LOG_INFO(LogNet, "Listening on port {}!", Port + Globals::AmountOfListens - 1); LOG_INFO(LogNet, "Listening on port {}{}!", Port + Globals::AmountOfListens - 1, Engine_Version <= 419 ? " (Wait like 10 seconds before joining though)" : "");
} }
AWorldSettings* UWorld::GetWorldSettings(const bool bCheckStreamingPersistent, const bool bChecked) const AWorldSettings* UWorld::GetWorldSettings(const bool bCheckStreamingPersistent, const bool bChecked) const

View File

@@ -386,6 +386,9 @@ void Offsets::FindAll()
Engine_Version == 424 ? (Fortnite_Version >= 11.00 && Fortnite_Version <= 11.10 ? 0x57 : Engine_Version == 424 ? (Fortnite_Version >= 11.00 && Fortnite_Version <= 11.10 ? 0x57 :
(Fortnite_Version == 11.30 || Fortnite_Version == 11.31 ? 0x59 : 0x5A)) : 0x56; (Fortnite_Version == 11.30 || Fortnite_Version == 11.31 ? 0x59 : 0x5A)) : 0x56;
if (Engine_Version == 421)
Offsets::PropertyClass = 0x70;
// ^ I know this makes no sense, 7.40-8.40 is 0x57, other 7-10 is 0x56, 11.00-11.10 = 0x57, 11.30-11.31 = 0x59, other S11 is 0x5A // ^ I know this makes no sense, 7.40-8.40 is 0x57, other 7-10 is 0x56, 11.00-11.10 = 0x57, 11.30-11.31 = 0x59, other S11 is 0x5A
else if (std::floor(Fortnite_Version) == 12 || std::floor(Fortnite_Version) == 13) else if (std::floor(Fortnite_Version) == 12 || std::floor(Fortnite_Version) == 13)
@@ -437,18 +440,23 @@ void Offsets::FindAll()
} }
Offsets::IsNetRelevantFor = FindIsNetRelevantForOffset(); Offsets::IsNetRelevantFor = FindIsNetRelevantForOffset();
Offsets::UnderlyingType = Offsets::PropertyClass;
} }
void Offsets::Print() void Offsets::Print()
{ {
LOG_INFO(LogDev, "Offset_Internal: 0x{:x}", Offset_Internal);
LOG_INFO(LogDev, "SuperStruct: 0x{:x}", SuperStruct);
LOG_INFO(LogDev, "Children: 0x{:x}", Children);
LOG_INFO(LogDev, "PropertiesSize: 0x{:x}", PropertiesSize);
LOG_INFO(LogDev, "Func: 0x{:x}", Func); LOG_INFO(LogDev, "Func: 0x{:x}", Func);
LOG_INFO(LogDev, "PropertiesSize: 0x{:x}", PropertiesSize);
LOG_INFO(LogDev, "Children: 0x{:x}", Children);
LOG_INFO(LogDev, "SuperStruct: 0x{:x}", SuperStruct);
LOG_INFO(LogDev, "PropertyClass: 0x{:x}", PropertyClass);
LOG_INFO(LogDev, "UnderlyingType: 0x{:x}", UnderlyingType);
LOG_INFO(LogDev, "Offset_Internal: 0x{:x}", Offset_Internal);
LOG_INFO(LogDev, "ServerReplicateActors: 0x{:x}", ServerReplicateActors); LOG_INFO(LogDev, "ServerReplicateActors: 0x{:x}", ServerReplicateActors);
LOG_INFO(LogDev, "ReplicationFrame: 0x{:x}", ReplicationFrame); LOG_INFO(LogDev, "ReplicationFrame: 0x{:x}", ReplicationFrame);
LOG_INFO(LogDev, "IsNetRelevantFor: 0x{:x}", IsNetRelevantFor); LOG_INFO(LogDev, "IsNetRelevantFor: 0x{:x}", IsNetRelevantFor);
LOG_INFO(LogDev, "NetworkObjectList: 0x{:x}", NetworkObjectList);
LOG_INFO(LogDev, "ClientWorldPackageName: 0x{:x}", ClientWorldPackageName);
} }
void Addresses::Init() void Addresses::Init()

View File

@@ -84,6 +84,8 @@ namespace Offsets
extern inline uint64 PropertiesSize = 0; extern inline uint64 PropertiesSize = 0;
extern inline uint64 Children = 0; extern inline uint64 Children = 0;
extern inline uint64 SuperStruct = 0; extern inline uint64 SuperStruct = 0;
extern inline uint64 PropertyClass = 0;
extern inline uint64 UnderlyingType = 0;
extern inline uint64 Offset_Internal = 0; extern inline uint64 Offset_Internal = 0;
extern inline uint64 ServerReplicateActors = 0; extern inline uint64 ServerReplicateActors = 0;
extern inline uint64 ReplicationFrame = 0; extern inline uint64 ReplicationFrame = 0;

View File

@@ -9,6 +9,7 @@
#include "builder.h" #include "builder.h"
#include "FortLootPackage.h" #include "FortLootPackage.h"
#include "bots.h" #include "bots.h"
#include "FortLootLevel.h"
bool IsOperator(APlayerState* PlayerState, AFortPlayerController* PlayerController) bool IsOperator(APlayerState* PlayerState, AFortPlayerController* PlayerController)
{ {
@@ -200,6 +201,12 @@ void ServerCheatHook(AFortPlayerControllerAthena* PlayerController, FString Msg)
if (bShouldUpdate) if (bShouldUpdate)
WorldInventory->Update(); WorldInventory->Update();
auto GameState = Cast<AFortGameStateAthena>(GetWorld()->GetGameState());
auto ItemLevel = UFortLootLevel::GetItemLevel(WID->GetLootLevelData(), GameState->GetWorldLevel());
LOG_INFO(LogDev, "ItemLevel: {}", ItemLevel);
LOG_INFO(LogDev, "PickLevel: {}", WID->PickLevel(ItemLevel));
SendMessageToConsole(PlayerController, L"Granted item!"); SendMessageToConsole(PlayerController, L"Granted item!");
} }
else if (Command == "printsimulatelootdrops") else if (Command == "printsimulatelootdrops")
@@ -211,8 +218,9 @@ void ServerCheatHook(AFortPlayerControllerAthena* PlayerController, FString Msg)
} }
auto& lootTierGroup = Arguments[1]; auto& lootTierGroup = Arguments[1];
auto GameState = Cast<AFortGameStateAthena>(GetWorld()->GetGameState());
auto LootDrops = PickLootDrops(UKismetStringLibrary::Conv_StringToName(std::wstring(lootTierGroup.begin(), lootTierGroup.end()).c_str()), -1, true); auto LootDrops = PickLootDrops(UKismetStringLibrary::Conv_StringToName(std::wstring(lootTierGroup.begin(), lootTierGroup.end()).c_str()), GameState->GetWorldLevel(), -1, true);
for (int i = 0; i < LootDrops.size(); i++) for (int i = 0; i < LootDrops.size(); i++)
{ {

View File

@@ -81,6 +81,20 @@ static __int64 DispatchRequestHook(__int64 a1, __int64* a2, int a3)
return DispatchRequestOriginal(a1, a2, 3); return DispatchRequestOriginal(a1, a2, 3);
} }
static inline bool (*CanCreateInCurrentContextOriginal)(UObject* Template);
bool CanCreateInCurrentContextHook(UObject* Template)
{
auto Original = CanCreateInCurrentContextOriginal(Template);
if (!Original)
{
LOG_INFO(LogDev, "CanCreateInCurrentContext returned false, but we will return true.");
}
return true;
}
void (*ApplyHomebaseEffectsOnPlayerSetupOriginal)( void (*ApplyHomebaseEffectsOnPlayerSetupOriginal)(
__int64* GameState, __int64* GameState,
__int64 a2, __int64 a2,
@@ -426,6 +440,8 @@ DWORD WINAPI Main(LPVOID)
nullptr, false); nullptr, false);
} }
// Hooking::MinHook::Hook(FortPlayerControllerZoneDefault->VFTable[0xD0 / 8], CanCreateInCurrentContextHook, (PVOID*)&CanCreateInCurrentContextOriginal);
HookInstruction(Addresses::UpdateTrackedAttributesLea, (PVOID)UFortGadgetItemDefinition::UpdateTrackedAttributesHook, "/Script/FortniteGame.FortPlayerController.Suicide", ERelativeOffsets::LEA, FortPlayerControllerAthenaDefault); HookInstruction(Addresses::UpdateTrackedAttributesLea, (PVOID)UFortGadgetItemDefinition::UpdateTrackedAttributesHook, "/Script/FortniteGame.FortPlayerController.Suicide", ERelativeOffsets::LEA, FortPlayerControllerAthenaDefault);
HookInstruction(Addresses::CombinePickupLea, (PVOID)AFortPickup::CombinePickupHook, "/Script/Engine.PlayerController.SetVirtualJoystickVisibility", ERelativeOffsets::LEA, FortPlayerControllerAthenaDefault); HookInstruction(Addresses::CombinePickupLea, (PVOID)AFortPickup::CombinePickupHook, "/Script/Engine.PlayerController.SetVirtualJoystickVisibility", ERelativeOffsets::LEA, FortPlayerControllerAthenaDefault);

View File

@@ -144,6 +144,8 @@ static inline uint64 FindObjectArray()
static inline uint64 FindPickupInitialize() static inline uint64 FindPickupInitialize()
{ {
if (Engine_Version == 419)
return Memcury::Scanner::FindPattern("48 89 6C 24 ? 48 89 74 24 ? 57 48 83 EC 20 80 B9 ? ? ? ? ? 41 0F B6 E9").Get(); // 1.11
if (Engine_Version == 420) if (Engine_Version == 420)
return Memcury::Scanner::FindPattern("48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 41 56 48 83 EC 20 80 B9 ? ? ? ? ? 45 0F B6 F1 49 8B E8").Get(); // 4.1 return Memcury::Scanner::FindPattern("48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 41 56 48 83 EC 20 80 B9 ? ? ? ? ? 45 0F B6 F1 49 8B E8").Get(); // 4.1
if (Engine_Version == 421) if (Engine_Version == 421)

View File

@@ -39,6 +39,7 @@
#include "events.h" #include "events.h"
#include "FortAthenaMutator_Heist.h" #include "FortAthenaMutator_Heist.h"
#include "BGA.h" #include "BGA.h"
#include "objectviewer.h"
#define GAME_TAB 1 #define GAME_TAB 1
#define PLAYERS_TAB 2 #define PLAYERS_TAB 2
@@ -283,7 +284,7 @@ static inline void StaticUI()
#ifndef PROD #ifndef PROD
ImGui::Checkbox("Log ProcessEvent", &Globals::bLogProcessEvent); ImGui::Checkbox("Log ProcessEvent", &Globals::bLogProcessEvent);
ImGui::InputInt("Amount of bots to spawn", &AmountOfBotsToSpawn); // ImGui::InputInt("Amount of bots to spawn", &AmountOfBotsToSpawn);
#endif #endif
ImGui::Checkbox("Infinite Ammo", &Globals::bInfiniteAmmo); ImGui::Checkbox("Infinite Ammo", &Globals::bInfiniteAmmo);
@@ -480,40 +481,6 @@ static inline void MainUI()
SpawnBGAs(); SpawnBGAs();
} }
/*
if (ImGui::Button("New"))
{
static auto NextFn = FindObject<UFunction>("/Game/Athena/Prototype/Blueprints/Cube/CUBE.CUBE_C.Next");
static auto NewFn = FindObject<UFunction>("/Game/Athena/Prototype/Blueprints/Cube/CUBE.CUBE_C.New");
auto Loader = GetEventLoader("/Game/Athena/Prototype/Blueprints/Cube/CUBE.CUBE_C");
LOG_INFO(LogDev, "Loader: {}", __int64(Loader));
if (Loader)
{
int32 NewParam = 1;
// Loader->ProcessEvent(NextFn, &NewParam);
Loader->ProcessEvent(NewFn, &NewParam);
}
}
if (ImGui::Button("Next"))
{
static auto NextFn = FindObject<UFunction>("/Game/Athena/Prototype/Blueprints/Cube/CUBE.CUBE_C.Next");
static auto NewFn = FindObject<UFunction>("/Game/Athena/Prototype/Blueprints/Cube/CUBE.CUBE_C.New");
auto Loader = GetEventLoader("/Game/Athena/Prototype/Blueprints/Cube/CUBE.CUBE_C");
LOG_INFO(LogDev, "Loader: {}", __int64(Loader));
if (Loader)
{
int32 NewParam = 1;
Loader->ProcessEvent(NextFn, &NewParam);
// Loader->ProcessEvent(NewFn, &NewParam);
}
}
*/
if (!bIsInAutoRestart && (Engine_Version < 424 && ImGui::Button("Restart"))) if (!bIsInAutoRestart && (Engine_Version < 424 && ImGui::Button("Restart")))
{ {
if (Engine_Version < 424) if (Engine_Version < 424)
@@ -526,45 +493,6 @@ static inline void MainUI()
LOG_ERROR(LogGame, "Restarting is not supported on chapter 2 and above!"); LOG_ERROR(LogGame, "Restarting is not supported on chapter 2 and above!");
} }
} }
/*
if (ImGui::Button("TEST"))
{
auto GameMode = (AFortGameMode*)GetWorld()->GetGameMode();
auto GameState = GameMode->GetGameState();
static auto mutatorClass = FindObject<UClass>("/Script/FortniteGame.FortAthenaMutator");
auto AllMutators = UGameplayStatics::GetAllActorsOfClass(GetWorld(), mutatorClass);
for (int i = 0; i < AllMutators.Num(); i++)
{
auto Mutator = AllMutators.at(i);
LOG_INFO(LogDev, "[{}] Mutator: {}", i, Mutator->GetFullName());
if (auto DiscoMutator = Cast<AFortAthenaMutator_Disco>(Mutator))
{
auto& ControlPointSpawnData = DiscoMutator->GetControlPointSpawnData();
LOG_INFO(LogDev, "ControlPointSpawnData.Num(): {}", ControlPointSpawnData.Num());
}
else if (auto HeistMutator = Cast<AFortAthenaMutator_Heist>(Mutator))
{
auto& HeistExitCraftSpawnData = HeistMutator->GetHeistExitCraftSpawnData();
LOG_INFO(LogDev, "HeistExitCraftSpawnData.Num(): {}", HeistExitCraftSpawnData.Num());
for (int j = 0; j < HeistExitCraftSpawnData.Num(); j++)
{
auto& CurrentHeistExitCraftSpawnData = HeistExitCraftSpawnData.at(j);
auto CurveTable = CurrentHeistExitCraftSpawnData.SpawnDelayTime.GetCurve().CurveTable;
// LOG_INFO(LogDev, "{} {}", CurveTable ? CurveTable->GetFullName() : "InvalidTable",
// CurrentHeistExitCraftSpawnData.SpawnDelayTime.GetCurve().RowName.IsValid() ? CurrentHeistExitCraftSpawnData.SpawnDelayTime.GetCurve().RowName.ToString() : "InvalidName");
}
}
}
}
*/
if (!bStartedBus) if (!bStartedBus)
{ {
@@ -905,13 +833,29 @@ static inline void MainUI()
{ {
static std::string ClassNameToDump; static std::string ClassNameToDump;
static std::string FunctionNameToDump; static std::string FunctionNameToDump;
static std::string ObjectToDump;
static std::string FileNameToDumpTo;
static bool bExcludeUnhandled;
ImGui::Checkbox("Fill Vending Machines", &Globals::bFillVendingMachines); ImGui::Checkbox("Fill Vending Machines", &Globals::bFillVendingMachines);
ImGui::Checkbox("Enable Bot Tick", &bEnableBotTick); ImGui::Checkbox("Enable Bot Tick", &bEnableBotTick);
ImGui::Checkbox("Enable Combine Pickup", &bEnableCombinePickup); ImGui::Checkbox("Enable Combine Pickup", &bEnableCombinePickup);
ImGui::InputText("Class Name to mess with", &ClassNameToDump); ImGui::InputText("Class Name to mess with", &ClassNameToDump);
ImGui::InputText("Object to dump", &ObjectToDump);
ImGui::InputText("Function Name to mess with", &FunctionNameToDump); ImGui::InputText("Function Name to mess with", &FunctionNameToDump);
ImGui::InputText("File name to dump to", &FileNameToDumpTo);
ImGui::Checkbox("Exclude unhandled", &bExcludeUnhandled);
if (ImGui::Button("Dump Object Info"))
{
auto Object = FindObject(ObjectToDump);
LOG_INFO(LogDev, "r: {}", __int64(Object));
// null check is already handled
ObjectViewer::DumpContentsToFile(Object, FileNameToDumpTo, bExcludeUnhandled);
}
if (ImGui::Button("Print Class VFT")) if (ImGui::Button("Print Class VFT"))
{ {

View File

@@ -83,6 +83,7 @@ inline void InitLogger()
MakeLogger("LogVehicles"); MakeLogger("LogVehicles");
MakeLogger("LogBots"); MakeLogger("LogBots");
MakeLogger("LogCosmetics"); MakeLogger("LogCosmetics");
MakeLogger("LogObjectViewer");
} }
#define LOG_DEBUG(loggerName, ...) \ #define LOG_DEBUG(loggerName, ...) \

View File

@@ -0,0 +1,193 @@
#pragma once
#include "reboot.h"
#include <fstream>
static inline FName* GetNamePrivateOfProperty(void* Property)
{
FName* NamePrivate = nullptr;
if (Engine_Version >= 425)
NamePrivate = (FName*)(__int64(Property) + 0x28);
else
NamePrivate = &((UField*)Property)->NamePrivate;
return NamePrivate;
};
static inline bool IsPropertyA(void* Property, UClass* Class)
{
if (Engine_Version < 425)
{
if (((UField*)Property)->IsA(Class))
return true;
}
else
{
// TODO
}
return false;
}
namespace ObjectViewer
{
static inline void DumpContentsToFile(UObject* Object, const std::string& FileName, bool bExcludeUnhandled = false)
{
if (!Object/*->IsValidLowLevel()*/)
{
LOG_ERROR(LogObjectViewer, "Invalid object passed into DumpContentsToFile!");
return;
}
static auto ClassClass = FindObject<UClass>(L"/Script/CoreUObject.Class");
if (Object->IsA(ClassClass))
{
LOG_ERROR(LogObjectViewer, "Object passed into DumpContentsToFile was a class!");
return;
}
static auto BytePropertyClass = FindObject<UClass>(L"/Script/CoreUObject.ByteProperty");
static auto ObjectPropertyClass = FindObject<UClass>(L"/Script/CoreUObject.ObjectProperty");
static auto ClassPropertyClass = FindObject<UClass>(L"/Script/CoreUObject.ClassProperty");
static auto DoublePropertyClass = FindObject<UClass>(L"/Script/CoreUObject.DoubleProperty");
static auto FloatPropertyClass = FindObject<UClass>(L"/Script/CoreUObject.FloatProperty");
static auto Int8PropertyClass = FindObject<UClass>(L"/Script/CoreUObject.Int8Property");
static auto EnumPropertyClass = FindObject<UClass>(L"/Script/CoreUObject.EnumProperty");
static auto ArrayPropertyClass = FindObject<UClass>(L"/Script/CoreUObject.ArrayProperty");
static auto Int64PropertyClass = FindObject<UClass>(L"/Script/CoreUObject.Int64Property");
static auto UInt16PropertyClass = FindObject<UClass>(L"/Script/CoreUObject.UInt16Property");
static auto BoolPropertyClass = FindObject<UClass>(L"/Script/CoreUObject.BoolProperty");
static auto NamePropertyClass = FindObject<UClass>(L"/Script/CoreUObject.NameProperty");
static auto UInt32PropertyClass = FindObject<UClass>(L"/Script/CoreUObject.UInt32Property");
static auto FunctionClass = FindObject<UClass>(L"/Script/CoreUObject.Function");
static auto IntPropertyClass = FindObject<UClass>(L"/Script/CoreUObject.IntProperty");
static auto UInt64PropertyClass = FindObject<UClass>(L"/Script/CoreUObject.UInt64Property");
static auto StrPropertyClass = FindObject<UClass>(L"/Script/CoreUObject.StrProperty");
static auto SoftObjectPropertyClass = FindObject<UClass>(L"/Script/CoreUObject.SoftObjectProperty");
std::ofstream Stream(FileName);
if (!Stream.is_open())
{
LOG_ERROR(LogObjectViewer, "Failed to open file {}!", FileName);
return;
}
for (auto CurrentClass = Object->ClassPrivate; CurrentClass; CurrentClass = CurrentClass->GetSuperStruct())
{
void* Property = *(void**)(__int64(CurrentClass) + Offsets::Children);
while (Property)
{
std::string PropertyName = GetNamePrivateOfProperty(Property)->ToString();
int Offset = *(int*)(__int64(Property) + Offsets::Offset_Internal);
if (Offsets::PropertyClass)
{
if (IsPropertyA(Property, ObjectPropertyClass))
{
auto PropertyClass = *(UClass**)(__int64(Property) + Offsets::PropertyClass);
if (PropertyClass->IsValidLowLevel())
Stream << std::format("{} Object: {}\n", PropertyName, PropertyClass->GetPathName());
}
/*
else if (IsPropertyA(Property, SoftObjectPropertyClass))
{
auto PropertyClass = *(UClass**)(__int64(Property) + Offsets::PropertyClass);
if (PropertyClass->IsValidLowLevel())
{
auto SoftObjectPtr = *(TSoftObjectPtr<UObject>*)(__int64(Object) + Offset);
auto SoftObjectPtrObject = SoftObjectPtr.Get(PropertyClass);
Stream << std::format("{} SoftObjectPtr (type: {}): {}\n", PropertyName, PropertyClass->GetName(), SoftObjectPtrObject ? SoftObjectPtrObject->GetPathName() : "BadRead");
}
}
*/
}
if (IsPropertyA(Property, BytePropertyClass))
{
Stream << std::format("{} Byte: {}\n", PropertyName, *(uint8*)(__int64(Object) + Offset));
}
else if (IsPropertyA(Property, DoublePropertyClass))
{
Stream << std::format("{} Double: {}\n", PropertyName, *(double*)(__int64(Object) + Offset));
}
else if (IsPropertyA(Property, UInt16PropertyClass))
{
Stream << std::format("{} UInt16: {}\n", PropertyName, *(uint16*)(__int64(Object) + Offset));
}
else if (IsPropertyA(Property, Int8PropertyClass))
{
Stream << std::format("{} Int8: {}\n", PropertyName, *(int8*)(__int64(Object) + Offset));
}
else if (IsPropertyA(Property, NamePropertyClass))
{
Stream << std::format("{} Name: {}\n", PropertyName, (*(FName*)(__int64(Object) + Offset)).ToString());
}
else if (IsPropertyA(Property, StrPropertyClass))
{
Stream << std::format("{} String: {}\n", PropertyName, (*(FString*)(__int64(Object) + Offset)).ToString());
}
else if (IsPropertyA(Property, FloatPropertyClass))
{
Stream << std::format("{} Float: {}\n", PropertyName, *(float*)(__int64(Object) + Offset));
}
else if (IsPropertyA(Property, BoolPropertyClass))
{
auto FieldMask = GetFieldMask(Property);
Stream << std::format("{} Bool: {}\n", PropertyName, ReadBitfield((PlaceholderBitfield*)(__int64(Object) + Offset), FieldMask));
}
else if (IsPropertyA(Property, IntPropertyClass))
{
Stream << std::format("{} Int32: {}\n", PropertyName, *(int*)(__int64(Object) + Offset));
}
else if (IsPropertyA(Property, UInt32PropertyClass))
{
Stream << std::format("{} UInt32: {}\n", PropertyName, *(uint32*)(__int64(Object) + Offset));
}
else if (IsPropertyA(Property, UInt64PropertyClass))
{
Stream << std::format("{} UInt64: {}\n", PropertyName, *(uint64*)(__int64(Object) + Offset));
}
else if (IsPropertyA(Property, Int64PropertyClass))
{
Stream << std::format("{} Int64: {}\n", PropertyName, *(int64*)(__int64(Object) + Offset));
}
else if (IsPropertyA(Property, ArrayPropertyClass))
{
Stream << std::format("{} Array\n", PropertyName);
}
else if (IsPropertyA(Property, EnumPropertyClass))
{
using UNumericProperty = UObject;
auto EnumValueIg = *(uint8*)(__int64(Property) + Offset);
auto UnderlyingType = *(UNumericProperty**)(__int64(Property) + Offsets::UnderlyingType);
// Stream << std::format("{} Enum: {}\n", PropertyName, (int)EnumValueIg);
Stream << std::format("{} Enum\n", PropertyName);
}
else if (IsPropertyA(Property, FunctionClass))
{
}
else if (!bExcludeUnhandled)
{
// Stream << std::format("{}: {}\n", PropertyName, "UNHANDLED");
Stream << std::format("{}: {} {}\n", PropertyName, "UNHANDLED", ""/*, ((UObject*)Property)->GetName()*/);
}
Property = Engine_Version >= 425 ? *(void**)(__int64(Property) + 0x20) : ((UField*)Property)->Next;
}
}
return;
}
static inline void DumpContentsToFile(const std::string& ObjectName, const std::string& FileName, bool bExcludeUnhandled = false) { return DumpContentsToFile(FindObject(ObjectName), FileName, bExcludeUnhandled); }
}

View File

@@ -124,7 +124,7 @@ static inline void FillItemCollector(ABuildingItemCollectorActor* ItemCollector,
constexpr bool bPrint = false; 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) if (LootDrops.size() == 0)
continue; continue;