diff --git a/Project Reboot 3.0/AbilitySystemComponent.h b/Project Reboot 3.0/AbilitySystemComponent.h index d3d594b..90efa2e 100644 --- a/Project Reboot 3.0/AbilitySystemComponent.h +++ b/Project Reboot 3.0/AbilitySystemComponent.h @@ -29,6 +29,15 @@ struct FActiveGameplayEffectHandle unsigned char UnknownData00[0x3]; // 0x0005(0x0003) MISSED OFFSET }; +struct FGameplayAbilitySpecContainer : public FFastArraySerializer +{ + TArray& GetItems() + { + static auto ItemsOffset = FindOffsetStruct("/Script/GameplayAbilities.GameplayAbilitySpecContainer", "Items"); + return *(TArray*)(__int64(this) + ItemsOffset); + } +}; + class UAbilitySystemComponent : public UObject { public: @@ -50,11 +59,18 @@ public: return Get>(SpawnedAttributesOffset); } - FActiveGameplayEffectHandle ApplyGameplayEffectToSelf(UClass* GameplayEffectClass, float Level, const FGameplayEffectContextHandle& EffectContext); + FGameplayAbilitySpecContainer* GetActivatableAbilities() + { + static auto ActivatableAbilitiesOffset = this->GetOffset("ActivatableAbilities"); + return GetPtr(ActivatableAbilitiesOffset); + } + + bool HasAbility(UObject* DefaultAbility); + FActiveGameplayEffectHandle ApplyGameplayEffectToSelf(UClass* GameplayEffectClass, float Level, const FGameplayEffectContextHandle& EffectContext = FGameplayEffectContextHandle()); // FGameplayEffectContextHandle MakeEffectContext(); void RemoveActiveGameplayEffectBySourceEffect(UClass* GEClass, int StacksToRemove, UAbilitySystemComponent* Instigator); void ConsumeAllReplicatedData(FGameplayAbilitySpecHandle AbilityHandle, FPredictionKey* AbilityOriginalPredictionKey); - FGameplayAbilitySpecHandle GiveAbilityEasy(UClass* AbilityClass, UObject* SourceObject = nullptr); + FGameplayAbilitySpecHandle GiveAbilityEasy(UClass* AbilityClass, UObject* SourceObject = nullptr, bool bDoNotRegive = true); FGameplayAbilitySpec* FindAbilitySpecFromHandle(FGameplayAbilitySpecHandle Handle); static void InternalServerTryActivateAbilityHook(UAbilitySystemComponent* AbilitySystemComponent, FGameplayAbilitySpecHandle Handle, bool InputPressed, const FPredictionKey* PredictionKey, const FGameplayEventData* TriggerEventData); diff --git a/Project Reboot 3.0/AbilitySystemComponent_Abilities.cpp b/Project Reboot 3.0/AbilitySystemComponent_Abilities.cpp index fb9c21b..6fc6409 100644 --- a/Project Reboot 3.0/AbilitySystemComponent_Abilities.cpp +++ b/Project Reboot 3.0/AbilitySystemComponent_Abilities.cpp @@ -50,6 +50,23 @@ FActiveGameplayEffectHandle UAbilitySystemComponent::ApplyGameplayEffectToSelf(U return ContextHandle; } */ +bool UAbilitySystemComponent::HasAbility(UObject* DefaultAbility) +{ + auto ActivatableAbilities = GetActivatableAbilities(); + + auto& Items = ActivatableAbilities->GetItems(); + + for (int i = 0; i < Items.Num(); i++) + { + auto Spec = Items.AtPtr(i, FGameplayAbilitySpec::GetStructSize()); + + if (Spec->GetAbility() == DefaultAbility) + return true; + } + + return false; +} + void UAbilitySystemComponent::RemoveActiveGameplayEffectBySourceEffect(UClass* GEClass, int StacksToRemove, UAbilitySystemComponent* Instigator) { static auto RemoveActiveGameplayEffectBySourceEffectFn = FindObject(L"/Script/GameplayAbilities.AbilitySystemComponent.RemoveActiveGameplayEffectBySourceEffect"); @@ -114,8 +131,7 @@ void UAbilitySystemComponent::InternalServerTryActivateAbilityHook(UAbilitySyste AbilitySystemComponent->ClientActivateAbilityFailed(Handle, *(int16_t*)(__int64(PredictionKey) + CurrentOffset)); SetBitfield((PlaceholderBitfield*)(__int64(Spec) + InputPressedOffset), 1, false); // InputPressed = false - static auto ActivatableAbilitiesOffset = AbilitySystemComponent->GetOffset("ActivatableAbilities"); - AbilitySystemComponent->Get(ActivatableAbilitiesOffset).MarkItemDirty(Spec); + AbilitySystemComponent->GetActivatableAbilities()->MarkItemDirty(Spec); } else { @@ -123,11 +139,19 @@ void UAbilitySystemComponent::InternalServerTryActivateAbilityHook(UAbilitySyste } } -FGameplayAbilitySpecHandle UAbilitySystemComponent::GiveAbilityEasy(UClass* AbilityClass, UObject* SourceObject) +FGameplayAbilitySpecHandle UAbilitySystemComponent::GiveAbilityEasy(UClass* AbilityClass, UObject* SourceObject, bool bDoNotRegive) { // LOG_INFO(LogDev, "Making spec!"); - auto NewSpec = MakeNewSpec(AbilityClass, SourceObject); + auto DefaultAbility = AbilityClass->CreateDefaultObject(); + + if (!DefaultAbility) + return FGameplayAbilitySpecHandle(); + + if (bDoNotRegive && HasAbility(DefaultAbility)) + return FGameplayAbilitySpecHandle(); + + auto NewSpec = MakeNewSpec((UClass*)DefaultAbility, SourceObject, true); // LOG_INFO(LogDev, "Made spec!"); diff --git a/Project Reboot 3.0/BuildingActor.h b/Project Reboot 3.0/BuildingActor.h index 4bcd6d9..a847522 100644 --- a/Project Reboot 3.0/BuildingActor.h +++ b/Project Reboot 3.0/BuildingActor.h @@ -56,6 +56,13 @@ public: } } + bool IsPlayerBuildable() + { + static auto bIsPlayerBuildableOffset = GetOffset("bIsPlayerBuildable"); + static auto bIsPlayerBuildableFieldMask = GetFieldMask(GetProperty("bIsPlayerBuildable")); + return ReadBitfieldValue(bIsPlayerBuildableOffset, bIsPlayerBuildableFieldMask); + } + static inline void (*OnDamageServerOriginal)(ABuildingActor* BuildingActor, float Damage, FGameplayTagContainer DamageTags, FVector Momentum, /* FHitResult */ __int64 HitInfo, APlayerController* InstigatedBy, AActor* DamageCauser, /* FGameplayEffectContextHandle */ __int64 EffectContext); diff --git a/Project Reboot 3.0/Delegate.h b/Project Reboot 3.0/Delegate.h new file mode 100644 index 0000000..3f59c93 --- /dev/null +++ b/Project Reboot 3.0/Delegate.h @@ -0,0 +1,2 @@ +#pragma once + diff --git a/Project Reboot 3.0/DelegateBase.h b/Project Reboot 3.0/DelegateBase.h new file mode 100644 index 0000000..6ba0a21 --- /dev/null +++ b/Project Reboot 3.0/DelegateBase.h @@ -0,0 +1,20 @@ +#pragma once + +#include "inc.h" + + +/* +typedef TAlignedBytes<16, 16> FAlignedInlineDelegateType; +#if USE_SMALL_DELEGATES +typedef FHeapAllocator FDelegateAllocatorType; +#else +typedef TInlineAllocator<2> FDelegateAllocatorType; +#endif +*/ + +class FDelegateBase +{ +public: + // FDelegateAllocatorType::ForElementType DelegateAllocator; + // int32 DelegateSize; +}; \ No newline at end of file diff --git a/Project Reboot 3.0/DelegateSignatureImpl.inl b/Project Reboot 3.0/DelegateSignatureImpl.inl new file mode 100644 index 0000000..06c01cc --- /dev/null +++ b/Project Reboot 3.0/DelegateSignatureImpl.inl @@ -0,0 +1,9 @@ +#pragma once + +#include "DelegateBase.h" + +template +class TBaseDelegate : public FDelegateBase +{ +public: +}; \ No newline at end of file diff --git a/Project Reboot 3.0/FortAbilitySet.h b/Project Reboot 3.0/FortAbilitySet.h index 571ba40..40a5547 100644 --- a/Project Reboot 3.0/FortAbilitySet.h +++ b/Project Reboot 3.0/FortAbilitySet.h @@ -2,6 +2,7 @@ #include "AbilitySystemComponent.h" #include "reboot.h" +#include "SoftObjectPtr.h" struct FGameplayEffectApplicationInfoHard { @@ -10,6 +11,13 @@ public: float Level; }; +struct FGameplayEffectApplicationInfo +{ + TSoftObjectPtr GameplayEffect; // 0x0000(0x0028) UNKNOWN PROPERTY: SoftClassProperty FortniteGame.GameplayEffectApplicationInfo.GameplayEffect + float Level; // 0x0028(0x0004) (Edit, ZeroConstructor, DisableEditOnInstance, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + unsigned char UnknownData01[0x4]; // 0x002C(0x0004) MISSED OFFSET +}; + class UFortAbilitySet : public UObject { public: diff --git a/Project Reboot 3.0/FortGameModeAthena.cpp b/Project Reboot 3.0/FortGameModeAthena.cpp index aea5cd2..eea2d7c 100644 --- a/Project Reboot 3.0/FortGameModeAthena.cpp +++ b/Project Reboot 3.0/FortGameModeAthena.cpp @@ -23,6 +23,7 @@ #include "Map.h" #include "OnlineReplStructs.h" #include "BGA.h" +#include "vendingmachine.h" enum class EDynamicFoundationEnabledState : uint8_t { @@ -41,13 +42,16 @@ enum class EDynamicFoundationType : uint8_t EDynamicFoundationType_MAX = 4 }; -std::string PlaylistName = "/Game/Athena/Playlists/Playlist_DefaultSolo.Playlist_DefaultSolo"; +std::string PlaylistName = +"/Game/Athena/Playlists/Playlist_DefaultSolo.Playlist_DefaultSolo"; // "/Game/Athena/Playlists/Playground/Playlist_Playground.Playlist_Playground"; // "/Game/Athena/Playlists/Carmine/Playlist_Carmine.Playlist_Carmine"; +// "/Game/Athena/Playlists/Fill/Playlist_Fill_Solo.Playlist_Fill_Solo"; +// "/Game/Athena/Playlists/Low/Playlist_Low_Solo.Playlist_Low_Solo"; -static UObject* GetPlaylistToUse() +static UFortPlaylist* GetPlaylistToUse() { - auto Playlist = FindObject(PlaylistName); + auto Playlist = FindObject(PlaylistName); if (Globals::bGoingToPlayEvent) { @@ -70,7 +74,7 @@ static UObject* GetPlaylistToUse() // SET OVERRIDE PLAYLIST DOWN HERE if (Globals::bCreative) - Playlist = FindObject("/Game/Athena/Playlists/Creative/Playlist_PlaygroundV2.Playlist_PlaygroundV2"); + Playlist = FindObject("/Game/Athena/Playlists/Creative/Playlist_PlaygroundV2.Playlist_PlaygroundV2"); return Playlist; } @@ -445,9 +449,7 @@ bool AFortGameModeAthena::Athena_ReadyToStartMatchHook(AFortGameModeAthena* Game } } - static auto CurrentPlaylistDataOffset = GameState->GetOffset("CurrentPlaylistData", false); - - auto CurrentPlaylist = CurrentPlaylistDataOffset == -1 && Fortnite_Version < 6 ? nullptr : GameState->GetCurrentPlaylist(); + GET_PLAYLIST(GameState); if (CurrentPlaylist) { @@ -706,6 +708,9 @@ void AFortGameModeAthena::Athena_HandleStartingNewPlayerHook(AFortGameModeAthena auto GameState = GameMode->GetGameStateAthena(); + static auto CurrentPlaylistDataOffset = GameState->GetOffset("CurrentPlaylistData", false); + auto CurrentPlaylist = CurrentPlaylistDataOffset == -1 && Fortnite_Version < 6 ? nullptr : GameState->GetCurrentPlaylist(); + LOG_INFO(LogPlayer, "HandleStartingNewPlayer!"); // if (Engine_Version < 427) @@ -716,6 +721,7 @@ void AFortGameModeAthena::Athena_HandleStartingNewPlayerHook(AFortGameModeAthena { LastNum69 = AmountOfRestarts; + // FillVendingMachines(); SpawnBGAs(); auto SpawnIsland_FloorLoot = FindObject("/Game/Athena/Environments/Blueprints/Tiered_Athena_FloorLoot_Warmup.Tiered_Athena_FloorLoot_Warmup_C"); @@ -883,7 +889,6 @@ void AFortGameModeAthena::Athena_HandleStartingNewPlayerHook(AFortGameModeAthena PlayerStateAthena->GetWorldPlayerId() = PlayerStateAthena->GetPlayerID(); // ++CurrentPlayerId; // PlayerStateAthena->Get(PlayerIdOffset); // } - if (Globals::bAbilitiesEnabled) { static auto GameplayAbilitySet = (UFortAbilitySet*)(Fortnite_Version >= 8.30 ? // LoadObject(L"/Game/Abilities/Player/Generic/Traits/DefaultPlayer/GAS_AthenaPlayer.GAS_AthenaPlayer") ? LoadObject(L"/Game/Abilities/Player/Generic/Traits/DefaultPlayer/GAS_AthenaPlayer.GAS_AthenaPlayer", UFortAbilitySet::StaticClass()) : @@ -891,10 +896,19 @@ void AFortGameModeAthena::Athena_HandleStartingNewPlayerHook(AFortGameModeAthena LOG_INFO(LogDev, "GameplayAbilitySet {}", __int64(GameplayAbilitySet)); + auto AbilitySystemComponent = PlayerStateAthena->GetAbilitySystemComponent(); + if (GameplayAbilitySet) { LOG_INFO(LogDev, "GameplayAbilitySet Name {}", GameplayAbilitySet->GetName()); - GameplayAbilitySet->GiveToAbilitySystem(PlayerStateAthena->GetAbilitySystemComponent()); + GameplayAbilitySet->GiveToAbilitySystem(AbilitySystemComponent); + } + + GET_PLAYLIST(GameState); + + if (CurrentPlaylist) + { + // CurrentPlaylist->ApplyModifiersToActor(PlayerStateAthena); // scuffed we need to do as pawn spawns } } diff --git a/Project Reboot 3.0/FortGameStateAthena.cpp b/Project Reboot 3.0/FortGameStateAthena.cpp index d1fdd9e..a1f8a59 100644 --- a/Project Reboot 3.0/FortGameStateAthena.cpp +++ b/Project Reboot 3.0/FortGameStateAthena.cpp @@ -9,20 +9,20 @@ } */ -UObject*& AFortGameStateAthena::GetCurrentPlaylist() +UFortPlaylist*& AFortGameStateAthena::GetCurrentPlaylist() { static auto CurrentPlaylistInfoOffset = GetOffset("CurrentPlaylistInfo", false); if (CurrentPlaylistInfoOffset == -1) { static auto CurrentPlaylistDataOffset = GetOffset("CurrentPlaylistData"); - return Get(CurrentPlaylistDataOffset); + return Get(CurrentPlaylistDataOffset); } auto CurrentPlaylistInfo = this->GetPtr(CurrentPlaylistInfoOffset); static auto BasePlaylistOffset = FindOffsetStruct("/Script/FortniteGame.PlaylistPropertyArray", "BasePlaylist"); - return *(UObject**)(__int64(CurrentPlaylistInfo) + BasePlaylistOffset); + return *(UFortPlaylist**)(__int64(CurrentPlaylistInfo) + BasePlaylistOffset); } int AFortGameStateAthena::GetAircraftIndex(AFortPlayerState* PlayerState) diff --git a/Project Reboot 3.0/FortGameStateAthena.h b/Project Reboot 3.0/FortGameStateAthena.h index e05644c..5e6f5b1 100644 --- a/Project Reboot 3.0/FortGameStateAthena.h +++ b/Project Reboot 3.0/FortGameStateAthena.h @@ -2,6 +2,7 @@ #include "GameState.h" #include "FortPlayerState.h" +#include "FortPlaylist.h" enum class EAthenaGamePhase : uint8_t { @@ -30,7 +31,7 @@ public: return Get(GamePhaseOffset); } - UObject*& GetCurrentPlaylist(); + UFortPlaylist*& GetCurrentPlaylist(); // void AddPlayerStateToGameMemberInfo(class AFortPlayerStateAthena* PlayerState); diff --git a/Project Reboot 3.0/FortGameplayAbilityAthena_PeriodicItemGrant.cpp b/Project Reboot 3.0/FortGameplayAbilityAthena_PeriodicItemGrant.cpp new file mode 100644 index 0000000..7a30a1a --- /dev/null +++ b/Project Reboot 3.0/FortGameplayAbilityAthena_PeriodicItemGrant.cpp @@ -0,0 +1,7 @@ +#include "FortGameplayAbilityAthena_PeriodicItemGrant.h" + +void UFortGameplayAbilityAthena_PeriodicItemGrant::StartItemAwardTimersHook(UObject* Context, FFrame& Stack, void* Ret) +{ + LOG_INFO(LogDev, "StartItemAwardTimersHook!"); + 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 new file mode 100644 index 0000000..2d35103 --- /dev/null +++ b/Project Reboot 3.0/FortGameplayAbilityAthena_PeriodicItemGrant.h @@ -0,0 +1,12 @@ +#pragma once + +#include "Object.h" +#include "Stack.h" + +class UFortGameplayAbilityAthena_PeriodicItemGrant : public UObject // UFortGameplayAbility +{ +public: + static inline void (*StartItemAwardTimersOriginal)(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/FortItem.h b/Project Reboot 3.0/FortItem.h index f4c0bf7..6d74954 100644 --- a/Project Reboot 3.0/FortItem.h +++ b/Project Reboot 3.0/FortItem.h @@ -42,6 +42,20 @@ struct FFortItemEntry : FFastArraySerializerItem static auto StructSize = GetStruct()->GetPropertiesSize(); return StructSize; } + + static FFortItemEntry* MakeItemEntry(UFortItemDefinition* ItemDefinition, int Count = 1, int LoadedAmmo = 0) + { + auto Entry = Alloc(GetStructSize()); + + if (!Entry) + return nullptr; + + Entry->GetItemDefinition() = ItemDefinition; + Entry->GetCount() = Count; + Entry->GetLoadedAmmo() = LoadedAmmo; + + return Entry; + } }; class UFortItem : public UObject diff --git a/Project Reboot 3.0/FortKismetLibrary.cpp b/Project Reboot 3.0/FortKismetLibrary.cpp index a25bcc9..8ce60da 100644 --- a/Project Reboot 3.0/FortKismetLibrary.cpp +++ b/Project Reboot 3.0/FortKismetLibrary.cpp @@ -352,6 +352,40 @@ void UFortKismetLibrary::K2_GiveItemToPlayerHook(UObject* Context, FFrame& Stack return K2_GiveItemToPlayerOriginal(Context, Stack, Ret); } +void UFortKismetLibrary::K2_GiveBuildingResourceHook(UObject* Context, FFrame& Stack, void* Ret) +{ + LOG_INFO(LogDev, "K2_GiveBuildingResourceHook!"); + + AFortPlayerController* Controller; + EFortResourceType ResourceType; + int ResourceAmount; + + Stack.StepCompiledIn(&Controller); + Stack.StepCompiledIn(&ResourceType); + Stack.StepCompiledIn(&ResourceAmount); + + if (!Controller) + return K2_GiveBuildingResourceOriginal(Context, Stack, Ret); + + auto WorldInventory = Controller->GetWorldInventory(); + + if (!WorldInventory) + return K2_GiveBuildingResourceOriginal(Context, Stack, Ret); + + auto ItemDefinition = UFortKismetLibrary::K2_GetResourceItemDefinition(ResourceType); + + if (!ItemDefinition) + return K2_GiveBuildingResourceOriginal(Context, Stack, Ret); + + bool bShouldUpdate = false; + WorldInventory->AddItem(ItemDefinition, &bShouldUpdate, ResourceAmount, 0); + + if (bShouldUpdate) + WorldInventory->Update(); + + return K2_GiveBuildingResourceOriginal(Context, Stack, Ret); +} + 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 feb87d5..dfe1863 100644 --- a/Project Reboot 3.0/FortKismetLibrary.h +++ b/Project Reboot 3.0/FortKismetLibrary.h @@ -79,6 +79,7 @@ public: static inline void (*K2_SpawnPickupInWorldWithLootTierOriginal)(UObject* Context, FFrame& Stack, void* Ret); static inline bool (*SpawnInstancedPickupInWorldOriginal)(UObject* Context, FFrame& Stack, bool* Ret); static inline void (*SpawnItemVariantPickupInWorldOriginal)(UObject* Context, FFrame& Stack, void* Ret); + static inline void (*K2_GiveBuildingResourceOriginal)(UObject* Context, FFrame& Stack, void* Ret); static inline void (*PickLootDropsWithNamedWeightsOriginal)(UObject* Context, FFrame& Stack, void* Ret); static UFortResourceItemDefinition* K2_GetResourceItemDefinition(EFortResourceType ResourceType); @@ -93,6 +94,7 @@ public: static void K2_RemoveItemFromPlayerHook(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_GiveBuildingResourceHook(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_SpawnPickupInWorldWithClassHook(UObject* Context, FFrame& Stack, AFortPickup** Ret); diff --git a/Project Reboot 3.0/FortLootPackage.cpp b/Project Reboot 3.0/FortLootPackage.cpp index 0e760bb..c2e5941 100644 --- a/Project Reboot 3.0/FortLootPackage.cpp +++ b/Project Reboot 3.0/FortLootPackage.cpp @@ -378,9 +378,6 @@ std::vector PickLootDrops(FName TierGroupName, bool bPrint, int recurs LTDTables.clear(); LPTables.clear(); - LTDTables.push_back(LoadObject(L"/Game/Items/Datatables/AthenaLootTierData_Client.AthenaLootTierData_Client")); - LPTables.push_back(LoadObject(L"/Game/Items/Datatables/AthenaLootPackages_Client.AthenaLootPackages_Client")); - bool bFoundPlaylistTable = false; if (CurrentPlaylist) @@ -410,6 +407,12 @@ std::vector PickLootDrops(FName TierGroupName, bool bPrint, int recurs } } } + + if (!bFoundPlaylistTable) + { + LTDTables.push_back(LoadObject(L"/Game/Items/Datatables/AthenaLootTierData_Client.AthenaLootTierData_Client")); + LPTables.push_back(LoadObject(L"/Game/Items/Datatables/AthenaLootPackages_Client.AthenaLootPackages_Client")); + } } std::vector TierGroupLTDs; diff --git a/Project Reboot 3.0/FortPlayerController.cpp b/Project Reboot 3.0/FortPlayerController.cpp index 889e6be..9bf99a3 100644 --- a/Project Reboot 3.0/FortPlayerController.cpp +++ b/Project Reboot 3.0/FortPlayerController.cpp @@ -147,7 +147,7 @@ void AFortPlayerController::ServerExecuteInventoryItemHook(AFortPlayerController LOG_INFO(LogDev, "Equipping Gadget: {}", ItemDefinition->GetFullName()); } - /* +#if 0 if (GadgetItemDefinition) { static auto AbilitySetOffset = GadgetItemDefinition->GetOffset("AbilitySet"); @@ -228,7 +228,7 @@ void AFortPlayerController::ServerExecuteInventoryItemHook(AFortPlayerController Pawn->ServerChoosePart((EFortCustomPartType)i, CharacterParts.at(i)); } } - */ +#endif if (auto DecoItemDefinition = Cast(ItemDefinition)) { @@ -489,8 +489,6 @@ void AFortPlayerController::ServerAttemptAircraftJumpHook(AFortPlayerController* // PlayerController->ServerRestartPlayer(); } - - void AFortPlayerController::ServerDropAllItemsHook(AFortPlayerController* PlayerController, UFortItemDefinition* IgnoreItemDef) { PlayerController->DropAllItems({ IgnoreItemDef }); @@ -605,6 +603,15 @@ void AFortPlayerController::ServerCreateBuildingActorHook(UObject* Context, FFra WorldInventory->Update(); } + auto GameState = Cast(((AFortGameMode*)GetWorld()->GetGameMode())->GetGameState()); + + GET_PLAYLIST(GameState); + + if (CurrentPlaylist) + { + // CurrentPlaylist->ApplyModifiersToActor(BuildingActor); // seems automatic + } + return ServerCreateBuildingActorOriginal(Context, Stack, Ret); } @@ -976,6 +983,8 @@ void AFortPlayerController::ClientOnPawnDiedHook(AFortPlayerController* PlayerCo RemoveFromAlivePlayers(GameMode, PlayerController, KillerPlayerState == DeadPlayerState ? nullptr : KillerPlayerState, KillerPawn, KillerWeaponDef, DeathCause, 0); + LOG_INFO(LogDev, "Removed!"); + if (Fortnite_Version < 6) // Spectating { LOG_INFO(LogDev, "Starting Spectating!"); diff --git a/Project Reboot 3.0/FortPlayerControllerAthena.cpp b/Project Reboot 3.0/FortPlayerControllerAthena.cpp index 028a176..b0fc4fe 100644 --- a/Project Reboot 3.0/FortPlayerControllerAthena.cpp +++ b/Project Reboot 3.0/FortPlayerControllerAthena.cpp @@ -20,7 +20,7 @@ void AFortPlayerControllerAthena::ServerRestartPlayerHook(AFortPlayerControllerA void AFortPlayerControllerAthena::ServerGiveCreativeItemHook(AFortPlayerControllerAthena* Controller, FFortItemEntry CreativeItem) { - // Don't worry, the validate has a check if it is a creative enabled mode or not, but we need to add a volume check. + // Don't worry, the validate has a check if it is a creative enabled mode or not, but we need to add a volume check and permission check I think. auto CreativeItemPtr = &CreativeItem; auto ItemDefinition = CreativeItemPtr->GetItemDefinition(); diff --git a/Project Reboot 3.0/FortPlaylist.h b/Project Reboot 3.0/FortPlaylist.h new file mode 100644 index 0000000..2901fb2 --- /dev/null +++ b/Project Reboot 3.0/FortPlaylist.h @@ -0,0 +1,273 @@ +#pragma once + +#include "Object.h" +#include "Array.h" +#include "FortAbilitySet.h" +#include "SoftObjectPtr.h" +#include "FortPlayerPawnAthena.h" +#include "GameplayTagContainer.h" +#include "BuildingActor.h" +#include "FortPlayerPawnAthena.h" + +struct FGameplayTagRequirements +{ + FGameplayTagContainer RequireTags; // 0x0000(0x0020) (Edit, BlueprintVisible, NativeAccessSpecifierPublic) + FGameplayTagContainer IgnoreTags; // 0x0020(0x0020) (Edit, BlueprintVisible, NativeAccessSpecifierPublic) +}; + +enum class EFortDeliveryInfoBuildingActorSpecification : uint8_t +{ + All = 0, + PlayerBuildable = 1, + NonPlayerBuildable = 2, + EFortDeliveryInfoBuildingActorSpecification_MAX = 3 +}; + +struct FFortDeliveryInfoRequirementsFilter +{ + bool ShouldApplyToPawns() + { + static auto bApplyToPlayerPawnsOffset = FindOffsetStruct("/Script/FortniteGame.FortDeliveryInfoRequirementsFilter", "bApplyToPlayerPawns"); + static auto bApplyToPlayerPawnsFieldMask = GetFieldMask(FindPropertyStruct("/Script/FortniteGame.FortDeliveryInfoRequirementsFilter", "bApplyToPlayerPawns")); + return ReadBitfield((PlaceholderBitfield*)(__int64(this) + bApplyToPlayerPawnsOffset), bApplyToPlayerPawnsFieldMask); + } + + bool ShouldApplyToBuildingActors() + { + static auto bApplyToBuildingActorsOffset = FindOffsetStruct("/Script/FortniteGame.FortDeliveryInfoRequirementsFilter", "bApplyToBuildingActors"); + static auto bApplyToBuildingActorsFieldMask = GetFieldMask(FindPropertyStruct("/Script/FortniteGame.FortDeliveryInfoRequirementsFilter", "bApplyToBuildingActors")); + return ReadBitfield((PlaceholderBitfield*)(__int64(this) + bApplyToBuildingActorsOffset), bApplyToBuildingActorsFieldMask); + } + + bool ShouldConsiderTeam() + { + static auto bConsiderTeamOffset = FindOffsetStruct("/Script/FortniteGame.FortDeliveryInfoRequirementsFilter", "bConsiderTeam"); + static auto bConsiderTeamFieldMask = GetFieldMask(FindPropertyStruct("/Script/FortniteGame.FortDeliveryInfoRequirementsFilter", "bConsiderTeam")); + return ReadBitfield((PlaceholderBitfield*)(__int64(this) + bConsiderTeamOffset), bConsiderTeamFieldMask); + } + + FGameplayTagRequirements& GetTargetTagRequirements() + { + static auto TargetTagRequirementsOffset = FindOffsetStruct("/Script/FortniteGame.FortDeliveryInfoRequirementsFilter", "TargetTagRequirements"); + return *(FGameplayTagRequirements*)(__int64(this) + TargetTagRequirementsOffset); + } + + EFortDeliveryInfoBuildingActorSpecification& GetBuildingActorSpecification() + { + static auto BuildingActorSpecificationOffset = FindOffsetStruct("/Script/FortniteGame.FortDeliveryInfoRequirementsFilter", "BuildingActorSpecification"); + return *(EFortDeliveryInfoBuildingActorSpecification*)(__int64(this) + BuildingActorSpecificationOffset); + } + + bool DoesActorFollowsRequirements(AActor* Actor) + { + // TODO ADD TEAM CHECK! (We can use UFortKismetLibrary::GetActorTeam) + + if (auto BuildingActor = Cast(Actor)) + { + if (!ShouldApplyToBuildingActors()) + return false; + + //if (GetTargetTagRequirements().RequireTags.GameplayTags.Num() > 0 && GetTargetTagRequirements().) // idk todo + + if (GetBuildingActorSpecification() == EFortDeliveryInfoBuildingActorSpecification::PlayerBuildable && BuildingActor->IsPlayerBuildable()) + return true; + + if (GetBuildingActorSpecification() == EFortDeliveryInfoBuildingActorSpecification::NonPlayerBuildable && !BuildingActor->IsPlayerBuildable()) + return true; + + return GetBuildingActorSpecification() == EFortDeliveryInfoBuildingActorSpecification::All; + } + + else if (auto Pawn = Cast(Actor)) + { + return ShouldApplyToPawns(); + } + + else if (auto PlayerState = Cast(Actor)) + { + return ShouldApplyToPawns(); // scuffed + } + + return false; + } +}; + +struct FFortGameplayEffectDeliveryInfo +{ + static UStruct* GetStruct() + { + static auto Struct = FindObject("/Script/FortniteGame.FortGameplayEffectDeliveryInfo"); + return Struct; + } + + static int GetStructSize() + { + return GetStruct()->GetPropertiesSize(); + } + + FFortDeliveryInfoRequirementsFilter* GetDeliveryRequirements() + { + static auto DeliveryRequirementsOffset = FindOffsetStruct("/Script/FortniteGame.FortGameplayEffectDeliveryInfo", "DeliveryRequirements"); + return (FFortDeliveryInfoRequirementsFilter*)(__int64(this) + DeliveryRequirementsOffset); + } + + TArray& GetGameplayEffects() + { + static auto GameplayEffectsOffset = FindOffsetStruct("/Script/FortniteGame.FortGameplayEffectDeliveryInfo", "GameplayEffects"); + return *(TArray*)(__int64(this) + GameplayEffectsOffset); + } +}; + +struct FFortAbilitySetDeliveryInfo +{ + static UStruct* GetStruct() + { + static auto Struct = FindObject("/Script/FortniteGame.FortAbilitySetDeliveryInfo"); + return Struct; + } + + static int GetStructSize() + { + return GetStruct()->GetPropertiesSize(); + } + + FFortDeliveryInfoRequirementsFilter* GetDeliveryRequirements() + { + static auto DeliveryRequirementsOffset = FindOffsetStruct("/Script/FortniteGame.FortAbilitySetDeliveryInfo", "DeliveryRequirements"); + return (FFortDeliveryInfoRequirementsFilter*)(__int64(this) + DeliveryRequirementsOffset); + } + + TArray>& GetAbilitySets() + { + static auto AbilitySetsOffset = FindOffsetStruct("/Script/FortniteGame.FortAbilitySetDeliveryInfo", "AbilitySets"); + return *(TArray>*)(__int64(this) + AbilitySetsOffset); + } +}; + +class UFortGameplayModifierItemDefinition : public UObject +{ +public: + TArray& GetPersistentGameplayEffects() + { + static auto PersistentGameplayEffectsOffset = GetOffset("PersistentGameplayEffects"); + return this->Get>(PersistentGameplayEffectsOffset); + } + + TArray& GetPersistentAbilitySets() + { + static auto PersistentAbilitySetsOffset = GetOffset("PersistentAbilitySets"); + return this->Get>(PersistentAbilitySetsOffset); + } + + void ApplyModifierToActor(AActor* Actor) + { + if (!Actor) + return; + + UAbilitySystemComponent* AbilitySystemComponent = nullptr; + + if (auto BuildingActor = Cast(Actor)) + { + static auto AbilitySystemComponentOffset = BuildingActor->GetOffset("AbilitySystemComponent"); + AbilitySystemComponent = BuildingActor->Get(AbilitySystemComponentOffset); + } + + else if (auto PlayerState = Cast(Actor)) + { + AbilitySystemComponent = PlayerState->GetAbilitySystemComponent(); + } + + else if (auto Pawn = Cast(Actor)) + { + static auto AbilitySystemComponentOffset = Pawn->GetOffset("AbilitySystemComponent"); + AbilitySystemComponent = Pawn->Get(AbilitySystemComponentOffset); + } + + if (!AbilitySystemComponent) + { + LOG_INFO(LogDev, "Unable to find ASC for {}", Actor->GetName()); + return; + } + + for (int z = 0; z < this->GetPersistentAbilitySets().Num(); z++) + { + auto& AbilitySetDeliveryInfo = this->GetPersistentAbilitySets().at(z, FFortAbilitySetDeliveryInfo::GetStructSize()); + + if (!AbilitySetDeliveryInfo.GetDeliveryRequirements()->DoesActorFollowsRequirements(Actor)) + continue; + + auto& CurrentAbilitySets = AbilitySetDeliveryInfo.GetAbilitySets(); + + for (int j = 0; j < CurrentAbilitySets.Num(); j++) + { + auto& CurrentAbilitySetSoft = CurrentAbilitySets.at(j); + auto CurrentAbilitySet = CurrentAbilitySetSoft.Get(UFortAbilitySet::StaticClass(), true); + + if (!CurrentAbilitySet) + continue; + + CurrentAbilitySet->GiveToAbilitySystem(AbilitySystemComponent); + } + } + + for (int z = 0; z < this->GetPersistentGameplayEffects().Num(); z++) + { + auto& GameplayEffectDeliveryInfo = this->GetPersistentGameplayEffects().at(z, FFortGameplayEffectDeliveryInfo::GetStructSize()); + + if (!GameplayEffectDeliveryInfo.GetDeliveryRequirements()->DoesActorFollowsRequirements(Actor)) + continue; + + auto& CurrentGameplayEffects = GameplayEffectDeliveryInfo.GetGameplayEffects(); + + for (int j = 0; j < CurrentGameplayEffects.Num(); j++) + { + auto& CurrentGameplayEffectInfo = CurrentGameplayEffects.at(j); + auto& CurrentGameplayEffectSoft = CurrentGameplayEffectInfo.GameplayEffect; + static auto ClassClass = FindObject("/Script/CoreUObject.Class"); + auto CurrentGameplayEffect = CurrentGameplayEffectSoft.Get(ClassClass, true); + + if (!CurrentGameplayEffect) + continue; + + LOG_INFO(LogDev, "Giving GameplayEffect {}", CurrentGameplayEffect->GetFullName()); + AbilitySystemComponent->ApplyGameplayEffectToSelf(CurrentGameplayEffect, CurrentGameplayEffectInfo.Level); + } + } + } +}; + +class UFortPlaylist : public UObject +{ +public: + TArray>& GetModifierList() + { + static auto ModifierListOffset = this->GetOffset("ModifierList"); + return this->Get>>(ModifierListOffset); + } + + void ApplyModifiersToActor(AActor* Actor) + { + if (!Actor) + return; + + static auto ModifierListOffset = this->GetOffset("ModifierList", false); + + if (ModifierListOffset == -1) + return; + + auto& ModifierList = this->GetModifierList(); + + static auto FortGameplayModifierItemDefinitionClass = FindObject("/Script/FortniteGame.FortGameplayModifierItemDefinition"); + + for (int i = 0; i < ModifierList.Num(); i++) + { + auto& ModifierSoft = ModifierList.at(i); + auto StrongModifier = ModifierSoft.Get(FortGameplayModifierItemDefinitionClass, true); + + if (!StrongModifier) + continue; + + StrongModifier->ApplyModifierToActor(Actor); + } + } +}; \ No newline at end of file diff --git a/Project Reboot 3.0/GameModeBase.cpp b/Project Reboot 3.0/GameModeBase.cpp index b4caae4..b44350c 100644 --- a/Project Reboot 3.0/GameModeBase.cpp +++ b/Project Reboot 3.0/GameModeBase.cpp @@ -2,6 +2,7 @@ #include "reboot.h" #include "FortPlayerControllerAthena.h" +#include "FortGameModeAthena.h" UClass* AGameModeBase::GetDefaultPawnClassForController(AController* InController) { @@ -60,6 +61,15 @@ APawn* AGameModeBase::SpawnDefaultPawnForHook(AGameModeBase* GameMode, AControll { auto NewPlayerAsAthena = Cast(NewPlayer); + auto GameState = ((AFortGameModeAthena*)GameMode)->GetGameStateAthena(); + + GET_PLAYLIST(GameState); + + if (CurrentPlaylist) + { + CurrentPlaylist->ApplyModifiersToActor(NewPlayerAsAthena->GetPlayerState()); // We need to move this! + } + /* if (Fortnite_Version >= 18) { static auto StormEffectClass = FindObject("/Game/Athena/SafeZone/GE_OutsideSafeZoneDamage.GE_OutsideSafeZoneDamage_C"); diff --git a/Project Reboot 3.0/Project Reboot 3.0.vcxproj b/Project Reboot 3.0/Project Reboot 3.0.vcxproj index 0130d3f..8483e97 100644 --- a/Project Reboot 3.0/Project Reboot 3.0.vcxproj +++ b/Project Reboot 3.0/Project Reboot 3.0.vcxproj @@ -186,6 +186,7 @@ + @@ -253,6 +254,8 @@ + + @@ -267,6 +270,7 @@ + @@ -282,6 +286,7 @@ + @@ -351,6 +356,7 @@ + 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 79e5888..b7a9c1d 100644 --- a/Project Reboot 3.0/Project Reboot 3.0.vcxproj.filters +++ b/Project Reboot 3.0/Project Reboot 3.0.vcxproj.filters @@ -182,6 +182,9 @@ Engine\Source\Runtime\Engine\Private + + FortniteGame\Source\FortniteGame\Private\Abilities + @@ -542,6 +545,18 @@ Reboot\Public + + FortniteGame\Source\FortniteGame\Public + + + FortniteGame\Source\FortniteGame\Public\Abilities + + + Engine\Source\Runtime\Core\Public\Delegates + + + Engine\Source\Runtime\Core\Public\Delegates + @@ -730,10 +745,22 @@ {653d6dbf-b361-41ea-a9b8-b85737412d66} + + {8c77fdeb-c742-4e09-9790-7d32f5240b38} + + + {d0555c50-6464-4766-ad1f-2a7ae8b3b5dd} + + + {d01c7b5d-ef89-43ec-b94f-882c419aa74b} + Engine\Source\Runtime\Engine\Private + + Engine\Source\Runtime\Core\Public\Delegates + \ No newline at end of file diff --git a/Project Reboot 3.0/dllmain.cpp b/Project Reboot 3.0/dllmain.cpp index a507142..9d3de3b 100644 --- a/Project Reboot 3.0/dllmain.cpp +++ b/Project Reboot 3.0/dllmain.cpp @@ -29,6 +29,9 @@ #include "InventoryManagementLibrary.h" #include "FortPlayerPawnAthena.h" +#include "FortGameplayAbilityAthena_PeriodicItemGrant.h" +#include "vendingmachine.h" + enum ENetMode { NM_Standalone, @@ -392,8 +395,15 @@ DWORD WINAPI Main(LPVOID) if (Addresses::FrameStep) // put all non rpc exec hooks in this scope { + 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); + Hooking::MinHook::Hook(FortKismetLibraryDefault, FindObject(L"/Script/FortniteGame.FortKismetLibrary.K2_GiveItemToPlayer"), UFortKismetLibrary::K2_GiveItemToPlayerHook, (PVOID*)&UFortKismetLibrary::K2_GiveItemToPlayerOriginal, false, true); + Hooking::MinHook::Hook(FortKismetLibraryDefault, FindObject(L"/Script/FortniteGame.FortKismetLibrary.K2_GiveBuildingResource"), + UFortKismetLibrary::K2_GiveBuildingResourceHook, (PVOID*)&UFortKismetLibrary::K2_GiveBuildingResourceOriginal, false, true); Hooking::MinHook::Hook(FortKismetLibraryDefault, FindObject(L"/Script/FortniteGame.FortKismetLibrary.GiveItemToInventoryOwner"), UFortKismetLibrary::GiveItemToInventoryOwnerHook, (PVOID*)&UFortKismetLibrary::GiveItemToInventoryOwnerOriginal, false, true); Hooking::MinHook::Hook(FortKismetLibraryDefault, FindObject(L"/Script/FortniteGame.FortKismetLibrary.K2_RemoveItemFromPlayerByGuid"), @@ -476,7 +486,6 @@ DWORD WINAPI Main(LPVOID) static auto PredictionKeyStruct = FindObject("/Script/GameplayAbilities.PredictionKey"); static auto PredictionKeySize = PredictionKeyStruct->GetPropertiesSize(); - if (Globals::bAbilitiesEnabled) { int InternalServerTryActivateAbilityIndex = 0; @@ -746,6 +755,11 @@ DWORD WINAPI Main(LPVOID) stream << Current << '\n'; } } + + /* else if (GetAsyncKeyState(VK_F12) & 1) + { + FillVendingMachines(); + } */ Sleep(1000 / 30); } diff --git a/Project Reboot 3.0/events.h b/Project Reboot 3.0/events.h index 928d97c..e780a00 100644 --- a/Project Reboot 3.0/events.h +++ b/Project Reboot 3.0/events.h @@ -5,6 +5,7 @@ #include "Object.h" #include "reboot.h" #include "GameplayStatics.h" +#include "FortPlaylist.h" struct Event { @@ -256,12 +257,12 @@ static inline std::vector Events = ) }; -static inline UObject* GetEventPlaylist() +static inline UFortPlaylist* GetEventPlaylist() { for (auto& CurrentEvent : Events) { if (CurrentEvent.Version == Fortnite_Version) - return FindObject(CurrentEvent.PlaylistName, nullptr, ANY_PACKAGE); + return FindObject(CurrentEvent.PlaylistName, nullptr, ANY_PACKAGE); } return nullptr; diff --git a/Project Reboot 3.0/globals.h b/Project Reboot 3.0/globals.h index 1edf640..33680a2 100644 --- a/Project Reboot 3.0/globals.h +++ b/Project Reboot 3.0/globals.h @@ -5,6 +5,5 @@ namespace Globals extern inline bool bCreative = false; extern inline bool bGoingToPlayEvent = false; extern inline bool bNoMCP = true; - extern inline bool bAbilitiesEnabled = true; extern inline bool bLogProcessEvent = false; } \ No newline at end of file diff --git a/Project Reboot 3.0/reboot.h b/Project Reboot 3.0/reboot.h index c7ab0a1..09b3bbc 100644 --- a/Project Reboot 3.0/reboot.h +++ b/Project Reboot 3.0/reboot.h @@ -207,6 +207,66 @@ inline void SetBitfield(void* Addr, uint8_t FieldMask, bool NewVal) *(bool*)Bitfield = NewVal; } +inline void* FindPropertyStruct(const std::string& StructName, const std::string& MemberName, bool bWarnIfNotFound = true) +{ + UObject* Struct = FindObject(StructName); + + if (!Struct) + { + if (bWarnIfNotFound) + LOG_WARN(LogFinder, "Unable to find struct4 {}", StructName); + + return nullptr; + } + + // LOG_INFO(LogFinder, "Struct: {}", Struct->GetFullName()); + + auto getFNameOfProp = [](void* Property) -> FName* + { + FName* NamePrivate = nullptr; + + if (Engine_Version >= 425) + NamePrivate = (FName*)(__int64(Property) + 0x28); + else + NamePrivate = &((UField*)Property)->NamePrivate; + + return NamePrivate; + }; + + for (auto CurrentClass = Struct; CurrentClass; CurrentClass = *(UObject**)(__int64(CurrentClass) + Offsets::SuperStruct)) + { + void* Property = *(void**)(__int64(CurrentClass) + Offsets::Children); + + if (Property) + { + std::string PropName = getFNameOfProp(Property)->ToString(); + + if (PropName == MemberName) + { + return Property; + } + + while (Property) + { + // LOG_INFO(LogFinder, "PropName: {}", PropName); + + if (PropName == MemberName) + { + return Property; + } + + Property = Engine_Version >= 425 ? *(void**)(__int64(Property) + 0x20) : ((UField*)Property)->Next; + PropName = Property ? getFNameOfProp(Property)->ToString() : ""; + } + } + } + + if (bWarnIfNotFound) + LOG_WARN(LogFinder, "Unable to find6 {}", MemberName); + + return nullptr; +} + inline int FindOffsetStruct(const std::string& StructName, const std::string& MemberName, bool bWarnIfNotFound = true) { UObject* Struct = FindObject(StructName); @@ -310,4 +370,7 @@ namespace MemberOffsets static inline float GetMaxTickRateHook() { return 30.f; } -#define VALIDATEOFFSET(offset) if (!offset) LOG_WARN(LogDev, "[{}] Invalid offset", __FUNCTIONNAME__); \ No newline at end of file +#define VALIDATEOFFSET(offset) if (!offset) LOG_WARN(LogDev, "[{}] Invalid offset", __FUNCTIONNAME__); + +#define GET_PLAYLIST(GameState) static auto CurrentPlaylistDataOffset = GameState->GetOffset("CurrentPlaylistData", false); \ +auto CurrentPlaylist = CurrentPlaylistDataOffset == -1 && Fortnite_Version < 6 ? nullptr : GameState->GetCurrentPlaylist(); \ No newline at end of file diff --git a/Project Reboot 3.0/vendingmachine.h b/Project Reboot 3.0/vendingmachine.h index 742cc57..897471b 100644 --- a/Project Reboot 3.0/vendingmachine.h +++ b/Project Reboot 3.0/vendingmachine.h @@ -3,19 +3,143 @@ #include "reboot.h" #include "BuildingGameplayActor.h" #include "GameplayStatics.h" +#include "FortLootPackage.h" using ABuildingItemCollectorActor = ABuildingGameplayActor; -void FillVendingMachine(ABuildingItemCollectorActor* VendingMachine) +struct FCollectorUnitInfo { + static UStruct* GetStruct() + { + static auto Struct = FindObject("/Script/FortniteGame.CollectorUnitInfo"); + return Struct; + } + static int GetPropertiesSize() + { + return GetStruct()->GetPropertiesSize(); + } + + TArray* GetOutputItemEntry() + { + static auto OutputItemEntryOffset = FindOffsetStruct("/Script/FortniteGame.CollectorUnitInfo", "OutputItemEntry"); + return (TArray*)(__int64(this) + OutputItemEntryOffset); + } + + UFortWorldItemDefinition*& GetOutputItem() + { + static auto OutputItemOffset = FindOffsetStruct("/Script/FortniteGame.CollectorUnitInfo", "OutputItem"); + return *(UFortWorldItemDefinition**)(__int64(this) + OutputItemOffset); + } +}; + +static inline void FillItemCollector(ABuildingItemCollectorActor* ItemCollector, FName& LootTierGroup, bool bUseInstanceLootValueOverrides, int recursive = 0) +{ + if (recursive >= 10) + return; + + static auto ItemCollectionsOffset = ItemCollector->GetOffset("ItemCollections"); + auto& ItemCollections = ItemCollector->Get>(ItemCollectionsOffset); + + uint8_t RarityToUse = -1; + + for (int ItemCollectorIt = 0; ItemCollectorIt < ItemCollections.Num(); ItemCollectorIt++) + { + auto ItemCollection = ItemCollections.AtPtr(ItemCollectorIt, FCollectorUnitInfo::GetPropertiesSize()); + + if (ItemCollection->GetOutputItemEntry()->Num() > 0) + { + ItemCollection->GetOutputItemEntry()->Free(); + ItemCollection->GetOutputItem() = nullptr; + } + + constexpr bool bPrint = false; + + std::vector LootDrops = PickLootDrops(LootTierGroup, bPrint); + + int tries = 0; + + while (LootDrops.size() == 0) + { + tries++; + LootDrops = PickLootDrops(LootTierGroup, bPrint); + + if (tries >= 10) + break; + } + + if (LootDrops.size() == 0) + continue; + + + for (int LootDropIt = 0; LootDropIt < LootDrops.size(); LootDropIt++) + { + auto WorldItemDefinition = Cast(LootDrops[LootDropIt].ItemDefinition); + + if (WorldItemDefinition && IsPrimaryQuickbar(WorldItemDefinition)) // nice + { + static auto RarityOffset = WorldItemDefinition->GetOffset("Rarity"); + + if (RarityToUse == -1) + RarityToUse = WorldItemDefinition->Get(RarityOffset); + + if (WorldItemDefinition->Get(RarityOffset) == RarityToUse) + { + bool bItemAlreadyInCollector = false; + + for (int ItemCollectorIt2 = 0; ItemCollectorIt2 < ItemCollections.Num(); ItemCollectorIt2++) + { + auto ItemCollection2 = ItemCollections.AtPtr(ItemCollectorIt2, FCollectorUnitInfo::GetPropertiesSize()); + + if (ItemCollection2->GetOutputItem() == WorldItemDefinition) + { + bItemAlreadyInCollector = true; + break; + } + } + + if (bItemAlreadyInCollector) + break; + + ItemCollection->GetOutputItem() = WorldItemDefinition; + } + + break; + } + } + + if (!ItemCollection->GetOutputItem()) + { + ItemCollectorIt--; // retry + continue; + } + + for (int LootDropIt = 0; LootDropIt < LootDrops.size(); LootDropIt++) + { + auto ItemEntry = FFortItemEntry::MakeItemEntry(LootDrops[LootDropIt].ItemDefinition, LootDrops[LootDropIt].Count, LootDrops[LootDropIt].LoadedAmmo); + ItemCollection->GetOutputItemEntry()->Add(*ItemEntry, FFortItemEntry::GetStructSize()); + } + } + + static auto bUseInstanceLootValueOverridesOffset = ItemCollector->GetOffset("bUseInstanceLootValueOverrides"); + ItemCollector->Get(bUseInstanceLootValueOverridesOffset) = bUseInstanceLootValueOverrides; + + static auto VendingMachineClass = FindObject("/Game/Athena/Items/Gameplay/VendingMachine/B_Athena_VendingMachine.B_Athena_VendingMachine_C"); + + if (ItemCollector->IsA(VendingMachineClass)) + { + static auto OverrideVendingMachineRarityOffset = ItemCollector->GetOffset("OverrideVendingMachineRarity"); + ItemCollector->Get(OverrideVendingMachineRarityOffset) = RarityToUse; + } } -void FillVendingMachines() +static inline void FillVendingMachines() { static auto VendingMachineClass = FindObject("/Game/Athena/Items/Gameplay/VendingMachine/B_Athena_VendingMachine.B_Athena_VendingMachine_C"); auto AllVendingMachines = UGameplayStatics::GetAllActorsOfClass(GetWorld(), VendingMachineClass); + auto OverrideLootTierGroup = UKismetStringLibrary::Conv_StringToName(L"Loot_AthenaVending"); // ItemCollector->GetLootTierGroupOverride(); + for (int i = 0; i < AllVendingMachines.Num(); i++) { auto VendingMachine = (ABuildingItemCollectorActor*)AllVendingMachines.at(i); @@ -23,7 +147,7 @@ void FillVendingMachines() if (!VendingMachine) continue; - FillVendingMachine(VendingMachine); + FillItemCollector(VendingMachine, OverrideLootTierGroup, true); } AllVendingMachines.Free();