pickup combining, almost finish shadow stones, fix some bugs with gadgets, clean up some code.
This commit is contained in:
Milxnor
2023-05-02 23:48:05 -04:00
parent 3b0f0ad4e1
commit f49f166c2d
27 changed files with 574 additions and 216 deletions

View File

@@ -3,6 +3,7 @@
#include "Transform.h" #include "Transform.h"
#include "reboot.h" #include "reboot.h"
#include "GameplayStatics.h"
bool AActor::HasAuthority() bool AActor::HasAuthority()
{ {
@@ -210,6 +211,40 @@ void AActor::GetActorEyesViewPoint(FVector* OutLocation, FRotator* OutRotation)
*OutRotation = AActor_GetActorEyesViewPoint_Params.OutRotation; *OutRotation = AActor_GetActorEyesViewPoint_Params.OutRotation;
} }
AActor* AActor::GetClosestActor(UClass* ActorClass, float DistMax, std::function<bool(AActor*)> AdditionalCheck)
{
float TargetDist = FLT_MAX;
AActor* TargetActor = nullptr;
TArray<AActor*> AllActors = UGameplayStatics::GetAllActorsOfClass(GetWorld(), ActorClass);
auto ActorLocation = GetActorLocation();
for (int i = 0; i < AllActors.Num(); i++)
{
auto Actor = AllActors.at(i);
if (!Actor || Actor == this)
continue;
if (!AdditionalCheck(Actor))
continue;
auto CurrentActorLocation = Actor->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;
if (Dist <= DistMax && Dist < TargetDist)
{
TargetDist = Dist;
TargetActor = Actor;
}
}
AllActors.Free();
return TargetActor;
}
bool AActor::IsAlwaysRelevant() bool AActor::IsAlwaysRelevant()
{ {
static auto bAlwaysRelevantOffset = GetOffset("bAlwaysRelevant"); static auto bAlwaysRelevantOffset = GetOffset("bAlwaysRelevant");

View File

@@ -49,7 +49,8 @@ public:
float& GetMinNetUpdateFrequency(); float& GetMinNetUpdateFrequency();
const AActor* GetNetOwner() const; const AActor* GetNetOwner() const;
void GetActorEyesViewPoint(FVector* OutLocation, FRotator* OutRotation) const; void GetActorEyesViewPoint(FVector* OutLocation, FRotator* OutRotation) const;
AActor* GetClosestActor(UClass* ActorClass, float DistMax, std::function<bool(AActor*)> AdditionalCheck = [&](AActor*) { return true; });
bool IsRelevancyOwnerFor(const AActor* ReplicatedActor, const AActor* ActorOwner, const AActor* ConnectionActor) const bool IsRelevancyOwnerFor(const AActor* ReplicatedActor, const AActor* ActorOwner, const AActor* ConnectionActor) const
{ {
// we should call virtual function but eh // we should call virtual function but eh

View File

@@ -1,6 +1,15 @@
#pragma once #pragma once
#include "reboot.h"
class UAttributeSet : public UObject class UAttributeSet : public UObject
{ {
public: public:
};
struct FGameplayAttribute
{
FString AttributeName;
void* Attribute;
UStruct* AttributeOwner;
}; };

View File

@@ -48,7 +48,7 @@ public:
return this->GetPtr<TArray<FGameplayEffectApplicationInfoHard>>(GrantedGameplayEffectsOffset); return this->GetPtr<TArray<FGameplayEffectApplicationInfoHard>>(GrantedGameplayEffectsOffset);
} }
void ApplyGrantedGameplayAffectsToAbilitySystem(UAbilitySystemComponent* AbilitySystemComponent) void ApplyGrantedGameplayAffectsToAbilitySystem(UAbilitySystemComponent* AbilitySystemComponent) // i dont think this is proper
{ {
if (!FGameplayEffectApplicationInfoHard::GetStruct()) if (!FGameplayEffectApplicationInfoHard::GetStruct())
return; return;

View File

@@ -3,6 +3,8 @@
#include "SoftObjectPath.h" #include "SoftObjectPath.h"
#include "FortPlayerStateAthena.h" #include "FortPlayerStateAthena.h"
#include "addresses.h" #include "addresses.h"
#include "FortPlayerPawnAthena.h"
#include "FortPlayerControllerAthena.h"
void UFortGadgetItemDefinition::UnequipGadgetData(AFortPlayerController* PlayerController, UFortItem* Item) void UFortGadgetItemDefinition::UnequipGadgetData(AFortPlayerController* PlayerController, UFortItem* Item)
{ {
@@ -10,64 +12,21 @@ void UFortGadgetItemDefinition::UnequipGadgetData(AFortPlayerController* PlayerC
__int64 (*RemoveGadgetDataOriginal)(UFortGadgetItemDefinition* a1, __int64 a2, UFortItem* a3) = decltype(RemoveGadgetDataOriginal)(Addresses::RemoveGadgetData); __int64 (*RemoveGadgetDataOriginal)(UFortGadgetItemDefinition* a1, __int64 a2, UFortItem* a3) = decltype(RemoveGadgetDataOriginal)(Addresses::RemoveGadgetData);
RemoveGadgetDataOriginal(this, __int64(PlayerController->GetInterfaceAddress(FortInventoryOwnerInterfaceClass)), Item); RemoveGadgetDataOriginal(this, __int64(PlayerController->GetInterfaceAddress(FortInventoryOwnerInterfaceClass)), Item);
/* auto Pawn = PlayerController->GetMyFortPawn(); if (auto CosmeticLoadoutPC = PlayerController->GetCosmeticLoadout())
if (Pawn)
{ {
static auto OriginalFootstepBankOffset = Pawn->GetOffset("OriginalFootstepBank"); if (auto CharacterToApply = CosmeticLoadoutPC->GetCharacter())
static auto FootstepBankOverrideOffset = Pawn->GetOffset("FootstepBankOverride");
Pawn->Get(FootstepBankOverrideOffset) = Pawn->Get(OriginalFootstepBankOffset);
static auto AnimBPOverrideOffset = Pawn->GetOffset("AnimBPOverride");
static auto OriginalAnimBPOffset = Pawn->GetOffset("OriginalAnimBP");
Pawn->Get(AnimBPOverrideOffset) = Pawn->Get(OriginalAnimBPOffset);
}
static auto AbilitySetOffset = this->GetOffset("AbilitySet");
auto& AbilitySetSoft = this->Get<TSoftObjectPtr<UFortAbilitySet>>(AbilitySetOffset);
auto StrongAbilitySet = AbilitySetSoft.Get(UFortAbilitySet::StaticClass(), true);
if (StrongAbilitySet)
{
auto PlayerState = (AFortPlayerStateAthena*)PlayerController->GetPlayerState();
auto ASC = PlayerState ? PlayerState->GetAbilitySystemComponent() : nullptr;
if (ASC)
{ {
if (FGameplayEffectApplicationInfoHard::GetStruct()) ApplyCID(Cast<AFortPlayerPawn>(PlayerController->GetMyFortPawn()), CharacterToApply); // idk why no automatic
{
auto AS_GrantedGameplayEffects = StrongAbilitySet->GetGrantedGameplayEffects();
if (AS_GrantedGameplayEffects)
{
for (int i = 0; i < AS_GrantedGameplayEffects->Num(); i++)
{
ASC->RemoveActiveGameplayEffectBySourceEffect(AS_GrantedGameplayEffects->at(i, FGameplayEffectApplicationInfoHard::GetStructSize()).GameplayEffect, ASC, 1);
}
}
}
auto& ActivatableAbilitiesItems = ASC->GetActivatableAbilities()->GetItems();
auto AS_GameplayAbilities = StrongAbilitySet->GetGameplayAbilities();
for (int j = 0; j < AS_GameplayAbilities->Num(); j++)
{
auto CurrentDefaultAbility = AS_GameplayAbilities->at(j)->CreateDefaultObject();
for (int i = 0; i < ActivatableAbilitiesItems.Num(); i++)
{
auto Spec = ActivatableAbilitiesItems.AtPtr(i, FGameplayAbilitySpec::GetStructSize());
if (Spec->GetAbility() == CurrentDefaultAbility)
{
ASC->ClearAbility(Spec->GetHandle());
}
}
}
} }
} }
}
PlayerController->ApplyCosmeticLoadout(); void UFortGadgetItemDefinition::UpdateTrackedAttributesHook(UFortGadgetItemDefinition* GadgetItemDefinition)
*/ {
// LOG_INFO(LogDev, "UpdateTrackedAttributesHook Return: 0x{:x}", __int64(_ReturnAddress()) - __int64(GetModuleHandleW(0)));
if (GadgetItemDefinition->ShouldDestroyGadgetWhenTrackedAttributesIsZero())
{
// PlayerState->MulticastTriggerOnGadgetTrackedAttributeDestroyedFX
}
} }

View File

@@ -19,6 +19,17 @@ public:
return ReadBitfieldValue(bDropAllOnEquipOffset, bDropAllOnEquipFieldMask); return ReadBitfieldValue(bDropAllOnEquipOffset, bDropAllOnEquipFieldMask);
} }
bool ShouldDestroyGadgetWhenTrackedAttributesIsZero()
{
static auto bDestroyGadgetWhenTrackedAttributesIsZeroOffset = GetOffset("bDestroyGadgetWhenTrackedAttributesIsZero", false);
if (bDestroyGadgetWhenTrackedAttributesIsZeroOffset == -1)
return false;
static auto bDestroyGadgetWhenTrackedAttributesIsZeroFieldMask = GetFieldMask(GetProperty("bDestroyGadgetWhenTrackedAttributesIsZero"));
return ReadBitfieldValue(bDestroyGadgetWhenTrackedAttributesIsZeroOffset, bDestroyGadgetWhenTrackedAttributesIsZeroFieldMask);
}
UAttributeSet* GetAttributeSet() UAttributeSet* GetAttributeSet()
{ {
static auto AttributeSetOffset = this->GetOffset("AttributeSet", false); static auto AttributeSetOffset = this->GetOffset("AttributeSet", false);
@@ -34,6 +45,8 @@ public:
void UnequipGadgetData(AFortPlayerController* PlayerController, UFortItem* Item); void UnequipGadgetData(AFortPlayerController* PlayerController, UFortItem* Item);
static void UpdateTrackedAttributesHook(UFortGadgetItemDefinition* GadgetItemDefinition);
static UClass* StaticClass() static UClass* StaticClass()
{ {
static auto Class = FindObject<UClass>("/Script/FortniteGame.FortGadgetItemDefinition"); static auto Class = FindObject<UClass>("/Script/FortniteGame.FortGadgetItemDefinition");

View File

@@ -1,7 +1,15 @@
#include "FortGameplayAbilityAthena_PeriodicItemGrant.h" #include "FortGameplayAbilityAthena_PeriodicItemGrant.h"
void UFortGameplayAbilityAthena_PeriodicItemGrant::StopItemAwardTimersHook(UObject* Context, FFrame& Stack, void* Ret)
{
// (Milxnor) We need clear all the timers in ActiveTimers.
return StopItemAwardTimersOriginal(Context, Stack, Ret);
}
void UFortGameplayAbilityAthena_PeriodicItemGrant::StartItemAwardTimersHook(UObject* Context, FFrame& Stack, void* Ret) void UFortGameplayAbilityAthena_PeriodicItemGrant::StartItemAwardTimersHook(UObject* Context, FFrame& Stack, void* Ret)
{ {
LOG_INFO(LogDev, "StartItemAwardTimersHook!"); // (Milxnor) We need to loop through ItemsToGrant, and then using the Pair.Value we set a timer and then the Pair.Key for the item to grant, then we add the timer to ActiveTimers.
return StartItemAwardTimersOriginal(Context, Stack, Ret); return StartItemAwardTimersOriginal(Context, Stack, Ret);
} }

View File

@@ -38,6 +38,7 @@ struct FActiveItemGrantInfo
class UFortGameplayAbilityAthena_PeriodicItemGrant : public UObject // UFortGameplayAbility class UFortGameplayAbilityAthena_PeriodicItemGrant : public UObject // UFortGameplayAbility
{ {
public: public:
static inline void (*StopItemAwardTimersOriginal)(UObject* Context, FFrame& Stack, void* Ret);
static inline void (*StartItemAwardTimersOriginal)(UObject* Context, FFrame& Stack, void* Ret); static inline void (*StartItemAwardTimersOriginal)(UObject* Context, FFrame& Stack, void* Ret);
TMap<FActiveItemGrantInfo, FScalableFloat>& GetItemsToGrant() TMap<FActiveItemGrantInfo, FScalableFloat>& GetItemsToGrant()
@@ -52,5 +53,6 @@ public:
return Get<TArray<FTimerHandle>>(ActiveTimersOffset); return Get<TArray<FTimerHandle>>(ActiveTimersOffset);
} }
static void StopItemAwardTimersHook(UObject* Context, FFrame& Stack, void* Ret);
static void StartItemAwardTimersHook(UObject* Context, FFrame& Stack, void* Ret); static void StartItemAwardTimersHook(UObject* Context, FFrame& Stack, void* Ret);
}; };

View File

@@ -146,7 +146,8 @@ std::pair<std::vector<UFortItem*>, std::vector<UFortItem*>> AFortInventory::AddI
if (FortPlayerController && WorldItemDefinition->IsValidLowLevel()) if (FortPlayerController && WorldItemDefinition->IsValidLowLevel())
{ {
bool AreGadgetsEnabled = Addresses::ApplyGadgetData && Addresses::RemoveGadgetData && Globals::bEnableAGIDs; bool AreGadgetsEnabled = Addresses::ApplyGadgetData && Addresses::RemoveGadgetData && Globals::bEnableAGIDs;
bool bWasGadget = false;
if (AreGadgetsEnabled) if (AreGadgetsEnabled)
{ {
if (auto GadgetItemDefinition = Cast<UFortGadgetItemDefinition>(WorldItemDefinition)) if (auto GadgetItemDefinition = Cast<UFortGadgetItemDefinition>(WorldItemDefinition))
@@ -156,10 +157,14 @@ std::pair<std::vector<UFortItem*>, std::vector<UFortItem*>> AFortInventory::AddI
FortPlayerController->DropAllItems({ GadgetItemDefinition }); FortPlayerController->DropAllItems({ GadgetItemDefinition });
} }
bool (*ApplyGadgetData)(UFortGadgetItemDefinition * a1, __int64 a2, UFortItem* a3, unsigned __int8 a4) = decltype(ApplyGadgetData)(Addresses::ApplyGadgetData); bool (*ApplyGadgetData)(UFortGadgetItemDefinition* a1, __int64 a2, UFortItem* a3, unsigned __int8 a4) = decltype(ApplyGadgetData)(Addresses::ApplyGadgetData);
static auto FortInventoryOwnerInterfaceClass = FindObject<UClass>("/Script/FortniteGame.FortInventoryOwnerInterface"); static auto FortInventoryOwnerInterfaceClass = FindObject<UClass>("/Script/FortniteGame.FortInventoryOwnerInterface");
auto Interface = __int64(FortPlayerController->GetInterfaceAddress(FortInventoryOwnerInterfaceClass)); auto Interface = __int64(FortPlayerController->GetInterfaceAddress(FortInventoryOwnerInterfaceClass));
LOG_INFO(LogDev, "Res: {}", ApplyGadgetData(GadgetItemDefinition, Interface, NewItemInstance, true)); bool idktbh = true; // Something to do with durability
bool DidApplyingGadgetSucceed = ApplyGadgetData(GadgetItemDefinition, Interface, NewItemInstance, idktbh);
LOG_INFO(LogDev, "DidApplyingGadgetSucceed: {}", DidApplyingGadgetSucceed);
bWasGadget = true;
if (Fortnite_Version < 7) if (Fortnite_Version < 7)
{ {
@@ -168,6 +173,7 @@ std::pair<std::vector<UFortItem*>, std::vector<UFortItem*>> AFortInventory::AddI
if (PickaxeInstance) if (PickaxeInstance)
{ {
RemoveItem(PickaxeInstance->GetItemEntry()->GetItemGuid(), nullptr, PickaxeInstance->GetItemEntry()->GetCount(), true); RemoveItem(PickaxeInstance->GetItemEntry()->GetItemGuid(), nullptr, PickaxeInstance->GetItemEntry()->GetCount(), true);
Update();
} }
} }
} }
@@ -177,6 +183,15 @@ std::pair<std::vector<UFortItem*>, std::vector<UFortItem*>> AFortInventory::AddI
{ {
LOG_INFO(LogDev, "Force focus {}", ItemDefinition->GetFullName()); LOG_INFO(LogDev, "Force focus {}", ItemDefinition->GetFullName());
FortPlayerController->ServerExecuteInventoryItemHook(FortPlayerController, NewItemInstance->GetItemEntry()->GetItemGuid()); FortPlayerController->ServerExecuteInventoryItemHook(FortPlayerController, NewItemInstance->GetItemEntry()->GetItemGuid());
FortPlayerController->ClientEquipItem(NewItemInstance->GetItemEntry()->GetItemGuid(), true);
}
if (bWasGadget)
{
if (Fortnite_Version < 7)
{
// FortPlayerController->AddPickaxeToInventory();
}
} }
} }
else else
@@ -325,32 +340,26 @@ bool AFortInventory::RemoveItem(const FGuid& ItemGuid, bool* bShouldUpdate, int
auto FortPlayerController = Cast<AFortPlayerController>(GetOwner()); auto FortPlayerController = Cast<AFortPlayerController>(GetOwner());
bool bWasGadget = false;
for (int i = 0; i < ItemInstances.Num(); i++) for (int i = 0; i < ItemInstances.Num(); i++)
{ {
if (ItemInstances.at(i)->GetItemEntry()->GetItemGuid() == ItemGuid) if (ItemInstances.at(i)->GetItemEntry()->GetItemGuid() == ItemGuid)
{ {
bool AreGadgetsEnabled = Addresses::ApplyGadgetData && Addresses::RemoveGadgetData && Globals::bEnableAGIDs; bool AreGadgetsEnabled = Addresses::ApplyGadgetData && Addresses::RemoveGadgetData && Globals::bEnableAGIDs;
if (AreGadgetsEnabled) if (FortPlayerController && AreGadgetsEnabled)
{ {
if (auto GadgetItemDefinition = Cast<UFortGadgetItemDefinition>(ItemDefinition)) if (auto GadgetItemDefinition = Cast<UFortGadgetItemDefinition>(ItemDefinition))
{ {
LOG_INFO(LogDev, "Unequipping Gadget!"); LOG_INFO(LogDev, "Unequipping Gadget!");
GadgetItemDefinition->UnequipGadgetData(FortPlayerController, ItemInstances.at(i)); GadgetItemDefinition->UnequipGadgetData(FortPlayerController, ItemInstances.at(i));
bWasGadget = true;
if (Fortnite_Version < 7) if (Fortnite_Version < 7)
{ {
auto CosmeticLoadout = FortPlayerController->GetCosmeticLoadout(); FortPlayerController->AddPickaxeToInventory();
// LOG_INFO(LogDev, "CosmeticLoadout: {}", __int64(CosmeticLoadout));
auto CosmeticLoadoutPickaxe = CosmeticLoadout ? CosmeticLoadout->GetPickaxe() : nullptr;
// LOG_INFO(LogDev, "CosmeticLoadoutPickaxe: {}", __int64(CosmeticLoadoutPickaxe));
// LOG_INFO(LogDev, "CosmeticLoadoutPickaxe Name: {}", CosmeticLoadoutPickaxe ? CosmeticLoadoutPickaxe->GetFullName() : "InvalidObject");
static auto WeaponDefinitionOffset = FindOffsetStruct("/Script/FortniteGame.AthenaPickaxeItemDefinition", "WeaponDefinition");
auto PickaxeDefinition = CosmeticLoadoutPickaxe ? CosmeticLoadoutPickaxe->Get<UFortItemDefinition*>(WeaponDefinitionOffset)
: FindObject<UFortItemDefinition>(L"/Game/Athena/Items/Weapons/WID_Harvest_Pickaxe_Athena_C_T01.WID_Harvest_Pickaxe_Athena_C_T01");
this->AddItem(PickaxeDefinition, nullptr);
} }
} }
} }

View File

@@ -394,27 +394,6 @@ void UFortKismetLibrary::K2_GiveBuildingResourceHook(UObject* Context, FFrame& S
return K2_GiveBuildingResourceOriginal(Context, Stack, Ret); return K2_GiveBuildingResourceOriginal(Context, Stack, Ret);
} }
int UFortKismetLibrary::K2_RemoveFortItemFromPlayerHook1(AFortPlayerController* PlayerController, UFortItem* Item, int AmountToRemove, bool bForceRemoval)
{
LOG_INFO(LogDev, "K2_RemoveFortItemFromPlayerHookNative!");
if (!PlayerController || !Item)
return 0;
auto WorldInventory = PlayerController->GetWorldInventory();
if (!WorldInventory)
return 0;
bool bShouldUpdate = false;
WorldInventory->RemoveItem(Item->GetItemEntry()->GetItemGuid(), &bShouldUpdate, AmountToRemove, bForceRemoval);
if (bShouldUpdate)
WorldInventory->Update();
return 1; // idk probably how much we removed
}
void UFortKismetLibrary::K2_RemoveFortItemFromPlayerHook(UObject* Context, FFrame& Stack, void* Ret) void UFortKismetLibrary::K2_RemoveFortItemFromPlayerHook(UObject* Context, FFrame& Stack, void* Ret)
{ {
AFortPlayerController* PlayerController = nullptr; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) AFortPlayerController* PlayerController = nullptr; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic)

View File

@@ -95,7 +95,6 @@ public:
static void K2_RemoveItemFromPlayerByGuidHook(UObject* Context, FFrame& Stack, void* Ret); static void K2_RemoveItemFromPlayerByGuidHook(UObject* Context, FFrame& Stack, void* Ret);
static void K2_GiveItemToPlayerHook(UObject* Context, FFrame& Stack, void* Ret); static void K2_GiveItemToPlayerHook(UObject* Context, FFrame& Stack, void* Ret);
static void K2_GiveBuildingResourceHook(UObject* Context, FFrame& Stack, void* Ret); static void K2_GiveBuildingResourceHook(UObject* Context, FFrame& Stack, void* Ret);
static int K2_RemoveFortItemFromPlayerHook1(AFortPlayerController* PlayerController, UFortItem* Item, int AmountToRemove, bool bForceRemoval);
static void K2_RemoveFortItemFromPlayerHook(UObject* Context, FFrame& Stack, void* Ret); static void K2_RemoveFortItemFromPlayerHook(UObject* Context, FFrame& Stack, void* Ret);
static AFortPickup* K2_SpawnPickupInWorldHook(UObject* Context, FFrame& Stack, AFortPickup** Ret); static AFortPickup* K2_SpawnPickupInWorldHook(UObject* Context, FFrame& Stack, AFortPickup** Ret);
static AFortPickup* K2_SpawnPickupInWorldWithClassHook(UObject* Context, FFrame& Stack, AFortPickup** Ret); static AFortPickup* K2_SpawnPickupInWorldWithClassHook(UObject* Context, FFrame& Stack, AFortPickup** Ret);

View File

@@ -62,23 +62,13 @@ AFortPickup* AFortPickup::SpawnPickup(FFortItemEntry* ItemEntry, FVector Locatio
} }
else else
{ {
auto OldGuid = PrimaryPickupItemEntry->GetItemGuid(); PrimaryPickupItemEntry->CopyFromAnotherItemEntry(ItemEntry);
if (false)
{
CopyStruct(PrimaryPickupItemEntry, ItemEntry, FFortItemEntry::GetStructSize(), FFortItemEntry::GetStruct());
}
else
{
PrimaryPickupItemEntry->GetItemDefinition() = ItemEntry->GetItemDefinition();
PrimaryPickupItemEntry->GetLoadedAmmo() = ItemEntry->GetLoadedAmmo();
}
} }
static auto PickupSourceTypeFlagsOffset = Pickup->GetOffset("PickupSourceTypeFlags", false); static auto PickupSourceTypeFlagsOffset = Pickup->GetOffset("PickupSourceTypeFlags", false);
if (PickupSourceTypeFlagsOffset != -1) if (PickupSourceTypeFlagsOffset != -1)
Pickup->Get<int32>(PickupSourceTypeFlagsOffset) |= (int)PickupSource; Pickup->Get<int32>(PickupSourceTypeFlagsOffset) |= (int)PickupSource; // Assuming its the same enum on older versions.
PrimaryPickupItemEntry->GetCount() = OverrideCount == -1 ? ItemEntry->GetCount() : OverrideCount; PrimaryPickupItemEntry->GetCount() = OverrideCount == -1 ? ItemEntry->GetCount() : OverrideCount;
@@ -88,8 +78,50 @@ AFortPickup* AFortPickup::SpawnPickup(FFortItemEntry* ItemEntry, FVector Locatio
// static auto OptionalOwnerIDOffset = Pickup->GetOffset("OptionalOwnerID"); // static auto OptionalOwnerIDOffset = Pickup->GetOffset("OptionalOwnerID");
// Pickup->Get<int>(OptionalOwnerIDOffset) = PlayerState ? PlayerState->GetWorldPlayerId() : -1; // Pickup->Get<int>(OptionalOwnerIDOffset) = PlayerState ? PlayerState->GetWorldPlayerId() : -1;
auto PickupLocationData = Pickup->GetPickupLocationData();
Pickup->TossPickup(Location, Pawn, 0, bToss, PickupSource, SpawnSource); auto CanCombineWithPickup = [&](AActor* OtherPickupActor) -> bool
{
auto OtherPickup = (AFortPickup*)OtherPickupActor;
if (OtherPickup->GetPickupLocationData()->GetCombineTarget())
return false;
if (PrimaryPickupItemEntry->GetItemDefinition() == OtherPickup->GetPrimaryPickupItemEntry()->GetItemDefinition())
{
auto IncomingCount = OtherPickup->GetPrimaryPickupItemEntry()->GetCount();
if (PrimaryPickupItemEntry->GetCount() + IncomingCount > PrimaryPickupItemEntry->GetItemDefinition()->GetMaxStackSize())
return false;
return true;
}
return false;
};
if (Addresses::CombinePickupLea)
{
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.
{
Pickup->TossPickup(Location, Pawn, 0, bToss, PickupSource, SpawnSource);
}
else
{
Pickup->OnRep_PickupLocationData();
}
if (PickupSource == EFortPickupSourceTypeFlag::Container) // crashes if we do this then tosspickup if (PickupSource == EFortPickupSourceTypeFlag::Container) // crashes if we do this then tosspickup
{ {
@@ -126,6 +158,26 @@ AFortPickup* AFortPickup::SpawnPickup(UFortItemDefinition* ItemDef, FVector Loca
return Pickup; return Pickup;
} }
void AFortPickup::CombinePickupHook(AFortPickup* Pickup)
{
// LOG_INFO(LogDev, "CombinePickupHook!");
auto PickupToCombineInto = (AFortPickup*)Pickup->GetPickupLocationData()->GetCombineTarget();
if (!PickupToCombineInto->IsActorBeingDestroyed())
{
// TODO Add more checks
PickupToCombineInto->GetPrimaryPickupItemEntry()->GetCount() += Pickup->GetPrimaryPickupItemEntry()->GetCount();
PickupToCombineInto->OnRep_PrimaryPickupItemEntry();
PickupToCombineInto->ForceNetUpdate();
PickupToCombineInto->FlushNetDormancy();
Pickup->K2_DestroyActor();
}
}
char AFortPickup::CompletePickupAnimationHook(AFortPickup* Pickup) char AFortPickup::CompletePickupAnimationHook(AFortPickup* Pickup)
{ {
constexpr bool bTestPrinting = false; // we could just use our own logger but eh constexpr bool bTestPrinting = false; // we could just use our own logger but eh
@@ -355,18 +407,7 @@ char AFortPickup::CompletePickupAnimationHook(AFortPickup* Pickup)
if (bWasHoldingSameItemWhenSwap && NewSwappedItem != FGuid(-1, -1, -1, -1)) if (bWasHoldingSameItemWhenSwap && NewSwappedItem != FGuid(-1, -1, -1, -1))
{ {
static auto ClientEquipItemFn = FindObject<UFunction>("/Script/FortniteGame.FortPlayerControllerAthena.ClientEquipItem") ? FindObject<UFunction>("/Script/FortniteGame.FortPlayerControllerAthena.ClientEquipItem") : FindObject<UFunction>("/Script/FortniteGame.FortPlayerController.ClientEquipItem"); PlayerController->ClientEquipItem(NewSwappedItem, true);
if (ClientEquipItemFn)
{
struct
{
FGuid ItemGuid; // (ConstParm, Parm, ZeroConstructor, ReferenceParm, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic)
bool bForceExecution; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic)
} AFortPlayerController_ClientEquipItem_Params{ NewSwappedItem, true };
PlayerController->ProcessEvent(ClientEquipItemFn, &AFortPlayerController_ClientEquipItem_Params);
}
} }
return CompletePickupAnimationOriginal(Pickup); return CompletePickupAnimationOriginal(Pickup);

View File

@@ -49,12 +49,36 @@ struct FFortPickupLocationData
return *(AFortPawn**)(__int64(this) + ItemOwnerOffset); return *(AFortPawn**)(__int64(this) + ItemOwnerOffset);
} }
class AFortPickup*& GetCombineTarget()
{
static auto CombineTargetOffset = FindOffsetStruct("/Script/FortniteGame.FortPickupLocationData", "CombineTarget");
return *(AFortPickup**)(__int64(this) + CombineTargetOffset);
}
FVector& GetStartDirection() FVector& GetStartDirection()
{ {
static auto StartDirectionOffset = FindOffsetStruct("/Script/FortniteGame.FortPickupLocationData", "StartDirection"); static auto StartDirectionOffset = FindOffsetStruct("/Script/FortniteGame.FortPickupLocationData", "StartDirection");
return *(FVector*)(__int64(this) + StartDirectionOffset); return *(FVector*)(__int64(this) + StartDirectionOffset);
} }
FVector& GetFinalTossRestLocation()
{
static auto FinalTossRestLocationOffset = FindOffsetStruct("/Script/FortniteGame.FortPickupLocationData", "FinalTossRestLocation");
return *(FVector*)(__int64(this) + FinalTossRestLocationOffset);
}
FVector& GetLootInitialPosition()
{
static auto LootInitialPositionOffset = FindOffsetStruct("/Script/FortniteGame.FortPickupLocationData", "LootInitialPosition");
return *(FVector*)(__int64(this) + LootInitialPositionOffset);
}
FVector& GetLootFinalPosition()
{
static auto LootFinalPositionOffset = FindOffsetStruct("/Script/FortniteGame.FortPickupLocationData", "LootFinalPosition");
return *(FVector*)(__int64(this) + LootFinalPositionOffset);
}
FGuid& GetPickupGuid() FGuid& GetPickupGuid()
{ {
static auto PickupGuidOffset = FindOffsetStruct("/Script/FortniteGame.FortPickupLocationData", "PickupGuid"); static auto PickupGuidOffset = FindOffsetStruct("/Script/FortniteGame.FortPickupLocationData", "PickupGuid");
@@ -88,6 +112,12 @@ public:
return this->GetPtr<FFortItemEntry>(PrimaryPickupItemEntryOffset); return this->GetPtr<FFortItemEntry>(PrimaryPickupItemEntryOffset);
} }
void OnRep_PickupLocationData()
{
static auto OnRep_PickupLocationDataFn = FindObject<UFunction>(L"/Script/FortniteGame.FortPickup.OnRep_PickupLocationData");
this->ProcessEvent(OnRep_PickupLocationDataFn);
}
static AFortPickup* SpawnPickup(FFortItemEntry* ItemEntry, FVector Location, static AFortPickup* SpawnPickup(FFortItemEntry* ItemEntry, FVector Location,
EFortPickupSourceTypeFlag PickupSource = EFortPickupSourceTypeFlag::Other, EFortPickupSpawnSource SpawnSource = EFortPickupSpawnSource::Unset, 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);
@@ -96,6 +126,7 @@ public:
EFortPickupSourceTypeFlag PickupSource = EFortPickupSourceTypeFlag::Other, EFortPickupSpawnSource SpawnSource = EFortPickupSpawnSource::Unset, 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);
static void CombinePickupHook(AFortPickup* Pickup);
static char CompletePickupAnimationHook(AFortPickup* Pickup); static char CompletePickupAnimationHook(AFortPickup* Pickup);
static UClass* StaticClass(); static UClass* StaticClass();

View File

@@ -35,6 +35,22 @@ void AFortPlayerController::ClientReportDamagedResourceBuilding(ABuildingSMActor
this->ProcessEvent(fn, &AFortPlayerController_ClientReportDamagedResourceBuilding_Params); this->ProcessEvent(fn, &AFortPlayerController_ClientReportDamagedResourceBuilding_Params);
} }
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");
if (ClientEquipItemFn)
{
struct
{
FGuid ItemGuid; // (ConstParm, Parm, ZeroConstructor, ReferenceParm, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic)
bool bForceExecution; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic)
} AFortPlayerController_ClientEquipItem_Params{ ItemGuid, bForceExecution };
this->ProcessEvent(ClientEquipItemFn, &AFortPlayerController_ClientEquipItem_Params);
}
}
bool AFortPlayerController::DoesBuildFree() bool AFortPlayerController::DoesBuildFree()
{ {
if (Globals::bInfiniteMaterials) if (Globals::bInfiniteMaterials)
@@ -185,6 +201,10 @@ void AFortPlayerController::ApplyCosmeticLoadout()
} }
UFortKismetLibrary::StaticClass()->ProcessEvent(UpdatePlayerCustomCharacterPartsVisualizationFn, &PlayerStateAsFort); UFortKismetLibrary::StaticClass()->ProcessEvent(UpdatePlayerCustomCharacterPartsVisualizationFn, &PlayerStateAsFort);
PlayerStateAsFort->ForceNetUpdate();
PawnAsFort->ForceNetUpdate();
this->ForceNetUpdate();
} }
void AFortPlayerController::ServerLoadingScreenDroppedHook(UObject* Context, FFrame* Stack, void* Ret) void AFortPlayerController::ServerLoadingScreenDroppedHook(UObject* Context, FFrame* Stack, void* Ret)
@@ -879,6 +899,13 @@ void AFortPlayerController::ServerAttemptInventoryDropHook(AFortPlayerController
if (Count < 0 || !Pawn) if (Count < 0 || !Pawn)
return; return;
if (auto PlayerControllerAthena = Cast<AFortPlayerControllerAthena>(PlayerController))
{
if (PlayerControllerAthena->IsInGhostMode())
return;
}
auto WorldInventory = PlayerController->GetWorldInventory(); auto WorldInventory = PlayerController->GetWorldInventory();
auto ReplicatedEntry = WorldInventory->FindReplicatedEntry(ItemGuid); auto ReplicatedEntry = WorldInventory->FindReplicatedEntry(ItemGuid);

View File

@@ -87,6 +87,25 @@ public:
return CosmeticLoadout; return CosmeticLoadout;
} }
void AddPickaxeToInventory()
{
auto CosmeticLoadout = GetCosmeticLoadout();
auto CosmeticLoadoutPickaxe = CosmeticLoadout ? CosmeticLoadout->GetPickaxe() : nullptr;
static auto WeaponDefinitionOffset = FindOffsetStruct("/Script/FortniteGame.AthenaPickaxeItemDefinition", "WeaponDefinition");
auto PickaxeDefinition = CosmeticLoadoutPickaxe ? CosmeticLoadoutPickaxe->Get<UFortItemDefinition*>(WeaponDefinitionOffset)
: FindObject<UFortItemDefinition>(L"/Game/Athena/Items/Weapons/WID_Harvest_Pickaxe_Athena_C_T01.WID_Harvest_Pickaxe_Athena_C_T01");
auto WorldInventory = GetWorldInventory();
if (!WorldInventory || WorldInventory->GetPickaxeInstance())
return;
WorldInventory->AddItem(PickaxeDefinition, nullptr);
WorldInventory->Update();
}
bool& ShouldTryPickupSwap() bool& ShouldTryPickupSwap()
{ {
static auto bTryPickupSwapOffset = GetOffset("bTryPickupSwap"); static auto bTryPickupSwapOffset = GetOffset("bTryPickupSwap");
@@ -99,6 +118,8 @@ public:
return bTryPickupSwapOffset != -1; return bTryPickupSwapOffset != -1;
} }
void ClientEquipItem(const FGuid& ItemGuid, bool bForceExecution);
bool DoesBuildFree(); 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);
void ApplyCosmeticLoadout(); void ApplyCosmeticLoadout();

View File

@@ -14,7 +14,7 @@ void AFortPlayerControllerAthena::StartGhostModeHook(UObject* Context, FFrame* S
{ {
LOG_INFO(LogDev, __FUNCTION__); LOG_INFO(LogDev, __FUNCTION__);
auto Controller = (AFortPlayerControllerAthena*)Context; auto PlayerController = (AFortPlayerControllerAthena*)Context;
UFortWorldItemDefinition* ItemProvidingGhostMode = nullptr; UFortWorldItemDefinition* ItemProvidingGhostMode = nullptr;
@@ -26,11 +26,12 @@ void AFortPlayerControllerAthena::StartGhostModeHook(UObject* Context, FFrame* S
return StartGhostModeOriginal(Context, Stack, Ret); return StartGhostModeOriginal(Context, Stack, Ret);
} }
// if (!Controller->HasAuthority()) return StartGhostModeOriginal(Context, Stack, Ret); if (!PlayerController->HasAuthority()) // for real
return StartGhostModeOriginal(Context, Stack, Ret);
LOG_INFO(LogDev, "Attempting to give item {}", ItemProvidingGhostMode->IsValidLowLevel() ? ItemProvidingGhostMode->GetFullName() : "BadRead"); LOG_INFO(LogDev, "Attempting to give item {}", ItemProvidingGhostMode->IsValidLowLevel() ? ItemProvidingGhostMode->GetFullName() : "BadRead");
auto GhostModeRepData = Controller->GetGhostModeRepData(); auto GhostModeRepData = PlayerController->GetGhostModeRepData();
if (GhostModeRepData->IsInGhostMode()) if (GhostModeRepData->IsInGhostMode())
{ {
@@ -38,7 +39,7 @@ void AFortPlayerControllerAthena::StartGhostModeHook(UObject* Context, FFrame* S
return StartGhostModeOriginal(Context, Stack, Ret); return StartGhostModeOriginal(Context, Stack, Ret);
} }
auto WorldInventory = Controller->GetWorldInventory(); auto WorldInventory = PlayerController->GetWorldInventory();
if (!WorldInventory) if (!WorldInventory)
return StartGhostModeOriginal(Context, Stack, Ret); return StartGhostModeOriginal(Context, Stack, Ret);
@@ -53,7 +54,8 @@ void AFortPlayerControllerAthena::StartGhostModeHook(UObject* Context, FFrame* S
if (bShouldUpdate) if (bShouldUpdate)
WorldInventory->Update(); WorldInventory->Update();
Controller->ServerExecuteInventoryItemHook(Controller, GhostModeItemInstance->GetItemEntry()->GetItemGuid()); PlayerController->ServerExecuteInventoryItemHook(PlayerController, GhostModeItemInstance->GetItemEntry()->GetItemGuid());
PlayerController->ClientEquipItem(GhostModeItemInstance->GetItemEntry()->GetItemGuid(), true);
LOG_INFO(LogDev, "Finished!"); LOG_INFO(LogDev, "Finished!");
return StartGhostModeOriginal(Context, Stack, Ret); return StartGhostModeOriginal(Context, Stack, Ret);
@@ -65,25 +67,41 @@ void AFortPlayerControllerAthena::EndGhostModeHook(AFortPlayerControllerAthena*
LOG_INFO(LogDev, __FUNCTION__); LOG_INFO(LogDev, __FUNCTION__);
if (!PlayerController->HasAuthority()) // for real
return EndGhostModeOriginal(PlayerController);
auto WorldInventory = PlayerController->GetWorldInventory(); auto WorldInventory = PlayerController->GetWorldInventory();
if (!WorldInventory) if (!WorldInventory)
return EndGhostModeOriginal(PlayerController); return EndGhostModeOriginal(PlayerController);
auto GhostModeRepData = PlayerController->GetGhostModeRepData(); FGhostModeRepData* GhostModeRepData = PlayerController->GetGhostModeRepData();
UFortWorldItemDefinition* GhostModeItemDef = GhostModeRepData->GetGhostModeItemDef();
LOG_INFO(LogDev, "GhostModeItemDef: {}", GhostModeItemDef->IsValidLowLevel() ? GhostModeItemDef->GetFullName() : "BadRead");
if (!GhostModeItemDef) // bro IDFK
{
GhostModeItemDef = FindObject<UFortWorldItemDefinition>("/Game/Athena/Items/Gameplay/SpookyMist/AGID_SpookyMist.AGID_SpookyMist");
}
if (!GhostModeItemDef)
return EndGhostModeOriginal(PlayerController);
auto GhostModeItemDef = GhostModeRepData->GetGhostModeItemDef();
auto GhostModeItemInstance = WorldInventory->FindItemInstance(GhostModeItemDef); auto GhostModeItemInstance = WorldInventory->FindItemInstance(GhostModeItemDef);
if (GhostModeItemInstance) LOG_INFO(LogDev, "GhostModeItemInstance: {}", GhostModeItemInstance->IsValidLowLevel() ? GhostModeItemInstance->GetFullName() : "BadRead");
{
bool bShouldUpdate = false;
int Count = 1; // GhostModeItemInstance->GetItemEntry()->GetCount()
WorldInventory->RemoveItem(GhostModeItemInstance->GetItemEntry()->GetItemGuid(), &bShouldUpdate, Count);
if (bShouldUpdate) if (!GhostModeItemInstance)
WorldInventory->Update(); return EndGhostModeOriginal(PlayerController);
}
bool bShouldUpdate = false;
int Count = GhostModeItemInstance->GetItemEntry()->GetCount(); // 1
bool bForceRemoval = true; // false
WorldInventory->RemoveItem(GhostModeItemInstance->GetItemEntry()->GetItemGuid(), &bShouldUpdate, Count, bForceRemoval);
if (bShouldUpdate)
WorldInventory->Update();
return EndGhostModeOriginal(PlayerController); return EndGhostModeOriginal(PlayerController);
} }

View File

@@ -139,10 +139,24 @@ public:
FGhostModeRepData* GetGhostModeRepData() FGhostModeRepData* GetGhostModeRepData()
{ {
static auto GhostModeRepDataOffset = GetOffset("GhostModeRepData"); static auto GhostModeRepDataOffset = GetOffset("GhostModeRepData", false);
if (GhostModeRepDataOffset == -1)
return nullptr;
return GetPtr<FGhostModeRepData>(GhostModeRepDataOffset); return GetPtr<FGhostModeRepData>(GhostModeRepDataOffset);
} }
bool IsInGhostMode()
{
auto GhostModeRepData = GetGhostModeRepData();
if (!GhostModeRepData)
return false;
return GhostModeRepData->IsInGhostMode();
}
UAthenaMarkerComponent* GetMarkerComponent() UAthenaMarkerComponent* GetMarkerComponent()
{ {
static auto MarkerComponentOffset = GetOffset("MarkerComponent"); static auto MarkerComponentOffset = GetOffset("MarkerComponent");

View File

@@ -2,6 +2,7 @@
#include <memcury.h> #include <memcury.h>
#include "FortPlayerController.h" #include "FortPlayerController.h"
#include "FortGadgetItemDefinition.h" #include "FortGadgetItemDefinition.h"
#include "FortPlayerControllerAthena.h"
FFortAthenaLoadout* AFortPlayerPawn::GetCosmeticLoadout() FFortAthenaLoadout* AFortPlayerPawn::GetCosmeticLoadout()
{ {
@@ -273,6 +274,11 @@ void AFortPlayerPawn::ServerHandlePickupHook(AFortPlayerPawn* Pawn, AFortPickup*
return; return;
} }
auto PlayerControllerAthena = Cast<AFortPlayerControllerAthena>(Pawn->GetController());
if (PlayerControllerAthena && PlayerControllerAthena->IsInGhostMode())
return;
static auto IncomingPickupsOffset = Pawn->GetOffset("IncomingPickups"); static auto IncomingPickupsOffset = Pawn->GetOffset("IncomingPickups");
Pawn->Get<TArray<AFortPickup*>>(IncomingPickupsOffset).Add(Pickup); Pawn->Get<TArray<AFortPickup*>>(IncomingPickupsOffset).Add(Pickup);

View File

@@ -99,17 +99,9 @@ APawn* AGameModeBase::SpawnDefaultPawnForHook(AGameModeBase* GameMode, AControll
{ {
// TODO Check Playlist->bRequirePickaxeInStartingInventory // TODO Check Playlist->bRequirePickaxeInStartingInventory
auto CosmeticLoadout = NewPlayerAsAthena->GetCosmeticLoadoutOffset() != -1 ? NewPlayerAsAthena->GetCosmeticLoadout() : nullptr;
auto CosmeticLoadoutPickaxe = CosmeticLoadout ? CosmeticLoadout->GetPickaxe() : nullptr;
static auto WeaponDefinitionOffset = FindOffsetStruct("/Script/FortniteGame.AthenaPickaxeItemDefinition", "WeaponDefinition", false);
auto PickaxeDefinition = CosmeticLoadoutPickaxe ? CosmeticLoadoutPickaxe->Get<UFortItemDefinition*>(WeaponDefinitionOffset)
: FindObject<UFortItemDefinition>(L"/Game/Athena/Items/Weapons/WID_Harvest_Pickaxe_Athena_C_T01.WID_Harvest_Pickaxe_Athena_C_T01");
auto& StartingItems = ((AFortGameModeAthena*)GameMode)->GetStartingItems(); auto& StartingItems = ((AFortGameModeAthena*)GameMode)->GetStartingItems();
WorldInventory->AddItem(PickaxeDefinition, nullptr); NewPlayerAsAthena->AddPickaxeToInventory();
for (int i = 0; i < StartingItems.Num(); i++) for (int i = 0; i < StartingItems.Num(); i++)
{ {

View File

@@ -529,9 +529,6 @@
<ClInclude Include="BuildingTrap.h"> <ClInclude Include="BuildingTrap.h">
<Filter>FortniteGame\Source\FortniteGame\Public\Building</Filter> <Filter>FortniteGame\Source\FortniteGame\Public\Building</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="FortAthenaSupplyDrop.h">
<Filter>FortniteGame\Source\FortniteGame\Public\Building\GameplayActors</Filter>
</ClInclude>
<ClInclude Include="BuildingGameplayActor.h"> <ClInclude Include="BuildingGameplayActor.h">
<Filter>FortniteGame\Source\FortniteGame\Public\Building</Filter> <Filter>FortniteGame\Source\FortniteGame\Public\Building</Filter>
</ClInclude> </ClInclude>
@@ -842,6 +839,9 @@
<Filter>FortniteGame\Source\FortniteGame\Public\Mutators</Filter> <Filter>FortniteGame\Source\FortniteGame\Public\Mutators</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="discord.h" /> <ClInclude Include="discord.h" />
<ClInclude Include="FortAthenaSupplyDrop.h">
<Filter>FortniteGame\Source\FortniteGame\Public\Building</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Filter Include="Engine"> <Filter Include="Engine">
@@ -1081,6 +1081,9 @@
<Filter Include="Engine\Source\Runtime\Core\Private\GenericPlatform"> <Filter Include="Engine\Source\Runtime\Core\Private\GenericPlatform">
<UniqueIdentifier>{c04eb59f-e186-49a3-a145-1fd3dc1dcd3d}</UniqueIdentifier> <UniqueIdentifier>{c04eb59f-e186-49a3-a145-1fd3dc1dcd3d}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="Reboot\Private">
<UniqueIdentifier>{00ba0f86-7eef-4ffd-9a9d-47477e5193b2}</UniqueIdentifier>
</Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="UnrealEngine.cpp"> <None Include="UnrealEngine.cpp">

View File

@@ -279,6 +279,15 @@ void Addresses::FindAll()
LOG_INFO(LogDev, "Finding FreeArrayOfEntries"); LOG_INFO(LogDev, "Finding FreeArrayOfEntries");
Addresses::FreeArrayOfEntries = FindFreeArrayOfEntries(); Addresses::FreeArrayOfEntries = FindFreeArrayOfEntries();
LOG_INFO(LogDev, "Finding UpdateTrackedAttributesLea");
Addresses::UpdateTrackedAttributesLea = FindUpdateTrackedAttributesLea();
LOG_INFO(LogDev, "Finding CombinePickupLea");
Addresses::CombinePickupLea = FindCombinePickupLea();
LOG_INFO(LogDev, "Finding CreateBuildingActorCallForDeco");
Addresses::CreateBuildingActorCallForDeco = FindCreateBuildingActorCallForDeco();
LOG_INFO(LogDev, "Finished finding!"); LOG_INFO(LogDev, "Finished finding!");
} }
@@ -341,6 +350,9 @@ void Addresses::Print()
LOG_INFO(LogDev, "EnterAircraft: 0x{:x}", EnterAircraft - Base); LOG_INFO(LogDev, "EnterAircraft: 0x{:x}", EnterAircraft - Base);
LOG_INFO(LogDev, "SetTimer: 0x{:x}", SetTimer - Base); LOG_INFO(LogDev, "SetTimer: 0x{:x}", SetTimer - Base);
LOG_INFO(LogDev, "PickupInitialize: 0x{:x}", PickupInitialize - Base); LOG_INFO(LogDev, "PickupInitialize: 0x{:x}", PickupInitialize - Base);
LOG_INFO(LogDev, "UpdateTrackedAttributesLea: 0x{:x}", UpdateTrackedAttributesLea - Base);
LOG_INFO(LogDev, "CombinePickupLea: 0x{:x}", CombinePickupLea - Base);
LOG_INFO(LogDev, "CreateBuildingActorCallForDeco: 0x{:x}", CreateBuildingActorCallForDeco - Base);
} }
void Offsets::FindAll() void Offsets::FindAll()

View File

@@ -65,6 +65,9 @@ namespace Addresses
extern inline uint64 PickupInitialize = 0; extern inline uint64 PickupInitialize = 0;
extern inline uint64 FreeEntry = 0; extern inline uint64 FreeEntry = 0;
extern inline uint64 FreeArrayOfEntries = 0; extern inline uint64 FreeArrayOfEntries = 0;
extern inline uint64 UpdateTrackedAttributesLea = 0;
extern inline uint64 CombinePickupLea = 0;
extern inline uint64 CreateBuildingActorCallForDeco = 0;
void SetupVersion(); // Finds Engine Version void SetupVersion(); // Finds Engine Version
void FindAll(); void FindAll();

View File

@@ -426,6 +426,9 @@ DWORD WINAPI Main(LPVOID)
nullptr, false); nullptr, false);
} }
HookInstruction(Addresses::UpdateTrackedAttributesLea, (PVOID)UFortGadgetItemDefinition::UpdateTrackedAttributesHook, "/Script/FortniteGame.FortPlayerController.Suicide", ERelativeOffsets::LEA, FortPlayerControllerAthenaDefault);
HookInstruction(Addresses::CombinePickupLea, (PVOID)AFortPickup::CombinePickupHook, "/Script/Engine.PlayerController.SetVirtualJoystickVisibility", ERelativeOffsets::LEA, FortPlayerControllerAthenaDefault);
Hooking::MinHook::Hook(FortWeaponDefault, FindObject<UFunction>(L"/Script/FortniteGame.FortWeapon.ServerReleaseWeaponAbility"), Hooking::MinHook::Hook(FortWeaponDefault, FindObject<UFunction>(L"/Script/FortniteGame.FortWeapon.ServerReleaseWeaponAbility"),
AFortWeapon::ServerReleaseWeaponAbilityHook, (PVOID*)&AFortWeapon::ServerReleaseWeaponAbilityOriginal, false, true); AFortWeapon::ServerReleaseWeaponAbilityHook, (PVOID*)&AFortWeapon::ServerReleaseWeaponAbilityOriginal, false, true);
@@ -489,13 +492,33 @@ DWORD WINAPI Main(LPVOID)
AFortPlayerControllerAthena::ServerReadyToStartMatchHook, (PVOID*)&AFortPlayerControllerAthena::ServerReadyToStartMatchOriginal, false); AFortPlayerControllerAthena::ServerReadyToStartMatchHook, (PVOID*)&AFortPlayerControllerAthena::ServerReadyToStartMatchOriginal, false);
Hooking::MinHook::Hook(FortPlayerControllerAthenaDefault, FindObject<UFunction>(L"/Script/FortniteGame.FortPlayerControllerZone.ServerRequestSeatChange"), Hooking::MinHook::Hook(FortPlayerControllerAthenaDefault, FindObject<UFunction>(L"/Script/FortniteGame.FortPlayerControllerZone.ServerRequestSeatChange"),
AFortPlayerControllerAthena::ServerRequestSeatChangeHook, (PVOID*)&AFortPlayerControllerAthena::ServerRequestSeatChangeOriginal, false); AFortPlayerControllerAthena::ServerRequestSeatChangeHook, (PVOID*)&AFortPlayerControllerAthena::ServerRequestSeatChangeOriginal, false);
if (false) if (false)
{ {
Hooking::MinHook::Hook(FortPlayerControllerAthenaDefault, FindObject<UFunction>(L"/Script/FortniteGame.FortPlayerControllerGameplay.StartGhostMode"), // (Milxnor) TODO: This changes to a component in later seasons. Hooking::MinHook::Hook(FortPlayerControllerAthenaDefault, FindObject<UFunction>(L"/Script/FortniteGame.FortPlayerControllerGameplay.StartGhostMode"), // (Milxnor) TODO: This changes to a component in later seasons.
AFortPlayerControllerAthena::StartGhostModeHook, (PVOID*)&AFortPlayerControllerAthena::StartGhostModeOriginal, false, true); AFortPlayerControllerAthena::StartGhostModeHook, (PVOID*)&AFortPlayerControllerAthena::StartGhostModeOriginal, false, true); // We can exec hook since it only gets called via blueprint.
Hooking::MinHook::Hook(FortPlayerControllerAthenaDefault, FindObject<UFunction>(L"/Script/FortniteGame.FortPlayerControllerGameplay.EndGhostMode"),
AFortPlayerControllerAthena::EndGhostModeHook, (PVOID*)&AFortPlayerControllerAthena::EndGhostModeOriginal, false); auto EndGhostModeFn = FindObject<UFunction>(L"/Script/FortniteGame.FortPlayerControllerGameplay.EndGhostMode");
if (EndGhostModeFn)
{
auto EndGhostModeExec = (uint64)EndGhostModeFn->GetFunc();
for (int i = 0; i < 400; i++)
{
if (*(uint8_t*)(EndGhostModeExec + i) == 0xE9 // thanks 6.21
|| *(uint8_t*)(EndGhostModeExec + i) == 0xE8)
{
Hooking::MinHook::Hook((PVOID)Memcury::Scanner(EndGhostModeExec + i).RelativeOffset(1).Get(), AFortPlayerControllerAthena::EndGhostModeHook, (PVOID*)&AFortPlayerControllerAthena::EndGhostModeOriginal);
break;
}
}
// Hooking::MinHook::Hook(FortPlayerControllerAthenaDefault, FindObject<UFunction>(L"/Script/FortniteGame.FortPlayerControllerGameplay.EndGhostMode"),
// AFortPlayerControllerAthena::EndGhostModeHook, (PVOID*)&AFortPlayerControllerAthena::EndGhostModeOriginal, false);
}
} }
Hooking::MinHook::Hook(FortPlayerControllerAthenaDefault, FindObject<UFunction>(L"/Script/FortniteGame.FortPlayerControllerAthena.ServerGiveCreativeItem"), Hooking::MinHook::Hook(FortPlayerControllerAthenaDefault, FindObject<UFunction>(L"/Script/FortniteGame.FortPlayerControllerAthena.ServerGiveCreativeItem"),
AFortPlayerControllerAthena::ServerGiveCreativeItemHook, nullptr, true); AFortPlayerControllerAthena::ServerGiveCreativeItemHook, nullptr, true);
@@ -526,18 +549,15 @@ DWORD WINAPI Main(LPVOID)
AFortPlayerPawn::ServerSendZiplineStateHook, nullptr, false); AFortPlayerPawn::ServerSendZiplineStateHook, nullptr, false);
Hooking::MinHook::Hook((PVOID)GetFunctionIdxOrPtr(FindObject<UFunction>(L"/Script/FortniteGame.FortPlayerPawn.ServerOnExitVehicle"), true), AFortPlayerPawn::ServerOnExitVehicleHook, (PVOID*)&AFortPlayerPawn::ServerOnExitVehicleOriginal); Hooking::MinHook::Hook((PVOID)GetFunctionIdxOrPtr(FindObject<UFunction>(L"/Script/FortniteGame.FortPlayerPawn.ServerOnExitVehicle"), true), AFortPlayerPawn::ServerOnExitVehicleHook, (PVOID*)&AFortPlayerPawn::ServerOnExitVehicleOriginal);
bool bNativeHookRemoveFortItemFromPlayer = false;
if (bNativeHookRemoveFortItemFromPlayer)
{
Hooking::MinHook::Hook(FortKismetLibraryDefault, FindObject<UFunction>(L"/Script/FortniteGame.FortKismetLibrary.K2_RemoveFortItemFromPlayer"),
UFortKismetLibrary::K2_RemoveFortItemFromPlayerHook1, nullptr, false);
}
static auto FortGameplayAbilityAthena_PeriodicItemGrantDefault = FindObject<UFortGameplayAbilityAthena_PeriodicItemGrant>("/Script/FortniteGame.Default__FortGameplayAbilityAthena_PeriodicItemGrant"); static auto FortGameplayAbilityAthena_PeriodicItemGrantDefault = FindObject<UFortGameplayAbilityAthena_PeriodicItemGrant>("/Script/FortniteGame.Default__FortGameplayAbilityAthena_PeriodicItemGrant");
Hooking::MinHook::Hook(FortGameplayAbilityAthena_PeriodicItemGrantDefault, FindObject<UFunction>(L"/Script/FortniteGame.FortGameplayAbilityAthena_PeriodicItemGrant.StartItemAwardTimers"), if (FortGameplayAbilityAthena_PeriodicItemGrantDefault)
UFortGameplayAbilityAthena_PeriodicItemGrant::StartItemAwardTimersHook, (PVOID*)&UFortGameplayAbilityAthena_PeriodicItemGrant::StartItemAwardTimersOriginal, false, true); {
Hooking::MinHook::Hook(FortGameplayAbilityAthena_PeriodicItemGrantDefault, FindObject<UFunction>(L"/Script/FortniteGame.FortGameplayAbilityAthena_PeriodicItemGrant.StopItemAwardTimers"),
UFortGameplayAbilityAthena_PeriodicItemGrant::StopItemAwardTimersHook, (PVOID*)&UFortGameplayAbilityAthena_PeriodicItemGrant::StopItemAwardTimersOriginal, false, true);
Hooking::MinHook::Hook(FortGameplayAbilityAthena_PeriodicItemGrantDefault, FindObject<UFunction>(L"/Script/FortniteGame.FortGameplayAbilityAthena_PeriodicItemGrant.StartItemAwardTimers"),
UFortGameplayAbilityAthena_PeriodicItemGrant::StartItemAwardTimersHook, (PVOID*)&UFortGameplayAbilityAthena_PeriodicItemGrant::StartItemAwardTimersOriginal, false, true);
}
Hooking::MinHook::Hook(FindObject<AFortAthenaMutator_Barrier>(L"/Script/FortniteGame.Default__FortAthenaMutator_Barrier"), FindObject<UFunction>(L"/Script/FortniteGame.FortAthenaMutator_Barrier.OnGamePhaseStepChanged"), Hooking::MinHook::Hook(FindObject<AFortAthenaMutator_Barrier>(L"/Script/FortniteGame.Default__FortAthenaMutator_Barrier"), FindObject<UFunction>(L"/Script/FortniteGame.FortAthenaMutator_Barrier.OnGamePhaseStepChanged"),
AFortAthenaMutator_Barrier::OnGamePhaseStepChangedHook, (PVOID*)&AFortAthenaMutator_Barrier::OnGamePhaseStepChangedOriginal, false, true); AFortAthenaMutator_Barrier::OnGamePhaseStepChangedHook, (PVOID*)&AFortAthenaMutator_Barrier::OnGamePhaseStepChangedOriginal, false, true);
@@ -564,12 +584,8 @@ DWORD WINAPI Main(LPVOID)
Hooking::MinHook::Hook(FortPlayerPawnAthenaDefault, FindObject<UFunction>(L"/Script/FortniteGame.FortPlayerPawnAthena.OnCapsuleBeginOverlap") ? FindObject<UFunction>(L"/Script/FortniteGame.FortPlayerPawnAthena.OnCapsuleBeginOverlap") : FindObject<UFunction>(L"/Script/FortniteGame.FortPlayerPawn.OnCapsuleBeginOverlap"), Hooking::MinHook::Hook(FortPlayerPawnAthenaDefault, FindObject<UFunction>(L"/Script/FortniteGame.FortPlayerPawnAthena.OnCapsuleBeginOverlap") ? FindObject<UFunction>(L"/Script/FortniteGame.FortPlayerPawnAthena.OnCapsuleBeginOverlap") : FindObject<UFunction>(L"/Script/FortniteGame.FortPlayerPawn.OnCapsuleBeginOverlap"),
AFortPlayerPawnAthena::OnCapsuleBeginOverlapHook, (PVOID*)&AFortPlayerPawnAthena::OnCapsuleBeginOverlapOriginal, false, true); AFortPlayerPawnAthena::OnCapsuleBeginOverlapHook, (PVOID*)&AFortPlayerPawnAthena::OnCapsuleBeginOverlapOriginal, false, true);
if (!bNativeHookRemoveFortItemFromPlayer) Hooking::MinHook::Hook(FortKismetLibraryDefault, FindObject<UFunction>(L"/Script/FortniteGame.FortKismetLibrary.K2_RemoveFortItemFromPlayer"),
{ UFortKismetLibrary::K2_RemoveFortItemFromPlayerHook, (PVOID*)&UFortKismetLibrary::K2_RemoveFortItemFromPlayerOriginal, false, true);
Hooking::MinHook::Hook(FortKismetLibraryDefault, FindObject<UFunction>(L"/Script/FortniteGame.FortKismetLibrary.K2_RemoveFortItemFromPlayer"),
UFortKismetLibrary::K2_RemoveFortItemFromPlayerHook, (PVOID*)&UFortKismetLibrary::K2_RemoveFortItemFromPlayerOriginal, false, true);
}
Hooking::MinHook::Hook(FortKismetLibraryDefault, FindObject<UFunction>(L"/Script/FortniteGame.FortKismetLibrary.K2_SpawnPickupInWorld"), Hooking::MinHook::Hook(FortKismetLibraryDefault, FindObject<UFunction>(L"/Script/FortniteGame.FortKismetLibrary.K2_SpawnPickupInWorld"),
UFortKismetLibrary::K2_SpawnPickupInWorldHook, (PVOID*)&UFortKismetLibrary::K2_SpawnPickupInWorldOriginal, false, true); UFortKismetLibrary::K2_SpawnPickupInWorldHook, (PVOID*)&UFortKismetLibrary::K2_SpawnPickupInWorldOriginal, false, true);
Hooking::MinHook::Hook(FortKismetLibraryDefault, FindObject<UFunction>(L"/Script/FortniteGame.FortKismetLibrary.K2_SpawnPickupInWorldWithLootTier"), Hooking::MinHook::Hook(FortKismetLibraryDefault, FindObject<UFunction>(L"/Script/FortniteGame.FortKismetLibrary.K2_SpawnPickupInWorldWithLootTier"),
@@ -765,7 +781,6 @@ DWORD WINAPI Main(LPVOID)
// if (Fortnite_Version > 1.8 || Fortnite_Version == 1.11) // if (Fortnite_Version > 1.8 || Fortnite_Version == 1.11)
{ {
auto ClientOnPawnDiedCallAddr = FindFunctionCall(L"ClientOnPawnDied", Engine_Version == 416 ? std::vector<uint8_t>{ 0x48, 0x89, 0x54 } : std::vector<uint8_t>{ 0x48, 0x89, 0x5C }); auto ClientOnPawnDiedCallAddr = FindFunctionCall(L"ClientOnPawnDied", Engine_Version == 416 ? std::vector<uint8_t>{ 0x48, 0x89, 0x54 } : std::vector<uint8_t>{ 0x48, 0x89, 0x5C });
LOG_INFO(LogDev, "ahh!");
LOG_INFO(LogDev, "ClientOnPawnDiedCallAddr: 0x{:x}", ClientOnPawnDiedCallAddr - __int64(GetModuleHandleW(0))); LOG_INFO(LogDev, "ClientOnPawnDiedCallAddr: 0x{:x}", ClientOnPawnDiedCallAddr - __int64(GetModuleHandleW(0)));
Hooking::MinHook::Hook((PVOID)ClientOnPawnDiedCallAddr, AFortPlayerController::ClientOnPawnDiedHook, (PVOID*)&AFortPlayerController::ClientOnPawnDiedOriginal); Hooking::MinHook::Hook((PVOID)ClientOnPawnDiedCallAddr, AFortPlayerController::ClientOnPawnDiedHook, (PVOID*)&AFortPlayerController::ClientOnPawnDiedOriginal);
} }

View File

@@ -551,6 +551,77 @@ static inline uint64 FindSpecConstructor()
return 0; return 0;
} }
static inline uint64 FindCreateBuildingActorCallForDeco() // kill me
{
auto Addrr = Memcury::Scanner::FindStringRef(L"ServerCreateBuildingAndSpawnDeco called without a valid DecoItemDef").Get(); // honestly L (we should get it from the ufunc not string)
if (!Addrr)
return 0;
for (int i = 0; i < 10000; i++)
{
if ((*(uint8_t*)(uint8_t*)(Addrr + i) == 0xC6 && *(uint8_t*)(uint8_t*)(Addrr + i + 6) == 0xE8)) // Checked 10.40
{
return Addrr - i + 6;
}
}
return 0;
}
static inline uint64 FindUpdateTrackedAttributesLea() // kill me
{
// 10.40 = (__int64(GetModuleHandleW(0)) + 0x19E19A5)
// So we keep going until we find a lea with nullsub..
uint64 ApplyGadgetAttributesAddr = 0;
if (!ApplyGadgetAttributesAddr)
return 0;
for (int i = 0; i < 10000; i++)
{
if ((*(uint8_t*)(uint8_t*)(ApplyGadgetAttributesAddr + i) == 0x48 && *(uint8_t*)(uint8_t*)(ApplyGadgetAttributesAddr + i + 1) == 0x8D
&& *(uint8_t*)(uint8_t*)(ApplyGadgetAttributesAddr + i + 2) == 0x05))
{
auto loadAddress = Memcury::Scanner(ApplyGadgetAttributesAddr + i).RelativeOffset(3).Get();
if (IsNullSub(loadAddress)) // Safety
return ApplyGadgetAttributesAddr + i;
}
}
return 0;
}
static inline uint64 FindCombinePickupLea() // kill me
{
/* 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!
if (!SetupCombinePickupDelegatesAddr)
return 0;
for (int i = 0; i < 1000; i++)
{
if (*(uint8_t*)(uint8_t*)(SetupCombinePickupDelegatesAddr + i) == 0x48 && *(uint8_t*)(uint8_t*)(SetupCombinePickupDelegatesAddr + i + 1) == 0x8D
&& *(uint8_t*)(uint8_t*)(SetupCombinePickupDelegatesAddr + i + 2) == 0x05) // Checked on 10.40, it was the first lea.
{
auto loadAddress = Memcury::Scanner(SetupCombinePickupDelegatesAddr + i).RelativeOffset(3).Get();
if (IsNullSub(loadAddress)) // Safety
return SetupCombinePickupDelegatesAddr + i;
}
}
return 0;
}
static inline uint64 FindCompletePickupAnimation() static inline uint64 FindCompletePickupAnimation()
{ {
if (Engine_Version == 416 || Engine_Version == 419) if (Engine_Version == 416 || Engine_Version == 419)
@@ -771,8 +842,43 @@ static inline uint64 FindFreeEntry()
return 0; return 0;
} }
static inline uint64 FindBeginningOfFuncEXP(uint64 Addr, int ToSearch = 1000)
{
for (int i = 0; i < ToSearch; i++)
{
if (Fortnite_Version >= 10)
{
if ((*(uint8_t*)(uint8_t*)(Addr - i) == 0x40 && *(uint8_t*)(uint8_t*)(Addr - i + 1) == 0x53))
{
return Addr - i;
}
}
if ((*(uint8_t*)(uint8_t*)(Addr - i) == 0x40 && *(uint8_t*)(uint8_t*)(Addr - i + 1) == 0x55))
{
return Addr - i;
}
if (*(uint8_t*)(uint8_t*)(Addr - i) == 0x48 && *(uint8_t*)(uint8_t*)(Addr - i + 1) == 0x89 && *(uint8_t*)(uint8_t*)(Addr - i + 2) == 0x5C)
{
return Addr - i;
}
/* if (*(uint8_t*)(uint8_t*)(Addr - i) == 0x48 && *(uint8_t*)(uint8_t*)(Addr - i + 1) == 0x8B && *(uint8_t*)(uint8_t*)(Addr - i + 2) == 0xC4)
{
return Addr - i;
} */
}
return 0;
}
static inline uint64 FindRemoveGadgetData() static inline uint64 FindRemoveGadgetData()
{ {
uint64 RemoveGadgetDataAddr = 0;
if (Engine_Version <= 423) if (Engine_Version <= 423)
{ {
auto Addr = Memcury::Scanner::FindStringRef(L"UFortGadgetItemDefinition::RemoveGadgetData - Removing Gadget Data for Gadget Item [%s]!", false).Get(); auto Addr = Memcury::Scanner::FindStringRef(L"UFortGadgetItemDefinition::RemoveGadgetData - Removing Gadget Data for Gadget Item [%s]!", false).Get();
@@ -781,56 +887,64 @@ static inline uint64 FindRemoveGadgetData()
Addr = Memcury::Scanner::FindStringRef(L"UFortGadgetItemDefinition::RemoveGadgetData - Removing Gadget Data for Gadet Item [%s]!", false).Get(); Addr = Memcury::Scanner::FindStringRef(L"UFortGadgetItemDefinition::RemoveGadgetData - Removing Gadget Data for Gadet Item [%s]!", false).Get();
if (!Addr) if (!Addr)
{
Addr = Memcury::Scanner::FindStringRef(L"UFortGadgetItemDefinition::RemoveGadgetData - Failed to get the Player Controller to cleanup Gadget Item [%s]!").Get(); Addr = Memcury::Scanner::FindStringRef(L"UFortGadgetItemDefinition::RemoveGadgetData - Failed to get the Player Controller to cleanup Gadget Item [%s]!").Get();
}
if (!Addr) if (!Addr)
return 0; return 0;
for (int i = 0; i < 1000; i++) RemoveGadgetDataAddr = FindBeginningOfFuncEXP(Addr);
{
if (Fortnite_Version >= 10)
{
if ((*(uint8_t*)(uint8_t*)(Addr - i) == 0x40 && *(uint8_t*)(uint8_t*)(Addr - i + 1) == 0x53))
{
return Addr - i;
}
}
if ((*(uint8_t*)(uint8_t*)(Addr - i) == 0x40 && *(uint8_t*)(uint8_t*)(Addr - i + 1) == 0x55))
{
return Addr - i;
}
if (*(uint8_t*)(uint8_t*)(Addr - i) == 0x48 && *(uint8_t*)(uint8_t*)(Addr - i + 1) == 0x89 && *(uint8_t*)(uint8_t*)(Addr - i + 2) == 0x5C)
{
return Addr - i;
}
/* if (*(uint8_t*)(uint8_t*)(Addr - i) == 0x48 && *(uint8_t*)(uint8_t*)(Addr - i + 1) == 0x8B && *(uint8_t*)(uint8_t*)(Addr - i + 2) == 0xC4)
{
return Addr - i;
} */
}
return 0;
// return FindBytes(StringRef, { 0x40, 0x55 }, 1000, 0, true);
} }
if (Engine_Version == 426) else if (Engine_Version == 426)
return Memcury::Scanner::FindPattern("48 85 D2 0F 84 ? ? ? ? 56 41 56 41 57 48 83 EC 30 48 8B 02 48").Get(); // 14.60 RemoveGadgetDataAddr = Memcury::Scanner::FindPattern("48 85 D2 0F 84 ? ? ? ? 56 41 56 41 57 48 83 EC 30 48 8B 02 48").Get(); // 14.60
LOG_INFO(LogDev, "RemoveGadgetData: 0x{:x}", RemoveGadgetDataAddr - __int64(GetModuleHandleW(0)));
return 0; if (!RemoveGadgetDataAddr)
return 0;
uint64 RemoveGadgetDataCall = Memcury::Scanner::FindPointerRef((PVOID)RemoveGadgetDataAddr, 0, false, false).Get();
if (!RemoveGadgetDataCall)
return RemoveGadgetDataAddr;
uint64 FortGadgetItemDefinition_RemoveGadgetDataAddr = FindBeginningOfFuncEXP(RemoveGadgetDataCall);
if (!FortGadgetItemDefinition_RemoveGadgetDataAddr)
return RemoveGadgetDataAddr;
uint64 FortGadgetItemDefinition_RemoveGadgetDataCall = Memcury::Scanner::FindPointerRef((PVOID)FortGadgetItemDefinition_RemoveGadgetDataAddr, 0, false, false).Get();
if (!FortGadgetItemDefinition_RemoveGadgetDataCall)
return FortGadgetItemDefinition_RemoveGadgetDataAddr;
uint64 AthenaGadgetItemDefinition_RemoveGadgetDataAddr = FindBeginningOfFuncEXP(FortGadgetItemDefinition_RemoveGadgetDataCall);
if (!AthenaGadgetItemDefinition_RemoveGadgetDataAddr)
return FortGadgetItemDefinition_RemoveGadgetDataAddr;
return AthenaGadgetItemDefinition_RemoveGadgetDataAddr;
} }
static inline uint64 FindApplyGadgetData() static inline uint64 FindApplyGadgetData()
{ {
if (Engine_Version >= 420 && Engine_Version <= 422) uint64 FortGadgetItemDefinition_ApplyGadgetDataAddr = 0;
return Memcury::Scanner::FindPattern("48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 48 83 EC 20 41 0F B6 D9 49 8B").Get(); // 4.1 & 6.21 & 7.40
if (Engine_Version >= 423 && Engine_Version <= 426)
return Memcury::Scanner::FindPattern("48 89 5C 24 ? 48 89 6C 24 ? 48 89 7C 24 ? 41 54 41 56 41 57 48 83 EC 20 41 0F").Get(); // 8.51 & 12.41
return 0; if (Engine_Version >= 420 && Engine_Version <= 422)
FortGadgetItemDefinition_ApplyGadgetDataAddr = Memcury::Scanner::FindPattern("48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 48 83 EC 20 41 0F B6 D9 49 8B").Get(); // 4.1 & 6.21 & 7.40
if (Engine_Version >= 423 && Engine_Version <= 426)
FortGadgetItemDefinition_ApplyGadgetDataAddr = Memcury::Scanner::FindPattern("48 89 5C 24 ? 48 89 6C 24 ? 48 89 7C 24 ? 41 54 41 56 41 57 48 83 EC 20 41 0F").Get(); // 8.51 & 12.41
uint64 FortGadgetItemDefinition_ApplyGadgetDataCall = Memcury::Scanner::FindPointerRef((PVOID)FortGadgetItemDefinition_ApplyGadgetDataAddr, 0, false, false).Get();
if (!FortGadgetItemDefinition_ApplyGadgetDataCall)
return FortGadgetItemDefinition_ApplyGadgetDataAddr;
auto AthenaGadgetItemDefinition_ApplyGadgetDataAddr = FindBeginningOfFuncEXP(FortGadgetItemDefinition_ApplyGadgetDataCall);
if (!AthenaGadgetItemDefinition_ApplyGadgetDataAddr)
return FortGadgetItemDefinition_ApplyGadgetDataAddr;
return AthenaGadgetItemDefinition_ApplyGadgetDataAddr;
} }
static inline uint64 FindGetInterfaceAddress() static inline uint64 FindGetInterfaceAddress()

