From 95ed3da300ad458b1fac47c7958e453dc4ba355e Mon Sep 17 00:00:00 2001
From: Jannify <23176718+Jannify@users.noreply.github.com>
Date: Thu, 28 Sep 2023 15:57:22 +0200
Subject: [PATCH 01/14] Handle uncatched MainMenu errors from Sn Update
---
...LoadButton_RestoreParentsSettings_Patch.cs | 19 ++++++++++++++++
.../SystemsSpawner_SetupSingleton_Patch.cs | 22 +++++++++++++++++++
2 files changed, 41 insertions(+)
create mode 100644 NitroxPatcher/Patches/Persistent/MainMenuLoadButton_RestoreParentsSettings_Patch.cs
create mode 100644 NitroxPatcher/Patches/Persistent/SystemsSpawner_SetupSingleton_Patch.cs
diff --git a/NitroxPatcher/Patches/Persistent/MainMenuLoadButton_RestoreParentsSettings_Patch.cs b/NitroxPatcher/Patches/Persistent/MainMenuLoadButton_RestoreParentsSettings_Patch.cs
new file mode 100644
index 0000000000..97afc16037
--- /dev/null
+++ b/NitroxPatcher/Patches/Persistent/MainMenuLoadButton_RestoreParentsSettings_Patch.cs
@@ -0,0 +1,19 @@
+using System.Reflection;
+using NitroxModel.Helper;
+using UnityEngine.UI;
+
+namespace NitroxPatcher.Patches.Persistent;
+
+///
+/// MainMenuLoadButton.RestoreParentsSettings() is throwing null refs because we copy it for our MainMenu and then destroy it.
+/// Unfortunately OnDestroy can't be prevented when destroying MBs so we fix the NRE here.
+///
+public sealed partial class MainMenuLoadButton_RestoreParentsSettings_Patch : NitroxPatch, IPersistentPatch
+{
+ private static readonly MethodInfo TARGET_METHOD = Reflect.Method((MainMenuLoadButton lb) => lb.RestoreParentsSettings());
+
+ public static bool Prefix(GridLayoutGroup ___gridLayoutGroup, ScrollRect ___scrollRect)
+ {
+ return ___gridLayoutGroup && ___scrollRect;
+ }
+}
diff --git a/NitroxPatcher/Patches/Persistent/SystemsSpawner_SetupSingleton_Patch.cs b/NitroxPatcher/Patches/Persistent/SystemsSpawner_SetupSingleton_Patch.cs
new file mode 100644
index 0000000000..dc48a687b0
--- /dev/null
+++ b/NitroxPatcher/Patches/Persistent/SystemsSpawner_SetupSingleton_Patch.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Reflection;
+using HarmonyLib;
+using NitroxModel.Helper;
+
+namespace NitroxPatcher.Patches.Persistent;
+
+///
+/// Patch to suppress SentrySdk NRE as it's destroyed by us
+///
+public sealed partial class SystemsSpawner_SetupSingleton_Patch : NitroxPatch, IPersistentPatch
+{
+ private static readonly MethodInfo TARGET_METHOD = AccessTools.EnumeratorMoveNext(Reflect.Method((SystemsSpawner s) => s.SetupSingleton(default)));
+
+ public static void Finalizer(ref Exception __exception)
+ {
+ if (__exception is NullReferenceException)
+ {
+ __exception = null;
+ }
+ }
+}
From 5c30d7145fb727d0e2915c567c93935d94281f7a Mon Sep 17 00:00:00 2001
From: Jannify <23176718+Jannify@users.noreply.github.com>
Date: Sat, 24 Jun 2023 17:42:00 +0200
Subject: [PATCH 02/14] Add controller support for server list
---
.../MonoBehaviours/Discord/DiscordClient.cs | 3 +-
.../Gui/MainMenu/MainMenuAddServerWindow.cs | 158 ++++++
.../Gui/MainMenu/MainMenuMods.cs | 1 +
.../Gui/MainMenu/MainMenuMultiplayerPanel.cs | 494 ++++++++----------
.../Gui/MainMenu/MainMenuServerButton.cs | 136 +++++
5 files changed, 505 insertions(+), 287 deletions(-)
create mode 100644 NitroxClient/MonoBehaviours/Gui/MainMenu/MainMenuAddServerWindow.cs
create mode 100644 NitroxClient/MonoBehaviours/Gui/MainMenu/MainMenuServerButton.cs
diff --git a/NitroxClient/MonoBehaviours/Discord/DiscordClient.cs b/NitroxClient/MonoBehaviours/Discord/DiscordClient.cs
index 8fb6a0dd1b..ea935fff2b 100644
--- a/NitroxClient/MonoBehaviours/Discord/DiscordClient.cs
+++ b/NitroxClient/MonoBehaviours/Discord/DiscordClient.cs
@@ -109,7 +109,8 @@ private void ActivityJoin(string secret)
string[] splitSecret = secret.Split(':');
string ip = string.Join(":", splitSecret.Take(splitSecret.Length - 1));
string port = splitSecret.Last();
- _ = MainMenuMultiplayerPanel.OpenJoinServerMenuAsync(ip, port);
+ int portInt = int.Parse(port);
+ _ = MainMenuServerButton.OpenJoinServerMenuAsync(ip, portInt);
}
private void ActivityJoinRequest(ref User user)
diff --git a/NitroxClient/MonoBehaviours/Gui/MainMenu/MainMenuAddServerWindow.cs b/NitroxClient/MonoBehaviours/Gui/MainMenu/MainMenuAddServerWindow.cs
new file mode 100644
index 0000000000..f156428aa3
--- /dev/null
+++ b/NitroxClient/MonoBehaviours/Gui/MainMenu/MainMenuAddServerWindow.cs
@@ -0,0 +1,158 @@
+using System.Collections;
+using NitroxClient.Unity.Helper;
+using NitroxModel.Serialization;
+using UnityEngine;
+using UWE;
+
+namespace NitroxClient.MonoBehaviours.Gui.MainMenu;
+
+public static class MainMenuAddServerWindow
+{
+ private static Rect addServerWindowRect = new(Screen.width / 2 - 250, 200, 500, 200);
+
+ private static string serverHostInput;
+ private static string serverNameInput;
+ private static string serverPortInput;
+
+ private static bool shouldFocus;
+ private static bool showingAddServer;
+
+ public static void OnExternalGUI()
+ {
+ if (showingAddServer)
+ {
+ addServerWindowRect = GUILayout.Window(GUIUtility.GetControlID(FocusType.Keyboard), addServerWindowRect, DoAddServerWindow, Language.main.Get("Nitrox_AddServer"));
+ }
+ }
+
+ public static void ShowAddServerWindow()
+ {
+ serverNameInput = "local";
+ serverHostInput = "127.0.0.1";
+ serverPortInput = ServerList.DEFAULT_PORT.ToString();
+ showingAddServer = true;
+ shouldFocus = true;
+ uGUI_MainMenu.main.canvasGroup.interactable = false;
+ }
+
+ public static void HideAddServerWindow()
+ {
+ IEnumerator SetWindowComponents()
+ {
+ showingAddServer = false;
+ shouldFocus = true;
+ yield return null;
+ uGUI_MainMenu.main.canvasGroup.interactable = true;
+ }
+
+ CoroutineHost.StartCoroutine(SetWindowComponents());
+ }
+
+ private static void OnAddServerButtonClicked()
+ {
+ serverNameInput = serverNameInput.Trim();
+ serverHostInput = serverHostInput.Trim();
+ if (int.TryParse(serverPortInput.Trim(), out int serverPort))
+ {
+ MainMenuMultiplayerPanel.Main.CreateServerButton(serverNameInput, serverHostInput, serverPort);
+ ServerList.Instance.Add(new ServerList.Entry(serverNameInput, serverHostInput, serverPort));
+ ServerList.Instance.Save();
+
+ HideAddServerWindow();
+ }
+ else
+ {
+ Log.InGame("Server port was not a valid number!");
+ }
+ }
+
+ private static void OnCancelButtonClicked()
+ {
+ HideAddServerWindow();
+ }
+
+ private static void DoAddServerWindow(int windowId)
+ {
+ Event e = Event.current;
+ if (e.isKey)
+ {
+ switch (e.keyCode)
+ {
+ case KeyCode.Return:
+ OnAddServerButtonClicked();
+ break;
+ case KeyCode.Escape:
+ OnCancelButtonClicked();
+ break;
+ }
+ }
+
+ GUISkinUtils.RenderWithSkin(GetGUISkin(),
+ () =>
+ {
+ using (new GUILayout.VerticalScope("Box"))
+ {
+ using (new GUILayout.HorizontalScope())
+ {
+ GUILayout.Label(Language.main.Get("Nitrox_AddServerName"));
+ GUI.SetNextControlName("serverNameField");
+ // 120 so users can't go too crazy.
+ serverNameInput = GUILayout.TextField(serverNameInput, 120);
+ }
+
+ using (new GUILayout.HorizontalScope())
+ {
+ GUILayout.Label(Language.main.Get("Nitrox_AddServerHost"));
+ GUI.SetNextControlName("serverHostField");
+ // 120 so users can't go too crazy.
+ serverHostInput = GUILayout.TextField(serverHostInput, 120);
+ }
+
+ using (new GUILayout.HorizontalScope())
+ {
+ GUILayout.Label(Language.main.Get("Nitrox_AddServerPort"));
+ GUI.SetNextControlName("serverPortField");
+ serverPortInput = GUILayout.TextField(serverPortInput);
+ }
+
+ if (GUILayout.Button(Language.main.Get("Nitrox_AddServerAdd")))
+ {
+ OnAddServerButtonClicked();
+ }
+
+ if (GUILayout.Button(Language.main.Get("Nitrox_Cancel")))
+ {
+ OnCancelButtonClicked();
+ }
+ }
+ });
+
+ if (shouldFocus)
+ {
+ GUI.FocusControl("serverNameField");
+ shouldFocus = false;
+ }
+ }
+
+ private static GUISkin GetGUISkin()
+ {
+ return GUISkinUtils.RegisterDerivedOnce("menus.server",
+ s =>
+ {
+ s.textField.fontSize = 14;
+ s.textField.richText = false;
+ s.textField.alignment = TextAnchor.MiddleLeft;
+ s.textField.wordWrap = true;
+ s.textField.stretchHeight = true;
+ s.textField.padding = new RectOffset(10, 10, 5, 5);
+
+ s.label.fontSize = 14;
+ s.label.alignment = TextAnchor.MiddleRight;
+ s.label.stretchHeight = true;
+ s.label.fixedWidth = 80; //change this when adding new labels that need more space.
+
+ s.button.fontSize = 14;
+ s.button.stretchHeight = true;
+ });
+ }
+}
diff --git a/NitroxClient/MonoBehaviours/Gui/MainMenu/MainMenuMods.cs b/NitroxClient/MonoBehaviours/Gui/MainMenu/MainMenuMods.cs
index 9743a976b2..c3532d3925 100644
--- a/NitroxClient/MonoBehaviours/Gui/MainMenu/MainMenuMods.cs
+++ b/NitroxClient/MonoBehaviours/Gui/MainMenu/MainMenuMods.cs
@@ -55,6 +55,7 @@ private void MultiplayerMenuMods()
header.GetComponent().translationKey = "Nitrox_Multiplayer";
Destroy(loadedMultiplayer.RequireGameObject("Scroll View/Viewport/SavedGameAreaContent/NewGame"));
Destroy(loadedMultiplayer.GetComponent());
+ Destroy(loadedMultiplayer.GetComponentInChildren());
loadedMultiplayer.AddComponent().Setup(loadedMultiplayer, savedGamesRef);
diff --git a/NitroxClient/MonoBehaviours/Gui/MainMenu/MainMenuMultiplayerPanel.cs b/NitroxClient/MonoBehaviours/Gui/MainMenu/MainMenuMultiplayerPanel.cs
index 596457fa77..eaccaf0ff4 100644
--- a/NitroxClient/MonoBehaviours/Gui/MainMenu/MainMenuMultiplayerPanel.cs
+++ b/NitroxClient/MonoBehaviours/Gui/MainMenu/MainMenuMultiplayerPanel.cs
@@ -1,350 +1,272 @@
-using System;
-using System.Collections;
using System.Net;
-using System.Net.Sockets;
+using FMODUnity;
using NitroxClient.Communication;
using NitroxClient.GameLogic.Settings;
using NitroxClient.Unity.Helper;
using NitroxModel.Serialization;
using TMPro;
using UnityEngine;
-using UnityEngine.Events;
using UnityEngine.UI;
-using UWE;
-namespace NitroxClient.MonoBehaviours.Gui.MainMenu
+namespace NitroxClient.MonoBehaviours.Gui.MainMenu;
+
+public class MainMenuMultiplayerPanel : MonoBehaviour, uGUI_INavigableIconGrid, uGUI_IButtonReceiver
{
- public class MainMenuMultiplayerPanel : MonoBehaviour
+ public static MainMenuMultiplayerPanel Main;
+
+ private GameObject multiplayerButtonRef;
+
+ private Sprite normalSprite;
+ private Sprite selectedSprite;
+ private FMODAsset hoverSound;
+
+ private Transform serverAreaContent;
+ private GameObject selectedServerItem;
+
+ public JoinServer JoinServer { get; private set; }
+ public bool IsJoining{ get; set; }
+
+
+ public void Setup(GameObject loadedMultiplayer, GameObject savedGamesRef)
{
- public static MainMenuMultiplayerPanel Main;
- private Rect addServerWindowRect = new(Screen.width / 2 - 250, 200, 500, 200);
- private GameObject loadedMultiplayerRef;
- private GameObject savedGamesRef;
- private GameObject deleteButtonRef;
- private GameObject multiplayerButton;
- private Transform savedGameAreaContent;
- public JoinServer JoinServer { get; private set; }
-
- private string serverHostInput;
- private string serverNameInput;
- private string serverPortInput;
-
- private bool shouldFocus;
- private bool showingAddServer;
- private bool isJoining;
-
- public void Setup(GameObject loadedMultiplayer, GameObject savedGames)
- {
- Main = this;
- loadedMultiplayerRef = loadedMultiplayer;
- savedGamesRef = savedGames;
-
- //This sucks, but the only way around it is to establish a Subnautica resources cache and reference it everywhere we need it.
- //Given recent push-back on elaborate designs, I've just crammed it here until we can all get on the same page as far as code-quality standards are concerned.
- JoinServer = new GameObject("NitroxJoinServer").AddComponent();
- JoinServer.Setup(savedGamesRef);
-
- multiplayerButton = savedGamesRef.RequireGameObject("Scroll View/Viewport/SavedGameAreaContent/NewGame");
- savedGameAreaContent = loadedMultiplayerRef.RequireTransform("Scroll View/Viewport/SavedGameAreaContent");
- deleteButtonRef = savedGamesRef.GetComponent().saveInstance.GetComponent().deleteButton;
-
- CreateButton(translationKey: "Nitrox_AddServer", clickEvent: ShowAddServerWindow, disableTranslation: false);
- LoadSavedServers();
- _ = FindLANServersAsync();
- }
+ Main = this;
- private void CreateButton(string translationKey, UnityAction clickEvent, bool disableTranslation)
- {
- GameObject multiplayerButtonInst = Instantiate(multiplayerButton, savedGameAreaContent, false);
- Transform txt = multiplayerButtonInst.RequireTransform("NewGameButton/Text");
- txt.GetComponent().text = translationKey;
+ //This sucks, but the only way around it is to establish a Subnautica resources cache and reference it everywhere we need it.
+ //Given recent push-back on elaborate designs, I've just crammed it here until we can all get on the same page as far as code-quality standards are concerned.
+ JoinServer = new GameObject("NitroxJoinServer").AddComponent();
+ JoinServer.Setup(savedGamesRef);
- if (disableTranslation)
- {
- Destroy(txt.GetComponent());
- }
+ MainMenuLoadMenu loadMenu = loadedMultiplayer.GetComponentInChildren();
+ normalSprite = loadMenu.normalSprite;
+ selectedSprite = loadMenu.selectedSprite;
+ hoverSound = loadMenu.hoverSound;
- Button multiplayerButtonButton = multiplayerButtonInst.RequireTransform("NewGameButton").GetComponent