diff --git a/LazyPrune/Main.cs b/LazyPrune/Main.cs index f7b186c..0773772 100644 --- a/LazyPrune/Main.cs +++ b/LazyPrune/Main.cs @@ -7,7 +7,7 @@ namespace NAK.LazyPrune; public class LazyPrune : MelonMod { - private static MelonLogger.Instance Logger; + internal static MelonLogger.Instance Logger; //private const int MAX_OBJECTS_UNLOADED_AT_ONCE = 5; // just to alleviate hitch on mass destruction private const float OBJECT_CACHE_TIMEOUT = 3f; // minutes diff --git a/NAK_CVR_Mods.sln b/NAK_CVR_Mods.sln index f1314b6..3f6aa0b 100644 --- a/NAK_CVR_Mods.sln +++ b/NAK_CVR_Mods.sln @@ -55,6 +55,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LuaTTS", "LuaTTS\LuaTTS.csp EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LazyPrune", "LazyPrune\LazyPrune.csproj", "{8FA6D481-5801-4E4C-822E-DE561155D22B}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReconnectionSystemFix", "ReconnectionSystemFix\ReconnectionSystemFix.csproj", "{05C427DD-1261-4AAD-B316-A551FC126F2C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -165,6 +167,10 @@ Global {8FA6D481-5801-4E4C-822E-DE561155D22B}.Debug|Any CPU.Build.0 = Debug|Any CPU {8FA6D481-5801-4E4C-822E-DE561155D22B}.Release|Any CPU.ActiveCfg = Release|Any CPU {8FA6D481-5801-4E4C-822E-DE561155D22B}.Release|Any CPU.Build.0 = Release|Any CPU + {05C427DD-1261-4AAD-B316-A551FC126F2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {05C427DD-1261-4AAD-B316-A551FC126F2C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {05C427DD-1261-4AAD-B316-A551FC126F2C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {05C427DD-1261-4AAD-B316-A551FC126F2C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/ReconnectionSystemFix/Main.cs b/ReconnectionSystemFix/Main.cs new file mode 100644 index 0000000..5bd893c --- /dev/null +++ b/ReconnectionSystemFix/Main.cs @@ -0,0 +1,30 @@ +using MelonLoader; +using NAK.ReconnectionSystemFix.Patches; + +namespace NAK.ReconnectionSystemFix; + +public class ReconnectionSystemFix : MelonMod +{ + internal static MelonLogger.Instance Logger; + + public override void OnInitializeMelon() + { + Logger = LoggerInstance; + ApplyPatches(typeof(NetworkManagerPatches)); + ApplyPatches(typeof(AvatarUpdatePatches)); + ApplyPatches(typeof(CVRPlayerManagerPatches)); + } + + private void ApplyPatches(Type type) + { + try + { + HarmonyInstance.PatchAll(type); + } + catch (Exception e) + { + LoggerInstance.Msg($"Failed while patching {type.Name}!"); + LoggerInstance.Error(e); + } + } +} \ No newline at end of file diff --git a/ReconnectionSystemFix/Patches.cs b/ReconnectionSystemFix/Patches.cs new file mode 100644 index 0000000..dce5c47 --- /dev/null +++ b/ReconnectionSystemFix/Patches.cs @@ -0,0 +1,117 @@ +using ABI_RC.Core.IO; +using ABI_RC.Core.Networking; +using ABI_RC.Core.Networking.IO.Instancing; +using ABI_RC.Core.Networking.Jobs; +using ABI_RC.Core.Player; +using ABI_RC.Core.Savior; +using ABI_RC.Core.UI; +using ABI_RC.Core.Util; +using ABI_RC.Helpers; +using ABI_RC.Systems.Communications; +using ABI_RC.Systems.Communications.Settings; +using ABI_RC.Systems.GameEventSystem; +using DarkRift; +using HarmonyLib; +using UnityEngine; + +namespace NAK.ReconnectionSystemFix.Patches; + +internal static class NetworkManagerPatches +{ + internal static bool IsRecoveringFromReconnectionEvent; + private static float LatestReconnectTime; + + [HarmonyPrefix] + [HarmonyPatch(typeof(NetworkManager), nameof(NetworkManager.OnGameNetworkConnected))] + private static bool Prefix_NetworkManager_OnGameNetworkConnected(ref NetworkManager __instance) + { + if (Instances.IsReconnecting && !IsRecoveringFromReconnectionEvent) + { + IsRecoveringFromReconnectionEvent = true; + SchedulerSystem.AddJob(CheckIfConnectionIsStable, 1f, 1f, -1); + } + + LatestReconnectTime = Time.time; + + // CVRWorld.Start calls TryDeleteAllPlayers anyways ??? + + // if (Instances.IsConnectingInitially) // reimplemented method to add this check, cause i cant do transpiler :( + // { + // foreach (CVRPlayerEntity cvrplayerEntity in CVRPlayerManager.Instance.NetworkPlayers) + // { + // Object.Destroy(cvrplayerEntity.PlayerObject); + // cvrplayerEntity.Recycle(); + // } + // CVRPlayerManager.Instance.NetworkPlayers.Clear(); + // } + + SchedulerSystem.RemoveJob(__instance.ResetReconnectionAttempts); + __instance.ResetReconnectionAttempts(); + __instance.DisableRefreshJoinToken(); + + SchedulerSystem.AddJob(__instance.RefreshJoinToken, 300f, 0f, 1); + RichPresence.LastConnectedToServer = DiscordTime.TimeNow(); + if (__instance.GameNetwork.ConnectionState == ConnectionState.Connected) + { + using DRMessageHelper drmessageHelper = new(Tags.AuthenticationProfileSelection); + drmessageHelper.Write(Instances.IsReconnecting); // NOTE: this is broken on GS side + drmessageHelper.Write(Instances.RejoinToken); + drmessageHelper.Send(__instance.GameNetwork); + } + + MetaPort.Instance.CurrentInstanceId = Instances.RequestedInstance; + CohtmlHud.Instance.SetDisplayChain(0); + CohtmlHud.Instance.ClearViewDropText(); + Instances.ForceDisconnect = false; + Instances.IsConnectingInitially = false; + if (Instances.IsReconnecting) CVRGameEventSystem.Instance.OnConnectionRecovered.Invoke(MetaPort.Instance.CurrentInstanceId); + else if (Comms_SettingsHandler.MuteInputOnJoin) Comms_Manager.IsMicMuted = true; + Instances.IsReconnecting = false; + return false; + } + + private static void CheckIfConnectionIsStable() + { + ReconnectionSystemFix.Logger.Msg("Checking if connection is stable..."); + + if (Time.time - LatestReconnectTime > 3f) + { + ReconnectionSystemFix.Logger.Msg("Connection is stable!"); + IsRecoveringFromReconnectionEvent = false; + SchedulerSystem.RemoveJob(CheckIfConnectionIsStable); + } + } +} + +internal static class AvatarUpdatePatches +{ + [HarmonyPrefix] + [HarmonyPatch(typeof(AvatarUpdate), nameof(AvatarUpdate.Apply))] + private static bool Prefix_AvatarUpdate_Apply(Message message) + { + if (!NetworkManagerPatches.IsRecoveringFromReconnectionEvent) + return true; // normal operation + + // hack 2 + using DRMessageHelper drmessageHelper = new(message); + drmessageHelper.Read(out string _); + drmessageHelper.Read(out string avatarId); + return CVRPlayerManager.Instance.NetworkPlayers.All(player => player.AvatarId != avatarId); + } +} + +internal static class CVRPlayerManagerPatches +{ + [HarmonyPrefix] + [HarmonyPatch(typeof(CVRPlayerManager), nameof(CVRPlayerManager.TryCreatePlayer))] + private static bool Prefix_CVRPlayerManager_TryCreatePlayer(Message message) + { + if (!NetworkManagerPatches.IsRecoveringFromReconnectionEvent) + return true; // normal operation + + // hack + using DRMessageHelper drmessageHelper = new(message); + drmessageHelper.Read(out string userId); + return CVRPlayerManager.Instance.NetworkPlayers.All(player => player.Uuid != userId); + } +} \ No newline at end of file diff --git a/ReconnectionSystemFix/Properties/AssemblyInfo.cs b/ReconnectionSystemFix/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..547a5e5 --- /dev/null +++ b/ReconnectionSystemFix/Properties/AssemblyInfo.cs @@ -0,0 +1,30 @@ +using MelonLoader; +using NAK.ReconnectionSystemFix.Properties; +using System.Reflection; + +[assembly: AssemblyVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyTitle(nameof(NAK.ReconnectionSystemFix))] +[assembly: AssemblyCompany(AssemblyInfoParams.Author)] +[assembly: AssemblyProduct(nameof(NAK.ReconnectionSystemFix))] + +[assembly: MelonInfo( + typeof(NAK.ReconnectionSystemFix.ReconnectionSystemFix), + nameof(NAK.ReconnectionSystemFix), + AssemblyInfoParams.Version, + AssemblyInfoParams.Author, + downloadLink: "https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/ReconnectionSystemFix" +)] + +[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] +[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] +[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] +[assembly: HarmonyDontPatchAll] + +namespace NAK.ReconnectionSystemFix.Properties; +internal static class AssemblyInfoParams +{ + public const string Version = "1.0.0"; + public const string Author = "NotAKidoS"; +} \ No newline at end of file diff --git a/ReconnectionSystemFix/README.md b/ReconnectionSystemFix/README.md new file mode 100644 index 0000000..ec15036 --- /dev/null +++ b/ReconnectionSystemFix/README.md @@ -0,0 +1,14 @@ +# ReconnectionSystemFix + +Prevents recreating and reloading all remote players & avatars during a reconnection event. + +--- + +Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. +https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games + +> This mod is an independent creation not affiliated with, supported by, or approved by Alpha Blend Interactive. + +> Use of this mod is done so at the user's own risk and the creator cannot be held responsible for any issues arising from its use. + +> To the best of my knowledge, I have adhered to the Modding Guidelines established by Alpha Blend Interactive. diff --git a/ReconnectionSystemFix/ReconnectionSystemFix.csproj b/ReconnectionSystemFix/ReconnectionSystemFix.csproj new file mode 100644 index 0000000..bec5b03 --- /dev/null +++ b/ReconnectionSystemFix/ReconnectionSystemFix.csproj @@ -0,0 +1,6 @@ + + + + LoadedObjectHack + + diff --git a/ReconnectionSystemFix/format.json b/ReconnectionSystemFix/format.json new file mode 100644 index 0000000..49c5c26 --- /dev/null +++ b/ReconnectionSystemFix/format.json @@ -0,0 +1,24 @@ +{ + "_id": -1, + "name": "ReconnectionSystemFix", + "modversion": "1.0.0", + "gameversion": "2024r175", + "loaderversion": "0.6.1", + "modtype": "Mod", + "author": "NotAKidoS", + "description": "Prevents recreating and reloading all remote players & avatars during a reconnection event.", + "searchtags": [ + "reload", + "rejoin", + "fix", + "avatar", + "download" + ], + "requirements": [ + "None" + ], + "downloadlink": "https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/download/r30/ReconnectionSystemFix.dll", + "sourcelink": "https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/ReconnectionSystemFix/", + "changelog": "- Initial Release", + "embedcolor": "#e87d0d" +} \ No newline at end of file