diff --git a/Project Reboot 3.0/Actor.cpp b/Project Reboot 3.0/Actor.cpp index f415ef8..2d49522 100644 --- a/Project Reboot 3.0/Actor.cpp +++ b/Project Reboot 3.0/Actor.cpp @@ -3,6 +3,7 @@ #include "Transform.h" #include "reboot.h" +#include "GameplayStatics.h" bool AActor::HasAuthority() { @@ -210,6 +211,40 @@ void AActor::GetActorEyesViewPoint(FVector* OutLocation, FRotator* OutRotation) *OutRotation = AActor_GetActorEyesViewPoint_Params.OutRotation; } +AActor* AActor::GetClosestActor(UClass* ActorClass, float DistMax, std::function AdditionalCheck) +{ + float TargetDist = FLT_MAX; + AActor* TargetActor = nullptr; + + TArray 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() { static auto bAlwaysRelevantOffset = GetOffset("bAlwaysRelevant"); diff --git a/Project Reboot 3.0/Actor.h b/Project Reboot 3.0/Actor.h index a1af627..9d824de 100644 --- a/Project Reboot 3.0/Actor.h +++ b/Project Reboot 3.0/Actor.h @@ -49,7 +49,8 @@ public: float& GetMinNetUpdateFrequency(); const AActor* GetNetOwner() const; void GetActorEyesViewPoint(FVector* OutLocation, FRotator* OutRotation) const; - + AActor* GetClosestActor(UClass* ActorClass, float DistMax, std::function AdditionalCheck = [&](AActor*) { return true; }); + bool IsRelevancyOwnerFor(const AActor* ReplicatedActor, const AActor* ActorOwner, const AActor* ConnectionActor) const { // we should call virtual function but eh diff --git a/Project Reboot 3.0/AttributeSet.h b/Project Reboot 3.0/AttributeSet.h index 85b4bfb..720f627 100644 --- a/Project Reboot 3.0/AttributeSet.h +++ b/Project Reboot 3.0/AttributeSet.h @@ -1,6 +1,15 @@ #pragma once +#include "reboot.h" + class UAttributeSet : public UObject { public: +}; + +struct FGameplayAttribute +{ + FString AttributeName; + void* Attribute; + UStruct* AttributeOwner; }; \ No newline at end of file diff --git a/Project Reboot 3.0/FortAbilitySet.h b/Project Reboot 3.0/FortAbilitySet.h index 130d966..bfc6a0a 100644 --- a/Project Reboot 3.0/FortAbilitySet.h +++ b/Project Reboot 3.0/FortAbilitySet.h @@ -48,7 +48,7 @@ public: return this->GetPtr>(GrantedGameplayEffectsOffset); } - void ApplyGrantedGameplayAffectsToAbilitySystem(UAbilitySystemComponent* AbilitySystemComponent) + void ApplyGrantedGameplayAffectsToAbilitySystem(UAbilitySystemComponent* AbilitySystemComponent) // i dont think this is proper { if (!FGameplayEffectApplicationInfoHard::GetStruct()) return; diff --git a/Project Reboot 3.0/FortGadgetItemDefinition.cpp b/Project Reboot 3.0/FortGadgetItemDefinition.cpp index a6e8326..6b97e35 100644 --- a/Project Reboot 3.0/FortGadgetItemDefinition.cpp +++ b/Project Reboot 3.0/FortGadgetItemDefinition.cpp @@ -3,6 +3,8 @@ #include "SoftObjectPath.h" #include "FortPlayerStateAthena.h" #include "addresses.h" +#include "FortPlayerPawnAthena.h" +#include "FortPlayerControllerAthena.h" 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); RemoveGadgetDataOriginal(this, __int64(PlayerController->GetInterfaceAddress(FortInventoryOwnerInterfaceClass)), Item); - /* auto Pawn = PlayerController->GetMyFortPawn(); - - if (Pawn) + if (auto CosmeticLoadoutPC = PlayerController->GetCosmeticLoadout()) { - static auto OriginalFootstepBankOffset = Pawn->GetOffset("OriginalFootstepBank"); - 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>(AbilitySetOffset); - - auto StrongAbilitySet = AbilitySetSoft.Get(UFortAbilitySet::StaticClass(), true); - - if (StrongAbilitySet) - { - auto PlayerState = (AFortPlayerStateAthena*)PlayerController->GetPlayerState(); - auto ASC = PlayerState ? PlayerState->GetAbilitySystemComponent() : nullptr; - - if (ASC) + if (auto CharacterToApply = CosmeticLoadoutPC->GetCharacter()) { - if (FGameplayEffectApplicationInfoHard::GetStruct()) - { - 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()); - } - } - } + ApplyCID(Cast(PlayerController->GetMyFortPawn()), CharacterToApply); // idk why no automatic } } +} - PlayerController->ApplyCosmeticLoadout(); - */ +void UFortGadgetItemDefinition::UpdateTrackedAttributesHook(UFortGadgetItemDefinition* GadgetItemDefinition) +{ + // LOG_INFO(LogDev, "UpdateTrackedAttributesHook Return: 0x{:x}", __int64(_ReturnAddress()) - __int64(GetModuleHandleW(0))); + + if (GadgetItemDefinition->ShouldDestroyGadgetWhenTrackedAttributesIsZero()) + { + // PlayerState->MulticastTriggerOnGadgetTrackedAttributeDestroyedFX + } } \ No newline at end of file diff --git a/Project Reboot 3.0/FortGadgetItemDefinition.h b/Project Reboot 3.0/FortGadgetItemDefinition.h index 490f1bd..616adf5 100644 --- a/Project Reboot 3.0/FortGadgetItemDefinition.h +++ b/Project Reboot 3.0/FortGadgetItemDefinition.h @@ -19,6 +19,17 @@ public: 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() { static auto AttributeSetOffset = this->GetOffset("AttributeSet", false); @@ -34,6 +45,8 @@ public: void UnequipGadgetData(AFortPlayerController* PlayerController, UFortItem* Item); + static void UpdateTrackedAttributesHook(UFortGadgetItemDefinition* GadgetItemDefinition); + static UClass* StaticClass() { static auto Class = FindObject("/Script/FortniteGame.FortGadgetItemDefinition"); diff --git a/Project Reboot 3.0/FortGameplayAbilityAthena_PeriodicItemGrant.cpp b/Project Reboot 3.0/FortGameplayAbilityAthena_PeriodicItemGrant.cpp index 7a30a1a..3b88963 100644 --- a/Project Reboot 3.0/FortGameplayAbilityAthena_PeriodicItemGrant.cpp +++ b/Project Reboot 3.0/FortGameplayAbilityAthena_PeriodicItemGrant.cpp @@ -1,7 +1,15 @@ #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) { - 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); } \ No newline at end of file diff --git a/Project Reboot 3.0/FortGameplayAbilityAthena_PeriodicItemGrant.h b/Project Reboot 3.0/FortGameplayAbilityAthena_PeriodicItemGrant.h index 3282c9b..3c96196 100644 --- a/Project Reboot 3.0/FortGameplayAbilityAthena_PeriodicItemGrant.h +++ b/Project Reboot 3.0/FortGameplayAbilityAthena_PeriodicItemGrant.h @@ -38,6 +38,7 @@ struct FActiveItemGrantInfo class UFortGameplayAbilityAthena_PeriodicItemGrant : public UObject // UFortGameplayAbility { public: + static inline void (*StopItemAwardTimersOriginal)(UObject* Context, FFrame& Stack, void* Ret); static inline void (*StartItemAwardTimersOriginal)(UObject* Context, FFrame& Stack, void* Ret); TMap& GetItemsToGrant() @@ -52,5 +53,6 @@ public: return Get>(ActiveTimersOffset); } + static void StopItemAwardTimersHook(UObject* Context, FFrame& Stack, void* Ret); static void StartItemAwardTimersHook(UObject* Context, FFrame& Stack, void* Ret); }; \ No newline at end of file diff --git a/Project Reboot 3.0/FortInventory.cpp b/Project Reboot 3.0/FortInventory.cpp index 37a5214..475a0f9 100644 --- a/Project Reboot 3.0/FortInventory.cpp +++ b/Project Reboot 3.0/FortInventory.cpp @@ -146,7 +146,8 @@ std::pair, std::vector> AFortInventory::AddI if (FortPlayerController && WorldItemDefinition->IsValidLowLevel()) { bool AreGadgetsEnabled = Addresses::ApplyGadgetData && Addresses::RemoveGadgetData && Globals::bEnableAGIDs; - + bool bWasGadget = false; + if (AreGadgetsEnabled) { if (auto GadgetItemDefinition = Cast(WorldItemDefinition)) @@ -156,10 +157,14 @@ std::pair, std::vector> AFortInventory::AddI 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("/Script/FortniteGame.FortInventoryOwnerInterface"); 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) { @@ -168,6 +173,7 @@ std::pair, std::vector> AFortInventory::AddI if (PickaxeInstance) { RemoveItem(PickaxeInstance->GetItemEntry()->GetItemGuid(), nullptr, PickaxeInstance->GetItemEntry()->GetCount(), true); + Update(); } } } @@ -177,6 +183,15 @@ std::pair, std::vector> AFortInventory::AddI { LOG_INFO(LogDev, "Force focus {}", ItemDefinition->GetFullName()); FortPlayerController->ServerExecuteInventoryItemHook(FortPlayerController, NewItemInstance->GetItemEntry()->GetItemGuid()); + FortPlayerController->ClientEquipItem(NewItemInstance->GetItemEntry()->GetItemGuid(), true); + } + + if (bWasGadget) + { + if (Fortnite_Version < 7) + { + // FortPlayerController->AddPickaxeToInventory(); + } } } else @@ -325,32 +340,26 @@ bool AFortInventory::RemoveItem(const FGuid& ItemGuid, bool* bShouldUpdate, int auto FortPlayerController = Cast(GetOwner()); + bool bWasGadget = false; + for (int i = 0; i < ItemInstances.Num(); i++) { if (ItemInstances.at(i)->GetItemEntry()->GetItemGuid() == ItemGuid) { bool AreGadgetsEnabled = Addresses::ApplyGadgetData && Addresses::RemoveGadgetData && Globals::bEnableAGIDs; - if (AreGadgetsEnabled) + if (FortPlayerController && AreGadgetsEnabled) { if (auto GadgetItemDefinition = Cast(ItemDefinition)) { LOG_INFO(LogDev, "Unequipping Gadget!"); GadgetItemDefinition->UnequipGadgetData(FortPlayerController, ItemInstances.at(i)); + bWasGadget = true; + if (Fortnite_Version < 7) { - auto CosmeticLoadout = FortPlayerController->GetCosmeticLoadout(); - // 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(WeaponDefinitionOffset) - : FindObject(L"/Game/Athena/Items/Weapons/WID_Harvest_Pickaxe_Athena_C_T01.WID_Harvest_Pickaxe_Athena_C_T01"); - - this->AddItem(PickaxeDefinition, nullptr); + FortPlayerController->AddPickaxeToInventory(); } } } diff --git a/Project Reboot 3.0/FortKismetLibrary.cpp b/Project Reboot 3.0/FortKismetLibrary.cpp index 79c71de..5933086 100644 --- a/Project Reboot 3.0/FortKismetLibrary.cpp +++ b/Project Reboot 3.0/FortKismetLibrary.cpp @@ -394,27 +394,6 @@ void UFortKismetLibrary::K2_GiveBuildingResourceHook(UObject* Context, FFrame& S 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) { AFortPlayerController* PlayerController = nullptr; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) diff --git a/Project Reboot 3.0/FortKismetLibrary.h b/Project Reboot 3.0/FortKismetLibrary.h index 5de30cf..dfe1863 100644 --- a/Project Reboot 3.0/FortKismetLibrary.h +++ b/Project Reboot 3.0/FortKismetLibrary.h @@ -95,7 +95,6 @@ public: static void K2_RemoveItemFromPlayerByGuidHook(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 int K2_RemoveFortItemFromPlayerHook1(AFortPlayerController* PlayerController, UFortItem* Item, int AmountToRemove, bool bForceRemoval); static void K2_RemoveFortItemFromPlayerHook(UObject* Context, FFrame& Stack, void* Ret); static AFortPickup* K2_SpawnPickupInWorldHook(UObject* Context, FFrame& Stack, AFortPickup** Ret); static AFortPickup* K2_SpawnPickupInWorldWithClassHook(UObject* Context, FFrame& Stack, AFortPickup** Ret); diff --git a/Project Reboot 3.0/FortPickup.cpp b/Project Reboot 3.0/FortPickup.cpp index 3d16302..7f5c143 100644 --- a/Project Reboot 3.0/FortPickup.cpp +++ b/Project Reboot 3.0/FortPickup.cpp @@ -62,23 +62,13 @@ AFortPickup* AFortPickup::SpawnPickup(FFortItemEntry* ItemEntry, FVector Locatio } else { - auto OldGuid = PrimaryPickupItemEntry->GetItemGuid(); - - if (false) - { - CopyStruct(PrimaryPickupItemEntry, ItemEntry, FFortItemEntry::GetStructSize(), FFortItemEntry::GetStruct()); - } - else - { - PrimaryPickupItemEntry->GetItemDefinition() = ItemEntry->GetItemDefinition(); - PrimaryPickupItemEntry->GetLoadedAmmo() = ItemEntry->GetLoadedAmmo(); - } + PrimaryPickupItemEntry->CopyFromAnotherItemEntry(ItemEntry); } static auto PickupSourceTypeFlagsOffset = Pickup->GetOffset("PickupSourceTypeFlags", false); if (PickupSourceTypeFlagsOffset != -1) - Pickup->Get(PickupSourceTypeFlagsOffset) |= (int)PickupSource; + Pickup->Get(PickupSourceTypeFlagsOffset) |= (int)PickupSource; // Assuming its the same enum on older versions. PrimaryPickupItemEntry->GetCount() = OverrideCount == -1 ? ItemEntry->GetCount() : OverrideCount; @@ -88,8 +78,50 @@ AFortPickup* AFortPickup::SpawnPickup(FFortItemEntry* ItemEntry, FVector Locatio // static auto OptionalOwnerIDOffset = Pickup->GetOffset("OptionalOwnerID"); // Pickup->Get(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 { @@ -126,6 +158,26 @@ AFortPickup* AFortPickup::SpawnPickup(UFortItemDefinition* ItemDef, FVector Loca 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) { 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)) { - static auto ClientEquipItemFn = FindObject("/Script/FortniteGame.FortPlayerControllerAthena.ClientEquipItem") ? FindObject("/Script/FortniteGame.FortPlayerControllerAthena.ClientEquipItem") : FindObject("/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{ NewSwappedItem, true }; - - PlayerController->ProcessEvent(ClientEquipItemFn, &AFortPlayerController_ClientEquipItem_Params); - } + PlayerController->ClientEquipItem(NewSwappedItem, true); } return CompletePickupAnimationOriginal(Pickup); diff --git a/Project Reboot 3.0/FortPickup.h b/Project Reboot 3.0/FortPickup.h index cdf9ec1..ff9d11f 100644 --- a/Project Reboot 3.0/FortPickup.h +++ b/Project Reboot 3.0/FortPickup.h @@ -49,12 +49,36 @@ struct FFortPickupLocationData return *(AFortPawn**)(__int64(this) + ItemOwnerOffset); } + class AFortPickup*& GetCombineTarget() + { + static auto CombineTargetOffset = FindOffsetStruct("/Script/FortniteGame.FortPickupLocationData", "CombineTarget"); + return *(AFortPickup**)(__int64(this) + CombineTargetOffset); + } + FVector& GetStartDirection() { static auto StartDirectionOffset = FindOffsetStruct("/Script/FortniteGame.FortPickupLocationData", "StartDirection"); 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() { static auto PickupGuidOffset = FindOffsetStruct("/Script/FortniteGame.FortPickupLocationData", "PickupGuid"); @@ -88,6 +112,12 @@ public: return this->GetPtr(PrimaryPickupItemEntryOffset); } + void OnRep_PickupLocationData() + { + static auto OnRep_PickupLocationDataFn = FindObject(L"/Script/FortniteGame.FortPickup.OnRep_PickupLocationData"); + this->ProcessEvent(OnRep_PickupLocationDataFn); + } + static AFortPickup* SpawnPickup(FFortItemEntry* ItemEntry, FVector Location, EFortPickupSourceTypeFlag PickupSource = EFortPickupSourceTypeFlag::Other, EFortPickupSpawnSource SpawnSource = EFortPickupSpawnSource::Unset, class AFortPawn* Pawn = nullptr, UClass* OverrideClass = nullptr, bool bToss = true, int OverrideCount = -1); @@ -96,6 +126,7 @@ public: EFortPickupSourceTypeFlag PickupSource = EFortPickupSourceTypeFlag::Other, EFortPickupSpawnSource SpawnSource = EFortPickupSpawnSource::Unset, int LoadedAmmo = -1, class AFortPawn* Pawn = nullptr, UClass* OverrideClass = nullptr, bool bToss = true); + static void CombinePickupHook(AFortPickup* Pickup); static char CompletePickupAnimationHook(AFortPickup* Pickup); static UClass* StaticClass(); diff --git a/Project Reboot 3.0/FortPlayerController.cpp b/Project Reboot 3.0/FortPlayerController.cpp index d336f35..52b0f11 100644 --- a/Project Reboot 3.0/FortPlayerController.cpp +++ b/Project Reboot 3.0/FortPlayerController.cpp @@ -35,6 +35,22 @@ void AFortPlayerController::ClientReportDamagedResourceBuilding(ABuildingSMActor this->ProcessEvent(fn, &AFortPlayerController_ClientReportDamagedResourceBuilding_Params); } +void AFortPlayerController::ClientEquipItem(const FGuid& ItemGuid, bool bForceExecution) +{ + static auto ClientEquipItemFn = FindObject("/Script/FortniteGame.FortPlayerControllerAthena.ClientEquipItem") ? FindObject("/Script/FortniteGame.FortPlayerControllerAthena.ClientEquipItem") : FindObject("/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() { if (Globals::bInfiniteMaterials) @@ -185,6 +201,10 @@ void AFortPlayerController::ApplyCosmeticLoadout() } UFortKismetLibrary::StaticClass()->ProcessEvent(UpdatePlayerCustomCharacterPartsVisualizationFn, &PlayerStateAsFort); + + PlayerStateAsFort->ForceNetUpdate(); + PawnAsFort->ForceNetUpdate(); + this->ForceNetUpdate(); } void AFortPlayerController::ServerLoadingScreenDroppedHook(UObject* Context, FFrame* Stack, void* Ret) @@ -879,6 +899,13 @@ void AFortPlayerController::ServerAttemptInventoryDropHook(AFortPlayerController if (Count < 0 || !Pawn) return; + if (auto PlayerControllerAthena = Cast(PlayerController)) + { + if (PlayerControllerAthena->IsInGhostMode()) + return; + } + + auto WorldInventory = PlayerController->GetWorldInventory(); auto ReplicatedEntry = WorldInventory->FindReplicatedEntry(ItemGuid); diff --git a/Project Reboot 3.0/FortPlayerController.h b/Project Reboot 3.0/FortPlayerController.h index 27f349d..1e24d61 100644 --- a/Project Reboot 3.0/FortPlayerController.h +++ b/Project Reboot 3.0/FortPlayerController.h @@ -87,6 +87,25 @@ public: 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(WeaponDefinitionOffset) + : FindObject(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() { static auto bTryPickupSwapOffset = GetOffset("bTryPickupSwap"); @@ -99,6 +118,8 @@ public: return bTryPickupSwapOffset != -1; } + void ClientEquipItem(const FGuid& ItemGuid, bool bForceExecution); + bool DoesBuildFree(); void DropAllItems(const std::vector& IgnoreItemDefs, bool bIgnoreSecondaryQuickbar = false, bool bRemoveIfNotDroppable = false); void ApplyCosmeticLoadout(); diff --git a/Project Reboot 3.0/FortPlayerControllerAthena.cpp b/Project Reboot 3.0/FortPlayerControllerAthena.cpp index 821bd89..3966055 100644 --- a/Project Reboot 3.0/FortPlayerControllerAthena.cpp +++ b/Project Reboot 3.0/FortPlayerControllerAthena.cpp @@ -14,7 +14,7 @@ void AFortPlayerControllerAthena::StartGhostModeHook(UObject* Context, FFrame* S { LOG_INFO(LogDev, __FUNCTION__); - auto Controller = (AFortPlayerControllerAthena*)Context; + auto PlayerController = (AFortPlayerControllerAthena*)Context; UFortWorldItemDefinition* ItemProvidingGhostMode = nullptr; @@ -26,11 +26,12 @@ void AFortPlayerControllerAthena::StartGhostModeHook(UObject* Context, FFrame* S 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"); - auto GhostModeRepData = Controller->GetGhostModeRepData(); + auto GhostModeRepData = PlayerController->GetGhostModeRepData(); if (GhostModeRepData->IsInGhostMode()) { @@ -38,7 +39,7 @@ void AFortPlayerControllerAthena::StartGhostModeHook(UObject* Context, FFrame* S return StartGhostModeOriginal(Context, Stack, Ret); } - auto WorldInventory = Controller->GetWorldInventory(); + auto WorldInventory = PlayerController->GetWorldInventory(); if (!WorldInventory) return StartGhostModeOriginal(Context, Stack, Ret); @@ -53,7 +54,8 @@ void AFortPlayerControllerAthena::StartGhostModeHook(UObject* Context, FFrame* S if (bShouldUpdate) WorldInventory->Update(); - Controller->ServerExecuteInventoryItemHook(Controller, GhostModeItemInstance->GetItemEntry()->GetItemGuid()); + PlayerController->ServerExecuteInventoryItemHook(PlayerController, GhostModeItemInstance->GetItemEntry()->GetItemGuid()); + PlayerController->ClientEquipItem(GhostModeItemInstance->GetItemEntry()->GetItemGuid(), true); LOG_INFO(LogDev, "Finished!"); return StartGhostModeOriginal(Context, Stack, Ret); @@ -65,25 +67,41 @@ void AFortPlayerControllerAthena::EndGhostModeHook(AFortPlayerControllerAthena* LOG_INFO(LogDev, __FUNCTION__); + if (!PlayerController->HasAuthority()) // for real + return EndGhostModeOriginal(PlayerController); + auto WorldInventory = PlayerController->GetWorldInventory(); if (!WorldInventory) 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("/Game/Athena/Items/Gameplay/SpookyMist/AGID_SpookyMist.AGID_SpookyMist"); + } + + if (!GhostModeItemDef) + return EndGhostModeOriginal(PlayerController); - auto GhostModeItemDef = GhostModeRepData->GetGhostModeItemDef(); auto GhostModeItemInstance = WorldInventory->FindItemInstance(GhostModeItemDef); - if (GhostModeItemInstance) - { - bool bShouldUpdate = false; - int Count = 1; // GhostModeItemInstance->GetItemEntry()->GetCount() - WorldInventory->RemoveItem(GhostModeItemInstance->GetItemEntry()->GetItemGuid(), &bShouldUpdate, Count); + LOG_INFO(LogDev, "GhostModeItemInstance: {}", GhostModeItemInstance->IsValidLowLevel() ? GhostModeItemInstance->GetFullName() : "BadRead"); - if (bShouldUpdate) - WorldInventory->Update(); - } + if (!GhostModeItemInstance) + 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); } diff --git a/Project Reboot 3.0/FortPlayerControllerAthena.h b/Project Reboot 3.0/FortPlayerControllerAthena.h index 237d0bf..0a3ac22 100644 --- a/Project Reboot 3.0/FortPlayerControllerAthena.h +++ b/Project Reboot 3.0/FortPlayerControllerAthena.h @@ -139,10 +139,24 @@ public: FGhostModeRepData* GetGhostModeRepData() { - static auto GhostModeRepDataOffset = GetOffset("GhostModeRepData"); + static auto GhostModeRepDataOffset = GetOffset("GhostModeRepData", false); + + if (GhostModeRepDataOffset == -1) + return nullptr; + return GetPtr(GhostModeRepDataOffset); } + bool IsInGhostMode() + { + auto GhostModeRepData = GetGhostModeRepData(); + + if (!GhostModeRepData) + return false; + + return GhostModeRepData->IsInGhostMode(); + } + UAthenaMarkerComponent* GetMarkerComponent() { static auto MarkerComponentOffset = GetOffset("MarkerComponent"); diff --git a/Project Reboot 3.0/FortPlayerPawn.cpp b/Project Reboot 3.0/FortPlayerPawn.cpp index 1a3ffea..8302142 100644 --- a/Project Reboot 3.0/FortPlayerPawn.cpp +++ b/Project Reboot 3.0/FortPlayerPawn.cpp @@ -2,6 +2,7 @@ #include #include "FortPlayerController.h" #include "FortGadgetItemDefinition.h" +#include "FortPlayerControllerAthena.h" FFortAthenaLoadout* AFortPlayerPawn::GetCosmeticLoadout() { @@ -273,6 +274,11 @@ void AFortPlayerPawn::ServerHandlePickupHook(AFortPlayerPawn* Pawn, AFortPickup* return; } + auto PlayerControllerAthena = Cast(Pawn->GetController()); + + if (PlayerControllerAthena && PlayerControllerAthena->IsInGhostMode()) + return; + static auto IncomingPickupsOffset = Pawn->GetOffset("IncomingPickups"); Pawn->Get>(IncomingPickupsOffset).Add(Pickup); diff --git a/Project Reboot 3.0/GameModeBase.cpp b/Project Reboot 3.0/GameModeBase.cpp index 8e7e46d..93eebee 100644 --- a/Project Reboot 3.0/GameModeBase.cpp +++ b/Project Reboot 3.0/GameModeBase.cpp @@ -99,17 +99,9 @@ APawn* AGameModeBase::SpawnDefaultPawnForHook(AGameModeBase* GameMode, AControll { // 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(WeaponDefinitionOffset) - : FindObject(L"/Game/Athena/Items/Weapons/WID_Harvest_Pickaxe_Athena_C_T01.WID_Harvest_Pickaxe_Athena_C_T01"); - auto& StartingItems = ((AFortGameModeAthena*)GameMode)->GetStartingItems(); - WorldInventory->AddItem(PickaxeDefinition, nullptr); + NewPlayerAsAthena->AddPickaxeToInventory(); for (int i = 0; i < StartingItems.Num(); i++) { diff --git a/Project Reboot 3.0/Project Reboot 3.0.vcxproj.filters b/Project Reboot 3.0/Project Reboot 3.0.vcxproj.filters index 74c70a4..c82a0d6 100644 --- a/Project Reboot 3.0/Project Reboot 3.0.vcxproj.filters +++ b/Project Reboot 3.0/Project Reboot 3.0.vcxproj.filters @@ -529,9 +529,6 @@ FortniteGame\Source\FortniteGame\Public\Building - - FortniteGame\Source\FortniteGame\Public\Building\GameplayActors - FortniteGame\Source\FortniteGame\Public\Building @@ -842,6 +839,9 @@ FortniteGame\Source\FortniteGame\Public\Mutators + + FortniteGame\Source\FortniteGame\Public\Building + @@ -1081,6 +1081,9 @@ {c04eb59f-e186-49a3-a145-1fd3dc1dcd3d} + + {00ba0f86-7eef-4ffd-9a9d-47477e5193b2} + diff --git a/Project Reboot 3.0/addresses.cpp b/Project Reboot 3.0/addresses.cpp index 78d0cbd..9f4450d 100644 --- a/Project Reboot 3.0/addresses.cpp +++ b/Project Reboot 3.0/addresses.cpp @@ -279,6 +279,15 @@ void Addresses::FindAll() LOG_INFO(LogDev, "Finding FreeArrayOfEntries"); 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!"); } @@ -341,6 +350,9 @@ void Addresses::Print() LOG_INFO(LogDev, "EnterAircraft: 0x{:x}", EnterAircraft - Base); LOG_INFO(LogDev, "SetTimer: 0x{:x}", SetTimer - 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() diff --git a/Project Reboot 3.0/addresses.h b/Project Reboot 3.0/addresses.h index 8023a01..237fdfa 100644 --- a/Project Reboot 3.0/addresses.h +++ b/Project Reboot 3.0/addresses.h @@ -65,6 +65,9 @@ namespace Addresses extern inline uint64 PickupInitialize = 0; extern inline uint64 FreeEntry = 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 FindAll(); diff --git a/Project Reboot 3.0/dllmain.cpp b/Project Reboot 3.0/dllmain.cpp index e1d9379..25866dc 100644 --- a/Project Reboot 3.0/dllmain.cpp +++ b/Project Reboot 3.0/dllmain.cpp @@ -426,6 +426,9 @@ DWORD WINAPI Main(LPVOID) 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(L"/Script/FortniteGame.FortWeapon.ServerReleaseWeaponAbility"), AFortWeapon::ServerReleaseWeaponAbilityHook, (PVOID*)&AFortWeapon::ServerReleaseWeaponAbilityOriginal, false, true); @@ -489,13 +492,33 @@ DWORD WINAPI Main(LPVOID) AFortPlayerControllerAthena::ServerReadyToStartMatchHook, (PVOID*)&AFortPlayerControllerAthena::ServerReadyToStartMatchOriginal, false); Hooking::MinHook::Hook(FortPlayerControllerAthenaDefault, FindObject(L"/Script/FortniteGame.FortPlayerControllerZone.ServerRequestSeatChange"), AFortPlayerControllerAthena::ServerRequestSeatChangeHook, (PVOID*)&AFortPlayerControllerAthena::ServerRequestSeatChangeOriginal, false); + if (false) { Hooking::MinHook::Hook(FortPlayerControllerAthenaDefault, FindObject(L"/Script/FortniteGame.FortPlayerControllerGameplay.StartGhostMode"), // (Milxnor) TODO: This changes to a component in later seasons. - AFortPlayerControllerAthena::StartGhostModeHook, (PVOID*)&AFortPlayerControllerAthena::StartGhostModeOriginal, false, true); - Hooking::MinHook::Hook(FortPlayerControllerAthenaDefault, FindObject(L"/Script/FortniteGame.FortPlayerControllerGameplay.EndGhostMode"), - AFortPlayerControllerAthena::EndGhostModeHook, (PVOID*)&AFortPlayerControllerAthena::EndGhostModeOriginal, false); + AFortPlayerControllerAthena::StartGhostModeHook, (PVOID*)&AFortPlayerControllerAthena::StartGhostModeOriginal, false, true); // We can exec hook since it only gets called via blueprint. + + auto EndGhostModeFn = FindObject(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(L"/Script/FortniteGame.FortPlayerControllerGameplay.EndGhostMode"), + // AFortPlayerControllerAthena::EndGhostModeHook, (PVOID*)&AFortPlayerControllerAthena::EndGhostModeOriginal, false); + } } + Hooking::MinHook::Hook(FortPlayerControllerAthenaDefault, FindObject(L"/Script/FortniteGame.FortPlayerControllerAthena.ServerGiveCreativeItem"), AFortPlayerControllerAthena::ServerGiveCreativeItemHook, nullptr, true); @@ -526,18 +549,15 @@ DWORD WINAPI Main(LPVOID) AFortPlayerPawn::ServerSendZiplineStateHook, nullptr, false); Hooking::MinHook::Hook((PVOID)GetFunctionIdxOrPtr(FindObject(L"/Script/FortniteGame.FortPlayerPawn.ServerOnExitVehicle"), true), AFortPlayerPawn::ServerOnExitVehicleHook, (PVOID*)&AFortPlayerPawn::ServerOnExitVehicleOriginal); - bool bNativeHookRemoveFortItemFromPlayer = false; - - if (bNativeHookRemoveFortItemFromPlayer) - { - Hooking::MinHook::Hook(FortKismetLibraryDefault, FindObject(L"/Script/FortniteGame.FortKismetLibrary.K2_RemoveFortItemFromPlayer"), - UFortKismetLibrary::K2_RemoveFortItemFromPlayerHook1, nullptr, false); - } - static auto FortGameplayAbilityAthena_PeriodicItemGrantDefault = FindObject("/Script/FortniteGame.Default__FortGameplayAbilityAthena_PeriodicItemGrant"); - Hooking::MinHook::Hook(FortGameplayAbilityAthena_PeriodicItemGrantDefault, FindObject(L"/Script/FortniteGame.FortGameplayAbilityAthena_PeriodicItemGrant.StartItemAwardTimers"), - UFortGameplayAbilityAthena_PeriodicItemGrant::StartItemAwardTimersHook, (PVOID*)&UFortGameplayAbilityAthena_PeriodicItemGrant::StartItemAwardTimersOriginal, false, true); + if (FortGameplayAbilityAthena_PeriodicItemGrantDefault) + { + Hooking::MinHook::Hook(FortGameplayAbilityAthena_PeriodicItemGrantDefault, FindObject(L"/Script/FortniteGame.FortGameplayAbilityAthena_PeriodicItemGrant.StopItemAwardTimers"), + UFortGameplayAbilityAthena_PeriodicItemGrant::StopItemAwardTimersHook, (PVOID*)&UFortGameplayAbilityAthena_PeriodicItemGrant::StopItemAwardTimersOriginal, false, true); + Hooking::MinHook::Hook(FortGameplayAbilityAthena_PeriodicItemGrantDefault, FindObject(L"/Script/FortniteGame.FortGameplayAbilityAthena_PeriodicItemGrant.StartItemAwardTimers"), + UFortGameplayAbilityAthena_PeriodicItemGrant::StartItemAwardTimersHook, (PVOID*)&UFortGameplayAbilityAthena_PeriodicItemGrant::StartItemAwardTimersOriginal, false, true); + } Hooking::MinHook::Hook(FindObject(L"/Script/FortniteGame.Default__FortAthenaMutator_Barrier"), FindObject(L"/Script/FortniteGame.FortAthenaMutator_Barrier.OnGamePhaseStepChanged"), AFortAthenaMutator_Barrier::OnGamePhaseStepChangedHook, (PVOID*)&AFortAthenaMutator_Barrier::OnGamePhaseStepChangedOriginal, false, true); @@ -564,12 +584,8 @@ DWORD WINAPI Main(LPVOID) Hooking::MinHook::Hook(FortPlayerPawnAthenaDefault, FindObject(L"/Script/FortniteGame.FortPlayerPawnAthena.OnCapsuleBeginOverlap") ? FindObject(L"/Script/FortniteGame.FortPlayerPawnAthena.OnCapsuleBeginOverlap") : FindObject(L"/Script/FortniteGame.FortPlayerPawn.OnCapsuleBeginOverlap"), AFortPlayerPawnAthena::OnCapsuleBeginOverlapHook, (PVOID*)&AFortPlayerPawnAthena::OnCapsuleBeginOverlapOriginal, false, true); - if (!bNativeHookRemoveFortItemFromPlayer) - { - Hooking::MinHook::Hook(FortKismetLibraryDefault, FindObject(L"/Script/FortniteGame.FortKismetLibrary.K2_RemoveFortItemFromPlayer"), - UFortKismetLibrary::K2_RemoveFortItemFromPlayerHook, (PVOID*)&UFortKismetLibrary::K2_RemoveFortItemFromPlayerOriginal, false, true); - } - + Hooking::MinHook::Hook(FortKismetLibraryDefault, FindObject(L"/Script/FortniteGame.FortKismetLibrary.K2_RemoveFortItemFromPlayer"), + UFortKismetLibrary::K2_RemoveFortItemFromPlayerHook, (PVOID*)&UFortKismetLibrary::K2_RemoveFortItemFromPlayerOriginal, false, true); Hooking::MinHook::Hook(FortKismetLibraryDefault, FindObject(L"/Script/FortniteGame.FortKismetLibrary.K2_SpawnPickupInWorld"), UFortKismetLibrary::K2_SpawnPickupInWorldHook, (PVOID*)&UFortKismetLibrary::K2_SpawnPickupInWorldOriginal, false, true); Hooking::MinHook::Hook(FortKismetLibraryDefault, FindObject(L"/Script/FortniteGame.FortKismetLibrary.K2_SpawnPickupInWorldWithLootTier"), @@ -765,7 +781,6 @@ DWORD WINAPI Main(LPVOID) // if (Fortnite_Version > 1.8 || Fortnite_Version == 1.11) { auto ClientOnPawnDiedCallAddr = FindFunctionCall(L"ClientOnPawnDied", Engine_Version == 416 ? std::vector{ 0x48, 0x89, 0x54 } : std::vector{ 0x48, 0x89, 0x5C }); - LOG_INFO(LogDev, "ahh!"); LOG_INFO(LogDev, "ClientOnPawnDiedCallAddr: 0x{:x}", ClientOnPawnDiedCallAddr - __int64(GetModuleHandleW(0))); Hooking::MinHook::Hook((PVOID)ClientOnPawnDiedCallAddr, AFortPlayerController::ClientOnPawnDiedHook, (PVOID*)&AFortPlayerController::ClientOnPawnDiedOriginal); } diff --git a/Project Reboot 3.0/finder.h b/Project Reboot 3.0/finder.h index 1a43155..2f3235b 100644 --- a/Project Reboot 3.0/finder.h +++ b/Project Reboot 3.0/finder.h @@ -551,6 +551,77 @@ static inline uint64 FindSpecConstructor() 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() { if (Engine_Version == 416 || Engine_Version == 419) @@ -771,8 +842,43 @@ static inline uint64 FindFreeEntry() 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() { + uint64 RemoveGadgetDataAddr = 0; + if (Engine_Version <= 423) { 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(); if (!Addr) - { Addr = Memcury::Scanner::FindStringRef(L"UFortGadgetItemDefinition::RemoveGadgetData - Failed to get the Player Controller to cleanup Gadget Item [%s]!").Get(); - } if (!Addr) return 0; - for (int i = 0; i < 1000; 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; - // return FindBytes(StringRef, { 0x40, 0x55 }, 1000, 0, true); + RemoveGadgetDataAddr = FindBeginningOfFuncEXP(Addr); } - 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 + else if (Engine_Version == 426) + 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() { - if (Engine_Version >= 420 && Engine_Version <= 422) - 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 + uint64 FortGadgetItemDefinition_ApplyGadgetDataAddr = 0; - 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() diff --git a/Project Reboot 3.0/gui.h b/Project Reboot 3.0/gui.h index 2957309..abd7031 100644 --- a/Project Reboot 3.0/gui.h +++ b/Project Reboot 3.0/gui.h @@ -806,7 +806,6 @@ static inline void MainUI() if (WeaponsFile.is_open()) { WeaponsFile << FortniteVersionStr; - static auto FortWeaponItemDefinitionClass = FindObject("/Script/FortniteGame.FortWeaponItemDefinition"); auto DumpItemDefinitionClass = [&WeaponsFile](UClass* Class) { auto AllObjects = GetAllObjectsOfClass(Class); @@ -831,6 +830,7 @@ static inline void MainUI() DumpItemDefinitionClass(UFortWeaponItemDefinition::StaticClass()); DumpItemDefinitionClass(UFortGadgetItemDefinition::StaticClass()); + DumpItemDefinitionClass(FindObject("/Script/FortniteGame.FortAmmoItemDefinition")); } else std::cout << "Failed to open playlist file!\n"; diff --git a/Project Reboot 3.0/hooking.h b/Project Reboot 3.0/hooking.h index 7dde4dc..79694e4 100644 --- a/Project Reboot 3.0/hooking.h +++ b/Project Reboot 3.0/hooking.h @@ -338,4 +338,43 @@ namespace Hooking *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(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(FunctionToReplace); + + uint64 FunctionAddr = __int64(UFunc->GetFunc()); // GetFunctionIdxOrPtr(FindObject(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); } \ No newline at end of file diff --git a/vendor/memcury.h b/vendor/memcury.h index 2b3cce9..877f8ad 100644 --- a/vendor/memcury.h +++ b/vendor/memcury.h @@ -758,10 +758,13 @@ 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 }; + if (!Pointer) + return Scanner(add); + auto textSection = PE::Section::GetSection(".text"); const auto scanBytes = reinterpret_cast(textSection.GetSectionStart().Get()); @@ -803,14 +806,17 @@ } } } - - if (add == 0) + + if (bWarnIfNotFound) { - MessageBoxA(0, "FindPointerRef return nullptr", "Memcury", MB_OK); - } - else - { - // MessageBoxA(0, std::format("FindPointerRef return 0x{:x}", add.Get() - __int64(GetModuleHandleW(0))).c_str(), "Memcury", MB_OK); + if (add == 0) + { + MessageBoxA(0, "FindPointerRef return nullptr", "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); @@ -1423,4 +1429,6 @@ } */ return PtrRef.ScanFor(Bytes, false).Get(); - } \ No newline at end of file + } + + inline bool IsNullSub(uint64 Addr) { return *(uint8_t*)(Addr) == 0xC3 || *(uint8_t*)(Addr) == 0xC2; } \ No newline at end of file