mirror of
https://github.com/Milxnor/Project-Reboot-3.0.git
synced 2026-01-13 02:42:22 +01:00
abundant update
complete looting rewrite, improve combining pickups, add debug printing logs, fix some agids, fix cheat summon, fix issue with vehicle spawning.
This commit is contained in:
@@ -35,11 +35,6 @@ void SpawnBGAs() // hahah not "proper", there's a function that we can hook and
|
||||
|
||||
auto MapInfo = GameState->GetMapInfo();
|
||||
}
|
||||
else
|
||||
{
|
||||
// SpawnLocation.Z += 100;
|
||||
// SpawnLocation.Z -= 50; // proper frfr
|
||||
}
|
||||
|
||||
static auto SpawnLootTierGroupOffset = BGAConsumableSpawner->GetOffset("SpawnLootTierGroup");
|
||||
auto& SpawnLootTierGroup = BGAConsumableSpawner->Get<FName>(SpawnLootTierGroupOffset);
|
||||
@@ -48,8 +43,8 @@ void SpawnBGAs() // hahah not "proper", there's a function that we can hook and
|
||||
|
||||
for (auto& LootDrop : LootDrops)
|
||||
{
|
||||
static auto ConsumableClassOffset = LootDrop.ItemDefinition->GetOffset("ConsumableClass");
|
||||
auto ConsumableClassSoft = LootDrop.ItemDefinition->GetPtr<TSoftObjectPtr<UClass>>(ConsumableClassOffset);
|
||||
static auto ConsumableClassOffset = LootDrop->GetItemDefinition()->GetOffset("ConsumableClass");
|
||||
auto ConsumableClassSoft = LootDrop->GetItemDefinition()->GetPtr<TSoftObjectPtr<UClass>>(ConsumableClassOffset);
|
||||
|
||||
static auto BlueprintGeneratedClassClass = FindObject<UClass>(L"/Script/Engine.BlueprintGeneratedClass");
|
||||
auto StrongConsumableClass = ConsumableClassSoft->Get(BlueprintGeneratedClassClass, true);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "FortPickup.h"
|
||||
#include "FortLootPackage.h"
|
||||
#include "FortGameModeAthena.h"
|
||||
#include "gui.h"
|
||||
|
||||
bool ABuildingContainer::SpawnLoot(AFortPawn* Pawn)
|
||||
{
|
||||
@@ -12,14 +13,14 @@ bool ABuildingContainer::SpawnLoot(AFortPawn* Pawn)
|
||||
|
||||
// LOG_INFO(LogInteraction, "RedirectedLootTier: {}", RedirectedLootTier.ToString());
|
||||
|
||||
auto LootDrops = PickLootDrops(RedirectedLootTier, true);
|
||||
auto LootDrops = PickLootDrops(RedirectedLootTier, bDebugPrintLooting);
|
||||
|
||||
// LOG_INFO(LogInteraction, "LootDrops.size(): {}", LootDrops.size());
|
||||
|
||||
for (int i = 0; i < LootDrops.size(); i++)
|
||||
{
|
||||
auto& lootDrop = LootDrops.at(i);
|
||||
AFortPickup::SpawnPickup(lootDrop.ItemDefinition, LocationToSpawnLoot, lootDrop.Count, EFortPickupSourceTypeFlag::Container, EFortPickupSpawnSource::Unset, lootDrop.LoadedAmmo);
|
||||
AFortPickup::SpawnPickup(lootDrop->GetItemDefinition(), LocationToSpawnLoot, lootDrop->GetCount(), EFortPickupSourceTypeFlag::Container, EFortPickupSpawnSource::Unset, lootDrop->GetLoadedAmmo());
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -34,3 +34,10 @@ struct RowNameAndRowData
|
||||
FName RowName;
|
||||
StructType* RowData;
|
||||
};
|
||||
|
||||
struct FDataTableCategoryHandle
|
||||
{
|
||||
UDataTable* DataTable; // 0x0000(0x0008) (Edit, BlueprintVisible, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic)
|
||||
FName ColumnName; // 0x0008(0x0008) (Edit, BlueprintVisible, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic)
|
||||
FName RowContents; // 0x0010(0x0008) (Edit, BlueprintVisible, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic)
|
||||
};
|
||||
|
||||
@@ -40,6 +40,7 @@ void AFortAthenaMapInfo::SpawnLlamas()
|
||||
return;
|
||||
}
|
||||
|
||||
int AmountOfLlamasSpawned = 0;
|
||||
auto AmountOfLlamasToSpawn = CalcuateCurveMinAndMax(GetLlamaQuantityMin(), GetLlamaQuantityMax(), 1);
|
||||
|
||||
LOG_INFO(LogDev, "Attempting to spawn {} llamas.", AmountOfLlamasToSpawn);
|
||||
@@ -67,7 +68,7 @@ void AFortAthenaMapInfo::SpawnLlamas()
|
||||
|
||||
auto LlamaStart = GetWorld()->SpawnActor<AFortAthenaSupplyDrop>(GetLlamaClass(), InitialSpawnTransform, SpawnParameters);
|
||||
|
||||
LOG_INFO(LogDev, "LlamaStart: {}", __int64(LlamaStart));
|
||||
// LOG_INFO(LogDev, "LlamaStart: {}", __int64(LlamaStart));
|
||||
|
||||
if (!LlamaStart)
|
||||
continue;
|
||||
@@ -80,5 +81,8 @@ void AFortAthenaMapInfo::SpawnLlamas()
|
||||
LOG_INFO(LogDev, "Spawning Llama at {} {} {}", GroundLocation.X, GroundLocation.Y, GroundLocation.Z);
|
||||
|
||||
UGameplayStatics::FinishSpawningActor(LlamaStart, FinalSpawnTransform);
|
||||
AmountOfLlamasSpawned++;
|
||||
}
|
||||
|
||||
LOG_INFO(LogGame, "Spawned {} llamas.", AmountOfLlamasSpawned);
|
||||
}
|
||||
@@ -17,6 +17,15 @@ public:
|
||||
return GetPawnAtSeat_Params.ReturnValue;
|
||||
}
|
||||
|
||||
int FindSeatIndex(class AFortPlayerPawn* PlayerPawn)
|
||||
{
|
||||
static auto FindSeatIndexFn = FindObject<UFunction>("/Script/FortniteGame.FortAthenaVehicle.FindSeatIndex");
|
||||
struct { AFortPlayerPawn* PlayerPawn; int ReturnValue; } AFortAthenaVehicle_FindSeatIndex_Params{ PlayerPawn };
|
||||
this->ProcessEvent(FindSeatIndexFn, &AFortAthenaVehicle_FindSeatIndex_Params);
|
||||
|
||||
return AFortAthenaVehicle_FindSeatIndex_Params.ReturnValue;
|
||||
}
|
||||
|
||||
UFortWeaponItemDefinition* GetVehicleWeaponForSeat(int SeatIdx);
|
||||
|
||||
static UClass* StaticClass()
|
||||
|
||||
@@ -963,7 +963,7 @@ void AFortGameModeAthena::Athena_HandleStartingNewPlayerHook(AFortGameModeAthena
|
||||
{
|
||||
for (auto& LootDrop : LootDrops)
|
||||
{
|
||||
auto Pickup = AFortPickup::SpawnPickup(LootDrop.ItemDefinition, Location, LootDrop.Count, SpawnFlag, EFortPickupSpawnSource::Unset, LootDrop.LoadedAmmo);
|
||||
auto Pickup = AFortPickup::SpawnPickup(LootDrop->GetItemDefinition(), Location, LootDrop->GetCount(), SpawnFlag, EFortPickupSpawnSource::Unset, LootDrop->GetLoadedAmmo());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -996,7 +996,7 @@ void AFortGameModeAthena::Athena_HandleStartingNewPlayerHook(AFortGameModeAthena
|
||||
{
|
||||
for (auto& LootDrop : LootDrops)
|
||||
{
|
||||
auto Pickup = AFortPickup::SpawnPickup(LootDrop.ItemDefinition, Location, LootDrop.Count, SpawnFlag, EFortPickupSpawnSource::Unset, LootDrop.LoadedAmmo);
|
||||
auto Pickup = AFortPickup::SpawnPickup(LootDrop->GetItemDefinition(), Location, LootDrop->GetCount(), SpawnFlag, EFortPickupSpawnSource::Unset, LootDrop->GetLoadedAmmo());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1013,9 +1013,9 @@ void AFortGameModeAthena::Athena_HandleStartingNewPlayerHook(AFortGameModeAthena
|
||||
|
||||
if (Engine_Version >= 423 && Fortnite_Version <= 12.61) // 423+ we need to spawn manually and vehicle sync doesn't work on >S13.
|
||||
{
|
||||
static int LastNum420 = 1;
|
||||
static int LastNum420 = 114;
|
||||
|
||||
if (Globals::AmountOfListens != LastNum420)
|
||||
if (LastNum420 != Globals::AmountOfListens)
|
||||
{
|
||||
LastNum420 = Globals::AmountOfListens;
|
||||
|
||||
|
||||
@@ -154,7 +154,7 @@ std::pair<std::vector<UFortItem*>, std::vector<UFortItem*>> AFortInventory::AddI
|
||||
{
|
||||
if (GadgetItemDefinition->ShouldDropAllItemsOnEquip()) // idk shouldnt this be auto?
|
||||
{
|
||||
FortPlayerController->DropAllItems({ GadgetItemDefinition });
|
||||
FortPlayerController->DropAllItems({ GadgetItemDefinition }, false, false, Fortnite_Version < 7);
|
||||
}
|
||||
|
||||
bool (*ApplyGadgetData)(UFortGadgetItemDefinition* a1, __int64 a2, UFortItem* a3, unsigned __int8 a4) = decltype(ApplyGadgetData)(Addresses::ApplyGadgetData);
|
||||
@@ -165,17 +165,6 @@ std::pair<std::vector<UFortItem*>, std::vector<UFortItem*>> AFortInventory::AddI
|
||||
bool DidApplyingGadgetSucceed = ApplyGadgetData(GadgetItemDefinition, Interface, NewItemInstance, idktbh);
|
||||
LOG_INFO(LogDev, "DidApplyingGadgetSucceed: {}", DidApplyingGadgetSucceed);
|
||||
bWasGadget = true;
|
||||
|
||||
if (Fortnite_Version < 7)
|
||||
{
|
||||
auto PickaxeInstance = GetPickaxeInstance();
|
||||
|
||||
if (PickaxeInstance)
|
||||
{
|
||||
// RemoveItem(PickaxeInstance->GetItemEntry()->GetItemGuid(), nullptr, PickaxeInstance->GetItemEntry()->GetCount(), true);
|
||||
Update();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,14 +174,6 @@ std::pair<std::vector<UFortItem*>, std::vector<UFortItem*>> AFortInventory::AddI
|
||||
FortPlayerController->ServerExecuteInventoryItemHook(FortPlayerController, NewItemInstance->GetItemEntry()->GetItemGuid());
|
||||
FortPlayerController->ClientEquipItem(NewItemInstance->GetItemEntry()->GetItemGuid(), true);
|
||||
}
|
||||
|
||||
if (bWasGadget)
|
||||
{
|
||||
if (Fortnite_Version < 7)
|
||||
{
|
||||
// FortPlayerController->AddPickaxeToInventory();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -357,9 +338,12 @@ bool AFortInventory::RemoveItem(const FGuid& ItemGuid, bool* bShouldUpdate, int
|
||||
|
||||
bWasGadget = true;
|
||||
|
||||
if (Fortnite_Version < 7)
|
||||
if (bWasGadget)
|
||||
{
|
||||
// FortPlayerController->AddPickaxeToInventory();
|
||||
if (Fortnite_Version < 7 && GadgetItemDefinition->ShouldDropAllItemsOnEquip())
|
||||
{
|
||||
FortPlayerController->AddPickaxeToInventory();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include "NetSerialization.h"
|
||||
#include "Class.h"
|
||||
#include "GameplayAbilitySpec.h"
|
||||
|
||||
#include "reboot.h"
|
||||
|
||||
@@ -101,6 +104,24 @@ struct FFortItemEntry : FFastArraySerializerItem
|
||||
return *(int*)(__int64(this) + LoadedAmmoOffset);
|
||||
}
|
||||
|
||||
float& GetDurability()
|
||||
{
|
||||
static auto DurabilityOffset = FindOffsetStruct("/Script/FortniteGame.FortItemEntry", "Durability");
|
||||
return *(float*)(__int64(this) + DurabilityOffset);
|
||||
}
|
||||
|
||||
FGameplayAbilitySpecHandle& GetGameplayAbilitySpecHandle()
|
||||
{
|
||||
static auto GameplayAbilitySpecHandleOffset = FindOffsetStruct("/Script/FortniteGame.FortItemEntry", "GameplayAbilitySpecHandle");
|
||||
return *(FGameplayAbilitySpecHandle*)(__int64(this) + GameplayAbilitySpecHandleOffset);
|
||||
}
|
||||
|
||||
TWeakObjectPtr<class AFortInventory>& GetParentInventory()
|
||||
{
|
||||
static auto ParentInventoryOffset = FindOffsetStruct("/Script/FortniteGame.FortItemEntry", "ParentInventory");
|
||||
return *(TWeakObjectPtr<class AFortInventory>*)(__int64(this) + ParentInventoryOffset);
|
||||
}
|
||||
|
||||
void CopyFromAnotherItemEntry(FFortItemEntry* OtherItemEntry, bool bCopyGuid = false)
|
||||
{
|
||||
// We can use FortItemEntryStruct->CopyScriptStruct
|
||||
@@ -142,7 +163,7 @@ struct FFortItemEntry : FFastArraySerializerItem
|
||||
return StructSize;
|
||||
}
|
||||
|
||||
static FFortItemEntry* MakeItemEntry(UFortItemDefinition* ItemDefinition, int Count = 1, int LoadedAmmo = 0)
|
||||
static FFortItemEntry* MakeItemEntry(UFortItemDefinition* ItemDefinition, int Count = 1, int LoadedAmmo = 0, float Durability = 0x3F800000)
|
||||
{
|
||||
auto Entry = // (FFortItemEntry*)FMemory::Realloc(0, GetStructSize(), 0);
|
||||
Alloc<FFortItemEntry>(GetStructSize());
|
||||
@@ -150,14 +171,18 @@ struct FFortItemEntry : FFastArraySerializerItem
|
||||
if (!Entry)
|
||||
return nullptr;
|
||||
|
||||
Entry->MostRecentArrayReplicationKey = -1;
|
||||
Entry->MostRecentArrayReplicationKey = -1; // idk if we need to set this
|
||||
Entry->ReplicationID = -1;
|
||||
Entry->ReplicationKey = -1;
|
||||
|
||||
Entry->GetItemDefinition() = ItemDefinition;
|
||||
Entry->GetCount() = Count;
|
||||
Entry->GetLoadedAmmo() = LoadedAmmo;
|
||||
// Entry->bUpdateStatsOnCollection = true; // Idk what this does but fortnite does it soo
|
||||
Entry->GetDurability() = Durability;
|
||||
Entry->GetGameplayAbilitySpecHandle() = FGameplayAbilitySpecHandle(-1);
|
||||
Entry->GetParentInventory().ObjectIndex = -1;
|
||||
// CoCreateGuid((GUID*)&Entry->GetItemGuid());
|
||||
// Entry->bUpdateStatsOnCollection = true; // Idk what this does but fortnite does it i think
|
||||
|
||||
return Entry;
|
||||
}
|
||||
|
||||
@@ -35,6 +35,27 @@ UFortResourceItemDefinition* UFortKismetLibrary::K2_GetResourceItemDefinition(EF
|
||||
return params.ret;
|
||||
}
|
||||
|
||||
FVector UFortKismetLibrary::FindGroundLocationAt(UWorld* World, AActor* IgnoreActor, FVector InLocation, float TraceStartZ, float TraceEndZ, FName TraceName)
|
||||
{
|
||||
static auto FindGroundLocationAtFn = FindObject<UFunction>("/Script/FortniteGame.FortKismetLibrary.FindGroundLocationAt");
|
||||
|
||||
struct
|
||||
{
|
||||
UWorld* World; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic)
|
||||
AActor* IgnoreActor; // (ConstParm, Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic)
|
||||
FVector InLocation; // (ConstParm, Parm, OutParm, ZeroConstructor, ReferenceParm, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic)
|
||||
float TraceStartZ; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic)
|
||||
float TraceEndZ; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic)
|
||||
FName TraceName; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic)
|
||||
FVector ReturnValue; // (Parm, OutParm, ZeroConstructor, ReturnParm, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic)
|
||||
} UFortKismetLibrary_FindGroundLocationAt_Params{ World, IgnoreActor, InLocation, TraceStartZ, TraceEndZ, TraceName };
|
||||
|
||||
static auto DefaultClass = StaticClass();
|
||||
DefaultClass->ProcessEvent(FindGroundLocationAtFn, &UFortKismetLibrary_FindGroundLocationAt_Params);
|
||||
|
||||
return UFortKismetLibrary_FindGroundLocationAt_Params.ReturnValue;
|
||||
}
|
||||
|
||||
void UFortKismetLibrary::ApplyCharacterCosmetics(UObject* WorldContextObject, const TArray<UObject*>& CharacterParts, UObject* PlayerState, bool* bSuccess)
|
||||
{
|
||||
static auto fn = FindObject<UFunction>("/Script/FortniteGame.FortKismetLibrary.ApplyCharacterCosmetics");
|
||||
@@ -550,7 +571,7 @@ bool UFortKismetLibrary::PickLootDropsHook(UObject* Context, FFrame& Stack, bool
|
||||
{
|
||||
auto& LootDrop = LootDrops.at(i);
|
||||
|
||||
auto NewEntry = FFortItemEntry::MakeItemEntry(LootDrop.ItemDefinition, LootDrop.Count, LootDrop.LoadedAmmo);
|
||||
auto NewEntry = FFortItemEntry::MakeItemEntry(LootDrop->GetItemDefinition(), LootDrop->GetCount(), LootDrop->GetLoadedAmmo());
|
||||
|
||||
OutLootToDrop.AddPtr(NewEntry, FFortItemEntry::GetStructSize());
|
||||
}
|
||||
|
||||
@@ -84,6 +84,7 @@ public:
|
||||
|
||||
static UFortResourceItemDefinition* K2_GetResourceItemDefinition(EFortResourceType ResourceType);
|
||||
static void ApplyCharacterCosmetics(UObject* WorldContextObject, const TArray<UObject*>& CharacterParts, UObject* PlayerState, bool* bSuccess);
|
||||
static FVector FindGroundLocationAt(UWorld* World, AActor* IgnoreActor, FVector InLocation, float TraceStartZ, float TraceEndZ, FName TraceName);
|
||||
|
||||
static void PickLootDropsWithNamedWeightsHook(UObject* Context, FFrame& Stack, void* Ret);
|
||||
static void SpawnItemVariantPickupInWorldHook(UObject* Context, FFrame& Stack, void* Ret);
|
||||
|
||||
11
Project Reboot 3.0/FortLootLevel.h
Normal file
11
Project Reboot 3.0/FortLootLevel.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "DataTable.h"
|
||||
|
||||
class UFortLootLevel
|
||||
{
|
||||
int GetItemLevel(FDataTableCategoryHandle LootLevelData, int WorldLevel)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
@@ -8,6 +8,711 @@
|
||||
#include "FortGameModeAthena.h"
|
||||
|
||||
#include <random>
|
||||
#include <map>
|
||||
#include <numeric>
|
||||
|
||||
struct FFortGameFeatureLootTableData
|
||||
{
|
||||
TSoftObjectPtr<UDataTable> LootTierData;
|
||||
TSoftObjectPtr<UDataTable> LootPackageData;
|
||||
};
|
||||
|
||||
#ifdef EXPERIMENTAL_LOOTING
|
||||
float RandomFloatForLoot(float AllWeightsSum)
|
||||
{
|
||||
return (rand() * 0.000030518509) * AllWeightsSum;
|
||||
}
|
||||
|
||||
template <typename RowStructType = uint8>
|
||||
void CollectDataTablesRows(std::vector<UDataTable*> DataTables, std::map<FName, RowStructType*>* OutMap, std::function<bool(FName, RowStructType*)> Check = []() { return true; })
|
||||
{
|
||||
std::vector<UDataTable*> DataTablesToIterate;
|
||||
|
||||
static auto CompositeDataTableClass = FindObject<UClass>("/Script/Engine.CompositeDataTable");
|
||||
|
||||
for (auto DataTable : DataTables)
|
||||
{
|
||||
// if (auto CompositeDataTable = Cast<UCompositeDataTable>(DataTable))
|
||||
if (DataTable->IsA(CompositeDataTableClass))
|
||||
{
|
||||
auto CompositeDataTable = DataTable;
|
||||
|
||||
static auto ParentTablesOffset = DataTable->GetOffset("ParentTables");
|
||||
auto& ParentTables = DataTable->Get<TArray<UDataTable*>>(ParentTablesOffset);
|
||||
|
||||
for (int i = 0; i < ParentTables.Num(); i++)
|
||||
{
|
||||
DataTablesToIterate.push_back(ParentTables.at(i));
|
||||
}
|
||||
}
|
||||
|
||||
DataTablesToIterate.push_back(DataTable);
|
||||
}
|
||||
|
||||
for (auto CurrentDataTable : DataTablesToIterate)
|
||||
{
|
||||
for (auto& CurrentPair : CurrentDataTable->GetRowMap())
|
||||
{
|
||||
if (Check(CurrentPair.Key(), (RowStructType*)CurrentPair.Value()))
|
||||
(*OutMap)[CurrentPair.Key()] = (RowStructType*)CurrentPair.Value();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static T* PickWeightedElement(const std::map<FName, T*>& Elements, std::function<float(T*)> GetWeightFn, float TotalWeightParam = -1, bool bCheckIfWeightIsZero = false, int RandMultiplier = 1, FName* OutName = nullptr, bool bPrint = false)
|
||||
{
|
||||
float TotalWeight = TotalWeightParam;
|
||||
|
||||
if (TotalWeight == -1)
|
||||
{
|
||||
TotalWeight = std::accumulate(Elements.begin(), Elements.end(), 0.0f, [&](float acc, const std::pair<FName, T*>& p) {
|
||||
auto Weight = GetWeightFn(p.second);
|
||||
|
||||
if (bPrint)
|
||||
{
|
||||
LOG_INFO(LogLoot, "Adding weight: {}", Weight);
|
||||
}
|
||||
|
||||
return acc + Weight;
|
||||
});
|
||||
}
|
||||
|
||||
float RandomNumber = // UKismetMathLibrary::RandomFloatInRange(0, TotalWeight);
|
||||
RandMultiplier * RandomFloatForLoot(TotalWeight);
|
||||
|
||||
if (bPrint)
|
||||
{
|
||||
LOG_INFO(LogLoot, "RandomNumber: {} TotalWeight: {}", RandomNumber, TotalWeight);
|
||||
}
|
||||
|
||||
for (auto& Element : Elements)
|
||||
{
|
||||
float Weight = GetWeightFn(Element.second);
|
||||
|
||||
if (bCheckIfWeightIsZero && Weight == 0)
|
||||
continue;
|
||||
|
||||
if (RandomNumber <= Weight)
|
||||
{
|
||||
if (OutName)
|
||||
*OutName = Element.first;
|
||||
|
||||
return Element.second;
|
||||
}
|
||||
|
||||
RandomNumber -= Weight;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int GetItemLevel(const FDataTableCategoryHandle& LootLevelData, int WorldLevel)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
float GetAmountOfLootPackagesToDrop(FFortLootTierData* LootTierData, int OriginalNumberLootDrops)
|
||||
{
|
||||
if (LootTierData->GetLootPackageCategoryMinArray().Num() != LootTierData->GetLootPackageCategoryWeightArray().Num()
|
||||
|| LootTierData->GetLootPackageCategoryMinArray().Num() != LootTierData->GetLootPackageCategoryMaxArray().Num()
|
||||
)
|
||||
return 0;
|
||||
|
||||
// return OriginalNumberLootDrops;
|
||||
|
||||
float MinimumLootDrops = 0;
|
||||
|
||||
if (LootTierData->GetLootPackageCategoryMinArray().Num() > 0)
|
||||
{
|
||||
for (int i = 0; i < LootTierData->GetLootPackageCategoryMinArray().Num(); i++)
|
||||
{
|
||||
// Fortnite does more here, we need to figure it out.
|
||||
MinimumLootDrops += LootTierData->GetLootPackageCategoryMinArray().at(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (MinimumLootDrops > OriginalNumberLootDrops)
|
||||
{
|
||||
LOG_INFO(LogLoot, "Requested {} loot drops but minimum drops is {} for loot package {}", OriginalNumberLootDrops, MinimumLootDrops, LootTierData->GetLootPackage().ToString());
|
||||
// Fortnite doesn't return here?
|
||||
}
|
||||
|
||||
int SumLootPackageCategoryWeightArray = 0;
|
||||
|
||||
if (LootTierData->GetLootPackageCategoryWeightArray().Num() > 0)
|
||||
{
|
||||
for (int i = 0; i < LootTierData->GetLootPackageCategoryWeightArray().Num(); i++)
|
||||
{
|
||||
// Fortnite does more here, we need to figure it out.
|
||||
|
||||
if (LootTierData->GetLootPackageCategoryWeightArray().at(i) > 0)
|
||||
{
|
||||
auto LootPackageCategoryMaxArrayIt = LootTierData->GetLootPackageCategoryMaxArray().at(i);
|
||||
|
||||
float IDK = 0; // TODO
|
||||
|
||||
if (LootPackageCategoryMaxArrayIt < 0 || IDK < LootPackageCategoryMaxArrayIt)
|
||||
{
|
||||
SumLootPackageCategoryWeightArray += LootTierData->GetLootPackageCategoryWeightArray().at(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if (MinimumLootDrops < OriginalNumberLootDrops) // real commeneted one to one
|
||||
{
|
||||
// IDK
|
||||
|
||||
while (SumLootPackageCategoryWeightArray > 0)
|
||||
{
|
||||
// HONESTLY IDEK WHAT FORTNITE DOES HERE
|
||||
|
||||
float v29 = (float)rand() * 0.000030518509;
|
||||
|
||||
float v35 = (int)(float)((float)((float)((float)SumLootPackageCategoryWeightArray * v29)
|
||||
+ (float)((float)SumLootPackageCategoryWeightArray * v29))
|
||||
+ 0.5) >> 1;
|
||||
|
||||
// OutLootTierInfo->Hello++;
|
||||
MinimumLootDrops++;
|
||||
|
||||
if (MinimumLootDrops >= OriginalNumberLootDrops)
|
||||
return MinimumLootDrops;
|
||||
|
||||
SumLootPackageCategoryWeightArray--;
|
||||
}
|
||||
|
||||
/* if (MinimumLootDrops < OriginalNumberLootDrops)
|
||||
{
|
||||
std::cout << std::format("Requested {} loot drops but maximum drops is {} for loot package {}\n", OriginalNumberLootDrops, MinimumLootDrops, LootTierData->LootPackage.ToString());
|
||||
} */
|
||||
}
|
||||
|
||||
return MinimumLootDrops;
|
||||
}
|
||||
|
||||
/*struct UFortLootPackage
|
||||
{
|
||||
int CurrentIdx = 0;
|
||||
std::vector<FFortItemEntry> ItemEntries;
|
||||
}; */
|
||||
|
||||
FFortLootTierData* PickLootTierData(const std::vector<UDataTable*>& LTDTables, FName LootTierGroup, int WorldLevel = 0, int ForcedLootTier = -1, FName* OutRowName = nullptr) // Fortnite returns the row name and then finds the tier data again, but I really don't see the point of this.
|
||||
{
|
||||
float LootTier = ForcedLootTier;
|
||||
|
||||
if (LootTier == -1)
|
||||
{
|
||||
LootTier = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// buncha code im too lazy to reverse
|
||||
}
|
||||
|
||||
LootTier = 1; // ONG PROPER
|
||||
|
||||
// if (fabs(LootTier) <= 0.0000000099999999)
|
||||
// return 0;
|
||||
|
||||
std::map<FName, FFortLootTierData*> TierGroupLTDs;
|
||||
|
||||
CollectDataTablesRows<FFortLootTierData>(LTDTables, &TierGroupLTDs, [&](FName RowName, FFortLootTierData* TierData) -> bool {
|
||||
if (LootTierGroup == TierData->GetTierGroup())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
FFortLootTierData* ChosenRowLootTierData = PickWeightedElement<FFortLootTierData>(TierGroupLTDs,
|
||||
[](FFortLootTierData* LootTierData) -> float { return LootTierData->GetWeight(); }, -1,
|
||||
true, LootTier, OutRowName);
|
||||
|
||||
if (!ChosenRowLootTierData)
|
||||
return nullptr;
|
||||
|
||||
return ChosenRowLootTierData;
|
||||
}
|
||||
|
||||
void PickLootDropsFromLootPackage(const std::vector<UDataTable*>& LPTables, const FName& LootPackageName, std::vector<LootDrop>* OutEntries, int LootPackageCategory = -1, bool bPrint = false)
|
||||
{
|
||||
if (!OutEntries)
|
||||
return;
|
||||
|
||||
std::map<FName, FFortLootPackageData*> LootPackageIDMap;
|
||||
|
||||
CollectDataTablesRows<FFortLootPackageData>(LPTables, &LootPackageIDMap, [&](FName RowName, FFortLootPackageData* LootPackage) -> bool {
|
||||
if (LootPackage->GetLootPackageID() != LootPackageName)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (LootPackageCategory != -1 && LootPackage->GetLootPackageCategory() != LootPackageCategory) // idk if proper
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* if (WorldLevel >= 0)
|
||||
{
|
||||
if (LootPackage->MaxWorldLevel >= 0 && WorldLevel > LootPackage->MaxWorldLevel)
|
||||
return 0;
|
||||
|
||||
if (LootPackage->MinWorldLevel >= 0 && WorldLevel < LootPackage->MinWorldLevel)
|
||||
return 0;
|
||||
} */
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
if (LootPackageIDMap.size() == 0)
|
||||
{
|
||||
// std::cout << std::format("Loot Package {} has no valid weights.\n", LootPackageName.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
FName PickedPackageRowName;
|
||||
FFortLootPackageData* PickedPackage = PickWeightedElement<FFortLootPackageData>(LootPackageIDMap,
|
||||
[](FFortLootPackageData* LootPackageData) -> float { return LootPackageData->GetWeight(); },
|
||||
-1, true, 1, &PickedPackageRowName, bPrint);
|
||||
|
||||
if (!PickedPackage)
|
||||
return;
|
||||
|
||||
if (bPrint)
|
||||
LOG_INFO(LogLoot, "PickLootDropsFromLootPackage selected package {} with loot package category {} from LootPackageIDMap of size: {}", PickedPackageRowName.ToString(), LootPackageCategory, LootPackageIDMap.size());
|
||||
|
||||
if (PickedPackage->GetLootPackageCall().Data.Num() > 1)
|
||||
{
|
||||
if (PickedPackage->GetCount() > 0)
|
||||
{
|
||||
int v9 = 0;
|
||||
|
||||
while (v9 < PickedPackage->GetCount())
|
||||
{
|
||||
int LootPackageCategoryToUseForLPCall = 0; // hmm
|
||||
|
||||
PickLootDropsFromLootPackage(LPTables,
|
||||
PickedPackage->GetLootPackageCall().Data.Data ? UKismetStringLibrary::Conv_StringToName(PickedPackage->GetLootPackageCall()) : FName(0),
|
||||
OutEntries, LootPackageCategoryToUseForLPCall, bPrint
|
||||
);
|
||||
|
||||
v9++;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
auto ItemDefinition = PickedPackage->GetItemDefinition().Get(UFortItemDefinition::StaticClass(), true);
|
||||
|
||||
if (!ItemDefinition)
|
||||
{
|
||||
LOG_INFO(LogLoot, "Loot Package {} does not contain a LootPackageCall or ItemDefinition.", PickedPackage->GetLootPackageID().ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
int ItemLevel = 0;
|
||||
|
||||
auto WeaponItemDefinition = Cast<UFortWeaponItemDefinition>(ItemDefinition);
|
||||
int LoadedAmmo = WeaponItemDefinition ? WeaponItemDefinition->GetClipSize() : 0; // we shouldnt set loaded ammo here techinally
|
||||
|
||||
if (auto WorldItemDefinition = Cast<UFortWorldItemDefinition>(ItemDefinition))
|
||||
{
|
||||
ItemLevel = 0; // GetItemLevel(WorldItemDefinition->LootLevelData, 0);
|
||||
}
|
||||
|
||||
int CountMultiplier = 1;
|
||||
int FinalCount = CountMultiplier * PickedPackage->GetCount();
|
||||
|
||||
if (FinalCount > 0)
|
||||
{
|
||||
int FinalItemLevel = 0;
|
||||
|
||||
if (ItemLevel >= 0)
|
||||
FinalItemLevel = ItemLevel;
|
||||
|
||||
while (FinalCount > 0)
|
||||
{
|
||||
int CurrentCountForEntry = PickedPackage->GetCount(); // Idk calls some itemdefinition vfunc
|
||||
|
||||
OutEntries->push_back(LootDrop(FFortItemEntry::MakeItemEntry(ItemDefinition, CurrentCountForEntry, LoadedAmmo)));
|
||||
|
||||
if (Engine_Version >= 424)
|
||||
{
|
||||
/*
|
||||
|
||||
Alright, so Fortnite literally doesn't reference the first loot package category for chests and floor loot (didnt check rest).
|
||||
Usually the first loot package category in our case is ammo, so this is quite weird.
|
||||
I have no clue how Fortnite would actually add the ammo.
|
||||
|
||||
Guess what, on the chapter 2 new loot tier groups, like FactionChests, they don't even have a package which has ammo as its loot package call.
|
||||
|
||||
*/
|
||||
|
||||
bool IsWeapon = PickedPackage->GetLootPackageID().ToString().contains(".Weapon.") && WeaponItemDefinition; // ONG?
|
||||
|
||||
if (IsWeapon)
|
||||
{
|
||||
auto AmmoData = WeaponItemDefinition->GetAmmoData();
|
||||
|
||||
int AmmoCount = AmmoData->GetDropCount(); // idk about this one
|
||||
|
||||
OutEntries->push_back(LootDrop(FFortItemEntry::MakeItemEntry(WeaponItemDefinition->GetAmmoData(), AmmoCount)));
|
||||
}
|
||||
}
|
||||
|
||||
FinalCount -= CurrentCountForEntry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<LootDrop> PickLootDrops(FName TierGroupName, bool bPrint, int recursive)
|
||||
{
|
||||
std::vector<LootDrop> LootDrops;
|
||||
|
||||
if (recursive > 6)
|
||||
return LootDrops;
|
||||
|
||||
auto GameState = ((AFortGameModeAthena*)GetWorld()->GetGameMode())->GetGameStateAthena();
|
||||
static auto CurrentPlaylistDataOffset = GameState->GetOffset("CurrentPlaylistData", false);
|
||||
|
||||
static std::vector<UDataTable*> LTDTables;
|
||||
static std::vector<UDataTable*> LPTables;
|
||||
|
||||
static auto CompositeDataTableClass = FindObject<UClass>(L"/Script/Engine.CompositeDataTable");
|
||||
|
||||
static int LastNum1 = 14915;
|
||||
|
||||
auto CurrentPlaylist = CurrentPlaylistDataOffset == -1 && Fortnite_Version < 6 ? nullptr : GameState->GetCurrentPlaylist();
|
||||
|
||||
if (LastNum1 != Globals::AmountOfListens)
|
||||
{
|
||||
LastNum1 = Globals::AmountOfListens;
|
||||
|
||||
LTDTables.clear();
|
||||
LPTables.clear();
|
||||
|
||||
bool bFoundPlaylistTable = false;
|
||||
|
||||
if (CurrentPlaylist)
|
||||
{
|
||||
static auto LootTierDataOffset = CurrentPlaylist->GetOffset("LootTierData");
|
||||
auto& LootTierDataSoft = CurrentPlaylist->Get<TSoftObjectPtr<UDataTable>>(LootTierDataOffset);
|
||||
|
||||
static auto LootPackagesOffset = CurrentPlaylist->GetOffset("LootPackages");
|
||||
auto& LootPackagesSoft = CurrentPlaylist->Get<TSoftObjectPtr<UDataTable>>(LootPackagesOffset);
|
||||
|
||||
if (LootTierDataSoft.IsValid() && LootPackagesSoft.IsValid())
|
||||
{
|
||||
auto LootTierDataStr = LootTierDataSoft.SoftObjectPtr.ObjectID.AssetPathName.ToString();
|
||||
auto LootPackagesStr = LootPackagesSoft.SoftObjectPtr.ObjectID.AssetPathName.ToString();
|
||||
auto LootTierDataTableIsComposite = LootTierDataStr.contains("Composite");
|
||||
auto LootPackageTableIsComposite = LootPackagesStr.contains("Composite");
|
||||
|
||||
auto StrongLootTierData = LootTierDataSoft.Get(LootTierDataTableIsComposite ? CompositeDataTableClass : UDataTable::StaticClass(), true);
|
||||
auto StrongLootPackage = LootPackagesSoft.Get(LootPackageTableIsComposite ? CompositeDataTableClass : UDataTable::StaticClass(), true);
|
||||
|
||||
if (StrongLootTierData && StrongLootPackage)
|
||||
{
|
||||
LTDTables.push_back(StrongLootTierData);
|
||||
LPTables.push_back(StrongLootPackage);
|
||||
|
||||
bFoundPlaylistTable = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!bFoundPlaylistTable)
|
||||
{
|
||||
LTDTables.push_back(LoadObject<UDataTable>(L"/Game/Items/Datatables/AthenaLootTierData_Client.AthenaLootTierData_Client"));
|
||||
LPTables.push_back(LoadObject<UDataTable>(L"/Game/Items/Datatables/AthenaLootPackages_Client.AthenaLootPackages_Client"));
|
||||
}
|
||||
|
||||
// LTDTables.push_back(LoadObject<UDataTable>(L"/Game/Athena/Playlists/Playground/AthenaLootTierData_Client.AthenaLootTierData_Client"));
|
||||
// LPTables.push_back(LoadObject<UDataTable>(L"/Game/Athena/Playlists/Playground/AthenaLootPackages_Client.AthenaLootPackages_Client"));
|
||||
|
||||
static auto FortGameFeatureDataClass = FindObject<UClass>("/Script/FortniteGame.FortGameFeatureData");
|
||||
|
||||
if (FortGameFeatureDataClass)
|
||||
{
|
||||
for (int i = 0; i < ChunkedObjects->Num(); i++)
|
||||
{
|
||||
auto Object = ChunkedObjects->GetObjectByIndex(i);
|
||||
|
||||
if (!Object)
|
||||
continue;
|
||||
|
||||
if (Object->IsA(FortGameFeatureDataClass))
|
||||
{
|
||||
auto GameFeatureData = Object;
|
||||
static auto DefaultLootTableDataOffset = GameFeatureData->GetOffset("DefaultLootTableData");
|
||||
|
||||
if (DefaultLootTableDataOffset != -1)
|
||||
{
|
||||
auto DefaultLootTableData = GameFeatureData->GetPtr<FFortGameFeatureLootTableData>(DefaultLootTableDataOffset);
|
||||
|
||||
auto LootTierDataTableStr = DefaultLootTableData->LootTierData.SoftObjectPtr.ObjectID.AssetPathName.ToString();
|
||||
|
||||
auto LootTierDataTableIsComposite = LootTierDataTableStr.contains("Composite");
|
||||
auto LootPackageTableStr = DefaultLootTableData->LootPackageData.SoftObjectPtr.ObjectID.AssetPathName.ToString();
|
||||
auto LootPackageTableIsComposite = LootPackageTableStr.contains("Composite");
|
||||
|
||||
auto LootTierDataPtr = DefaultLootTableData->LootTierData.Get(LootTierDataTableIsComposite ? CompositeDataTableClass : UDataTable::StaticClass(), true);
|
||||
auto LootPackagePtr = DefaultLootTableData->LootPackageData.Get(LootPackageTableIsComposite ? CompositeDataTableClass : UDataTable::StaticClass(), true);
|
||||
|
||||
if (LootPackagePtr)
|
||||
{
|
||||
LPTables.push_back(LootPackagePtr);
|
||||
}
|
||||
|
||||
if (CurrentPlaylist)
|
||||
{
|
||||
static auto PlaylistOverrideLootTableDataOffset = GameFeatureData->GetOffset("PlaylistOverrideLootTableData");
|
||||
auto& PlaylistOverrideLootTableData = GameFeatureData->Get<TMap<FGameplayTag, FFortGameFeatureLootTableData>>(PlaylistOverrideLootTableDataOffset);
|
||||
|
||||
static auto GameplayTagContainerOffset = CurrentPlaylist->GetOffset("GameplayTagContainer");
|
||||
auto GameplayTagContainer = CurrentPlaylist->GetPtr<FGameplayTagContainer>(GameplayTagContainerOffset);
|
||||
|
||||
for (int i = 0; i < GameplayTagContainer->GameplayTags.Num(); i++)
|
||||
{
|
||||
auto& Tag = GameplayTagContainer->GameplayTags.At(i);
|
||||
|
||||
for (auto& Value : PlaylistOverrideLootTableData)
|
||||
{
|
||||
auto CurrentOverrideTag = Value.First;
|
||||
|
||||
if (Tag.TagName == CurrentOverrideTag.TagName)
|
||||
{
|
||||
auto OverrideLootPackageTableStr = Value.Second.LootPackageData.SoftObjectPtr.ObjectID.AssetPathName.ToString();
|
||||
auto bOverrideIsComposite = OverrideLootPackageTableStr.contains("Composite");
|
||||
|
||||
auto ptr = Value.Second.LootPackageData.Get(bOverrideIsComposite ? CompositeDataTableClass : UDataTable::StaticClass(), true);
|
||||
|
||||
if (ptr)
|
||||
{
|
||||
/* if (bOverrideIsComposite)
|
||||
{
|
||||
static auto ParentTablesOffset = ptr->GetOffset("ParentTables");
|
||||
|
||||
auto ParentTables = ptr->GetPtr<TArray<UDataTable*>>(ParentTablesOffset);
|
||||
|
||||
for (int z = 0; z < ParentTables->size(); z++)
|
||||
{
|
||||
auto ParentTable = ParentTables->At(z);
|
||||
|
||||
if (ParentTable)
|
||||
{
|
||||
LPTables.push_back(ParentTable);
|
||||
}
|
||||
}
|
||||
} */
|
||||
|
||||
LPTables.push_back(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (LootTierDataPtr)
|
||||
{
|
||||
LTDTables.push_back(LootTierDataPtr);
|
||||
}
|
||||
|
||||
if (CurrentPlaylist)
|
||||
{
|
||||
static auto PlaylistOverrideLootTableDataOffset = GameFeatureData->GetOffset("PlaylistOverrideLootTableData");
|
||||
auto& PlaylistOverrideLootTableData = GameFeatureData->Get<TMap<FGameplayTag, FFortGameFeatureLootTableData>>(PlaylistOverrideLootTableDataOffset);
|
||||
|
||||
static auto GameplayTagContainerOffset = CurrentPlaylist->GetOffset("GameplayTagContainer");
|
||||
auto GameplayTagContainer = CurrentPlaylist->GetPtr<FGameplayTagContainer>(GameplayTagContainerOffset);
|
||||
|
||||
for (int i = 0; i < GameplayTagContainer->GameplayTags.Num(); i++)
|
||||
{
|
||||
auto& Tag = GameplayTagContainer->GameplayTags.At(i);
|
||||
|
||||
for (auto& Value : PlaylistOverrideLootTableData)
|
||||
{
|
||||
auto CurrentOverrideTag = Value.First;
|
||||
|
||||
if (Tag.TagName == CurrentOverrideTag.TagName)
|
||||
{
|
||||
auto OverrideLootTierDataStr = Value.Second.LootTierData.SoftObjectPtr.ObjectID.AssetPathName.ToString();
|
||||
auto bOverrideIsComposite = OverrideLootTierDataStr.contains("Composite");
|
||||
|
||||
auto ptr = Value.Second.LootTierData.Get(bOverrideIsComposite ? CompositeDataTableClass : UDataTable::StaticClass(), true);
|
||||
|
||||
if (ptr)
|
||||
{
|
||||
/* if (bOverrideIsComposite)
|
||||
{
|
||||
static auto ParentTablesOffset = ptr->GetOffset("ParentTables");
|
||||
|
||||
auto ParentTables = ptr->GetPtr<TArray<UDataTable*>>(ParentTablesOffset);
|
||||
|
||||
for (int z = 0; z < ParentTables->size(); z++)
|
||||
{
|
||||
auto ParentTable = ParentTables->At(z);
|
||||
|
||||
if (ParentTable)
|
||||
{
|
||||
LTDTables.push_back(ParentTable);
|
||||
}
|
||||
}
|
||||
} */
|
||||
|
||||
LTDTables.push_back(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < LTDTables.size(); i++)
|
||||
{
|
||||
auto& Table = LTDTables.at(i);
|
||||
|
||||
if (!Table->IsValidLowLevel())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Table->AddToRoot();
|
||||
LOG_INFO(LogDev, "[{}] LTD {}", i, Table->GetFullName());
|
||||
}
|
||||
|
||||
for (int i = 0; i < LPTables.size(); i++)
|
||||
{
|
||||
auto& Table = LPTables.at(i);
|
||||
|
||||
if (!Table->IsValidLowLevel())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Table->AddToRoot();
|
||||
LOG_INFO(LogDev, "[{}] LP {}", i, Table->GetFullName());
|
||||
}
|
||||
}
|
||||
|
||||
if (Fortnite_Version <= 6 || std::floor(Fortnite_Version) == 9) // ahhh
|
||||
{
|
||||
LTDTables.clear();
|
||||
LPTables.clear();
|
||||
|
||||
bool bFoundPlaylistTable = false;
|
||||
|
||||
if (CurrentPlaylist)
|
||||
{
|
||||
static auto LootTierDataOffset = CurrentPlaylist->GetOffset("LootTierData");
|
||||
auto& LootTierDataSoft = CurrentPlaylist->Get<TSoftObjectPtr<UDataTable>>(LootTierDataOffset);
|
||||
|
||||
static auto LootPackagesOffset = CurrentPlaylist->GetOffset("LootPackages");
|
||||
auto& LootPackagesSoft = CurrentPlaylist->Get<TSoftObjectPtr<UDataTable>>(LootPackagesOffset);
|
||||
|
||||
if (LootTierDataSoft.IsValid() && LootPackagesSoft.IsValid())
|
||||
{
|
||||
auto LootTierDataStr = LootTierDataSoft.SoftObjectPtr.ObjectID.AssetPathName.ToString();
|
||||
auto LootPackagesStr = LootPackagesSoft.SoftObjectPtr.ObjectID.AssetPathName.ToString();
|
||||
auto LootTierDataTableIsComposite = LootTierDataStr.contains("Composite");
|
||||
auto LootPackageTableIsComposite = LootPackagesStr.contains("Composite");
|
||||
|
||||
auto StrongLootTierData = LootTierDataSoft.Get(LootTierDataTableIsComposite ? CompositeDataTableClass : UDataTable::StaticClass(), true);
|
||||
auto StrongLootPackage = LootPackagesSoft.Get(LootPackageTableIsComposite ? CompositeDataTableClass : UDataTable::StaticClass(), true);
|
||||
|
||||
if (StrongLootTierData && StrongLootPackage)
|
||||
{
|
||||
LTDTables.push_back(StrongLootTierData);
|
||||
LPTables.push_back(StrongLootPackage);
|
||||
|
||||
bFoundPlaylistTable = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!bFoundPlaylistTable)
|
||||
{
|
||||
LTDTables.push_back(LoadObject<UDataTable>(L"/Game/Items/Datatables/AthenaLootTierData_Client.AthenaLootTierData_Client"));
|
||||
LPTables.push_back(LoadObject<UDataTable>(L"/Game/Items/Datatables/AthenaLootPackages_Client.AthenaLootPackages_Client"));
|
||||
}
|
||||
}
|
||||
|
||||
if (LTDTables.size() <= 0 || LPTables.size() <= 0)
|
||||
{
|
||||
LOG_WARN(LogLoot, "Empty tables! ({} {})", LTDTables.size(), LPTables.size());
|
||||
return LootDrops;
|
||||
}
|
||||
|
||||
FName LootTierRowName;
|
||||
auto ChosenRowLootTierData = PickLootTierData(LTDTables, TierGroupName, 0, -1, &LootTierRowName);
|
||||
|
||||
if (!ChosenRowLootTierData)
|
||||
{
|
||||
return LootDrops;
|
||||
}
|
||||
else if (bPrint)
|
||||
{
|
||||
LOG_INFO(LogLoot, "Picked loot tier data row {}", LootTierRowName.ToString());
|
||||
}
|
||||
|
||||
// auto ChosenLootPackageName = ChosenRowLootTierData->GetLootPackage().ToString();
|
||||
|
||||
// if (ChosenLootPackageName.contains(".Empty")) { return PickLootDropsNew(TierGroupName, bPrint, ++recursive); }
|
||||
|
||||
float NumLootPackageDrops = ChosenRowLootTierData->GetNumLootPackageDrops();
|
||||
|
||||
float NumberLootDrops = 0;
|
||||
|
||||
if (NumLootPackageDrops > 0)
|
||||
{
|
||||
if (NumLootPackageDrops < 1)
|
||||
{
|
||||
NumberLootDrops = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
NumberLootDrops = (int)(float)((float)(NumLootPackageDrops + NumLootPackageDrops) - 0.5) >> 1;
|
||||
float v20 = NumLootPackageDrops - NumberLootDrops;
|
||||
if (v20 > 0.0000099999997)
|
||||
{
|
||||
NumberLootDrops += v20 >= (rand() * 0.000030518509);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float AmountOfLootPackageDrops = GetAmountOfLootPackagesToDrop(ChosenRowLootTierData, NumberLootDrops);
|
||||
|
||||
LootDrops.reserve(AmountOfLootPackageDrops);
|
||||
|
||||
if (AmountOfLootPackageDrops > 0)
|
||||
{
|
||||
for (int i = 0; i < AmountOfLootPackageDrops; i++)
|
||||
{
|
||||
if (i >= ChosenRowLootTierData->GetLootPackageCategoryMinArray().Num())
|
||||
break;
|
||||
|
||||
for (int j = 0; j < ChosenRowLootTierData->GetLootPackageCategoryMinArray().at(i); j++)
|
||||
{
|
||||
if (ChosenRowLootTierData->GetLootPackageCategoryMinArray().at(i) < 1)
|
||||
break;
|
||||
|
||||
int LootPackageCategory = i;
|
||||
|
||||
PickLootDropsFromLootPackage(LPTables, ChosenRowLootTierData->GetLootPackage(), &LootDrops, LootPackageCategory, bPrint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return LootDrops;
|
||||
}
|
||||
#else
|
||||
|
||||
float GetRandomFloatForLooting(float min, float max)
|
||||
{
|
||||
@@ -72,12 +777,6 @@ static FFortLootPackageData* GetLootPackage(std::vector<FFortLootPackageData*>&
|
||||
return SelectedItem;
|
||||
}
|
||||
|
||||
struct FFortGameFeatureLootTableData
|
||||
{
|
||||
TSoftObjectPtr<UDataTable> LootTierData;
|
||||
TSoftObjectPtr<UDataTable> LootPackageData;
|
||||
};
|
||||
|
||||
std::vector<LootDrop> PickLootDrops(FName TierGroupName, bool bPrint, int recursive)
|
||||
{
|
||||
std::vector<LootDrop> LootDrops;
|
||||
@@ -644,13 +1343,9 @@ std::vector<LootDrop> PickLootDrops(FName TierGroupName, bool bPrint, int recurs
|
||||
|
||||
auto WeaponDef = Cast<UFortWeaponItemDefinition>(ItemDef);
|
||||
|
||||
LootDrop lootDrop{};
|
||||
lootDrop.ItemDefinition = ItemDef;
|
||||
lootDrop.LoadedAmmo = WeaponDef ? WeaponDef->GetClipSize() : 0;
|
||||
lootDrop.Count = LootPackageCall->GetCount();
|
||||
|
||||
LootDrops.push_back(lootDrop);
|
||||
LootDrops.push_back(LootDrop(FFortItemEntry::MakeItemEntry(ItemDef, LootPackageCall->GetCount(), WeaponDef ? WeaponDef->GetClipSize() : 0));
|
||||
}
|
||||
|
||||
return LootDrops;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -5,13 +5,9 @@
|
||||
#include "Array.h"
|
||||
#include "FortWorldItemDefinition.h"
|
||||
#include "SoftObjectPtr.h"
|
||||
#include "FortItem.h"
|
||||
|
||||
struct LootDrop
|
||||
{
|
||||
UFortItemDefinition* ItemDefinition;
|
||||
int Count;
|
||||
int LoadedAmmo;
|
||||
};
|
||||
#define EXPERIMENTAL_LOOTING
|
||||
|
||||
struct FFortLootPackageData
|
||||
{
|
||||
@@ -46,6 +42,12 @@ public:
|
||||
return *(int*)(__int64(this) + CountOffset);
|
||||
}
|
||||
|
||||
int& GetLootPackageCategory()
|
||||
{
|
||||
static auto LootPackageCategoryOffset = FindOffsetStruct("/Script/FortniteGame.FortLootPackageData", "LootPackageCategory");
|
||||
return *(int*)(__int64(this) + LootPackageCategoryOffset);
|
||||
}
|
||||
|
||||
FString& GetAnnotation()
|
||||
{
|
||||
static auto AnnotationOffset = FindOffsetStruct("/Script/FortniteGame.FortLootPackageData", "Annotation");
|
||||
@@ -99,4 +101,18 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
struct LootDrop
|
||||
{
|
||||
FFortItemEntry* ItemEntry;
|
||||
|
||||
FFortItemEntry* operator->() {
|
||||
return ItemEntry;
|
||||
}
|
||||
|
||||
~LootDrop()
|
||||
{
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<LootDrop> PickLootDrops(FName TierGroupName, bool bPrint = false, int recursive = 0);
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "FortPlayerController.h"
|
||||
#include <memcury.h>
|
||||
#include "GameplayStatics.h"
|
||||
#include "gui.h"
|
||||
|
||||
void AFortPickup::TossPickup(FVector FinalLocation, AFortPawn* ItemOwner, int OverrideMaxStackCount, bool bToss, EFortPickupSourceTypeFlag InPickupSourceTypeFlags, EFortPickupSpawnSource InPickupSpawnSource)
|
||||
{
|
||||
@@ -30,7 +31,7 @@ void AFortPickup::SpawnMovementComponent()
|
||||
|
||||
AFortPickup* AFortPickup::SpawnPickup(FFortItemEntry* ItemEntry, FVector Location,
|
||||
EFortPickupSourceTypeFlag PickupSource, EFortPickupSpawnSource SpawnSource,
|
||||
class AFortPawn* Pawn, UClass* OverrideClass, bool bToss, int OverrideCount)
|
||||
class AFortPawn* Pawn, UClass* OverrideClass, bool bToss, int OverrideCount, AFortPickup* IgnoreCombinePickup)
|
||||
{
|
||||
if (bToss)
|
||||
{
|
||||
@@ -85,14 +86,17 @@ AFortPickup* AFortPickup::SpawnPickup(FFortItemEntry* ItemEntry, FVector Locatio
|
||||
{
|
||||
auto OtherPickup = (AFortPickup*)OtherPickupActor;
|
||||
|
||||
if (OtherPickup->GetPickupLocationData()->GetCombineTarget())
|
||||
if (OtherPickup == IgnoreCombinePickup || OtherPickup->GetPickupLocationData()->GetCombineTarget())
|
||||
return false;
|
||||
|
||||
if (PrimaryPickupItemEntry->GetItemDefinition() == OtherPickup->GetPrimaryPickupItemEntry()->GetItemDefinition())
|
||||
{
|
||||
auto IncomingCount = OtherPickup->GetPrimaryPickupItemEntry()->GetCount();
|
||||
// auto IncomingCount = OtherPickup->GetPrimaryPickupItemEntry()->GetCount();
|
||||
|
||||
if (PrimaryPickupItemEntry->GetCount() + IncomingCount > PrimaryPickupItemEntry->GetItemDefinition()->GetMaxStackSize())
|
||||
// if (PrimaryPickupItemEntry->GetCount() + IncomingCount == PrimaryPickupItemEntry->GetItemDefinition()->GetMaxStackSize())
|
||||
// return false;
|
||||
|
||||
if (OtherPickup->GetPrimaryPickupItemEntry()->GetCount() == PrimaryPickupItemEntry->GetItemDefinition()->GetMaxStackSize()) // Other pickup is already at the max size.
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@@ -106,21 +110,29 @@ AFortPickup* AFortPickup::SpawnPickup(FFortItemEntry* ItemEntry, FVector Locatio
|
||||
PickupLocationData->GetCombineTarget() = (AFortPickup*)Pickup->GetClosestActor(AFortPickup::StaticClass(), 4, CanCombineWithPickup);
|
||||
}
|
||||
|
||||
// our little remake of tosspickup
|
||||
|
||||
Pickup->GetPickupLocationData()->GetLootFinalPosition() = Location;
|
||||
Pickup->GetPickupLocationData()->GetLootInitialPosition() = Pickup->GetActorLocation();
|
||||
Pickup->GetPickupLocationData()->GetFlyTime() = 1.4f; // not right really
|
||||
Pickup->GetPickupLocationData()->GetItemOwner() = Pawn;
|
||||
Pickup->GetPickupLocationData()->GetFinalTossRestLocation() = Pickup->GetActorLocation(); // ong ong proper
|
||||
|
||||
if (!PickupLocationData->GetCombineTarget()) // I don't think we should call TossPickup for every pickup.
|
||||
if (!PickupLocationData->GetCombineTarget()) // I don't think we should call TossPickup for every pickup anyways.
|
||||
{
|
||||
Pickup->TossPickup(Location, Pawn, 0, bToss, PickupSource, SpawnSource);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto ActorLocation = Pickup->GetActorLocation();
|
||||
auto CurrentActorLocation = PickupLocationData->GetCombineTarget()->GetActorLocation();
|
||||
|
||||
int Dist = float(sqrtf(powf(CurrentActorLocation.X - ActorLocation.X, 2.0) + powf(CurrentActorLocation.Y - ActorLocation.Y, 2.0) + powf(CurrentActorLocation.Z - ActorLocation.Z, 2.0))) / 100.f;
|
||||
|
||||
// LOG_INFO(LogDev, "Distance: {}", Dist);
|
||||
|
||||
// our little remake of tosspickup
|
||||
|
||||
PickupLocationData->GetLootFinalPosition() = Location;
|
||||
PickupLocationData->GetLootInitialPosition() = Pickup->GetActorLocation();
|
||||
PickupLocationData->GetFlyTime() = 1.f / Dist; // Higher the dist quicker it should be. // not right
|
||||
PickupLocationData->GetItemOwner() = Pawn;
|
||||
PickupLocationData->GetFinalTossRestLocation() = PickupLocationData->GetCombineTarget()->GetActorLocation(); // Pickup->GetActorLocation() // ong ong proper
|
||||
|
||||
Pickup->OnRep_PickupLocationData();
|
||||
Pickup->ForceNetUpdate();
|
||||
}
|
||||
|
||||
if (PickupSource == EFortPickupSourceTypeFlag::Container) // crashes if we do this then tosspickup
|
||||
@@ -142,7 +154,7 @@ AFortPickup* AFortPickup::SpawnPickup(FFortItemEntry* ItemEntry, FVector Locatio
|
||||
}
|
||||
|
||||
AFortPickup* AFortPickup::SpawnPickup(UFortItemDefinition* ItemDef, FVector Location, int Count, EFortPickupSourceTypeFlag PickupSource, EFortPickupSpawnSource SpawnSource,
|
||||
int LoadedAmmo, AFortPawn* Pawn, UClass* OverrideClass, bool bToss)
|
||||
int LoadedAmmo, AFortPawn* Pawn, UClass* OverrideClass, bool bToss, AFortPickup* IgnoreCombinePickup)
|
||||
{
|
||||
if (LoadedAmmo == -1)
|
||||
{
|
||||
@@ -153,7 +165,7 @@ AFortPickup* AFortPickup::SpawnPickup(UFortItemDefinition* ItemDef, FVector Loca
|
||||
}
|
||||
|
||||
auto ItemEntry = FFortItemEntry::MakeItemEntry(ItemDef, Count, LoadedAmmo);
|
||||
auto Pickup = SpawnPickup(ItemEntry, Location, PickupSource, SpawnSource, Pawn, OverrideClass, bToss);
|
||||
auto Pickup = SpawnPickup(ItemEntry, Location, PickupSource, SpawnSource, Pawn, OverrideClass, bToss, -1, IgnoreCombinePickup);
|
||||
// VirtualFree(ItemEntry);
|
||||
return Pickup;
|
||||
}
|
||||
@@ -164,27 +176,40 @@ void AFortPickup::CombinePickupHook(AFortPickup* Pickup)
|
||||
|
||||
auto PickupToCombineInto = (AFortPickup*)Pickup->GetPickupLocationData()->GetCombineTarget();
|
||||
|
||||
if (!PickupToCombineInto->IsActorBeingDestroyed())
|
||||
{
|
||||
// TODO Add more checks
|
||||
if (PickupToCombineInto->IsActorBeingDestroyed())
|
||||
return;
|
||||
|
||||
PickupToCombineInto->GetPrimaryPickupItemEntry()->GetCount() += Pickup->GetPrimaryPickupItemEntry()->GetCount();
|
||||
const int IncomingCount = Pickup->GetPrimaryPickupItemEntry()->GetCount();
|
||||
const int OriginalCount = PickupToCombineInto->GetPrimaryPickupItemEntry()->GetCount();
|
||||
|
||||
// add more checks?
|
||||
|
||||
auto ItemDefinition = PickupToCombineInto->GetPrimaryPickupItemEntry()->GetItemDefinition();
|
||||
|
||||
int CountToAdd = IncomingCount;
|
||||
|
||||
if (OriginalCount + CountToAdd > ItemDefinition->GetMaxStackSize())
|
||||
{
|
||||
const int OverStackCount = OriginalCount + CountToAdd - ItemDefinition->GetMaxStackSize();
|
||||
CountToAdd = ItemDefinition->GetMaxStackSize() - OriginalCount;
|
||||
|
||||
auto ItemOwner = Pickup->GetPickupLocationData()->GetItemOwner();
|
||||
|
||||
auto NewOverStackPickup = AFortPickup::SpawnPickup(ItemDefinition, PickupToCombineInto->GetActorLocation(), OverStackCount,
|
||||
EFortPickupSourceTypeFlag::Player, EFortPickupSpawnSource::Unset, -1, ItemOwner, nullptr, false, PickupToCombineInto);
|
||||
}
|
||||
|
||||
PickupToCombineInto->GetPrimaryPickupItemEntry()->GetCount() += CountToAdd;
|
||||
PickupToCombineInto->OnRep_PrimaryPickupItemEntry();
|
||||
|
||||
PickupToCombineInto->ForceNetUpdate();
|
||||
PickupToCombineInto->FlushNetDormancy();
|
||||
|
||||
Pickup->K2_DestroyActor();
|
||||
}
|
||||
}
|
||||
|
||||
char AFortPickup::CompletePickupAnimationHook(AFortPickup* Pickup)
|
||||
{
|
||||
constexpr bool bTestPrinting = false; // we could just use our own logger but eh
|
||||
|
||||
if constexpr (bTestPrinting)
|
||||
LOG_INFO(LogDev, "CompletePickupAnimationHook!");
|
||||
|
||||
auto Pawn = Cast<AFortPlayerPawn>(Pickup->GetPickupLocationData()->GetPickupTarget());
|
||||
|
||||
if (!Pawn)
|
||||
@@ -234,7 +259,7 @@ char AFortPickup::CompletePickupAnimationHook(AFortPickup* Pickup)
|
||||
|
||||
std::vector<std::pair<FFortItemEntry*, FFortItemEntry*>> PairsToMarkDirty; // vector of sets or something so no duplicates??
|
||||
|
||||
if constexpr (bTestPrinting)
|
||||
if (bDebugPrintSwapping)
|
||||
LOG_INFO(LogDev, "Start cpyCount: {}", cpyCount);
|
||||
|
||||
bool bWasHoldingSameItemWhenSwap = false;
|
||||
@@ -300,7 +325,7 @@ char AFortPickup::CompletePickupAnimationHook(AFortPickup* Pickup)
|
||||
|
||||
bHasSwapped = true;
|
||||
|
||||
if constexpr (bTestPrinting)
|
||||
if (bDebugPrintSwapping)
|
||||
LOG_INFO(LogDev, "[{}] Swapping: {}", i, ItemDefinitionToSwap->GetFullName());
|
||||
|
||||
// bForceDontAddItem = true;
|
||||
@@ -311,7 +336,7 @@ char AFortPickup::CompletePickupAnimationHook(AFortPickup* Pickup)
|
||||
|
||||
if (CurrentItemEntry->GetItemDefinition() == PickupItemDefinition)
|
||||
{
|
||||
if constexpr (bTestPrinting)
|
||||
if (bDebugPrintSwapping)
|
||||
LOG_INFO(LogDev, "[{}] Found stack of item!", i);
|
||||
|
||||
if (CurrentItemEntry->GetCount() < PickupItemDefinition->GetMaxStackSize())
|
||||
@@ -327,7 +352,7 @@ char AFortPickup::CompletePickupAnimationHook(AFortPickup* Pickup)
|
||||
|
||||
bEverStacked = true;
|
||||
|
||||
if constexpr (bTestPrinting)
|
||||
if (bDebugPrintSwapping)
|
||||
LOG_INFO(LogDev, "[{}] We are stacking {}.", i, AmountToStack);
|
||||
|
||||
// if (cpyCount > 0)
|
||||
@@ -339,7 +364,7 @@ char AFortPickup::CompletePickupAnimationHook(AFortPickup* Pickup)
|
||||
|
||||
if ((bIsInventoryFull || bForceOverflow) && cpyCount > 0) // overflow
|
||||
{
|
||||
if constexpr (bTestPrinting)
|
||||
if (bDebugPrintSwapping)
|
||||
LOG_INFO(LogDev, "[{}] Overflow", i);
|
||||
|
||||
UFortWorldItemDefinition* ItemDefinitionToSpawn = PickupItemDefinition;
|
||||
@@ -359,7 +384,7 @@ char AFortPickup::CompletePickupAnimationHook(AFortPickup* Pickup)
|
||||
|
||||
if (cpyCount > 0 && !bIsInventoryFull && !bForceDontAddItem)
|
||||
{
|
||||
if constexpr (bTestPrinting)
|
||||
if (bDebugPrintSwapping)
|
||||
LOG_INFO(LogDev, "Attempting to add to inventory.");
|
||||
|
||||
if (bDoesStackExist ? PickupItemDefinition->DoesAllowMultipleStacks() : true)
|
||||
@@ -375,7 +400,7 @@ char AFortPickup::CompletePickupAnimationHook(AFortPickup* Pickup)
|
||||
else
|
||||
cpyCount -= NewItemCount;
|
||||
|
||||
if constexpr (bTestPrinting)
|
||||
if (bDebugPrintSwapping)
|
||||
LOG_INFO(LogDev, "Added item with count {} to inventory.", NewItemCount);
|
||||
|
||||
if (bHasSwapped && NewSwappedItem == FGuid(-1, -1, -1, -1))
|
||||
|
||||
@@ -120,11 +120,11 @@ public:
|
||||
|
||||
static AFortPickup* SpawnPickup(FFortItemEntry* ItemEntry, FVector Location,
|
||||
EFortPickupSourceTypeFlag PickupSource = EFortPickupSourceTypeFlag::Other, EFortPickupSpawnSource SpawnSource = EFortPickupSpawnSource::Unset,
|
||||
class AFortPawn* Pawn = nullptr, UClass* OverrideClass = nullptr, bool bToss = true, int OverrideCount = -1);
|
||||
class AFortPawn* Pawn = nullptr, UClass* OverrideClass = nullptr, bool bToss = true, int OverrideCount = -1, AFortPickup* IgnoreCombinePickup = nullptr);
|
||||
|
||||
static AFortPickup* SpawnPickup(class UFortItemDefinition* ItemDef, FVector Location, int Count,
|
||||
EFortPickupSourceTypeFlag PickupSource = EFortPickupSourceTypeFlag::Other, EFortPickupSpawnSource SpawnSource = EFortPickupSpawnSource::Unset,
|
||||
int LoadedAmmo = -1, class AFortPawn* Pawn = nullptr, UClass* OverrideClass = nullptr, bool bToss = true);
|
||||
int LoadedAmmo = -1, class AFortPawn* Pawn = nullptr, UClass* OverrideClass = nullptr, bool bToss = true, AFortPickup* IgnoreCombinePickup = nullptr);
|
||||
|
||||
static void CombinePickupHook(AFortPickup* Pickup);
|
||||
static char CompletePickupAnimationHook(AFortPickup* Pickup);
|
||||
|
||||
@@ -61,7 +61,7 @@ bool AFortPlayerController::DoesBuildFree()
|
||||
return ReadBitfieldValue(bBuildFreeOffset, bBuildFreeFieldMask);
|
||||
}
|
||||
|
||||
void AFortPlayerController::DropAllItems(const std::vector<UFortItemDefinition*>& IgnoreItemDefs, bool bIgnoreSecondaryQuickbar, bool bRemoveIfNotDroppable)
|
||||
void AFortPlayerController::DropAllItems(const std::vector<UFortItemDefinition*>& IgnoreItemDefs, bool bIgnoreSecondaryQuickbar, bool bRemoveIfNotDroppable, bool RemovePickaxe)
|
||||
{
|
||||
auto Pawn = this->GetMyFortPawn();
|
||||
|
||||
@@ -78,6 +78,8 @@ void AFortPlayerController::DropAllItems(const std::vector<UFortItemDefinition*>
|
||||
|
||||
std::vector<std::pair<FGuid, int>> GuidAndCountsToRemove;
|
||||
|
||||
auto PickaxeInstance = WorldInventory->GetPickaxeInstance();
|
||||
|
||||
for (int i = 0; i < ItemInstances.Num(); i++)
|
||||
{
|
||||
auto ItemInstance = ItemInstances.at(i);
|
||||
@@ -86,6 +88,13 @@ void AFortPlayerController::DropAllItems(const std::vector<UFortItemDefinition*>
|
||||
continue;
|
||||
|
||||
auto ItemEntry = ItemInstance->GetItemEntry();
|
||||
|
||||
if (RemovePickaxe && ItemInstance == PickaxeInstance)
|
||||
{
|
||||
GuidAndCountsToRemove.push_back({ ItemEntry->GetItemGuid(), ItemEntry->GetCount() });
|
||||
continue;
|
||||
}
|
||||
|
||||
auto WorldItemDefinition = Cast<UFortWorldItemDefinition>(ItemEntry->GetItemDefinition());
|
||||
|
||||
if (!WorldItemDefinition || std::find(IgnoreItemDefs.begin(), IgnoreItemDefs.end(), WorldItemDefinition) != IgnoreItemDefs.end())
|
||||
@@ -482,16 +491,42 @@ void AFortPlayerController::ServerAttemptInteractHook(UObject* Context, FFrame*
|
||||
auto VehicleWeapon = Pawn->EquipWeaponDefinition(VehicleWeaponDefinition, NewVehicleInstance->GetItemEntry()->GetItemGuid());
|
||||
// PlayerController->ServerExecuteInventoryItemHook(PlayerController, newitem->GetItemEntry()->GetItemGuid());
|
||||
|
||||
/* if (WeaponComponent)
|
||||
/* static auto GetSeatWeaponComponentFn = FindObject<UFunction>("/Script/FortniteGame.FortAthenaVehicle.GetSeatWeaponComponent");
|
||||
|
||||
if (GetSeatWeaponComponentFn)
|
||||
{
|
||||
struct { int SeatIndex; UObject* ReturnValue; } AFortAthenaVehicle_GetSeatWeaponComponent_Params{};
|
||||
|
||||
Vehicle->ProcessEvent(GetSeatWeaponComponentFn, &AFortAthenaVehicle_GetSeatWeaponComponent_Params);
|
||||
|
||||
UObject* WeaponComponent = AFortAthenaVehicle_GetSeatWeaponComponent_Params.ReturnValue;
|
||||
|
||||
if (!WeaponComponent)
|
||||
return;
|
||||
|
||||
static auto WeaponSeatDefinitionStructSize = FindObject<UClass>("/Script/FortniteGame.WeaponSeatDefinition")->GetPropertiesSize();
|
||||
static auto VehicleWeaponOffset = FindOffsetStruct("/Script/FortniteGame.WeaponSeatDefinition", "VehicleWeapon");
|
||||
static auto SeatIndexOffset = FindOffsetStruct("/Script/FortniteGame.WeaponSeatDefinition", "SeatIndex");
|
||||
static auto WeaponSeatDefinitionsOffset = WeaponComponent->GetOffset("WeaponSeatDefinitions");
|
||||
auto& WeaponSeatDefinitions = WeaponComponent->Get<TArray<__int64>>(WeaponSeatDefinitionsOffset);
|
||||
|
||||
for (int i = 0; i < WeaponSeatDefinitions.Num(); i++)
|
||||
{
|
||||
auto WeaponSeat = WeaponSeatDefinitions.AtPtr(i, WeaponSeatDefinitionStructSize);
|
||||
|
||||
if (*(int*)(__int64(WeaponSeat) + SeatIndexOffset) != Vehicle->FindSeatIndex(Pawn))
|
||||
continue;
|
||||
|
||||
auto VehicleGrantedWeaponItem = (TWeakObjectPtr<UFortItem>*)(__int64(WeaponSeat) + 0x20);
|
||||
|
||||
VehicleGrantedWeaponItem->ObjectIndex = NewVehicleInstance->InternalIndex;
|
||||
VehicleGrantedWeaponItem->ObjectSerialNumber = GetItemByIndex(NewVehicleInstance->InternalIndex)->SerialNumber;
|
||||
|
||||
static auto bWeaponEquippedOffset = WeaponComponent->GetOffset("bWeaponEquipped");
|
||||
WeaponComponent->Get<bool>(bWeaponEquippedOffset) = true;
|
||||
|
||||
static auto CachedWeaponOffset = WeaponComponent->GetOffset("CachedWeapon");
|
||||
WeaponComponent->Get<AFortWeapon*>(CachedWeaponOffset) = VehicleWeapon;
|
||||
|
||||
static auto CachedWeaponDefOffset = WeaponComponent->GetOffset("CachedWeaponDef");
|
||||
WeaponComponent->Get<UFortWeaponItemDefinition*>(CachedWeaponDefOffset) = VehicleWeaponDefinition;
|
||||
break;
|
||||
}
|
||||
} */
|
||||
|
||||
return;
|
||||
|
||||
@@ -87,7 +87,7 @@ public:
|
||||
return CosmeticLoadout;
|
||||
}
|
||||
|
||||
void AddPickaxeToInventory()
|
||||
UFortItem* AddPickaxeToInventory()
|
||||
{
|
||||
auto CosmeticLoadout = GetCosmeticLoadout();
|
||||
auto CosmeticLoadoutPickaxe = CosmeticLoadout ? CosmeticLoadout->GetPickaxe() : nullptr;
|
||||
@@ -100,10 +100,12 @@ public:
|
||||
auto WorldInventory = GetWorldInventory();
|
||||
|
||||
if (!WorldInventory || WorldInventory->GetPickaxeInstance())
|
||||
return;
|
||||
return nullptr;
|
||||
|
||||
WorldInventory->AddItem(PickaxeDefinition, nullptr);
|
||||
auto NewAndModifiedInstances = WorldInventory->AddItem(PickaxeDefinition, nullptr);
|
||||
WorldInventory->Update();
|
||||
|
||||
return NewAndModifiedInstances.first.size() > 0 ? NewAndModifiedInstances.first[0] : nullptr;
|
||||
}
|
||||
|
||||
bool& ShouldTryPickupSwap()
|
||||
@@ -121,7 +123,7 @@ public:
|
||||
void ClientEquipItem(const FGuid& ItemGuid, bool bForceExecution);
|
||||
|
||||
bool DoesBuildFree();
|
||||
void DropAllItems(const std::vector<UFortItemDefinition*>& IgnoreItemDefs, bool bIgnoreSecondaryQuickbar = false, bool bRemoveIfNotDroppable = false);
|
||||
void DropAllItems(const std::vector<UFortItemDefinition*>& IgnoreItemDefs, bool bIgnoreSecondaryQuickbar = false, bool bRemoveIfNotDroppable = false, bool RemovePickaxe = false);
|
||||
void ApplyCosmeticLoadout();
|
||||
|
||||
static void ServerLoadingScreenDroppedHook(UObject* Context, FFrame* Stack, void* Ret);
|
||||
|
||||
@@ -44,6 +44,13 @@ void AFortPlayerControllerAthena::StartGhostModeHook(UObject* Context, FFrame* S
|
||||
if (!WorldInventory)
|
||||
return StartGhostModeOriginal(Context, Stack, Ret);
|
||||
|
||||
auto PickaxeInstance = WorldInventory->GetPickaxeInstance();
|
||||
|
||||
if (PickaxeInstance)
|
||||
{
|
||||
WorldInventory->RemoveItem(PickaxeInstance->GetItemEntry()->GetItemGuid(), nullptr, PickaxeInstance->GetItemEntry()->GetCount(), true);
|
||||
}
|
||||
|
||||
bool bShouldUpdate = false;
|
||||
auto NewAndModifiedInstances = WorldInventory->AddItem(ItemProvidingGhostMode, &bShouldUpdate, 1);
|
||||
auto GhostModeItemInstance = NewAndModifiedInstances.first[0];
|
||||
@@ -51,7 +58,7 @@ void AFortPlayerControllerAthena::StartGhostModeHook(UObject* Context, FFrame* S
|
||||
if (!GhostModeItemInstance)
|
||||
return StartGhostModeOriginal(Context, Stack, Ret);
|
||||
|
||||
if (bShouldUpdate)
|
||||
// if (bShouldUpdate)
|
||||
WorldInventory->Update();
|
||||
|
||||
PlayerController->ServerExecuteInventoryItemHook(PlayerController, GhostModeItemInstance->GetItemEntry()->GetItemGuid());
|
||||
@@ -95,12 +102,20 @@ void AFortPlayerControllerAthena::EndGhostModeHook(AFortPlayerControllerAthena*
|
||||
if (!GhostModeItemInstance)
|
||||
return EndGhostModeOriginal(PlayerController);
|
||||
|
||||
auto PickaxeInstance = PlayerController->AddPickaxeToInventory();
|
||||
WorldInventory->Update();
|
||||
|
||||
if (PickaxeInstance)
|
||||
{
|
||||
PlayerController->ClientEquipItem(PickaxeInstance->GetItemEntry()->GetItemGuid(), true);
|
||||
}
|
||||
|
||||
bool bShouldUpdate = false;
|
||||
int Count = GhostModeItemInstance->GetItemEntry()->GetCount(); // 1
|
||||
bool bForceRemoval = true; // false
|
||||
WorldInventory->RemoveItem(GhostModeItemInstance->GetItemEntry()->GetItemGuid(), &bShouldUpdate, Count, bForceRemoval);
|
||||
|
||||
if (bShouldUpdate)
|
||||
// if (bShouldUpdate)
|
||||
WorldInventory->Update();
|
||||
|
||||
return EndGhostModeOriginal(PlayerController);
|
||||
|
||||
@@ -140,17 +140,7 @@ UFortWeaponItemDefinition* AFortPlayerPawn::GetVehicleWeaponDefinition(AFortAthe
|
||||
if (!Vehicle)
|
||||
return nullptr;
|
||||
|
||||
static auto FindSeatIndexFn = FindObject<UFunction>("/Script/FortniteGame.FortAthenaVehicle.FindSeatIndex");
|
||||
/* auto Vehicle = GetVehicle();
|
||||
|
||||
if (!Vehicle)
|
||||
return nullptr; */
|
||||
|
||||
struct { AFortPlayerPawn* PlayerPawn; int ReturnValue; } AFortAthenaVehicle_FindSeatIndex_Params{ this };
|
||||
Vehicle->ProcessEvent(FindSeatIndexFn, &AFortAthenaVehicle_FindSeatIndex_Params);
|
||||
|
||||
auto SeatIndex = AFortAthenaVehicle_FindSeatIndex_Params.ReturnValue;
|
||||
return Vehicle->GetVehicleWeaponForSeat(SeatIndex);
|
||||
return Vehicle->GetVehicleWeaponForSeat(Vehicle->FindSeatIndex(this));
|
||||
}
|
||||
|
||||
void AFortPlayerPawn::UnEquipVehicleWeaponDefinition(UFortWeaponItemDefinition* VehicleWeaponDefinition)
|
||||
|
||||
@@ -38,8 +38,8 @@ int UFortWeaponItemDefinition::GetClipSize()
|
||||
UFortWorldItemDefinition* UFortWeaponItemDefinition::GetAmmoData()
|
||||
{
|
||||
static auto AmmoDataOffset = GetOffset("AmmoData");
|
||||
auto AmmoData = Get<TSoftObjectPtr<UFortWorldItemDefinition>>(AmmoDataOffset);
|
||||
return AmmoData.Get();
|
||||
auto AmmoData = GetPtr<TSoftObjectPtr<UFortWorldItemDefinition>>(AmmoDataOffset);
|
||||
return AmmoData->Get();
|
||||
}
|
||||
|
||||
UClass* UFortWeaponItemDefinition::StaticClass()
|
||||
|
||||
@@ -20,6 +20,12 @@ public:
|
||||
return ReadBitfieldValue(bCanBeDroppedOffset, bCanBeDroppedFieldMask);
|
||||
}
|
||||
|
||||
int& GetDropCount()
|
||||
{
|
||||
static auto DropCountOffset = GetOffset("DropCount");
|
||||
return Get<int>(DropCountOffset);
|
||||
}
|
||||
|
||||
EWorldItemDropBehavior& GetDropBehavior()
|
||||
{
|
||||
static auto DropBehaviorOffset = GetOffset("DropBehavior");
|
||||
|
||||
@@ -29,4 +29,9 @@ struct FName
|
||||
{
|
||||
return ComparisonIndex.Value == other.ComparisonIndex.Value;
|
||||
}
|
||||
|
||||
bool operator<(FName Other) const
|
||||
{
|
||||
return this->ComparisonIndex.Value < Other.ComparisonIndex.Value;
|
||||
}
|
||||
};
|
||||
@@ -335,6 +335,7 @@
|
||||
<ClInclude Include="FortItem.h" />
|
||||
<ClInclude Include="FortItemDefinition.h" />
|
||||
<ClInclude Include="FortKismetLibrary.h" />
|
||||
<ClInclude Include="FortLootLevel.h" />
|
||||
<ClInclude Include="FortLootPackage.h" />
|
||||
<ClInclude Include="FortMinigame.h" />
|
||||
<ClInclude Include="FortMountedCannon.h" />
|
||||
|
||||
@@ -694,9 +694,6 @@
|
||||
<ClInclude Include="ReversePredicate.h">
|
||||
<Filter>Engine\Source\Runtime\Core\Public\Templates</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="UnrealTypeTraits.h">
|
||||
<Filter>Engine\Source\Runtime\Core\Public\Templates</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IsEnum.h">
|
||||
<Filter>Engine\Source\Runtime\Core\Public\Templates</Filter>
|
||||
</ClInclude>
|
||||
@@ -848,6 +845,12 @@
|
||||
<ClInclude Include="Vector2D.h">
|
||||
<Filter>Engine\Source\Runtime\Core\Public\Math</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="UnrealTypeTraits.h">
|
||||
<Filter>Engine\Source\Runtime\Core\Public\Templates</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="FortLootLevel.h">
|
||||
<Filter>FortniteGame\Source\FortniteGame\Public\Items</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Engine">
|
||||
|
||||
@@ -490,7 +490,7 @@ void ServerCheatHook(AFortPlayerControllerAthena* PlayerController, FString Msg)
|
||||
return;
|
||||
}
|
||||
|
||||
auto Pawn = ReceivingController->GetMyFortPawn();
|
||||
auto Pawn = ReceivingController->GetPawn();
|
||||
|
||||
if (!Pawn)
|
||||
{
|
||||
@@ -519,11 +519,25 @@ void ServerCheatHook(AFortPlayerControllerAthena* PlayerController, FString Msg)
|
||||
|
||||
if (ClassObj)
|
||||
{
|
||||
int AmountSpawned = 0;
|
||||
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
FActorSpawnParameters SpawnParameters{};
|
||||
// SpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn;
|
||||
|
||||
auto Loc = Pawn->GetActorLocation();
|
||||
// Loc.Z += 1000;
|
||||
GetWorld()->SpawnActor<AActor>(ClassObj, Loc, FQuat());
|
||||
Loc.Z += 1000;
|
||||
auto NewActor = GetWorld()->SpawnActor<AActor>(ClassObj, Loc, FQuat(), FVector(1, 1, 1), SpawnParameters);
|
||||
|
||||
if (!NewActor)
|
||||
{
|
||||
SendMessageToConsole(PlayerController, L"Failed to spawn an actor!");
|
||||
}
|
||||
else
|
||||
{
|
||||
AmountSpawned++;
|
||||
}
|
||||
}
|
||||
|
||||
SendMessageToConsole(PlayerController, L"Summoned!");
|
||||
|
||||
@@ -627,12 +627,26 @@ static inline uint64 FindUpdateTrackedAttributesLea() // kill me
|
||||
|
||||
static inline uint64 FindCombinePickupLea() // kill me
|
||||
{
|
||||
return 0;
|
||||
|
||||
/* uint64 OnRep_PickupLocationDataAddr = 0; // TODO (Idea: Find SetupCombinePickupDelegates from this).
|
||||
|
||||
if (!OnRep_PickupLocationDataAddr)
|
||||
return 0; */
|
||||
|
||||
uint64 SetupCombinePickupDelegatesAddr = Memcury::Scanner::FindPattern("48 89 AC 24 ? ? ? ? 48 89 B4 24 ? ? ? ? 48 89 BC 24 ? ? ? ? 0F 29 B4 24 ? ? ? ? 75").Get(); // Haha so funny thing, this isn't actually the start its the middle because it's in function chunks yay!
|
||||
uint64 SetupCombinePickupDelegatesAddr = 0;
|
||||
|
||||
bool bShouldCheckSafety = true;
|
||||
|
||||
if (Engine_Version <= 420)
|
||||
{
|
||||
SetupCombinePickupDelegatesAddr = Memcury::Scanner::FindPattern("49 89 73 10 49 89 7B 18 4D 89 73 20 4D 89 7B E8 41 0F 29 73 ? 75").Get(); // found on 4.1
|
||||
bShouldCheckSafety = false; // it's like "corrupted" and not just return
|
||||
}
|
||||
else if (Engine_Version >= 421)
|
||||
{
|
||||
SetupCombinePickupDelegatesAddr = Memcury::Scanner::FindPattern("48 89 AC 24 ? ? ? ? 48 89 B4 24 ? ? ? ? 48 89 BC 24 ? ? ? ? 0F 29 B4 24 ? ? ? ? 75").Get(); // Haha so funny thing, this isn't actually the start its the middle because it's in function chunks yay!
|
||||
}
|
||||
|
||||
if (!SetupCombinePickupDelegatesAddr)
|
||||
return 0;
|
||||
@@ -644,7 +658,7 @@ static inline uint64 FindCombinePickupLea() // kill me
|
||||
{
|
||||
auto loadAddress = Memcury::Scanner(SetupCombinePickupDelegatesAddr + i).RelativeOffset(3).Get();
|
||||
|
||||
if (IsNullSub(loadAddress)) // Safety
|
||||
if (!bShouldCheckSafety || IsNullSub(loadAddress))
|
||||
return SetupCombinePickupDelegatesAddr + i;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,8 +48,9 @@
|
||||
#define DUMP_TAB 7
|
||||
#define UNBAN_TAB 8
|
||||
#define DEVELOPER_TAB 9
|
||||
#define SETTINGS_TAB 10
|
||||
#define CREDITS_TAB 11
|
||||
#define DEBUGLOG_TAB 10
|
||||
#define SETTINGS_TAB 11
|
||||
#define CREDITS_TAB 12
|
||||
|
||||
#define MAIN_PLAYERTAB 1
|
||||
#define INVENTORY_PLAYERTAB 2
|
||||
@@ -61,6 +62,8 @@ extern inline bool bSwitchedInitialLevel = false;
|
||||
extern inline bool bIsInAutoRestart = false;
|
||||
extern inline float AutoBusStartSeconds = 60;
|
||||
extern inline int NumRequiredPlayersToStart = 2;
|
||||
extern inline bool bDebugPrintLooting = false;
|
||||
extern inline bool bDebugPrintSwapping = false;
|
||||
|
||||
// THE BASE CODE IS FROM IMGUI GITHUB
|
||||
|
||||
@@ -376,6 +379,14 @@ static inline void MainTabs()
|
||||
bInformationTab = false;
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if (ImGui::BeginTabItem("Debug Logs"))
|
||||
{
|
||||
Tab = DEBUGLOG_TAB;
|
||||
PlayerTab = -1;
|
||||
bInformationTab = false;
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (false && ImGui::BeginTabItem(("Credits")))
|
||||
@@ -954,6 +965,11 @@ static inline void MainUI()
|
||||
}
|
||||
*/
|
||||
}
|
||||
else if (Tab == DEBUGLOG_TAB)
|
||||
{
|
||||
ImGui::Checkbox("Looting Debug Log", &bDebugPrintLooting);
|
||||
ImGui::Checkbox("Swapping Debug Log", &bDebugPrintSwapping);
|
||||
}
|
||||
else if (Tab == SETTINGS_TAB)
|
||||
{
|
||||
// ImGui::Checkbox("Use custom lootpool (from Win64/lootpool.txt)", &Defines::bCustomLootpool);
|
||||
|
||||
@@ -49,7 +49,7 @@ struct PlaceholderBitfield
|
||||
|
||||
inline bool AreVehicleWeaponsEnabled()
|
||||
{
|
||||
return Fortnite_Version < 9;
|
||||
return Fortnite_Version > 6;
|
||||
}
|
||||
|
||||
inline bool IsRestartingSupported()
|
||||
|
||||
@@ -184,11 +184,22 @@ static inline void SpawnVehicles2()
|
||||
static auto FortAthenaVehicleSpawnerClass = FindObject<UClass>("/Script/FortniteGame.FortAthenaVehicleSpawner");
|
||||
TArray<AActor*> AllVehicleSpawners = UGameplayStatics::GetAllActorsOfClass(GetWorld(), FortAthenaVehicleSpawnerClass);
|
||||
|
||||
int AmountOfVehiclesSpawned = 0;
|
||||
|
||||
for (int i = 0; i < AllVehicleSpawners.Num(); i++)
|
||||
{
|
||||
auto VehicleSpawner = AllVehicleSpawners.at(i);
|
||||
auto Vehicle = SpawnVehicleFromSpawner(VehicleSpawner);
|
||||
|
||||
if (Vehicle)
|
||||
{
|
||||
AmountOfVehiclesSpawned++;
|
||||
}
|
||||
}
|
||||
|
||||
auto AllVehicleSpawnersNum = AllVehicleSpawners.Num();
|
||||
|
||||
AllVehicleSpawners.Free();
|
||||
|
||||
LOG_INFO(LogGame, "Spawned {}/{} vehicles.", AmountOfVehiclesSpawned, AllVehicleSpawnersNum);
|
||||
}
|
||||
@@ -134,7 +134,7 @@ static inline void FillItemCollector(ABuildingItemCollectorActor* ItemCollector,
|
||||
|
||||
for (int LootDropIt = 0; LootDropIt < LootDrops.size(); LootDropIt++)
|
||||
{
|
||||
auto WorldItemDefinition = Cast<UFortWorldItemDefinition>(LootDrops[LootDropIt].ItemDefinition);
|
||||
UFortWorldItemDefinition* WorldItemDefinition = Cast<UFortWorldItemDefinition>(LootDrops[LootDropIt]->GetItemDefinition());
|
||||
|
||||
if (!WorldItemDefinition)
|
||||
continue;
|
||||
@@ -182,7 +182,7 @@ static inline void FillItemCollector(ABuildingItemCollectorActor* ItemCollector,
|
||||
|
||||
for (int LootDropIt = 0; LootDropIt < LootDrops.size(); LootDropIt++)
|
||||
{
|
||||
auto ItemEntry = FFortItemEntry::MakeItemEntry(LootDrops[LootDropIt].ItemDefinition, LootDrops[LootDropIt].Count, LootDrops[LootDropIt].LoadedAmmo);
|
||||
auto ItemEntry = FFortItemEntry::MakeItemEntry(LootDrops[LootDropIt]->GetItemDefinition(), LootDrops[LootDropIt]->GetCount(), LootDrops[LootDropIt]->GetLoadedAmmo());
|
||||
|
||||
if (!ItemEntry)
|
||||
continue;
|
||||
|
||||
8
vendor/memcury.h
vendored
8
vendor/memcury.h
vendored
@@ -1431,4 +1431,10 @@
|
||||
return PtrRef.ScanFor(Bytes, false).Get();
|
||||
}
|
||||
|
||||
inline bool IsNullSub(uint64 Addr) { return *(uint8_t*)(Addr) == 0xC3 || *(uint8_t*)(Addr) == 0xC2; }
|
||||
inline bool IsNullSub(uint64 Addr)
|
||||
{
|
||||
// if (*(uint8_t*)(Addr) == 0xEB && *(uint8_t*)(Addr + 1) == 0xF7) // positive sp value has been detected, the output may be wrong!
|
||||
// return true;
|
||||
|
||||
return *(uint8_t*)(Addr) == 0xC3 || *(uint8_t*)(Addr) == 0xC2;
|
||||
}
|
||||
Reference in New Issue
Block a user