diff --git a/Project Reboot 3.0/AthenaDeimosRift.cpp b/Project Reboot 3.0/AthenaDeimosRift.cpp deleted file mode 100644 index 726519f..0000000 --- a/Project Reboot 3.0/AthenaDeimosRift.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "AthenaDeimosRift.h" - -void AAthenaDeimosRift::QueueActorsToSpawnHook(UObject* Context, FFrame* Stack, void* Ret) -{ - LOG_INFO(LogDev, "QueueActorsToSpawnHook!"); - return QueueActorsToSpawnOriginal(Context, Stack, Ret); -} \ No newline at end of file diff --git a/Project Reboot 3.0/AthenaDeimosRift.h b/Project Reboot 3.0/AthenaDeimosRift.h deleted file mode 100644 index 0258bed..0000000 --- a/Project Reboot 3.0/AthenaDeimosRift.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include "BuildingRift.h" -#include "Stack.h" - -class AAthenaDeimosRift : public ABuildingRift -{ -public: - static inline void (*QueueActorsToSpawnOriginal)(UObject* Context, FFrame* Stack, void* Ret); - - static void QueueActorsToSpawnHook(UObject* Context, FFrame* Stack, void* Ret); -}; \ No newline at end of file diff --git a/Project Reboot 3.0/BuildingContainer.h b/Project Reboot 3.0/BuildingContainer.h index 444c95b..a1d14b6 100644 --- a/Project Reboot 3.0/BuildingContainer.h +++ b/Project Reboot 3.0/BuildingContainer.h @@ -13,6 +13,38 @@ public: return this->ReadBitfieldValue(bDestroyContainerOnSearchOffset, bDestroyContainerOnSearchFieldMask); } + bool IsAlreadySearched() + { + static auto bAlreadySearchedOffset = this->GetOffset("bAlreadySearched"); + static auto bAlreadySearchedFieldMask = GetFieldMask(this->GetProperty("bAlreadySearched")); + return this->ReadBitfieldValue(bAlreadySearchedOffset, bAlreadySearchedFieldMask); + } + + void SetAlreadySearched(bool bNewValue, bool bOnRep = true) + { + static auto bAlreadySearchedOffset = this->GetOffset("bAlreadySearched"); + static auto bAlreadySearchedFieldMask = GetFieldMask(this->GetProperty("bAlreadySearched")); + this->SetBitfieldValue(bAlreadySearchedOffset, bAlreadySearchedFieldMask, bNewValue); + + if (bOnRep) + { + static auto OnRep_bAlreadySearchedFn = FindObject(L"/Script/FortniteGame.BuildingContainer.OnRep_bAlreadySearched"); + this->ProcessEvent(OnRep_bAlreadySearchedFn); + } + } + + FVector& GetLootSpawnLocation() + { + static auto LootSpawnLocationOffset = GetOffset("LootSpawnLocation"); + return Get(LootSpawnLocationOffset); + } + + float& GetLootNoiseRange() + { + static auto LootNoiseRangeOffset = GetOffset("LootNoiseRange"); + return Get(LootNoiseRangeOffset); + } + bool SpawnLoot(AFortPawn* Pawn); static UClass* StaticClass() diff --git a/Project Reboot 3.0/BuildingGameplayActorSpawnMachine.cpp b/Project Reboot 3.0/BuildingGameplayActorSpawnMachine.cpp index 021a6e4..67406c6 100644 --- a/Project Reboot 3.0/BuildingGameplayActorSpawnMachine.cpp +++ b/Project Reboot 3.0/BuildingGameplayActorSpawnMachine.cpp @@ -86,13 +86,16 @@ void ABuildingGameplayActorSpawnMachine::RebootingDelegateHook(ABuildingGameplay auto StrongResurrectionLocation = ResurrectionComponent->GetResurrectionLocation().Get(); - LOG_INFO(LogDev, "StrongResurrectionLocation: {} IsClientReady: {}", __int64(StrongResurrectionLocation), PlayerState->GetRespawnData()->IsClientReady()); + LOG_INFO(LogDev, "StrongResurrectionLocation: {} IsRespawnDataAvailable: {}", __int64(StrongResurrectionLocation), PlayerState->GetRespawnData()->IsRespawnDataAvailable()); if (!StrongResurrectionLocation) return; - GameMode->RestartPlayerAtPlayerStart(PlayerController, StrongResurrectionLocation); - // PlayerController->ServerRestartPlayer(); + // GameMode->RestartPlayerAtPlayerStart(PlayerController, StrongResurrectionLocation); + + PlayerState->GetRespawnData()->IsRespawnDataAvailable() = false; + PlayerController->SetPlayerIsWaiting(true); + PlayerController->ServerRestartPlayer(); /* static auto PawnClass = FindObject("/Game/Athena/PlayerPawn_Athena.PlayerPawn_Athena_C"); auto NewPawn = GetWorld()->SpawnActor(PawnClass, StrongResurrectionLocation->GetTransform()); @@ -105,6 +108,11 @@ void ABuildingGameplayActorSpawnMachine::RebootingDelegateHook(ABuildingGameplay if (!NewPawn) // Failed to restart player return; + bool bEnterSkydiving = false; // TODO get from like curve table iirc idk or the variable + + PlayerController->ClientClearDeathNotification(); + // PlayerController->RespawnPlayerAfterDeath(bEnterSkydiving); + NewPawn->SetHealth(100); NewPawn->SetMaxHealth(100); diff --git a/Project Reboot 3.0/FortAthenaMutator_Bots.h b/Project Reboot 3.0/FortAthenaMutator_Bots.h new file mode 100644 index 0000000..3d8a128 --- /dev/null +++ b/Project Reboot 3.0/FortAthenaMutator_Bots.h @@ -0,0 +1,32 @@ +#pragma once + +#include "FortAthenaMutator.h" + +class AFortAthenaMutator_Bots : public AFortAthenaMutator // AFortAthenaMutator_SpawningPolicyEQS +{ +public: + class AFortPlayerPawnAthena* SpawnBot(UClass* BotPawnClass, AActor* InSpawnLocator, const FVector& InSpawnLocation, const FRotator& InSpawnRotation, bool bSnapToGround) + { + static auto SpawnBotFn = FindObject(L"/Script/FortniteGame.FortAthenaMutator_Bots.SpawnBot"); + + struct + { + UClass* BotPawnClass; // (Parm, ZeroConstructor, IsPlainOldData, NoDestructor, UObjectWrapper, HasGetValueTypeHash, NativeAccessSpecifierPublic) + AActor* InSpawnLocator; // (ConstParm, Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + FVector InSpawnLocation; // (ConstParm, Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + FRotator InSpawnRotation; // (ConstParm, Parm, ZeroConstructor, IsPlainOldData, NoDestructor, NativeAccessSpecifierPublic) + bool bSnapToGround; // (ConstParm, Parm, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + AFortPlayerPawnAthena* ReturnValue; // (Parm, OutParm, ZeroConstructor, ReturnParm, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic) + } AFortAthenaMutator_Bots_SpawnBot_Params{ BotPawnClass, InSpawnLocator, InSpawnLocation, InSpawnRotation, bSnapToGround }; + + this->ProcessEvent(SpawnBotFn, &AFortAthenaMutator_Bots_SpawnBot_Params); + + return AFortAthenaMutator_Bots_SpawnBot_Params.ReturnValue; + } + + static UClass* StaticClass() + { + static auto Class = FindObject("/Script/FortniteGame.FortAthenaMutator_Bots"); + return Class; + } +}; \ No newline at end of file diff --git a/Project Reboot 3.0/FortAthenaMutator_Disco.h b/Project Reboot 3.0/FortAthenaMutator_Disco.h index 32202ed..33289f6 100644 --- a/Project Reboot 3.0/FortAthenaMutator_Disco.h +++ b/Project Reboot 3.0/FortAthenaMutator_Disco.h @@ -23,7 +23,7 @@ public: static UClass* StaticClass() { - static auto Class = FindObject("/Script/FortniteGame.FortAthenaMutator_Disco"); + static auto Class = FindObject(L"/Script/FortniteGame.FortAthenaMutator_Disco"); return Class; } diff --git a/Project Reboot 3.0/FortAthenaMutator_Heist.h b/Project Reboot 3.0/FortAthenaMutator_Heist.h index 808a3e3..8e8fede 100644 --- a/Project Reboot 3.0/FortAthenaMutator_Heist.h +++ b/Project Reboot 3.0/FortAthenaMutator_Heist.h @@ -36,7 +36,7 @@ public: static UClass* StaticClass() { - static auto Class = FindObject("/Script/FortniteGame.FortAthenaMutator_Heist"); + static auto Class = FindObject(L"/Script/FortniteGame.FortAthenaMutator_Heist"); return Class; } }; \ No newline at end of file diff --git a/Project Reboot 3.0/FortAthenaNpcPatrollingComponent.h b/Project Reboot 3.0/FortAthenaNpcPatrollingComponent.h new file mode 100644 index 0000000..9423cf5 --- /dev/null +++ b/Project Reboot 3.0/FortAthenaNpcPatrollingComponent.h @@ -0,0 +1,23 @@ +#pragma once + +#include "ActorComponent.h" + +#include "FortAthenaPatrolPath.h" + +#include "reboot.h" + +class UFortAthenaNpcPatrollingComponent : public UActorComponent +{ +public: + void SetPatrolPath(AFortAthenaPatrolPath* NewPatrolPath) + { + static auto SetPatrolPathFn = FindObject(L"/Script/FortniteGame.FortAthenaNpcPatrollingComponent:SetPatrolPath"); + this->ProcessEvent(SetPatrolPathFn, &NewPatrolPath); + } + + static UClass* StaticClass() + { + static auto Class = FindObject(L"/Script/FortniteGame.FortAthenaNpcPatrollingComponent"); + return Class; + } +}; \ No newline at end of file diff --git a/Project Reboot 3.0/FortAthenaPatrolPath.h b/Project Reboot 3.0/FortAthenaPatrolPath.h new file mode 100644 index 0000000..873b00d --- /dev/null +++ b/Project Reboot 3.0/FortAthenaPatrolPath.h @@ -0,0 +1,8 @@ +#pragma once + +#include "Actor.h" + +class AFortAthenaPatrolPath : public AActor +{ +public: +}; \ No newline at end of file diff --git a/Project Reboot 3.0/FortGameModeAthena.cpp b/Project Reboot 3.0/FortGameModeAthena.cpp index 0932591..fc705e6 100644 --- a/Project Reboot 3.0/FortGameModeAthena.cpp +++ b/Project Reboot 3.0/FortGameModeAthena.cpp @@ -328,6 +328,24 @@ bool AFortGameModeAthena::Athena_ReadyToStartMatchHook(AFortGameModeAthena* Game { auto& AdditionalLevels = CurrentPlaylist->Get>>(AdditionalLevelsOffset); + static auto AdditionalLevelsServerOnlyOffset = CurrentPlaylist->GetOffset("AdditionalLevelsServerOnly", false); + + if (AdditionalLevelsServerOnlyOffset != -1) + { + TArray>& AdditionalLevelsServerOnly = CurrentPlaylist->Get>>(AdditionalLevelsServerOnlyOffset); + LOG_INFO(LogPlaylist, "Loading {} playlist server levels.", AdditionalLevelsServerOnly.Num()); + + for (int i = 0; i < AdditionalLevelsServerOnly.Num(); i++) + { + FName LevelFName = AdditionalLevelsServerOnly.at(i).SoftObjectPtr.ObjectID.AssetPathName; + auto LevelNameStr = LevelFName.ToString(); + LOG_INFO(LogPlaylist, "Loading server level {}.", LevelNameStr); + auto LevelNameWStr = std::wstring(LevelNameStr.begin(), LevelNameStr.end()); + + GameState->AddToAdditionalPlaylistLevelsStreamed(LevelFName, true); + } + } + LOG_INFO(LogPlaylist, "Loading {} playlist levels.", AdditionalLevels.Num()); for (int i = 0; i < AdditionalLevels.Num(); i++) @@ -336,25 +354,20 @@ bool AFortGameModeAthena::Athena_ReadyToStartMatchHook(AFortGameModeAthena* Game auto LevelNameStr = LevelFName.ToString(); LOG_INFO(LogPlaylist, "Loading level {}.", LevelNameStr); auto LevelNameWStr = std::wstring(LevelNameStr.begin(), LevelNameStr.end()); - - // bruh the onrep automatically streams if no levelstreamingdynamci found - // StreamLevel(LevelNameStr); - // FLatentActionInfo LatentInfo{}; - // UGameplayStatics::LoadStreamLevel(GetWorld(), LevelFName, true, false, LatentInfo); + GameState->AddToAdditionalPlaylistLevelsStreamed(LevelFName); - // ULevelStreamingDynamic::LoadLevelInstance(GetWorld(), LevelNameWStr.c_str(), FVector(), FRotator()); + /* - static auto AdditionalPlaylistLevelsStreamedOffset = GameState->GetOffset("AdditionalPlaylistLevelsStreamed", false); + Alright so us calling the OnRep for the level to stream I believe is a bit scuffy, but it's fine. + On newer versions there is another array of ULevelStreaming, and this gets used to see if all the playlist levels are visible. + That array doesn't get filled with the OnRep as I think the array is server only. + I am not sure if this array does anything, but theres a function that checks the array and it gets used especially in mutators. + Funny thing, AFortGameModeAthena::ReadyToStartMatch does not return true unless all of the levels in the array is fully streamed in, but since it's empty it passes. - if (AdditionalPlaylistLevelsStreamedOffset != -1) // i think its valid on every version but idgaf - { - if (Fortnite_Version < 11) // IDK What verison it actually wsa but they chnaged it to a struct - { - auto& AdditionalPlaylistLevelsStreamed = GameState->Get>(AdditionalPlaylistLevelsStreamedOffset); - AdditionalPlaylistLevelsStreamed.Add(LevelFName); - } - } + */ + + // There is another array of the ULevelStreaming, and I don't think this gets filled by the OnRep (since really our way is hacky as the OnRep has the implementation) } static auto OnRep_AdditionalPlaylistLevelsStreamedFn = FindObject(L"/Script/FortniteGame.FortGameState.OnRep_AdditionalPlaylistLevelsStreamed"); @@ -435,7 +448,11 @@ bool AFortGameModeAthena::Athena_ReadyToStartMatchHook(AFortGameModeAthena* Game } static auto bWorldIsReadyOffset = GameMode->GetOffset("bWorldIsReady"); - SetBitfield(GameMode->GetPtr(bWorldIsReadyOffset), 1, true); // idk when we actually set this + SetBitfield(GameMode->GetPtr(bWorldIsReadyOffset), 1, true); // idk when we actually set this (probably after we listen) + + SetupAIDirector(); + SetupServerBotManager(); + // SetupNavConfig(UKismetStringLibrary::Conv_StringToName(L"MANG")); // Calendar::SetSnow(1000); @@ -536,14 +553,12 @@ bool AFortGameModeAthena::Athena_ReadyToStartMatchHook(AFortGameModeAthena* Game static auto GameSessionOffset = GameMode->GetOffset("GameSession"); auto GameSession = GameMode->Get(GameSessionOffset); - static auto MaxPlayersOffset = GameSession->GetOffset("MaxPlayers"); + static auto MaxPlayersOffset = GameSession->GetOffset("MaxPlayers"); GameSession->Get(MaxPlayersOffset) = 100; GameState->OnRep_CurrentPlaylistInfo(); // ? - // SetupNavConfig(); - static auto bAlwaysDBNOOffset = GameMode->GetOffset("bAlwaysDBNO"); // GameMode->Get(bAlwaysDBNOOffset) = true; @@ -582,10 +597,6 @@ bool AFortGameModeAthena::Athena_ReadyToStartMatchHook(AFortGameModeAthena* Game GetWorld()->Listen(); - SetupAIDirector(); - SetupServerBotManager(); - // SetupNavConfig(UKismetStringLibrary::Conv_StringToName(L"Deimos")); - if (auto TeamsArrayContainer = GameState->GetTeamsArrayContainer()) { TeamsArrayContainer->TeamIndexesArray.Free(); @@ -733,6 +744,8 @@ bool AFortGameModeAthena::Athena_ReadyToStartMatchHook(AFortGameModeAthena* Game if (Ret) { + LOG_INFO(LogDev, "Athena_ReadyToStartMatchOriginal RET!"); // if u dont see this, not good + // We are assuming it successfully became warmup. std::vector> FunctionsToCall; @@ -1160,7 +1173,7 @@ void AFortGameModeAthena::Athena_HandleStartingNewPlayerHook(AFortGameModeAthena static auto SquadIdOffset = PlayerStateAthena->GetOffset("SquadId", false); if (SquadIdOffset != -1) - PlayerStateAthena->GetSquadId() = PlayerStateAthena->GetTeamIndex() - 3; // wrong place to do this + PlayerStateAthena->GetSquadId() = PlayerStateAthena->GetTeamIndex() - NumToSubtractFromSquadId; // wrong place to do this TWeakObjectPtr WeakPlayerState{}; WeakPlayerState.ObjectIndex = PlayerStateAthena->InternalIndex; diff --git a/Project Reboot 3.0/FortGameSessionDedicatedAthena.cpp b/Project Reboot 3.0/FortGameSessionDedicatedAthena.cpp index 8560e01..c2aed41 100644 --- a/Project Reboot 3.0/FortGameSessionDedicatedAthena.cpp +++ b/Project Reboot 3.0/FortGameSessionDedicatedAthena.cpp @@ -4,6 +4,7 @@ #include "FortPlayerControllerAthena.h" #include "OnlineReplStructs.h" +#include "gui.h" uint8 AFortGameSessionDedicatedAthena::GetSquadIdForCurrentPlayerHook(AFortGameSessionDedicatedAthena* GameSessionDedicated, __int64 UniqueId) { @@ -23,7 +24,7 @@ uint8 AFortGameSessionDedicatedAthena::GetSquadIdForCurrentPlayerHook(AFortGameS if (PlayerState->GetPtr(UniqueIdOffset)->IsIdentical((FUniqueNetIdRepl*)&UniqueId)) { - return PlayerState->GetTeamIndex() - 3; + return PlayerState->GetTeamIndex() - NumToSubtractFromSquadId; } } diff --git a/Project Reboot 3.0/FortGameStateAthena.cpp b/Project Reboot 3.0/FortGameStateAthena.cpp index fa0e083..8456a1e 100644 --- a/Project Reboot 3.0/FortGameStateAthena.cpp +++ b/Project Reboot 3.0/FortGameStateAthena.cpp @@ -50,7 +50,7 @@ void AFortGameStateAthena::SetGamePhaseStep(EAthenaGamePhaseStep NewGamePhaseSte { // On newer versions there is a second param. - LOG_INFO(LogDev, "A1: {} FunctionToCallPair.second: {}", FunctionToCallPair.first->IsValidLowLevel() ? FunctionToCallPair.first->GetFullName() : "BadRead", __int64(FunctionToCallPair.second)); + // LOG_INFO(LogDev, "A1: {} FunctionToCallPair.second: {}", FunctionToCallPair.first->IsValidLowLevel() ? FunctionToCallPair.first->GetFullName() : "BadRead", __int64(FunctionToCallPair.second)); if (FunctionToCallPair.second->IsValidLowLevel() && FunctionToCallPair.first->IsValidLowLevel()) { @@ -272,6 +272,26 @@ TeamsArrayContainer* AFortGameStateAthena::GetTeamsArrayContainer() return Offset != -1 ? (TeamsArrayContainer*)(__int64(this) + Offset) : nullptr; } +void AFortGameStateAthena::AddToAdditionalPlaylistLevelsStreamed(const FName& Name, bool bServerOnly) +{ + static auto AdditionalPlaylistLevelsStreamedOffset = this->GetOffset("AdditionalPlaylistLevelsStreamed", false); + + if (!FAdditionalLevelStreamed::GetStruct()) + { + auto& AdditionalPlaylistLevelsStreamed = this->Get>(AdditionalPlaylistLevelsStreamedOffset); + AdditionalPlaylistLevelsStreamed.Add(Name); + } + else + { + auto& AdditionalPlaylistLevelsStreamed = this->Get>(AdditionalPlaylistLevelsStreamedOffset); + auto NewLevelStreamed = Alloc(FAdditionalLevelStreamed::GetStructSize()); + NewLevelStreamed->GetLevelName() = Name; + NewLevelStreamed->IsServerOnly() = bServerOnly; + + AdditionalPlaylistLevelsStreamed.AddPtr(NewLevelStreamed, FAdditionalLevelStreamed::GetStructSize()); + } +} + UClass* AFortGameStateAthena::StaticClass() { static auto Class = FindObject(L"/Script/FortniteGame.FortGameStateAthena"); diff --git a/Project Reboot 3.0/FortGameStateAthena.h b/Project Reboot 3.0/FortGameStateAthena.h index 4740080..5a1061f 100644 --- a/Project Reboot 3.0/FortGameStateAthena.h +++ b/Project Reboot 3.0/FortGameStateAthena.h @@ -66,6 +66,30 @@ struct FPlayerBuildableClassContainer TArray BuildingClasses; // 0x0000(0x0010) (ZeroConstructor, Transient, UObjectWrapper, NativeAccessSpecifierPublic) }; +struct FAdditionalLevelStreamed +{ +public: + static UStruct* GetStruct() + { + static auto Struct = FindObject(L"/Script/FortniteGame.AdditionalLevelStreamed"); + return Struct; + } + + static int GetStructSize() { return GetStruct()->GetPropertiesSize(); } + + FName& GetLevelName() + { + static auto LevelNameOffset = FindOffsetStruct("/Script/FortniteGame.AdditionalLevelStreamed", "LevelName"); + return *(FName*)(__int64(this) + LevelNameOffset); + } + + bool& IsServerOnly() + { + static auto bIsServerOnlyOffset = FindOffsetStruct("/Script/FortniteGame.AdditionalLevelStreamed", "bIsServerOnly"); + return *(bool*)(__int64(this) + bIsServerOnlyOffset); + } +}; + class AFortGameStateAthena : public AGameState { public: @@ -127,6 +151,7 @@ public: void OnRep_CurrentPlaylistInfo(); void OnRep_PlayersLeft(); TeamsArrayContainer* GetTeamsArrayContainer(); + void AddToAdditionalPlaylistLevelsStreamed(const FName& Name, bool bServerOnly = false); static UClass* StaticClass(); }; diff --git a/Project Reboot 3.0/FortItemDefinition.h b/Project Reboot 3.0/FortItemDefinition.h index 25c043b..c450356 100644 --- a/Project Reboot 3.0/FortItemDefinition.h +++ b/Project Reboot 3.0/FortItemDefinition.h @@ -21,7 +21,7 @@ public: static UClass* StaticClass() { - static auto Class = FindObject("/Script/FortniteGame.FortItemDefinition"); + static auto Class = FindObject(L"/Script/FortniteGame.FortItemDefinition"); return Class; } }; diff --git a/Project Reboot 3.0/FortPlayerController.cpp b/Project Reboot 3.0/FortPlayerController.cpp index 541b980..ad9db5d 100644 --- a/Project Reboot 3.0/FortPlayerController.cpp +++ b/Project Reboot 3.0/FortPlayerController.cpp @@ -747,6 +747,11 @@ void AFortPlayerController::ServerCreateBuildingActorHook(UObject* Context, FFra if (!PlayerController) // ?? return ServerCreateBuildingActorOriginal(Context, Stack, Ret); + auto WorldInventory = PlayerController->GetWorldInventory(); + + if (!WorldInventory) + return ServerCreateBuildingActorOriginal(Context, Stack, Ret); + auto PlayerStateAthena = Cast(PlayerController->GetPlayerState()); if (!PlayerStateAthena) @@ -816,7 +821,38 @@ void AFortPlayerController::ServerCreateBuildingActorHook(UObject* Context, FFra if (!bCanBuild) { - // LOG_INFO(LogDev, "cant build"); + ExistingBuildings.Free(); + return ServerCreateBuildingActorOriginal(Context, Stack, Ret); + } + + FTransform Transform{}; + Transform.Translation = BuildLocation; + Transform.Rotation = BuildRotator.Quaternion(); + Transform.Scale3D = { 1, 1, 1 }; + + auto BuildingActor = GetWorld()->SpawnActor(BuildingClass, Transform); + + if (!BuildingActor) + { + ExistingBuildings.Free(); + return ServerCreateBuildingActorOriginal(Context, Stack, Ret); + } + + auto MatDefinition = UFortKismetLibrary::K2_GetResourceItemDefinition(BuildingActor->GetResourceType()); + + auto MatInstance = WorldInventory->FindItemInstance(MatDefinition); + + bool bBuildFree = PlayerController->DoesBuildFree(); + + // LOG_INFO(LogDev, "MatInstance->GetItemEntry()->GetCount(): {}", MatInstance->GetItemEntry()->GetCount()); + + int MinimumMaterial = 10; + bool bShouldDestroy = MatInstance && MatInstance->GetItemEntry() ? MatInstance->GetItemEntry()->GetCount() < MinimumMaterial : true; + + if (bShouldDestroy && !bBuildFree) + { + ExistingBuildings.Free(); + BuildingActor->SilentDie(); return ServerCreateBuildingActorOriginal(Context, Stack, Ret); } @@ -829,36 +865,6 @@ void AFortPlayerController::ServerCreateBuildingActorHook(UObject* Context, FFra ExistingBuildings.Free(); - FTransform Transform{}; - Transform.Translation = BuildLocation; - Transform.Rotation = BuildRotator.Quaternion(); - Transform.Scale3D = { 1, 1, 1 }; - - auto BuildingActor = GetWorld()->SpawnActor(BuildingClass, Transform); - - if (!BuildingActor) - return ServerCreateBuildingActorOriginal(Context, Stack, Ret); - - auto MatDefinition = UFortKismetLibrary::K2_GetResourceItemDefinition(BuildingActor->GetResourceType()); - auto WorldInventory = PlayerController->GetWorldInventory(); - - if (!WorldInventory) - return ServerCreateBuildingActorOriginal(Context, Stack, Ret); - - auto MatInstance = WorldInventory->FindItemInstance(MatDefinition); - - bool bBuildFree = PlayerController->DoesBuildFree(); - - // LOG_INFO(LogDev, "MatInstance->GetItemEntry()->GetCount(): {}", MatInstance->GetItemEntry()->GetCount()); - - bool bShouldDestroy = MatInstance && MatInstance->GetItemEntry() ? MatInstance->GetItemEntry()->GetCount() < 10 : true; - - if (bShouldDestroy && !bBuildFree) - { - BuildingActor->SilentDie(); - return ServerCreateBuildingActorOriginal(Context, Stack, Ret); - } - BuildingActor->SetPlayerPlaced(true); BuildingActor->InitializeBuildingActor(PlayerController, BuildingActor, true); BuildingActor->SetTeam(PlayerStateAthena->GetTeamIndex()); // required? @@ -1212,7 +1218,7 @@ void AFortPlayerController::ClientOnPawnDiedHook(AFortPlayerController* PlayerCo if (Fortnite_Version > 1.8 || Fortnite_Version == 1.11) { auto DeathInfo = (void*)(__int64(DeadPlayerState) + MemberOffsets::FortPlayerStateAthena::DeathInfo); // Alloc(DeathInfoStructSize); - RtlSecureZeroMemory(DeathInfo, DeathInfoStructSize); + RtlSecureZeroMemory(DeathInfo, DeathInfoStructSize); // TODO FREE THE DEATHTAGS auto/*&*/ Tags = MemberOffsets::FortPlayerPawn::CorrectTags == 0 ? FGameplayTagContainer() : DeadPawn->Get(MemberOffsets::FortPlayerPawn::CorrectTags); diff --git a/Project Reboot 3.0/FortPlayerControllerAthena.h b/Project Reboot 3.0/FortPlayerControllerAthena.h index 82c28e0..9c587e1 100644 --- a/Project Reboot 3.0/FortPlayerControllerAthena.h +++ b/Project Reboot 3.0/FortPlayerControllerAthena.h @@ -175,6 +175,28 @@ public: return Get(CreativePlotLinkedVolumeOffset); } + void ClientClearDeathNotification() // actually in zone + { + auto ClientClearDeathNotificationFn = FindFunction("ClientClearDeathNotification"); + + if (ClientClearDeathNotificationFn) + this->ProcessEvent(ClientClearDeathNotificationFn); + } + + void RespawnPlayerAfterDeath(bool bEnterSkydiving) + { + static auto RespawnPlayerAfterDeathFn = FindObject("/Script/FortniteGame.FortPlayerControllerAthena.RespawnPlayerAfterDeath"); + + if (RespawnPlayerAfterDeathFn) + { + this->ProcessEvent(RespawnPlayerAfterDeathFn, &bEnterSkydiving); + } + else + { + // techinally we can remake this as all it really does on older versions is clear deathinfo + } + } + static void StartGhostModeHook(UObject* Context, FFrame* Stack, void* Ret); // we could native hook this but eh static void EndGhostModeHook(AFortPlayerControllerAthena* PlayerController); static void EnterAircraftHook(UObject* PC, AActor* Aircraft); diff --git a/Project Reboot 3.0/GameModeBase.cpp b/Project Reboot 3.0/GameModeBase.cpp index 340cb63..d110504 100644 --- a/Project Reboot 3.0/GameModeBase.cpp +++ b/Project Reboot 3.0/GameModeBase.cpp @@ -132,6 +132,7 @@ APawn* AGameModeBase::SpawnDefaultPawnForHook(AGameModeBase* GameMode, AControll bool bIsRespawning = false; + /* static auto RespawnDataOffset = PlayerStateAthena->GetOffset("RespawnData", false); if (RespawnDataOffset != -1) @@ -142,7 +143,12 @@ APawn* AGameModeBase::SpawnDefaultPawnForHook(AGameModeBase* GameMode, AControll { bIsRespawning = true; } - } + } */ + + /* auto DeathInfo = (void*)(__int64(PlayerStateAthena) + MemberOffsets::FortPlayerStateAthena::DeathInfo); + FVector DeathLocation = MemberOffsets::DeathInfo::DeathLocation != -1 ? *(FVector*)(__int64(DeathInfo) + MemberOffsets::DeathInfo::DeathLocation) : FVector(0, 0, 0); + + bIsRespawning = !(DeathLocation == FVector(0, 0, 0)); // bro kms */ auto ASC = PlayerStateAthena->GetAbilitySystemComponent(); auto GameState = ((AFortGameModeAthena*)GameMode)->GetGameStateAthena(); @@ -225,13 +231,13 @@ APawn* AGameModeBase::SpawnDefaultPawnForHook(AGameModeBase* GameMode, AControll } else { - LOG_INFO(LogDev, "Player is respawning!"); + // TODO I DONT KNOW WHEN TO DO THIS - auto DeathInfo = (void*)(__int64(PlayerStateAthena) + MemberOffsets::FortPlayerStateAthena::DeathInfo); + /* static auto DeathInfoStruct = FindObject(L"/Script/FortniteGame.DeathInfo"); static auto DeathInfoStructSize = DeathInfoStruct->GetPropertiesSize(); - RtlSecureZeroMemory(DeathInfo, DeathInfoStructSize); + RtlSecureZeroMemory(DeathInfo, DeathInfoStructSize); // TODO FREE THE DEATHTAGS static auto OnRep_DeathInfoFn = FindObject(L"/Script/FortniteGame.FortPlayerStateAthena.OnRep_DeathInfo"); @@ -239,6 +245,11 @@ APawn* AGameModeBase::SpawnDefaultPawnForHook(AGameModeBase* GameMode, AControll { PlayerStateAthena->ProcessEvent(OnRep_DeathInfoFn); } + + */ + + // NewPlayerAsAthena->ClientClearDeathNotification(); + // NewPlayerAsAthena->RespawnPlayerAfterDeath(true); } return NewPawn; diff --git a/Project Reboot 3.0/GenericPlatformMath.h b/Project Reboot 3.0/GenericPlatformMath.h index 95439f0..a4f9bc6 100644 --- a/Project Reboot 3.0/GenericPlatformMath.h +++ b/Project Reboot 3.0/GenericPlatformMath.h @@ -21,6 +21,11 @@ public: return (A <= B) ? A : B; } + static FORCEINLINE float InvSqrt(float F) + { + return 1.0f / sqrtf(F); + } + static FORCENOINLINE float Fmod(float X, float Y); static FORCEINLINE int32 FloorToInt(float F) diff --git a/Project Reboot 3.0/PlayerController.cpp b/Project Reboot 3.0/PlayerController.cpp index 2b88e7f..7b6ff7b 100644 --- a/Project Reboot 3.0/PlayerController.cpp +++ b/Project Reboot 3.0/PlayerController.cpp @@ -9,6 +9,13 @@ void APlayerController::ServerChangeName(FString& S) this->ProcessEvent(ServerChangeNameFn, &S); } +void APlayerController::SetPlayerIsWaiting(bool NewValue) +{ + static auto bPlayerIsWaitingOffset = GetOffset("bPlayerIsWaiting"); + static auto bPlayerIsWaitingFieldMask = GetFieldMask(this->GetProperty("bPlayerIsWaiting")); + this->SetBitfieldValue(bPlayerIsWaitingOffset, bPlayerIsWaitingFieldMask, NewValue); +} + UCheatManager*& APlayerController::SpawnCheatManager(UClass* CheatManagerClass) { GetCheatManager() = UGameplayStatics::SpawnObject(CheatManagerClass, this, true); diff --git a/Project Reboot 3.0/PlayerController.h b/Project Reboot 3.0/PlayerController.h index c709417..73dbf03 100644 --- a/Project Reboot 3.0/PlayerController.h +++ b/Project Reboot 3.0/PlayerController.h @@ -16,6 +16,7 @@ public: return this->Get(CheatManagerOffset); } + void SetPlayerIsWaiting(bool NewValue); void ServerChangeName(FString& S); UCheatManager*& SpawnCheatManager(UClass* CheatManagerClass); FRotator GetControlRotation(); diff --git a/Project Reboot 3.0/Project Reboot 3.0.vcxproj b/Project Reboot 3.0/Project Reboot 3.0.vcxproj index 1c5039a..a38bd50 100644 --- a/Project Reboot 3.0/Project Reboot 3.0.vcxproj +++ b/Project Reboot 3.0/Project Reboot 3.0.vcxproj @@ -176,7 +176,6 @@ - @@ -277,7 +276,6 @@ - @@ -322,6 +320,7 @@ + @@ -331,6 +330,8 @@ + + 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 2d528fa..af5809f 100644 --- a/Project Reboot 3.0/Project Reboot 3.0.vcxproj.filters +++ b/Project Reboot 3.0/Project Reboot 3.0.vcxproj.filters @@ -46,9 +46,6 @@ FortniteGame\Source\FortniteGame\Public\Items - - FortniteGame\Source\FortniteGame\Private\Pawns - Engine\Plugins\Runtime\GameplayAbilities\Source\GameplayAbilities\Private @@ -283,15 +280,15 @@ FortniteGame\Source\FortniteGame\Private\Building - - FortniteGame\Source\FortniteGame\Private\Deimos - FortniteGame\Source\FortniteGame\Private\Athena\Island Engine\Source\Runtime\Engine\Private + + FortniteGame\Source\FortniteGame\Private\Player + @@ -741,9 +738,6 @@ FortniteGame\Source\FortniteGame\Public\Athena\Vehicle - - FortniteGame\Source\FortniteGame\Public\Athena\Vehicle - Engine\Source\Runtime\Core\Public\Templates @@ -886,9 +880,6 @@ FortniteGame\Source\FortniteGame\Public - - FortniteGame\Source\FortniteGame\Public\Deimos - FortniteGame\Source\FortniteGame\Public\Building @@ -901,6 +892,18 @@ Engine\Source\Runtime\Engine\Classes\Engine + + FortniteGame\Source\FortniteGame\Public\Athena\Modifiers + + + FortniteGame\Source\FortniteGame\Public\AI + + + FortniteGame\Source\FortniteGame\Public\AI + + + FortniteGame\Source\FortniteGame\Public\Athena + @@ -1134,18 +1137,18 @@ {ade44d65-f7a4-4fc9-ac38-637c84493b58} - - {ac17e75e-ef4a-44f8-9b69-f55b6cde947d} - - - {aadf4f37-b2b9-4ce2-bebb-35719ef0aab1} - {7df06629-6271-4cd1-8f2c-ad8d6829b069} {2d9beb55-a616-440e-8861-6a05f0ee2ef3} + + {d4816986-6cba-4c02-aab1-19108664cbb1} + + + {8953303f-bfb2-4d61-945e-994fb1761cd8} + diff --git a/Project Reboot 3.0/commands.h b/Project Reboot 3.0/commands.h index e2e2e88..c190858 100644 --- a/Project Reboot 3.0/commands.h +++ b/Project Reboot 3.0/commands.h @@ -9,6 +9,7 @@ #include "builder.h" #include "FortLootPackage.h" #include "bots.h" +#include "FortAthenaMutator_Bots.h" bool IsOperator(APlayerState* PlayerState, AFortPlayerController* PlayerController) { diff --git a/Project Reboot 3.0/die.h b/Project Reboot 3.0/die.h index eaa1753..9b6726a 100644 --- a/Project Reboot 3.0/die.h +++ b/Project Reboot 3.0/die.h @@ -108,7 +108,7 @@ static void SetZoneToIndexHook(AFortGameModeAthena* GameModeAthena, int Override FortGameData = CurrentPlaylist ? CurrentPlaylist->Get>(GameDataOffset).Get() : nullptr; if (!FortGameData) - FortGameData = FindObject("/Game/Balance/AthenaGameData.AthenaGameData"); + FortGameData = FindObject(L"/Game/Balance/AthenaGameData.AthenaGameData"); LOG_INFO(LogDev, "FortGameData: {}", FortGameData ? FortGameData->GetFullName() : "InvalidObject"); diff --git a/Project Reboot 3.0/dllmain.cpp b/Project Reboot 3.0/dllmain.cpp index 1572536..94b7576 100644 --- a/Project Reboot 3.0/dllmain.cpp +++ b/Project Reboot 3.0/dllmain.cpp @@ -44,7 +44,6 @@ #include "PlaysetLevelStreamComponent.h" #include "FortAthenaVehicleSpawner.h" #include "FortGameSessionDedicatedAthena.h" -#include "AthenaDeimosRift.h" enum class EMeshNetworkNodeType : uint8_t { @@ -320,27 +319,31 @@ DWORD WINAPI Main(LPVOID) FindObject(L"/Script/FortniteGame.BuildingFoundation.SetDynamicFoundationEnabled"), ABuildingFoundation::SetDynamicFoundationEnabledHook, (PVOID*)&ABuildingFoundation::SetDynamicFoundationEnabledOriginal, false, true); */ - if (Fortnite_Version == 17.30) + if (Fortnite_Version == 17.30) // Rift Tour stuff { - // if (false) - { - Hooking::MinHook::Hook((PVOID)(__int64(GetModuleHandleW(0)) + 0x3E07910), (PVOID)GetMeshNetworkNodeTypeHook, nullptr); - // Hooking::MinHook::Hook((PVOID)(__int64(GetModuleHandleW(0)) + 0x3DED12C), (PVOID)ReturnTrueHook, nullptr); // 7FF7E556D12C - Hooking::MinHook::Hook((PVOID)(__int64(GetModuleHandleW(0)) + 0x3DED158), (PVOID)ReturnTrueHook, nullptr); // 7FF7E556D158 - } - + Hooking::MinHook::Hook((PVOID)(__int64(GetModuleHandleW(0)) + 0x3E07910), (PVOID)GetMeshNetworkNodeTypeHook, nullptr); + Hooking::MinHook::Hook((PVOID)(__int64(GetModuleHandleW(0)) + 0x3DED158), (PVOID)ReturnTrueHook, nullptr); // 7FF7E556D158 Hooking::MinHook::Hook((PVOID)(__int64(GetModuleHandleW(0)) + 0x3DECFC8), (PVOID)ReturnTrueHook, nullptr); // 7FF7E556CFC8 Hooking::MinHook::Hook((PVOID)(__int64(GetModuleHandleW(0)) + 0x3DED050), (PVOID)ReturnTrueHook, nullptr); // 7FF7E556D050 Hooking::MinHook::Hook((PVOID)(__int64(GetModuleHandleW(0)) + 0x3DECF40), (PVOID)ReturnFalseHook, nullptr); // 7FF7E556CF40 Hooking::MinHook::Hook((PVOID)(__int64(GetModuleHandleW(0)) + 0x3DE5CE8), (PVOID)ActivatePhaseAtIndexHook, (PVOID*)&ActivatePhaseAtIndexOriginal); // 7FF7E5565CE8 - // Hooking::MinHook::Hook((PVOID)(__int64(GetModuleHandleW(0)) + 0x3DE9268), (PVOID)FlowStep_SetPhaseToActiveHook, (PVOID*)&FlowStep_SetPhaseToActiveOriginal); // 7FF7E5569268 - // Hooking::MinHook::Hook((PVOID)(__int64(GetModuleHandleW(0)) + 0x3DE5998), (PVOID)SpecialEventScript_ActivatePhaseHook, (PVOID*)&SpecialEventScript_ActivatePhaseOriginal); // 7FF7E5565998 + } + else if (Fortnite_Version == 18.40) + { + Hooking::MinHook::Hook((PVOID)(__int64(GetModuleHandleW(0)) + 0x3E07910), (PVOID)GetMeshNetworkNodeTypeHook, nullptr); + Hooking::MinHook::Hook((PVOID)(__int64(GetModuleHandleW(0)) + 0x416AAB8), (PVOID)ReturnTrueHook, nullptr); // 7FF79E3EAAB8 + Hooking::MinHook::Hook((PVOID)(__int64(GetModuleHandleW(0)) + 0x416A840), (PVOID)ReturnTrueHook, nullptr); // 7FF79E3EA840 + Hooking::MinHook::Hook((PVOID)(__int64(GetModuleHandleW(0)) + 0x416A93C), (PVOID)ReturnTrueHook, nullptr); // 7FF79E3EA93C + // Hooking::MinHook::Hook((PVOID)(__int64(GetModuleHandleW(0)) + ), (PVOID)ReturnFalseHook, nullptr); // 7FF7E556CF40 + Hooking::MinHook::Hook((PVOID)(__int64(GetModuleHandleW(0)) + 0x41624C8), (PVOID)ActivatePhaseAtIndexHook, (PVOID*)&ActivatePhaseAtIndexOriginal); // 7FF79E3E24C8 } if (Fortnite_Version == 6.21) Hooking::MinHook::Hook((PVOID)(__int64(GetModuleHandleW(0)) + 0x191D2E0), (PVOID)CanCreateInCurrentContextHook, (PVOID*)&CanCreateInCurrentContextOriginal); else if (Fortnite_Version == 10.40) Hooking::MinHook::Hook((PVOID)(__int64(GetModuleHandleW(0)) + 0x22A30C0), (PVOID)CanCreateInCurrentContextHook, (PVOID*)&CanCreateInCurrentContextOriginal); + else if (Fortnite_Version == 12.41) + Hooking::MinHook::Hook((PVOID)(__int64(GetModuleHandleW(0)) + 0x2DBCBA0), (PVOID)CanCreateInCurrentContextHook, (PVOID*)&CanCreateInCurrentContextOriginal); if (bUseSwitchLevel) { @@ -780,9 +783,6 @@ DWORD WINAPI Main(LPVOID) Hooking::MinHook::Hook(InventoryManagementLibraryDefault, FindObject(L"/Script/FortniteGame.InventoryManagementLibrary.SwapItems"), UInventoryManagementLibrary::SwapItemsHook, (PVOID*)&UInventoryManagementLibrary::SwapItemsOriginal, false, true); - Hooking::MinHook::Hook(FindObject(L"/Script/FortniteGame.Default__AthenaDeimosRift"), FindObject(L"/Script/FortniteGame.AthenaDeimosRift.QueueActorsToSpawn"), - AAthenaDeimosRift::QueueActorsToSpawnHook, (PVOID*)&AAthenaDeimosRift::QueueActorsToSpawnOriginal, false, true); - Hooking::MinHook::Hook(FindObject(L"/Script/FortniteGame.Default__FortAthenaVehicleSpawner"), FindObject(L"/Script/FortniteGame.FortAthenaVehicleSpawner.SpawnVehicle"), AFortAthenaVehicleSpawner::SpawnVehicleHook, nullptr, false); diff --git a/Project Reboot 3.0/events.h b/Project Reboot 3.0/events.h index d2d696b..1295a88 100644 --- a/Project Reboot 3.0/events.h +++ b/Project Reboot 3.0/events.h @@ -132,6 +132,31 @@ static inline std::vector Events = false ), Event + ( + "The End Event Chapter 2", + "", + "", + 0, + { + + }, + { + { + { + false, + // "/Buffet/Gameplay/Blueprints/BP_Buffet_Master_Scripting.BP_Buffet_Master_Scripting_C.startevent" + "/Script/SpecialEventGameplayRuntime.SpecialEventScript.StartEventAtIndex" + }, + + 0 + } + }, + + "/Guava/Gameplay/BP_Guava_SpecialEventScript.BP_Guava_SpecialEventScript_C", // what + "/GuavaPlaylist/Playlist/Playlist_Guava.Playlist_Guava", + 18.40 + ), + Event ( "The Showdown", "/Game/Athena/Prototype/Blueprints/Cattus/BP_CattusDoggus_Scripting.BP_CattusDoggus_Scripting_C", @@ -698,11 +723,8 @@ static inline void StartEvent() CallOnReadys(); - if (Fortnite_Version == 17.30) + if (Fortnite_Version >= 17.30) { - static bool (*IsServerOrSomething)(UObject* SpecialEventScript) = decltype(IsServerOrSomething)(__int64(GetModuleHandleW(0)) + 0x3DECFC8); - LOG_INFO(LogDev, "IsServerOrSomething {}", IsServerOrSomething(EventScripting)); - static auto OnRep_RootStartTimeFn = FindObject("/Script/SpecialEventGameplayRuntime.SpecialEventScriptMeshActor.OnRep_RootStartTime"); static auto MeshRootStartEventFn = FindObject("/Script/SpecialEventGameplayRuntime.SpecialEventScriptMeshActor.MeshRootStartEvent"); auto SpecialEventScriptMeshActorClass = FindObject("/Script/SpecialEventGameplayRuntime.SpecialEventScriptMeshActor"); @@ -714,11 +736,9 @@ static inline void StartEvent() if (SpecialEventScriptMeshActor) { - static bool (*sub_7FF7E556D158)(UObject* MeshScriptActor) = decltype(sub_7FF7E556D158)(__int64(GetModuleHandleW(0)) + 0x3DED158); - LOG_INFO(LogDev, "sub_7FF7E556D158 {}", sub_7FF7E556D158(SpecialEventScriptMeshActor)); - // if (false) { + LOG_INFO(LogDev, "MeshRootStartEventFn!"); SpecialEventScriptMeshActor->ProcessEvent(MeshRootStartEventFn); SpecialEventScriptMeshActor->ProcessEvent(OnRep_RootStartTimeFn); diff --git a/Project Reboot 3.0/finder.h b/Project Reboot 3.0/finder.h index 124075f..22e760a 100644 --- a/Project Reboot 3.0/finder.h +++ b/Project Reboot 3.0/finder.h @@ -1225,8 +1225,10 @@ static inline uint64 FindAddNavigationSystemToWorld() if (Engine_Version == 421) addr = Memcury::Scanner::FindPattern("48 89 5C 24 ? 48 89 74 24 ? 57 48 83 EC 20 48 83 B9 ? ? ? ? ? 41 0F B6 F1 0F B6 FA 48", false).Get(); - if (Engine_Version == 423) + else if (Engine_Version == 423) addr = Memcury::Scanner::FindPattern("48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 48 83 EC 20 33 ED 41", false).Get(); + else if (Engine_Version == 425) + addr = Memcury::Scanner::FindPattern("48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 48 83 EC 20 33 ED 41 0F B6 F1").Get(); return addr; } diff --git a/Project Reboot 3.0/gui.h b/Project Reboot 3.0/gui.h index 5775b8b..1c6b0a5 100644 --- a/Project Reboot 3.0/gui.h +++ b/Project Reboot 3.0/gui.h @@ -58,6 +58,7 @@ #define LOADOUT_PLAYERTAB 4 #define FUN_PLAYERTAB 5 +extern inline int NumToSubtractFromSquadId = 2; extern inline int SecondsUntilTravel = 5; extern inline bool bSwitchedInitialLevel = false; extern inline bool bIsInAutoRestart = false; @@ -528,6 +529,7 @@ static inline void MainUI() auto Mission = AllMissions.at(i); static auto bCalendarAllowsSpawningOffset = Mission->GetOffset("bCalendarAllowsSpawning"); + LOG_INFO(LogDev, "Mission->Get(bCalendarAllowsSpawningOffset) Original: {}", Mission->Get(bCalendarAllowsSpawningOffset)); Mission->Get(bCalendarAllowsSpawningOffset) = true; } } @@ -544,6 +546,7 @@ static inline void MainUI() LOG_ERROR(LogGame, "Restarting is not supported on chapter 2 and above!"); } } + /* if (ImGui::Button("TEST")) {