View File

@@ -806,7 +806,6 @@ static inline void MainUI()
if (WeaponsFile.is_open()) if (WeaponsFile.is_open())
{ {
WeaponsFile << FortniteVersionStr; WeaponsFile << FortniteVersionStr;
static auto FortWeaponItemDefinitionClass = FindObject<UClass>("/Script/FortniteGame.FortWeaponItemDefinition");
auto DumpItemDefinitionClass = [&WeaponsFile](UClass* Class) { auto DumpItemDefinitionClass = [&WeaponsFile](UClass* Class) {
auto AllObjects = GetAllObjectsOfClass(Class); auto AllObjects = GetAllObjectsOfClass(Class);
@@ -831,6 +830,7 @@ static inline void MainUI()
DumpItemDefinitionClass(UFortWeaponItemDefinition::StaticClass()); DumpItemDefinitionClass(UFortWeaponItemDefinition::StaticClass());
DumpItemDefinitionClass(UFortGadgetItemDefinition::StaticClass()); DumpItemDefinitionClass(UFortGadgetItemDefinition::StaticClass());
DumpItemDefinitionClass(FindObject<UClass>("/Script/FortniteGame.FortAmmoItemDefinition"));
} }
else else
std::cout << "Failed to open playlist file!\n"; std::cout << "Failed to open playlist file!\n";

View File

@@ -338,4 +338,43 @@ namespace Hooking
*Addr = Original; *Addr = Original;
} */ } */
} }
}
static inline void ChangeBytesThing(uint8_t* instrAddr, uint8_t* DetourAddr, int Offset)
{
int64_t delta = DetourAddr - (instrAddr + Offset + 4);
*(int32_t*)(instrAddr + Offset) = static_cast<int32_t>(delta);
}
enum ERelativeOffsets
{
CALL = 1,
LEA = 3
};
static inline void HookInstruction(uint64 instrAddr, void* Detour, const std::string& FunctionToReplace, ERelativeOffsets Offset, UObject* DefaultClass = nullptr) // we need better name
{
if (!instrAddr)
return;
auto UFunc = FindObject<UFunction>(FunctionToReplace);
uint64 FunctionAddr = __int64(UFunc->GetFunc()); // GetFunctionIdxOrPtr(FindObject<UFunction>(FunctionToReplace));
if (IsBadReadPtr((void*)FunctionAddr))
{
auto Idx = FunctionAddr / 8;
FunctionAddr = (uint64)DefaultClass->VFTable[Idx];
}
if (__int64(instrAddr) - FunctionAddr < 0) // We do not want the FunctionAddr (detour) to be less than where we are replacing.
{
LOG_INFO(LogDev, "Hooking Instruction will not work! Function is after ({})!", FunctionToReplace);
return;
}
Hooking::MinHook::Hook((PVOID)FunctionAddr, Detour, nullptr, FunctionToReplace);
ChangeBytesThing((uint8_t*)instrAddr, (uint8_t*)FunctionAddr, (int)Offset);
} }

