From 430f3d59db19e6ed84ca8ca16ca50008651d1164 Mon Sep 17 00:00:00 2001 From: starfish Date: Sat, 11 Sep 2021 06:57:52 +0800 Subject: [PATCH 1/3] add CanPause check, enable pausing when no connections --- .../Transpilers/GameMain_Transpiler.cs | 69 +++++++++++-------- NebulaWorld/Multiplayer.cs | 16 +++++ NebulaWorld/SimulatedWorld.cs | 6 ++ 3 files changed, 61 insertions(+), 30 deletions(-) diff --git a/NebulaPatcher/Patches/Transpilers/GameMain_Transpiler.cs b/NebulaPatcher/Patches/Transpilers/GameMain_Transpiler.cs index a22761867..b5d5cf5ad 100644 --- a/NebulaPatcher/Patches/Transpilers/GameMain_Transpiler.cs +++ b/NebulaPatcher/Patches/Transpilers/GameMain_Transpiler.cs @@ -8,46 +8,55 @@ namespace NebulaPatcher.Patches.Transpiler [HarmonyPatch(typeof(GameMain))] class GameMain_Transpiler { - //Ignore Pausing in the multiplayer: + //Enable Pausing only when Multiplayer.CanPause is true: //Change: if (!this._paused) - //To: if (!this._paused || Multiplayer.IsActive) + //To: if (!(this._paused && Multiplayer.CanPause)) + //Change: if (this._fullscreenPaused && !this._fullscreenPausedUnlockOneFrame) + //To: if (this._fullscreenPaused && Multiplayer.CanPause && !this._fullscreenPausedUnlockOneFrame) [HarmonyTranspiler] [HarmonyPatch(nameof(GameMain.FixedUpdate))] - static IEnumerable PickupBeltItems_Transpiler(ILGenerator gen, IEnumerable instructions) + static IEnumerable FixedUpdate_Transpiler(IEnumerable instructions, ILGenerator iL) { - var found = false; - var codes = new List(instructions); - for (int i = 6; i < codes.Count; i++) - { - if (codes[i].opcode == OpCodes.Callvirt && - codes[i - 1].opcode == OpCodes.Ldc_I4_1 && - codes[i - 2].opcode == OpCodes.Br && - codes[i - 3].opcode == OpCodes.Ldc_I4_0 && - codes[i - 4].opcode == OpCodes.Br && - codes[i - 5].opcode == OpCodes.Ceq) - { - found = true; - //Define new jump for firct condition - Label targetLabel = gen.DefineLabel(); - codes[i + 4].labels.Add(targetLabel); + var codeMatcher = new CodeMatcher(instructions, iL) + .MatchForward(true, + new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(Player), "ApplyGamePauseState")), + new CodeMatch(OpCodes.Ldarg_0), + new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(GameMain), "_paused")), + new CodeMatch(OpCodes.Brtrue) + ); - //Add my condition - codes.InsertRange(i + 4, new CodeInstruction[] { - new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(Multiplayer), "get_" + nameof(Multiplayer.IsActive))), - new CodeInstruction(OpCodes.Brfalse_S, codes[i+3].operand) - }); + if (codeMatcher.IsInvalid) + { + NebulaModel.Logger.Log.Error("GameMain.FixedUpdate_Transpiler failed. Mod version not compatible with game version."); + return instructions; + } - //Change jump of first condition - codes[i + 3] = new CodeInstruction(OpCodes.Brfalse_S, targetLabel); + codeMatcher + .InsertAndAdvance( + new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(Multiplayer), "get_" + nameof(Multiplayer.CanPause))), + new CodeInstruction(OpCodes.And) + ) + .MatchForward(true, + new CodeMatch(OpCodes.Ldarg_0), + new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(GameMain), "_fullscreenPaused")) + ); - break; - } + if (codeMatcher.IsInvalid) + { + NebulaModel.Logger.Log.Error("GameMain.FixedUpdate_Transpiler 2 failed. Mod version not compatible with game version."); + return instructions; } - if (!found) - NebulaModel.Logger.Log.Error("GameMain FixedUpdate transpiler failed. Mod version not compatible with game version."); - return codes; + var label = codeMatcher.InstructionAt(1).operand; + + return codeMatcher + .Advance(2) + .InsertAndAdvance( + new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(Multiplayer), "get_" + nameof(Multiplayer.CanPause))), + new CodeInstruction(OpCodes.Brfalse_S, label) + ) + .InstructionEnumeration(); } } } diff --git a/NebulaWorld/Multiplayer.cs b/NebulaWorld/Multiplayer.cs index b44757a7a..ad871d02b 100644 --- a/NebulaWorld/Multiplayer.cs +++ b/NebulaWorld/Multiplayer.cs @@ -13,6 +13,13 @@ public static class Multiplayer public static bool IsInMultiplayerMenu { get; set; } + public static bool CanPause + { + get => canPause; + set => SetCanPause(value); + } + + private static bool canPause = true; public static void HostGame(NetworkProvider server) { @@ -25,6 +32,7 @@ public static void HostGame(NetworkProvider server) public static void JoinGame(NetworkProvider client) { IsLeavingGame = false; + CanPause = false; Session = new MultiplayerSession(client); ((NetworkProvider)Session.Network).Start(); @@ -33,6 +41,7 @@ public static void JoinGame(NetworkProvider client) public static void LeaveGame() { IsLeavingGame = true; + CanPause = true; bool wasGameLoaded = Session?.IsGameLoaded ?? false; @@ -59,5 +68,12 @@ public static void LeaveGame() multiplayerMenu.gameObject.SetActive(true); } } + + private static void SetCanPause(bool status) + { + canPause = status; + //Tell the user if the game is paused or not + GameObject.Find("UI Root/Overlay Canvas/In Game/Esc Menu/pause-text").SetActive(status); + } } } diff --git a/NebulaWorld/SimulatedWorld.cs b/NebulaWorld/SimulatedWorld.cs index 349eebe77..0f383d732 100644 --- a/NebulaWorld/SimulatedWorld.cs +++ b/NebulaWorld/SimulatedWorld.cs @@ -138,6 +138,7 @@ public void OnPlayerJoining() if (!IsPlayerJoining) { IsPlayerJoining = true; + Multiplayer.CanPause = true; GameMain.isFullscreenPaused = true; InGamePopup.ShowInfo("Loading", "Player joining the game, please wait", null); } @@ -148,6 +149,7 @@ public void OnAllPlayersSyncCompleted() IsPlayerJoining = false; InGamePopup.FadeOut(); GameMain.isFullscreenPaused = false; + Multiplayer.CanPause = false; } public void SpawnRemotePlayerModel(IPlayerData playerData) @@ -172,6 +174,10 @@ public void DestroyRemotePlayerModel(ushort playerId) { player.Destroy(); remotePlayersModels.Remove(playerId); + if (remotePlayersModels.Count == 0) + { + Multiplayer.CanPause = true; + } } } } From 98274d3c188f822ed1306444e5d9a12a4aef2fe8 Mon Sep 17 00:00:00 2001 From: starfish Date: Sun, 12 Sep 2021 04:20:03 +0800 Subject: [PATCH 2/3] move CanPause to MultiplayerSession --- .../Transpilers/GameMain_Transpiler.cs | 32 ++++++++++++------- NebulaWorld/Multiplayer.cs | 16 ---------- NebulaWorld/MultiplayerSession.cs | 12 +++++++ NebulaWorld/SimulatedWorld.cs | 28 ++++++++++++++-- 4 files changed, 57 insertions(+), 31 deletions(-) diff --git a/NebulaPatcher/Patches/Transpilers/GameMain_Transpiler.cs b/NebulaPatcher/Patches/Transpilers/GameMain_Transpiler.cs index b5d5cf5ad..343f84789 100644 --- a/NebulaPatcher/Patches/Transpilers/GameMain_Transpiler.cs +++ b/NebulaPatcher/Patches/Transpilers/GameMain_Transpiler.cs @@ -8,11 +8,11 @@ namespace NebulaPatcher.Patches.Transpiler [HarmonyPatch(typeof(GameMain))] class GameMain_Transpiler { - //Enable Pausing only when Multiplayer.CanPause is true: + //Enable Pausing only when there is no session or Multiplayer.Session.CanPause is true: //Change: if (!this._paused) - //To: if (!(this._paused && Multiplayer.CanPause)) + //To: if (!(this._paused && (Multiplayer.Session == null || Multiplayer.Session.CanPause))) //Change: if (this._fullscreenPaused && !this._fullscreenPausedUnlockOneFrame) - //To: if (this._fullscreenPaused && Multiplayer.CanPause && !this._fullscreenPausedUnlockOneFrame) + //To: if (this._fullscreenPaused && (Multiplayer.Session == null || Multiplayer.Session.CanPause) && !this._fullscreenPausedUnlockOneFrame) [HarmonyTranspiler] [HarmonyPatch(nameof(GameMain.FixedUpdate))] @@ -31,15 +31,20 @@ static IEnumerable FixedUpdate_Transpiler(IEnumerable enter loop + new CodeInstruction(OpCodes.Call, AccessTools.DeclaredPropertyGetter(typeof(Multiplayer), nameof(Multiplayer.Session))), + new CodeInstruction(OpCodes.Brfalse_S, skipLabel1), //_pasue == true && Multiplayer.Session == null => can pause, skip loop + new CodeInstruction(OpCodes.Call, AccessTools.DeclaredPropertyGetter(typeof(Multiplayer), nameof(Multiplayer.Session))), + new CodeInstruction(OpCodes.Callvirt, AccessTools.DeclaredPropertyGetter(typeof(MultiplayerSession), nameof(MultiplayerSession.CanPause))) ) .MatchForward(true, new CodeMatch(OpCodes.Ldarg_0), - new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(GameMain), "_fullscreenPaused")) + new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(GameMain), "_fullscreenPaused")), + new CodeMatch(OpCodes.Brfalse) ); if (codeMatcher.IsInvalid) @@ -48,13 +53,16 @@ static IEnumerable FixedUpdate_Transpiler(IEnumerable can pause, jump to next check + new CodeInstruction(OpCodes.Call, AccessTools.DeclaredPropertyGetter(typeof(Multiplayer), nameof(Multiplayer.Session))), + new CodeInstruction(OpCodes.Callvirt, AccessTools.DeclaredPropertyGetter(typeof(MultiplayerSession), nameof(MultiplayerSession.CanPause))), + new CodeInstruction(OpCodes.Brfalse_S, skipLabel2) //_fullscreenPaused && Multiplayer.Session.CanPause == fasle => can't pause, skip ) .InstructionEnumeration(); } diff --git a/NebulaWorld/Multiplayer.cs b/NebulaWorld/Multiplayer.cs index ad871d02b..b44757a7a 100644 --- a/NebulaWorld/Multiplayer.cs +++ b/NebulaWorld/Multiplayer.cs @@ -13,13 +13,6 @@ public static class Multiplayer public static bool IsInMultiplayerMenu { get; set; } - public static bool CanPause - { - get => canPause; - set => SetCanPause(value); - } - - private static bool canPause = true; public static void HostGame(NetworkProvider server) { @@ -32,7 +25,6 @@ public static void HostGame(NetworkProvider server) public static void JoinGame(NetworkProvider client) { IsLeavingGame = false; - CanPause = false; Session = new MultiplayerSession(client); ((NetworkProvider)Session.Network).Start(); @@ -41,7 +33,6 @@ public static void JoinGame(NetworkProvider client) public static void LeaveGame() { IsLeavingGame = true; - CanPause = true; bool wasGameLoaded = Session?.IsGameLoaded ?? false; @@ -68,12 +59,5 @@ public static void LeaveGame() multiplayerMenu.gameObject.SetActive(true); } } - - private static void SetCanPause(bool status) - { - canPause = status; - //Tell the user if the game is paused or not - GameObject.Find("UI Root/Overlay Canvas/In Game/Esc Menu/pause-text").SetActive(status); - } } } diff --git a/NebulaWorld/MultiplayerSession.cs b/NebulaWorld/MultiplayerSession.cs index 9ff984185..432026cbd 100644 --- a/NebulaWorld/MultiplayerSession.cs +++ b/NebulaWorld/MultiplayerSession.cs @@ -38,6 +38,16 @@ public class MultiplayerSession : IDisposable, IMultiplayerSession public bool IsGameLoaded { get; set; } + public bool CanPause + { + get => canPause; + set + { + canPause = value; + World?.SetPauseIndicator(value); + } + } + private bool canPause = true; public MultiplayerSession(NetworkProvider networkProvider) { @@ -62,6 +72,8 @@ public MultiplayerSession(NetworkProvider networkProvider) public void Dispose() { + CanPause = true; + Network?.Dispose(); Network = null; diff --git a/NebulaWorld/SimulatedWorld.cs b/NebulaWorld/SimulatedWorld.cs index 0f383d732..b1bb8f3d6 100644 --- a/NebulaWorld/SimulatedWorld.cs +++ b/NebulaWorld/SimulatedWorld.cs @@ -138,7 +138,7 @@ public void OnPlayerJoining() if (!IsPlayerJoining) { IsPlayerJoining = true; - Multiplayer.CanPause = true; + Multiplayer.Session.CanPause = true; GameMain.isFullscreenPaused = true; InGamePopup.ShowInfo("Loading", "Player joining the game, please wait", null); } @@ -149,7 +149,7 @@ public void OnAllPlayersSyncCompleted() IsPlayerJoining = false; InGamePopup.FadeOut(); GameMain.isFullscreenPaused = false; - Multiplayer.CanPause = false; + Multiplayer.Session.CanPause = false; } public void SpawnRemotePlayerModel(IPlayerData playerData) @@ -176,7 +176,7 @@ public void DestroyRemotePlayerModel(ushort playerId) remotePlayersModels.Remove(playerId); if (remotePlayersModels.Count == 0) { - Multiplayer.CanPause = true; + Multiplayer.Session.CanPause = true; } } } @@ -604,5 +604,27 @@ public void UpdatePingIndicator(string text) pingIndicator.text = text; } } + + public void SetPauseIndicator(bool canPause) + { + //Tell the user if the game is paused or not + var targetObject = GameObject.Find("UI Root/Overlay Canvas/In Game/Esc Menu/pause-text"); + var pauseText = targetObject?.GetComponent(); + var pauseLocalizer = targetObject?.GetComponent(); + if (pauseText && pauseLocalizer) + { + if (!canPause) + { + pauseText.text = "-- Nebula Multiplayer --".Translate(); + pauseLocalizer.stringKey = "-- Nebula Multiplayer --".Translate(); + } + else + { + pauseText.text = "游戏已暂停".Translate(); + pauseLocalizer.stringKey = "游戏已暂停".Translate(); + } + } + + } } } From 4aed6d54d41214d3dd5e249f71a12370efa57fee Mon Sep 17 00:00:00 2001 From: Chris Yeninas <844685+PhantomGamers@users.noreply.github.com> Date: Sun, 12 Sep 2021 15:35:25 -0400 Subject: [PATCH 3/3] address comments * fix typos * remove unnecessary assignment in MultiplayerSession.Dispose --- .../Patches/Transpilers/GameMain_Transpiler.cs | 14 +++++++------- NebulaWorld/MultiplayerSession.cs | 2 -- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/NebulaPatcher/Patches/Transpilers/GameMain_Transpiler.cs b/NebulaPatcher/Patches/Transpilers/GameMain_Transpiler.cs index 343f84789..57b9422ab 100644 --- a/NebulaPatcher/Patches/Transpilers/GameMain_Transpiler.cs +++ b/NebulaPatcher/Patches/Transpilers/GameMain_Transpiler.cs @@ -6,7 +6,7 @@ namespace NebulaPatcher.Patches.Transpiler { [HarmonyPatch(typeof(GameMain))] - class GameMain_Transpiler + internal class GameMain_Transpiler { //Enable Pausing only when there is no session or Multiplayer.Session.CanPause is true: //Change: if (!this._paused) @@ -16,9 +16,9 @@ class GameMain_Transpiler [HarmonyTranspiler] [HarmonyPatch(nameof(GameMain.FixedUpdate))] - static IEnumerable FixedUpdate_Transpiler(IEnumerable instructions, ILGenerator iL) + private static IEnumerable FixedUpdate_Transpiler(IEnumerable instructions, ILGenerator iL) { - var codeMatcher = new CodeMatcher(instructions, iL) + CodeMatcher codeMatcher = new CodeMatcher(instructions, iL) .MatchForward(true, new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(Player), "ApplyGamePauseState")), new CodeMatch(OpCodes.Ldarg_0), @@ -31,13 +31,13 @@ static IEnumerable FixedUpdate_Transpiler(IEnumerable enter loop + new CodeInstruction(OpCodes.Brfalse_S, nextLabel1), //_paused== false => enter loop new CodeInstruction(OpCodes.Call, AccessTools.DeclaredPropertyGetter(typeof(Multiplayer), nameof(Multiplayer.Session))), - new CodeInstruction(OpCodes.Brfalse_S, skipLabel1), //_pasue == true && Multiplayer.Session == null => can pause, skip loop + new CodeInstruction(OpCodes.Brfalse_S, skipLabel1), //_paused== true && Multiplayer.Session == null => can pause, skip loop new CodeInstruction(OpCodes.Call, AccessTools.DeclaredPropertyGetter(typeof(Multiplayer), nameof(Multiplayer.Session))), new CodeInstruction(OpCodes.Callvirt, AccessTools.DeclaredPropertyGetter(typeof(MultiplayerSession), nameof(MultiplayerSession.CanPause))) ) @@ -53,7 +53,7 @@ static IEnumerable FixedUpdate_Transpiler(IEnumerable