diff --git a/Project Reboot 3.0/AbilitySystemComponent.h b/Project Reboot 3.0/AbilitySystemComponent.h index 2a078d9..f313acd 100644 --- a/Project Reboot 3.0/AbilitySystemComponent.h +++ b/Project Reboot 3.0/AbilitySystemComponent.h @@ -15,9 +15,21 @@ struct PadHexB0 { char Pad[0xB0]; }; // using FPredictionKey = PadHex10; using FGameplayEventData = PadHexB0; -using FPredictionKey = __int64; // using FGameplayEventData = __int64; +struct FPredictionKey // todo move +{ + // __int64 real; + + static UStruct* GetStruct() + { + static auto Struct = FindObject("/Script/GameplayAbilities.PredictionKey"); + return Struct; + } + + static int GetStructSize() { return GetStruct()->GetPropertiesSize(); } +}; + struct FGameplayEffectContextHandle { unsigned char UnknownData00[0x18]; // 0x0000(0x0018) MISSED OFFSET @@ -72,6 +84,9 @@ public: return Subobject; } + void ServerEndAbility(FGameplayAbilitySpecHandle AbilityToEnd, FGameplayAbilityActivationInfo* ActivationInfo, FPredictionKey* PredictionKey); + void ClientEndAbility(FGameplayAbilitySpecHandle AbilityToEnd, FGameplayAbilityActivationInfo* ActivationInfo); + void ClientCancelAbility(FGameplayAbilitySpecHandle AbilityToCancel, FGameplayAbilityActivationInfo* ActivationInfo); bool HasAbility(UObject* DefaultAbility); FActiveGameplayEffectHandle ApplyGameplayEffectToSelf(UClass* GameplayEffectClass, float Level, const FGameplayEffectContextHandle& EffectContext = FGameplayEffectContextHandle()); // FGameplayEffectContextHandle MakeEffectContext(); @@ -83,4 +98,6 @@ public: void ClearAbility(const FGameplayAbilitySpecHandle& Handle); static void InternalServerTryActivateAbilityHook(UAbilitySystemComponent* AbilitySystemComponent, FGameplayAbilitySpecHandle Handle, bool InputPressed, const FPredictionKey* PredictionKey, const FGameplayEventData* TriggerEventData); -}; \ No newline at end of file +}; + +void LoopSpecs(UAbilitySystemComponent* AbilitySystemComponent, std::function func); \ No newline at end of file diff --git a/Project Reboot 3.0/AbilitySystemComponent_Abilities.cpp b/Project Reboot 3.0/AbilitySystemComponent_Abilities.cpp index b3d5bd4..7de9a57 100644 --- a/Project Reboot 3.0/AbilitySystemComponent_Abilities.cpp +++ b/Project Reboot 3.0/AbilitySystemComponent_Abilities.cpp @@ -50,6 +50,56 @@ FActiveGameplayEffectHandle UAbilitySystemComponent::ApplyGameplayEffectToSelf(U return ContextHandle; } */ +void UAbilitySystemComponent::ServerEndAbility(FGameplayAbilitySpecHandle AbilityToEnd, FGameplayAbilityActivationInfo* ActivationInfo, FPredictionKey* PredictionKey) +{ + static auto ServerEndAbilityFn = FindObject(L"/Script/GameplayAbilities.AbilitySystemComponent.ServerEndAbility"); + + auto Params = Alloc(ServerEndAbilityFn->GetPropertiesSize()); + + if (!Params) + return; + + static auto AbilityToEndOffset = FindOffsetStruct("/Script/GameplayAbilities.AbilitySystemComponent.ServerEndAbility", "AbilityToEnd"); + static auto ActivationInfoOffset = FindOffsetStruct("/Script/GameplayAbilities.AbilitySystemComponent.ServerEndAbility", "ActivationInfo"); + static auto PredictionKeyOffset = FindOffsetStruct("/Script/GameplayAbilities.AbilitySystemComponent.ServerEndAbility", "PredictionKey"); + + *(FGameplayAbilitySpecHandle*)(__int64(Params) + AbilityToEndOffset) = AbilityToEnd; + CopyStruct((FGameplayAbilityActivationInfo*)(__int64(Params) + ActivationInfoOffset), ActivationInfo, FGameplayAbilityActivationInfo::GetStructSize()); + CopyStruct((FPredictionKey*)(__int64(Params) + PredictionKeyOffset), PredictionKey, FPredictionKey::GetStructSize()); + + this->ProcessEvent(ServerEndAbilityFn, Params); +} + +void UAbilitySystemComponent::ClientEndAbility(FGameplayAbilitySpecHandle AbilityToEnd, FGameplayAbilityActivationInfo* ActivationInfo) +{ + static auto ClientEndAbilityFn = FindObject("/Script/GameplayAbilities.AbilitySystemComponent.ClientEndAbility"); + + auto Params = Alloc(ClientEndAbilityFn->GetPropertiesSize()); + + static auto AbilityToEndOffset = FindOffsetStruct("/Script/GameplayAbilities.AbilitySystemComponent.ClientEndAbility", "AbilityToEnd"); + static auto ActivationInfoOffset = FindOffsetStruct("/Script/GameplayAbilities.AbilitySystemComponent.ClientEndAbility", "ActivationInfo"); + + *(FGameplayAbilitySpecHandle*)(__int64(Params) + AbilityToEndOffset) = AbilityToEnd; + CopyStruct((FGameplayAbilityActivationInfo*)(__int64(Params) + ActivationInfoOffset), ActivationInfo, FGameplayAbilityActivationInfo::GetStructSize()); + + this->ProcessEvent(ClientEndAbilityFn, Params); +} + +void UAbilitySystemComponent::ClientCancelAbility(FGameplayAbilitySpecHandle AbilityToCancel, FGameplayAbilityActivationInfo* ActivationInfo) +{ + static auto ClientCancelAbilityFn = FindObject(L"/Script/GameplayAbilities.AbilitySystemComponent.ClientCancelAbility"); + + auto Params = Alloc(ClientCancelAbilityFn->GetPropertiesSize()); + + static auto AbilityToCancelOffset = FindOffsetStruct("/Script/GameplayAbilities.AbilitySystemComponent.ClientCancelAbility", "AbilityToCancel"); + static auto ActivationInfoOffset = FindOffsetStruct("/Script/GameplayAbilities.AbilitySystemComponent.ClientCancelAbility", "ActivationInfo"); + + *(FGameplayAbilitySpecHandle*)(__int64(Params) + AbilityToCancelOffset) = AbilityToCancel; + CopyStruct((FGameplayAbilityActivationInfo*)(__int64(Params) + ActivationInfoOffset), ActivationInfo, FGameplayAbilityActivationInfo::GetStructSize()); + + this->ProcessEvent(ClientCancelAbilityFn, Params); +} + bool UAbilitySystemComponent::HasAbility(UObject* DefaultAbility) { auto ActivatableAbilities = GetActivatableAbilities(); diff --git a/Project Reboot 3.0/BuildingContainer.cpp b/Project Reboot 3.0/BuildingContainer.cpp index 31d102e..6d2bfad 100644 --- a/Project Reboot 3.0/BuildingContainer.cpp +++ b/Project Reboot 3.0/BuildingContainer.cpp @@ -22,7 +22,7 @@ bool ABuildingContainer::SpawnLoot(AFortPawn* Pawn) { auto& lootDrop = LootDrops.at(i); - PickupCreateData CreateData{}; + PickupCreateData CreateData; CreateData.bToss = true; // CreateData.PawnOwner = Pawn; CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(lootDrop->GetItemDefinition(), lootDrop->GetCount(), lootDrop->GetLoadedAmmo()); diff --git a/Project Reboot 3.0/FortGameModeAthena.cpp b/Project Reboot 3.0/FortGameModeAthena.cpp index 581cf79..3f98f43 100644 --- a/Project Reboot 3.0/FortGameModeAthena.cpp +++ b/Project Reboot 3.0/FortGameModeAthena.cpp @@ -1129,7 +1129,7 @@ void AFortGameModeAthena::Athena_HandleStartingNewPlayerHook(AFortGameModeAthena for (auto& LootDrop : LootDrops) { - PickupCreateData CreateData{}; + PickupCreateData CreateData; CreateData.bToss = true; CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(LootDrop->GetItemDefinition(), LootDrop->GetCount(), LootDrop->GetLoadedAmmo()); CreateData.SpawnLocation = Location; diff --git a/Project Reboot 3.0/FortKismetLibrary.cpp b/Project Reboot 3.0/FortKismetLibrary.cpp index 1ad41f8..23ea462 100644 --- a/Project Reboot 3.0/FortKismetLibrary.cpp +++ b/Project Reboot 3.0/FortKismetLibrary.cpp @@ -137,7 +137,7 @@ void UFortKismetLibrary::SpawnItemVariantPickupInWorldHook(UObject* Context, FFr LOG_INFO(LogDev, "{} {} {}", Position.X, Position.Y, Position.Z); - PickupCreateData CreateData{}; + PickupCreateData CreateData; CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(ItemDefinition, ParamsPtr->GetNumberToSpawn(), -1); CreateData.SourceType = ParamsPtr->GetSourceType(); CreateData.Source = ParamsPtr->GetSource(); @@ -508,7 +508,7 @@ AFortPickup* UFortKismetLibrary::K2_SpawnPickupInWorldWithClassHook(UObject* Con LOG_INFO(LogDev, __FUNCTION__); - PickupCreateData CreateData{}; + PickupCreateData CreateData; CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(ItemDefinition, NumberToSpawn, -1); CreateData.Source = Source; CreateData.SourceType = SourceType; @@ -591,7 +591,7 @@ AFortPickup* UFortKismetLibrary::K2_SpawnPickupInWorldHook(UObject* Context, FFr auto Pawn = OptionalOwnerPC ? OptionalOwnerPC->GetMyFortPawn() : nullptr; - PickupCreateData CreateData{}; + PickupCreateData CreateData; CreateData.ItemEntry = FFortItemEntry::MakeItemEntry(ItemDefinition, NumberToSpawn, -1); CreateData.SpawnLocation = Position; CreateData.bToss = bToss; diff --git a/Project Reboot 3.0/FortPawn.cpp b/Project Reboot 3.0/FortPawn.cpp index 53a1793..35a91cd 100644 --- a/Project Reboot 3.0/FortPawn.cpp +++ b/Project Reboot 3.0/FortPawn.cpp @@ -5,7 +5,7 @@ AFortWeapon* AFortPawn::EquipWeaponDefinition(UFortWeaponItemDefinition* WeaponData, const FGuid& ItemEntryGuid) { - static auto EquipWeaponDefinitionFn = FindObject("/Script/FortniteGame.FortPawn.EquipWeaponDefinition"); + static auto EquipWeaponDefinitionFn = FindObject(L"/Script/FortniteGame.FortPawn.EquipWeaponDefinition"); FGuid TrackerGuid{}; @@ -40,6 +40,12 @@ bool AFortPawn::PickUpActor(AActor* PickupTarget, UFortDecoItemDefinition* Place return AFortPawn_PickUpActor_Params.ReturnValue; } +void AFortPawn::OnRep_IsDBNO() +{ + static auto OnRep_IsDBNOFn = FindObject(L"/Script/FortniteGame.FortPawn.OnRep_IsDBNO"); + this->ProcessEvent(OnRep_IsDBNOFn); +} + float AFortPawn::GetShield() { float Shield = 0; diff --git a/Project Reboot 3.0/FortPawn.h b/Project Reboot 3.0/FortPawn.h index b995ea5..0089f36 100644 --- a/Project Reboot 3.0/FortPawn.h +++ b/Project Reboot 3.0/FortPawn.h @@ -27,6 +27,23 @@ public: return ReadBitfieldValue(bIsDBNOOffset, bIsDBNOFieldMask); } + void SetDBNO(bool IsDBNO) + { + static auto bIsDBNOFieldMask = GetFieldMask(GetProperty("bIsDBNO")); + static auto bIsDBNOOffset = GetOffset("bIsDBNO"); + + this->SetBitfieldValue(bIsDBNOOffset, bIsDBNOFieldMask, IsDBNO); + } + + void SetHasPlayedDying(bool NewValue) + { + static auto bPlayedDyingFieldMask = GetFieldMask(GetProperty("bPlayedDying")); + static auto bPlayedDyingOffset = GetOffset("bPlayedDying"); + + this->SetBitfieldValue(bPlayedDyingOffset, bPlayedDyingFieldMask, NewValue); + } + + void OnRep_IsDBNO(); float GetShield(); float GetHealth(); void SetHealth(float NewHealth); diff --git a/Project Reboot 3.0/FortPickup.cpp b/Project Reboot 3.0/FortPickup.cpp index f5013b5..ddd2a19 100644 --- a/Project Reboot 3.0/FortPickup.cpp +++ b/Project Reboot 3.0/FortPickup.cpp @@ -42,7 +42,7 @@ AFortPickup* AFortPickup::SpawnPickup(PickupCreateData& PickupData) } */ static auto FortPickupAthenaClass = FindObject(L"/Script/FortniteGame.FortPickupAthena"); - auto PlayerState = PickupData.PawnOwner->IsValidLowLevel() ? Cast(PickupData.PawnOwner->GetPlayerState()) : nullptr; + auto PlayerState = PickupData.PawnOwner ? Cast(PickupData.PawnOwner->GetPlayerState()) : nullptr; FActorSpawnParameters SpawnParameters{}; // SpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn; diff --git a/Project Reboot 3.0/FortPlayerControllerAthena.h b/Project Reboot 3.0/FortPlayerControllerAthena.h index 442f3e9..2cb0667 100644 --- a/Project Reboot 3.0/FortPlayerControllerAthena.h +++ b/Project Reboot 3.0/FortPlayerControllerAthena.h @@ -197,6 +197,12 @@ public: } } + void ClientOnPawnRevived(AController* EventInstigator) + { + static auto ClientOnPawnRevivedFn = FindObject("/Script/FortniteGame.FortPlayerControllerZone.ClientOnPawnRevived"); + this->ProcessEvent(ClientOnPawnRevivedFn, &EventInstigator); + } + bool& IsMarkedAlive() { static auto bMarkedAliveOffset = GetOffset("bMarkedAlive"); diff --git a/Project Reboot 3.0/FortPlayerPawn.cpp b/Project Reboot 3.0/FortPlayerPawn.cpp index ac86b14..aeffacf 100644 --- a/Project Reboot 3.0/FortPlayerPawn.cpp +++ b/Project Reboot 3.0/FortPlayerPawn.cpp @@ -17,9 +17,97 @@ FFortAthenaLoadout* AFortPlayerPawn::GetCosmeticLoadout() return GetPtr(CosmeticLoadoutOffset); } -void AFortPlayerPawn::ServerReviveFromDBNOHook(AController* EventInstigator) +bool DBNOCheck(AFortPlayerPawn* Pawn, AController* EventInstigator) +{ + bool res = false; + + if (Pawn->IsDBNO()) + { + if (EventInstigator) + { + // idk what this does but this is my interpretation + + auto PlayerState = Cast(Pawn->GetPlayerState()); + auto InstigatorPlayerState = Cast(EventInstigator->GetPlayerState()); + + if (PlayerState && InstigatorPlayerState) + { + if (PlayerState->GetTeamIndex() == InstigatorPlayerState->GetTeamIndex()) + { + res = true; + } + } + } + } + + return res; +} + +void AFortPlayerPawn::ServerReviveFromDBNOHook(AFortPlayerPawn* Pawn, AController* EventInstigator) { LOG_INFO(LogDev, "ServerReviveFromDBNOHook!"); + + if (!DBNOCheck(Pawn, EventInstigator)) + return; + + auto PlayerController = Cast(Pawn->GetController()); + + if (!PlayerController) + return; + + auto PlayerState = Cast(PlayerController->GetPlayerState()); + + if (!PlayerState) + return; + + bool IsRevivingSelf = EventInstigator == PlayerController; + + /* + UObject* ReviveGameplayEffect = nullptr; + + if (IsRevivingSelf) + else + */ + + static auto GAB_AthenaDBNOClass = FindObject(L"/Game/Abilities/NPC/Generic/GAB_AthenaDBNO.Default__GAB_AthenaDBNO_C"); + + auto DBNOPawnASC = PlayerState->GetAbilitySystemComponent(); + + if (!DBNOPawnASC) + return; + + FGameplayAbilitySpec* DBNOSpec = nullptr; + + UObject* ClassToFind = GAB_AthenaDBNOClass->ClassPrivate; + + auto compareAbilities = [&DBNOSpec, &ClassToFind](FGameplayAbilitySpec* Spec) { + auto CurrentAbility = Spec->GetAbility(); + + if (CurrentAbility->ClassPrivate == ClassToFind) + { + DBNOSpec = Spec; + return; + } + }; + + LoopSpecs(DBNOPawnASC, compareAbilities); + + if (!DBNOSpec) + return; + + DBNOPawnASC->ClientCancelAbility(DBNOSpec->GetHandle(), DBNOSpec->GetActivationInfo()); + DBNOPawnASC->ClientEndAbility(DBNOSpec->GetHandle(), DBNOSpec->GetActivationInfo()); + DBNOPawnASC->ServerEndAbility(DBNOSpec->GetHandle(), DBNOSpec->GetActivationInfo(), nullptr); + + Pawn->SetDBNO(false); + Pawn->SetHasPlayedDying(false); + + Pawn->SetHealth(30); // TODO Get value from SetByCallerReviveHealth? + + Pawn->OnRep_IsDBNO(); + + PlayerController->ClientOnPawnRevived(EventInstigator); // We should call the function that calls this. + PlayerController->RespawnPlayerAfterDeath(false); // nooo } void AFortPlayerPawn::ServerHandlePickupWithRequestedSwapHook(UObject* Context, FFrame* Stack, void* Ret) diff --git a/Project Reboot 3.0/FortPlayerPawn.h b/Project Reboot 3.0/FortPlayerPawn.h index 0ea9331..476b0d6 100644 --- a/Project Reboot 3.0/FortPlayerPawn.h +++ b/Project Reboot 3.0/FortPlayerPawn.h @@ -44,7 +44,7 @@ public: UFortWeaponItemDefinition* GetVehicleWeaponDefinition(AFortAthenaVehicle* Vehicle); void UnEquipVehicleWeaponDefinition(UFortWeaponItemDefinition* VehicleWeaponDefinition); - static void ServerReviveFromDBNOHook(AController* EventInstigator); + static void ServerReviveFromDBNOHook(AFortPlayerPawn* Pawn, AController* EventInstigator); static void ServerHandlePickupWithRequestedSwapHook(UObject* Context, FFrame* Stack, void* Ret); // we could native hook this but idk static void StartGhostModeExitHook(UObject* Context, FFrame* Stack, void* Ret); // we could native hook this but eh static AActor* ServerOnExitVehicleHook(AFortPlayerPawn* Pawn, ETryExitVehicleBehavior ExitForceBehavior); // actually returns AFortAthenaVehicle diff --git a/Project Reboot 3.0/GameplayAbilitySpec.h b/Project Reboot 3.0/GameplayAbilitySpec.h index 90003b0..cfea209 100644 --- a/Project Reboot 3.0/GameplayAbilitySpec.h +++ b/Project Reboot 3.0/GameplayAbilitySpec.h @@ -23,6 +23,17 @@ struct FGameplayAbilitySpecHandle } */ }; +struct FGameplayAbilityActivationInfo // TODO Move +{ + static UStruct* GetStruct() + { + static auto Struct = FindObject("/Script/GameplayAbilities.GameplayAbilityActivationInfo"); + return Struct; + } + + static int GetStructSize() { return GetStruct()->GetPropertiesSize(); } +}; + struct FGameplayAbilitySpec : FFastArraySerializerItem { static int GetStructSize() @@ -45,6 +56,12 @@ struct FGameplayAbilitySpec : FFastArraySerializerItem static auto HandleOffset = FindOffsetStruct("/Script/GameplayAbilities.GameplayAbilitySpec", "Handle"); return *(FGameplayAbilitySpecHandle*)(__int64(this) + HandleOffset); } + + FGameplayAbilityActivationInfo* GetActivationInfo() + { + static auto ActivationInfoOffset = FindOffsetStruct("/Script/GameplayAbilities.GameplayAbilitySpec", "ActivationInfo"); + return (FGameplayAbilityActivationInfo*)(__int64(this) + ActivationInfoOffset); + } }; static FGameplayAbilitySpec* MakeNewSpec(UClass* GameplayAbilityClass, UObject* SourceObject = nullptr, bool bAlreadyIsDefault = false) diff --git a/Project Reboot 3.0/Object.cpp b/Project Reboot 3.0/Object.cpp index f86f75a..d7e359f 100644 --- a/Project Reboot 3.0/Object.cpp +++ b/Project Reboot 3.0/Object.cpp @@ -208,15 +208,15 @@ void UObject::AddToRoot() bool UObject::IsValidLowLevel() { - if (std::floor(Fortnite_Version) == 5) // real 1:1 - return true; + if (std::floor(Fortnite_Version) == 5) // real 1:1 // todo (milxnor) try without this + return !IsBadReadPtr(this, 8); if (this == nullptr) { // UE_LOG(LogUObjectBase, Warning, TEXT("NULL object")); return false; } - if (IsBadReadPtr(this, 8)) // needed? + if (IsBadReadPtr(this, 8)) // needed? (milxnor) { return false; } diff --git a/Project Reboot 3.0/dllmain.cpp b/Project Reboot 3.0/dllmain.cpp index 3e89c7d..ec4f67e 100644 --- a/Project Reboot 3.0/dllmain.cpp +++ b/Project Reboot 3.0/dllmain.cpp @@ -291,7 +291,7 @@ DWORD WINAPI Main(LPVOID) } bSwitchedInitialLevel = true; - Globals::bAutoRestart = IsRestartingSupported(); + // Globals::bAutoRestart = IsRestartingSupported(); static auto GameModeDefault = FindObject(L"/Script/FortniteGame.Default__FortGameModeAthena"); static auto FortPlayerControllerZoneDefault = FindObject(L"/Script/FortniteGame.Default__FortPlayerControllerZone"); diff --git a/Project Reboot 3.0/gui.h b/Project Reboot 3.0/gui.h index ac92a48..a98df50 100644 --- a/Project Reboot 3.0/gui.h +++ b/Project Reboot 3.0/gui.h @@ -278,13 +278,10 @@ static inline void StaticUI() { // ImGui::Checkbox("Auto Restart", &Globals::bAutoRestart); - if (false) + if (Globals::bAutoRestart) { - if (Globals::bAutoRestart) - { - ImGui::InputFloat(std::format("How long after {} players join the bus will start", NumRequiredPlayersToStart).c_str(), &AutoBusStartSeconds); - ImGui::InputInt("Num Players required for bus auto timer", &NumRequiredPlayersToStart); - } + ImGui::InputFloat(std::format("How long after {} players join the bus will start", NumRequiredPlayersToStart).c_str(), &AutoBusStartSeconds); + ImGui::InputInt("Num Players required for bus auto timer", &NumRequiredPlayersToStart); } } diff --git a/Project Reboot 3.0/reboot.h b/Project Reboot 3.0/reboot.h index ec9f29d..ad69d39 100644 --- a/Project Reboot 3.0/reboot.h +++ b/Project Reboot 3.0/reboot.h @@ -371,6 +371,9 @@ inline int FindOffsetStruct(const std::string& StructName, const std::string& Me // template static void CopyStruct(void* Dest, void* Src, size_t Size, UStruct* Struct = nullptr) { + if (!Src) + return; + memcpy_s(Dest, Size, Src, Size); if (Struct) @@ -394,7 +397,9 @@ public: template static T* Alloc(size_t Size = sizeof(T), bool bUseFMemoryRealloc = false) { - return bUseFMemoryRealloc ? (T*)FMemory::Realloc(0, Size, 0) : (T*)VirtualAlloc(0, Size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); + auto mem = bUseFMemoryRealloc ? (T*)FMemory::Realloc(0, Size, 0) : (T*)VirtualAlloc(0, Size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); + // RtlSecureZeroMemory(mem, Size); + return mem; } namespace MemberOffsets