fixed looting

This commit is contained in:
Milxnor
2023-06-28 11:58:20 -04:00
parent feea0e20f3
commit 26abeab332
14 changed files with 244 additions and 161 deletions

View File

@@ -175,6 +175,19 @@ void AFortGameModeAthena::HandleSpawnRateForActorClass(UClass* ActorClass, float
}
}
void AFortGameModeAthena::StartAircraftPhase()
{
if (Addresses::StartAircraftPhase)
{
static void (*StartAircraftPhaseOriginal)(AFortGameModeAthena*, bool bDoNotSpawnAircraft) = decltype(StartAircraftPhaseOriginal)(Addresses::StartAircraftPhase);
StartAircraftPhaseOriginal(this, false); // love the double negative fortnite
}
else
{
UKismetSystemLibrary::ExecuteConsoleCommand(GetWorld(), L"startaircraft", nullptr);
}
}
void AFortGameModeAthena::PauseSafeZone(bool bPaused)
{
auto GameState = GetGameStateAthena();

View File

@@ -263,6 +263,7 @@ public:
UClass* GetVehicleClassOverride(UClass* DefaultClass);
void SkipAircraft();
void PauseSafeZone(bool bPaused = true);
void StartAircraftPhase();
static void HandleSpawnRateForActorClass(UClass* ActorClass, float SpawnPercentage); // idk where to put

View File

@@ -249,7 +249,7 @@ std::pair<std::vector<UFortItem*>, std::vector<UFortItem*>> AFortInventory::AddI
return Ret;
}
bool AFortInventory::RemoveItem(const FGuid& ItemGuid, bool* bShouldUpdate, int Count, bool bForceRemoval)
bool AFortInventory::RemoveItem(const FGuid& ItemGuid, bool* bShouldUpdate, int Count, bool bForceRemoval, bool bIgnoreVariables)
{
if (bShouldUpdate)
*bShouldUpdate = false;
@@ -280,7 +280,7 @@ bool AFortInventory::RemoveItem(const FGuid& ItemGuid, bool* bShouldUpdate, int
bool bOverrideChangeStackSize = false;
if (ItemDefinition->ShouldPersistWhenFinalStackEmpty())
if (!bIgnoreVariables && ItemDefinition->ShouldPersistWhenFinalStackEmpty())
{
bool bIsFinalStack = true;

View File

@@ -101,7 +101,7 @@ public:
std::pair<std::vector<UFortItem*>, std::vector<UFortItem*>> AddItem(FFortItemEntry* ItemEntry, bool* bShouldUpdate, bool bShowItemToast = false, int OverrideCount = -1);
std::pair<std::vector<UFortItem*>, std::vector<UFortItem*>> AddItem(UFortItemDefinition* ItemDefinition, bool* bShouldUpdate, int Count = 1, int LoadedAmmo = -1, bool bShowItemToast = false);
bool RemoveItem(const FGuid& ItemGuid, bool* bShouldUpdate, int Count, bool bForceRemoval = false);
bool RemoveItem(const FGuid& ItemGuid, bool* bShouldUpdate, int Count, bool bForceRemoval = false, bool bIgnoreVariables = false);
void SwapItem(const FGuid& ItemGuid, FFortItemEntry* NewItemEntry, int OverrideNewCount = -1, std::pair<FFortItemEntry*, FFortItemEntry*>* outEntries = nullptr);
void ModifyCount(UFortItem* ItemInstance, int New, bool bRemove = false, std::pair<FFortItemEntry*, FFortItemEntry*>* outEntries = nullptr, bool bUpdate = true, bool bShowItemToast = false);

View File

@@ -121,11 +121,11 @@ float GetAmountOfLootPackagesToDrop(FFortLootTierData* LootTierData, int Origina
{
// HONESTLY IDEK WHAT FORTNITE DOES HERE
float v29 = (float)rand() * 0.000030518509;
float v29 = (float)rand() * 0.000030518509f;
float v35 = (int)(float)((float)((float)((float)SumLootPackageCategoryWeightArray * v29)
+ (float)((float)SumLootPackageCategoryWeightArray * v29))
+ 0.5) >> 1;
+ 0.5f) >> 1;
// OutLootTierInfo->Hello++;
MinimumLootDrops++;
@@ -153,27 +153,30 @@ float GetAmountOfLootPackagesToDrop(FFortLootTierData* LootTierData, int Origina
FFortLootTierData* PickLootTierData(const std::vector<UDataTable*>& LTDTables, FName LootTierGroup, int ForcedLootTier = -1, FName* OutRowName = nullptr) // Fortnite returns the row name and then finds the tier data again, but I really don't see the point of this.
{
// This like isn't right, at all.
float LootTier = ForcedLootTier;
float IdkForcedWeightorsomething = -1;
if (LootTier == -1)
{
// IdkForcedWeightorsomething = weightofAlltherowsithink // we don't ened to do this since the pickweightedeleent already does that
// LootTier = ??
}
else
{
// ITS SO MUCH TO REVERSE AAAAA
// buncha code im too lazy to reverse
}
// if (fabs(LootTier) <= 0.0000000099999999)
// if (fabs(LootTier) <= 0.0000000099999999f)
// return 0;
int Multiplier = LootTier == -1 ? 1 : LootTier; // Idk i think we need to fill out the code above for this to work properly maybe
LOOTING_MAP_TYPE<FName, FFortLootTierData*> TierGroupLTDs;
CollectDataTablesRows<FFortLootTierData>(LTDTables, &TierGroupLTDs, [&](FName RowName, FFortLootTierData* TierData) -> bool {
if (LootTierGroup == TierData->GetTierGroup())
{
if ((LootTier == -1 ? true : LootTier == TierData->GetLootTier())) // idek if this is proper
if ((LootTier == -1 ? true : LootTier == TierData->GetLootTier()))
{
return true;
}
@@ -186,20 +189,18 @@ FFortLootTierData* PickLootTierData(const std::vector<UDataTable*>& LTDTables, F
FFortLootTierData* ChosenRowLootTierData = PickWeightedElement<FName, FFortLootTierData*>(TierGroupLTDs,
[](FFortLootTierData* LootTierData) -> float { return LootTierData->GetWeight(); }, RandomFloatForLoot, -1,
true, 1, OutRowName, false, false, IdkForcedWeightorsomething);
true, Multiplier, OutRowName);
return ChosenRowLootTierData;
}
void PickLootDropsFromLootPackage(const std::vector<UDataTable*>& LPTables, FName LootPackageName, std::vector<LootDrop>* OutEntries, int LootPackageCategory = -1, int WorldLevel = 0, bool bPrint = false, bool bCombineDrops = true)
void PickLootDropsFromLootPackage(const std::vector<UDataTable*>& LPTables, const FName& LootPackageName, std::vector<LootDrop>* OutEntries, int LootPackageCategory = -1, int WorldLevel = 0, bool bPrint = false, bool bCombineDrops = true)
{
if (!OutEntries)
return;
LOOTING_MAP_TYPE<FName, FFortLootPackageData*> LootPackageIDMap;
float TotalWeight = 0;
CollectDataTablesRows<FFortLootPackageData>(LPTables, &LootPackageIDMap, [&](FName RowName, FFortLootPackageData* LootPackage) -> bool {
if (LootPackage->GetLootPackageID() != LootPackageName)
{
@@ -214,18 +215,16 @@ void PickLootDropsFromLootPackage(const std::vector<UDataTable*>& LPTables, FNam
if (WorldLevel >= 0)
{
if (LootPackage->GetMaxWorldLevel() >= 0 && WorldLevel > LootPackage->GetMaxWorldLevel())
return false;
return 0;
if (LootPackage->GetMinWorldLevel() >= 0 && WorldLevel < LootPackage->GetMinWorldLevel())
return false;
return 0;
}
TotalWeight += LootPackage->GetWeight();
return true;
});
if (TotalWeight == 0)
if (LootPackageIDMap.size() == 0)
{
// std::cout << std::format("Loot Package {} has no valid weights.\n", LootPackageName.ToString());
return;
@@ -233,7 +232,8 @@ void PickLootDropsFromLootPackage(const std::vector<UDataTable*>& LPTables, FNam
FName PickedPackageRowName;
FFortLootPackageData* PickedPackage = PickWeightedElement<FName, FFortLootPackageData*>(LootPackageIDMap,
[](FFortLootPackageData* LootPackageData) -> float { return LootPackageData->GetWeight(); }, RandomFloatForLoot, -1, true, 1, &PickedPackageRowName, bPrint);
[](FFortLootPackageData* LootPackageData) -> float { return LootPackageData->GetWeight(); }, RandomFloatForLoot,
-1, true, 1, &PickedPackageRowName, bPrint);
if (!PickedPackage)
return;
@@ -250,7 +250,7 @@ void PickLootDropsFromLootPackage(const std::vector<UDataTable*>& LPTables, FNam
while (v9 < PickedPackage->GetCount())
{
int LootPackageCategoryToUseForLPCall = 0; // hmm
PickLootDropsFromLootPackage(LPTables,
PickedPackage->GetLootPackageCall().Data.Data ? UKismetStringLibrary::Conv_StringToName(PickedPackage->GetLootPackageCall()) : FName(0),
OutEntries, LootPackageCategoryToUseForLPCall, WorldLevel, bPrint
@@ -270,7 +270,7 @@ void PickLootDropsFromLootPackage(const std::vector<UDataTable*>& LPTables, FNam
LOG_INFO(LogLoot, "Loot Package {} does not contain a LootPackageCall or ItemDefinition.", PickedPackage->GetLootPackageID().ToString());
return;
}
auto WeaponItemDefinition = Cast<UFortWeaponItemDefinition>(ItemDefinition);
int LoadedAmmo = WeaponItemDefinition ? WeaponItemDefinition->GetClipSize() : 0; // we shouldnt set loaded ammo here techinally
@@ -332,14 +332,14 @@ void PickLootDropsFromLootPackage(const std::vector<UDataTable*>& LPTables, FNam
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?
@@ -366,6 +366,8 @@ void PickLootDropsFromLootPackage(const std::vector<UDataTable*>& LPTables, FNam
}
}
// #define brudda
std::vector<LootDrop> PickLootDrops(FName TierGroupName, int WorldLevel, int ForcedLootTier, bool bPrint, int recursive, bool bCombineDrops)
{
std::vector<LootDrop> LootDrops;
@@ -509,6 +511,23 @@ std::vector<LootDrop> PickLootDrops(FName TierGroupName, int WorldLevel, int For
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);
}
}
@@ -552,7 +571,7 @@ std::vector<LootDrop> PickLootDrops(FName TierGroupName, int WorldLevel, int For
auto ParentTables = ptr->GetPtr<TArray<UDataTable*>>(ParentTablesOffset);
for (int z = 0; z < ParentTables->size(); ++z)
for (int z = 0; z < ParentTables->size(); z++)
{
auto ParentTable = ParentTables->At(z);
@@ -598,7 +617,7 @@ std::vector<LootDrop> PickLootDrops(FName TierGroupName, int WorldLevel, int For
Table->AddToRoot();
LOG_INFO(LogDev, "[{}] LP {}", i, Table->GetFullName());
}
}
}
if (!Addresses::LoadAsset)
@@ -649,13 +668,13 @@ std::vector<LootDrop> PickLootDrops(FName TierGroupName, int WorldLevel, int For
}
}
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, ForcedLootTier, &LootTierRowName);
@@ -685,11 +704,11 @@ std::vector<LootDrop> PickLootDrops(FName TierGroupName, int WorldLevel, int For
}
else
{
NumberLootDrops = (int)(float)((float)(NumLootPackageDrops + NumLootPackageDrops) - 0.5) >> 1;
NumberLootDrops = (int)(float)((float)(NumLootPackageDrops + NumLootPackageDrops) - 0.5f) >> 1;
float v20 = NumLootPackageDrops - NumberLootDrops;
if (v20 > 0.0000099999997)
if (v20 > 0.0000099999997f)
{
NumberLootDrops += v20 >= (rand() * 0.000030518509);
NumberLootDrops += v20 >= (rand() * 0.000030518509f);
}
}
}

View File

@@ -141,10 +141,10 @@ static inline float RandomFloatForLoot(float AllWeightsSum)
}
template <typename KeyType, typename ValueType>
FORCEINLINE static ValueType PickWeightedElement(const std::map<KeyType, ValueType>& Elements,
FORCEINLINE static ValueType PickWeightedElement(const std::map<KeyType, ValueType>& Elements,
std::function<float(ValueType)> GetWeightFn,
std::function<float(float)> RandomFloatGenerator = RandomFloatForLoot,
float TotalWeightParam = -1, bool bCheckIfWeightIsZero = false, int RandMultiplier = 1, KeyType* OutName = nullptr, bool bPrint = false, bool bKeepGoingUntilWeGetValue = false, float AHHH = 1)
std::function<float(float)> RandomFloatGenerator = RandomFloatForLoot,
float TotalWeightParam = -1, bool bCheckIfWeightIsZero = false, int RandMultiplier = 1, KeyType* OutName = nullptr, bool bPrint = false, bool bKeepGoingUntilWeGetValue = false)
{
float TotalWeight = TotalWeightParam;
@@ -158,14 +158,15 @@ FORCEINLINE static ValueType PickWeightedElement(const std::map<KeyType, ValueTy
// if (Weight != 0)
{
LOG_INFO(LogLoot, "Adding weight {}", Weight);
}
}
}
return acc + Weight;
});
}
float RandomNumber = RandMultiplier * RandomFloatGenerator(AHHH == -1 ? TotalWeight : AHHH);
float RandomNumber = // UKismetMathLibrary::RandomFloatInRange(0, TotalWeight);
RandMultiplier * RandomFloatGenerator(TotalWeight);
if (bPrint)
{

View File

@@ -37,7 +37,9 @@ void AFortPlayerController::ClientReportDamagedResourceBuilding(ABuildingSMActor
void AFortPlayerController::ClientEquipItem(const FGuid& ItemGuid, bool bForceExecution)
{
static auto ClientEquipItemFn = FindObject<UFunction>("/Script/FortniteGame.FortPlayerControllerAthena.ClientEquipItem") ? FindObject<UFunction>("/Script/FortniteGame.FortPlayerControllerAthena.ClientEquipItem") : FindObject<UFunction>("/Script/FortniteGame.FortPlayerController.ClientEquipItem");
static auto ClientEquipItemFn = FindObject<UFunction>(L"/Script/FortniteGame.FortPlayerControllerAthena.ClientEquipItem")
? FindObject<UFunction>(L"/Script/FortniteGame.FortPlayerControllerAthena.ClientEquipItem")
: FindObject<UFunction>(L"/Script/FortniteGame.FortPlayerController.ClientEquipItem");
if (ClientEquipItemFn)
{
@@ -920,7 +922,9 @@ AActor* AFortPlayerController::SpawnToyInstanceHook(UObject* Context, FFrame* St
if (!ToyClass)
return nullptr;
auto NewToy = GetWorld()->SpawnActor<AActor>(ToyClass, SpawnPosition, CreateSpawnParameters(ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn, false, PlayerController));
auto Params = CreateSpawnParameters(ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn, false, PlayerController);
auto NewToy = GetWorld()->SpawnActor<AActor>(ToyClass, SpawnPosition, Params);
// free(Params); // ?
static auto ActiveToyInstancesOffset = PlayerController->GetOffset("ActiveToyInstances");
auto& ActiveToyInstances = PlayerController->Get<TArray<AActor*>>(ActiveToyInstancesOffset);
@@ -993,7 +997,9 @@ void AFortPlayerController::ServerAttemptInventoryDropHook(AFortPlayerController
static auto DropBehaviorOffset = ItemDefinition->GetOffset("DropBehavior", false);
if (!ItemDefinition->ShouldIgnoreRespawningOnDrop() && (DropBehaviorOffset != -1 ? ItemDefinition->GetDropBehavior() != EWorldItemDropBehavior::DestroyOnDrop : true))
EWorldItemDropBehavior DropBehavior = DropBehaviorOffset != -1 ? ItemDefinition->GetDropBehavior() : EWorldItemDropBehavior::EWorldItemDropBehavior_MAX;
if (!ItemDefinition->ShouldIgnoreRespawningOnDrop() && DropBehavior != EWorldItemDropBehavior::DestroyOnDrop)
{
PickupCreateData CreateData;
CreateData.ItemEntry = ReplicatedEntry;
@@ -1013,7 +1019,7 @@ void AFortPlayerController::ServerAttemptInventoryDropHook(AFortPlayerController
bool bShouldUpdate = false;
if (!WorldInventory->RemoveItem(ItemGuid, &bShouldUpdate, Count, true))
if (!WorldInventory->RemoveItem(ItemGuid, &bShouldUpdate, Count, true, DropBehavior == EWorldItemDropBehavior::DropAsPickupDestroyOnEmpty))
return;
if (bShouldUpdate)
@@ -1171,28 +1177,23 @@ uint8 ToDeathCause(const FGameplayTagContainer& TagContainer, bool bWasDBNO = fa
return sub_7FF7AB499410(TagContainer, bWasDBNO);
}
std::vector<APlayerController*> PlayerControllersDead; // make atomic?
// std::array<std::atomic<APlayerController*>, 100> PlayerControllersDead;
std::atomic<int> numValidElements(0);
DWORD WINAPI SpectateThread(LPVOID)
DWORD WINAPI SpectateThread(LPVOID PC)
{
while (1)
{
for (auto PC : PlayerControllersDead)
// for (int i = 0; i < PlayerControllersDead.size(); ++i)
{
// auto PC = PlayerControllersDead.at(i).load();
auto PlayerController = (UObject*)PC;
static auto SpectateOnDeathFn = FindObject<UFunction>(L"/Script/FortniteGame.FortPlayerControllerZone.SpectateOnDeath") ?
FindObject<UFunction>(L"/Script/FortniteGame.FortPlayerControllerZone.SpectateOnDeath") :
FindObject<UFunction>(L"/Script/FortniteGame.FortPlayerControllerAthena.SpectateOnDeath");
if (!PlayerController->IsValidLowLevel())
return 0;
PC->ProcessEvent(SpectateOnDeathFn);
}
auto SpectatingPC = Cast<AFortPlayerControllerAthena>(PlayerController);
Sleep(4000);
}
if (!SpectatingPC)
return 0;
Sleep(3000);
LOG_INFO(LogDev, "bugha!");
SpectatingPC->SpectateOnDeath();
return 0;
}
@@ -1434,110 +1435,98 @@ void AFortPlayerController::ClientOnPawnDiedHook(AFortPlayerController* PlayerCo
LOG_INFO(LogDev, "PlayersLeft: {} IsDBNO: {}", GameState->GetPlayersLeft(), DeadPawn->IsDBNO());
if (bHandleDeath && !DeadPawn->IsDBNO())
if (!DeadPawn->IsDBNO())
{
if (Fortnite_Version > 1.8 || Fortnite_Version == 1.11)
if (bHandleDeath)
{
static void (*RemoveFromAlivePlayers)(AFortGameModeAthena * GameMode, AFortPlayerController * PlayerController, APlayerState * PlayerState, APawn * FinisherPawn,
UFortWeaponItemDefinition * FinishingWeapon, uint8_t DeathCause, char a7)
= decltype(RemoveFromAlivePlayers)(Addresses::RemoveFromAlivePlayers);
AActor* DamageCauser = *(AActor**)(__int64(DeathReport) + MemberOffsets::DeathReport::DamageCauser);
UFortWeaponItemDefinition* KillerWeaponDef = nullptr;
static auto FortProjectileBaseClass = FindObject<UClass>(L"/Script/FortniteGame.FortProjectileBase");
if (DamageCauser)
if (Fortnite_Version > 1.8 || Fortnite_Version == 1.11)
{
if (DamageCauser->IsA(FortProjectileBaseClass))
static void (*RemoveFromAlivePlayers)(AFortGameModeAthena * GameMode, AFortPlayerController * PlayerController, APlayerState * PlayerState, APawn * FinisherPawn,
UFortWeaponItemDefinition * FinishingWeapon, uint8_t DeathCause, char a7)
= decltype(RemoveFromAlivePlayers)(Addresses::RemoveFromAlivePlayers);
AActor* DamageCauser = *(AActor**)(__int64(DeathReport) + MemberOffsets::DeathReport::DamageCauser);
UFortWeaponItemDefinition* KillerWeaponDef = nullptr;
static auto FortProjectileBaseClass = FindObject<UClass>(L"/Script/FortniteGame.FortProjectileBase");
if (DamageCauser)
{
auto Owner = Cast<AFortWeapon>(DamageCauser->GetOwner());
KillerWeaponDef = Owner->IsValidLowLevel() ? Owner->GetWeaponData() : nullptr; // I just added the IsValidLowLevel check because what if the weapon destroys?
}
if (auto Weapon = Cast<AFortWeapon>(DamageCauser))
{
KillerWeaponDef = Weapon->GetWeaponData();
}
}
RemoveFromAlivePlayers(GameMode, PlayerController, KillerPlayerState == DeadPlayerState ? nullptr : KillerPlayerState, KillerPawn, KillerWeaponDef, DeathCause, 0);
/*
STATS:
Note: This isn't the exact order relative to other functions.
ClientSendMatchStatsForPlayer
ClientSendTeamStatsForPlayer
ClientSendEndBattleRoyaleMatchForPlayer
*/
// FAthenaMatchStats.Stats[ERewardSource] // hmm
/*
// We need to check if their entire team is dead then I think we send it????
auto DeadControllerAthena = Cast<AFortPlayerControllerAthena>(PlayerController);
if (DeadControllerAthena && FAthenaMatchTeamStats::GetStruct())
{
auto MatchReport = DeadControllerAthena->GetMatchReport();
LOG_INFO(LogDev, "MatchReport: {}", __int64(MatchReport));
if (MatchReport)
{
MatchReport->GetTeamStats()->GetPlace() = DeadPlayerState->GetPlace();
MatchReport->GetTeamStats()->GetTotalPlayers() = AmountOfPlayersWhenBusStart; // hmm
MatchReport->HasTeamStats() = true;
DeadControllerAthena->ClientSendTeamStatsForPlayer(MatchReport->GetTeamStats());
}
}
*/
LOG_INFO(LogDev, "Removed!");
if (Fortnite_Version < 6) // Spectating
{
static auto bAllowSpectateAfterDeathOffset = GameMode->GetOffset("bAllowSpectateAfterDeath");
bool bAllowSpectate = false; // GameMode->Get<bool>(bAllowSpectateAfterDeathOffset);
LOG_INFO(LogDev, "bAllowSpectate: {}", bAllowSpectate);
if (bAllowSpectate)
{
LOG_INFO(LogDev, "Starting Spectating!");
static auto PlayerToSpectateOnDeathOffset = PlayerController->GetOffset("PlayerToSpectateOnDeath");
PlayerController->Get<APawn*>(PlayerToSpectateOnDeathOffset) = KillerPawn;
PlayerControllersDead.push_back(PlayerController);
/* if (numValidElements < PlayerControllersDead.size())
if (DamageCauser->IsA(FortProjectileBaseClass))
{
PlayerControllersDead[numValidElements].store(PlayerController);
numValidElements.fetch_add(1);
} */
static bool bCreatedThread = false;
if (!bCreatedThread)
auto Owner = Cast<AFortWeapon>(DamageCauser->GetOwner());
KillerWeaponDef = Owner->IsValidLowLevel() ? Owner->GetWeaponData() : nullptr; // I just added the IsValidLowLevel check because what if the weapon destroys (idk)?
}
if (auto Weapon = Cast<AFortWeapon>(DamageCauser))
{
bCreatedThread = true;
CreateThread(0, 0, SpectateThread, 0, 0, 0);
KillerWeaponDef = Weapon->GetWeaponData();
}
}
RemoveFromAlivePlayers(GameMode, PlayerController, KillerPlayerState == DeadPlayerState ? nullptr : KillerPlayerState, KillerPawn, KillerWeaponDef, DeathCause, 0);
/*
STATS:
Note: This isn't the exact order relative to other functions.
ClientSendMatchStatsForPlayer
ClientSendTeamStatsForPlayer
ClientSendEndBattleRoyaleMatchForPlayer
*/
// FAthenaMatchStats.Stats[ERewardSource] // hmm
/*
// We need to check if their entire team is dead then I think we send it????
auto DeadControllerAthena = Cast<AFortPlayerControllerAthena>(PlayerController);
if (DeadControllerAthena && FAthenaMatchTeamStats::GetStruct())
{
auto MatchReport = DeadControllerAthena->GetMatchReport();
LOG_INFO(LogDev, "MatchReport: {}", __int64(MatchReport));
if (MatchReport)
{
MatchReport->GetTeamStats()->GetPlace() = DeadPlayerState->GetPlace();
MatchReport->GetTeamStats()->GetTotalPlayers() = AmountOfPlayersWhenBusStart; // hmm
MatchReport->HasTeamStats() = true;
DeadControllerAthena->ClientSendTeamStatsForPlayer(MatchReport->GetTeamStats());
}
}
*/
LOG_INFO(LogDev, "Removed!");
}
// LOG_INFO(LogDev, "KillerPlayerState->Place: {}", KillerPlayerState ? KillerPlayerState->GetPlace() : -1);
}
// LOG_INFO(LogDev, "KillerPlayerState->Place: {}", KillerPlayerState ? KillerPlayerState->GetPlace() : -1);
if (Fortnite_Version < 6) // Spectating (is this the actual build or is it like 6.10 when they added it auto).
{
static auto bAllowSpectateAfterDeathOffset = GameMode->GetOffset("bAllowSpectateAfterDeath");
bool bAllowSpectate = GameMode->Get<bool>(bAllowSpectateAfterDeathOffset);
LOG_INFO(LogDev, "bAllowSpectate: {}", bAllowSpectate);
if (bAllowSpectate)
{
LOG_INFO(LogDev, "Starting Spectating!");
static auto PlayerToSpectateOnDeathOffset = PlayerController->GetOffset("PlayerToSpectateOnDeath");
PlayerController->Get<APawn*>(PlayerToSpectateOnDeathOffset) = KillerPawn;
CreateThread(0, 0, SpectateThread, (LPVOID)PlayerController, 0, 0);
}
}
}
if (IsRestartingSupported() && Globals::bAutoRestart && !bIsInAutoRestart)

View File

@@ -141,6 +141,15 @@ public:
static inline void (*StartGhostModeOriginal)(UObject* Context, FFrame* Stack, void* Ret);
static inline void (*EndGhostModeOriginal)(AFortPlayerControllerAthena* PlayerController);
void SpectateOnDeath() // actually in zone
{
static auto SpectateOnDeathFn = FindObject<UFunction>(L"/Script/FortniteGame.FortPlayerControllerZone.SpectateOnDeath") ?
FindObject<UFunction>(L"/Script/FortniteGame.FortPlayerControllerZone.SpectateOnDeath") :
FindObject<UFunction>(L"/Script/FortniteGame.FortPlayerControllerAthena.SpectateOnDeath");
this->ProcessEvent(SpectateOnDeathFn);
}
class UAthenaResurrectionComponent*& GetResurrectionComponent()
{
static auto ResurrectionComponentOffset = GetOffset("ResurrectionComponent");

View File

@@ -312,6 +312,9 @@ void Addresses::FindAll()
LOG_INFO(LogDev, "Finding AddToAlivePlayers");
Addresses::AddToAlivePlayers = FindAddToAlivePlayers();
LOG_INFO(LogDev, "Finding StartAircraftPhase");
Addresses::StartAircraftPhase = FindStartAircraftPhase();
// LOG_INFO(LogDev, "Finding GetSessionInterface");
// Addresses::GetSessionInterface = FindGetSessionInterface();
@@ -392,6 +395,7 @@ void Addresses::Print()
LOG_INFO(LogDev, "FinishResurrection: 0x{:x}", FinishResurrection - Base);
LOG_INFO(LogDev, "AddToAlivePlayers: 0x{:x}", AddToAlivePlayers - Base);
LOG_INFO(LogDev, "GetSessionInterface: 0x{:x}", GetSessionInterface - Base);
LOG_INFO(LogDev, "StartAircraftPhase: 0x{:x}", StartAircraftPhase - Base);
}
void Offsets::FindAll()

View File

@@ -76,7 +76,8 @@ namespace Addresses
extern inline uint64 AddToAlivePlayers = 0;
extern inline uint64 GameSessionPatch = 0;
extern inline uint64 GetSessionInterface = 0; // Matchmaking
extern inline uint64 StartAircraftPhase = 0;
void SetupVersion(); // Finds Engine Version
void FindAll();
void Print();

View File

@@ -3,6 +3,47 @@
#include "reboot.h"
#include "FortPlayerControllerAthena.h"
uint64 FindStartAircraftPhase()
{
if (Engine_Version < 427) // they scuf it
{
auto strRef = Memcury::Scanner::FindStringRef(L"STARTAIRCRAFT").Get();
if (!strRef)
return 0;
int NumCalls = 0;
for (int i = 0; i < 150; i++)
{
if (*(uint8_t*)(strRef + i) == 0xE8)
{
LOG_INFO(LogDev, "Found call 0x{:x}", __int64(strRef + i) - __int64(GetModuleHandleW(0)));
NumCalls++;
if (NumCalls == 2) // First is the str compare ig
{
return Memcury::Scanner(strRef + i).RelativeOffset(1).Get();
}
}
}
}
else
{
auto StatAddress = Memcury::Scanner::FindStringRef(L"STAT_StartAircraftPhase").Get();
for (int i = 0; i < 1000; i++)
{
if (*(uint8_t*)(uint8_t*)(StatAddress - i) == 0x48 && *(uint8_t*)(uint8_t*)(StatAddress - i + 1) == 0x8B && *(uint8_t*)(uint8_t*)(StatAddress - i + 2) == 0xC4)
{
return StatAddress - i;
}
}
}
return 0;
}
uint64 FindGetSessionInterface()
{
auto strRef = Memcury::Scanner::FindStringRef(L"OnDestroyReservedSessionComplete %s bSuccess: %d", true, 0, Fortnite_Version >= 19).Get();

View File

@@ -495,6 +495,7 @@ static inline uint64 FindGetMaxTickRate() // UEngine::getmaxtickrate
// return FindBytes(stringRef, Fortnite_Version <= 4.1 ? std::vector<uint8_t>{ 0x40, 0x53 } : std::vector<uint8_t>{ 0x48, 0x89, 0x5C }, 1000, 0, true);
}
uint64 FindStartAircraftPhase();
uint64 FindGetSessionInterface();
uint64 FindGetPlayerViewpoint();
uint64 ApplyGameSessionPatch();

View File

@@ -104,7 +104,7 @@ static inline LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM
static inline void SetIsLategame(bool Value)
{
Globals::bLateGame.store(Value);
StartingShield = 100;
StartingShield = Value ? 100 : 0;
}
static inline void Restart() // todo move?
@@ -528,7 +528,7 @@ static inline DWORD WINAPI LateGameThread(LPVOID)
return Aircrafts;
};
UKismetSystemLibrary::ExecuteConsoleCommand(GetWorld(), L"startaircraft", nullptr);
GameMode->StartAircraftPhase();
while (GetAircrafts().size() <= 0)
{
@@ -795,7 +795,7 @@ static inline void MainUI()
}
else
{
UKismetSystemLibrary::ExecuteConsoleCommand(GetWorld(), L"startaircraft", nullptr);
GameMode->StartAircraftPhase();
}
}
}
@@ -1086,9 +1086,10 @@ static inline void MainUI()
{
auto CurrentBuildingSMActor = (ABuildingSMActor*)AllBuildingSMActors.at(i);
if (!CurrentBuildingSMActor->IsPlayerPlaced()) continue;
if (CurrentBuildingSMActor->IsDestroyed() || CurrentBuildingSMActor->IsActorBeingDestroyed() || !CurrentBuildingSMActor->IsPlayerPlaced()) continue;
CurrentBuildingSMActor->K2_DestroyActor();
CurrentBuildingSMActor->SilentDie();
// CurrentBuildingSMActor->K2_DestroyActor();
}
AllBuildingSMActors.Free();
@@ -1137,9 +1138,12 @@ static inline void MainUI()
static auto DefaultGliderRedeployCanRedeployOffset = FindOffsetStruct("/Script/FortniteGame.FortGameStateAthena", "DefaultGliderRedeployCanRedeploy", false);
static auto DefaultParachuteDeployTraceForGroundDistanceOffset = GameState->GetOffset("DefaultParachuteDeployTraceForGroundDistance", false);
if (DefaultParachuteDeployTraceForGroundDistanceOffset != -1)
if (Globals::bStartedListening) // it resets accordingly to ProHenis b4 this
{
ImGui::InputFloat("Automatic Parachute Pullout Distance", GameState->GetPtr<float>(DefaultParachuteDeployTraceForGroundDistanceOffset));
if (DefaultParachuteDeployTraceForGroundDistanceOffset != -1)
{
ImGui::InputFloat("Automatic Parachute Pullout Distance", GameState->GetPtr<float>(DefaultParachuteDeployTraceForGroundDistanceOffset));
}
}
if (DefaultGliderRedeployCanRedeployOffset != -1)

View File

@@ -20,7 +20,7 @@ extern inline int Engine_Version = 0; // For example, 420, 421, etc. // Prevent
extern inline double Fortnite_Version = 0; // For example, 4.1, 6.21, etc. // Prevent using this when possible.
extern inline int Fortnite_CL = 0;
#define PROD // this doesnt do anything besides remove processeventhook and some assert stuff
// #define PROD // this doesnt do anything besides remove processeventhook and some assert stuff
struct PlaceholderBitfield
{