26
vendor/memcury.h vendored
View File

@@ -758,10 +758,13 @@
return Scanner(add); return Scanner(add);
} }
static auto FindPointerRef(void* Pointer, int useRefNum = 0, bool bUseFirstResult = false) -> Scanner // credit me and ender static auto FindPointerRef(void* Pointer, int useRefNum = 0, bool bUseFirstResult = false, bool bWarnIfNotFound = true) -> Scanner // credit me and ender
{ {
PE::Address add{ nullptr }; PE::Address add{ nullptr };
if (!Pointer)
return Scanner(add);
auto textSection = PE::Section::GetSection(".text"); auto textSection = PE::Section::GetSection(".text");
const auto scanBytes = reinterpret_cast<std::uint8_t*>(textSection.GetSectionStart().Get()); const auto scanBytes = reinterpret_cast<std::uint8_t*>(textSection.GetSectionStart().Get());
@@ -803,14 +806,17 @@
} }
} }
} }
if (add == 0) if (bWarnIfNotFound)
{ {
MessageBoxA(0, "FindPointerRef return nullptr", "Memcury", MB_OK); if (add == 0)
} {
else MessageBoxA(0, "FindPointerRef return nullptr", "Memcury", MB_OK);
{ }
// MessageBoxA(0, std::format("FindPointerRef return 0x{:x}", add.Get() - __int64(GetModuleHandleW(0))).c_str(), "Memcury", MB_OK); else
{
// MessageBoxA(0, std::format("FindPointerRef return 0x{:x}", add.Get() - __int64(GetModuleHandleW(0))).c_str(), "Memcury", MB_OK);
}
} }
return Scanner(add); return Scanner(add);
@@ -1423,4 +1429,6 @@
} */ } */
return PtrRef.ScanFor(Bytes, false).Get(); return PtrRef.ScanFor(Bytes, false).Get();
} }
inline bool IsNullSub(uint64 Addr) { return *(uint8_t*)(Addr) == 0xC3 || *(uint8_t*)(Addr) == 0xC2; }