using System.Collections; using System.Collections.Generic; using System.Linq; using System.Net; using System.Text; using System.Threading.Tasks; using FMODUnity; using NitroxClient.Communication; using NitroxClient.GameLogic.Settings; using NitroxClient.Unity.Helper; using NitroxModel; using NitroxModel.Serialization; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; using UWE; namespace NitroxClient.MonoBehaviours.Gui.MainMenu.ServersList; public class MainMenuServerListPanel : MonoBehaviour, uGUI_INavigableIconGrid, uGUI_IButtonReceiver { public const string NAME = "MultiplayerServerList"; public static MainMenuServerListPanel Main; public static Sprite NormalSprite; public static Sprite SelectedSprite; public static FMODAsset HoverSound; private GameObject multiplayerNewServerButtonRef; private GameObject multiplayerServerButtonRef; private Transform serverAreaContent; private GameObject selectedServerItem; private ScrollRect scrollRect; private GameObject scrollBar; public bool IsJoining { get; set; } public void Setup(GameObject savedGamesRef) { Main = this; MainMenuLoadMenu loadMenu = savedGamesRef.GetComponentInChildren(); NormalSprite = loadMenu.normalSprite; SelectedSprite = loadMenu.selectedSprite; HoverSound = loadMenu.hoverSound; multiplayerNewServerButtonRef = savedGamesRef.RequireGameObject("Scroll View/Viewport/SavedGameAreaContent/NewGame"); serverAreaContent = transform.RequireTransform("Scroll View/Viewport/SavedGameAreaContent"); serverAreaContent.gameObject.name = "ServerAreaContent"; serverAreaContent.GetComponent().spacing = new Vector2(0, 5); scrollRect = transform.RequireGameObject("Scroll View").GetComponent(); scrollBar = scrollRect.RequireGameObject("Scrollbar"); multiplayerServerButtonRef = savedGamesRef.GetComponent().saveInstance; MainMenuServerButton.Setup(multiplayerServerButtonRef.GetComponent()); RefreshServerEntries(); } public bool OnButtonDown(GameInput.Button button) { switch (button) { case GameInput.Button.UISubmit: OnConfirm(); return true; case GameInput.Button.UICancel: OnBack(); return true; case GameInput.Button.UIClear: OnClear(); return true; default: return false; } } public void OnBack() { DeselectAllItems(); MainMenuRightSide.main.OpenGroup("Home"); } public void OnClear() { if (selectedServerItem && selectedServerItem.TryGetComponent(out MainMenuServerButton serverButton)) { serverButton.RequestDelete(); } } public void OnConfirm() { if (!selectedServerItem) { return; } if (selectedServerItem.gameObject.name == "NewServer") { DeselectAllItems(); MainMenuRightSide.main.OpenGroup(MainMenuCreateServerPanel.NAME); } else if (selectedServerItem.TryGetComponent(out MainMenuServerButton serverButton)) { _ = serverButton.OnJoinButtonClicked().ContinueWithHandleError(Log.Error); } } object uGUI_INavigableIconGrid.GetSelectedItem() => selectedServerItem; bool uGUI_INavigableIconGrid.ShowSelector => false; bool uGUI_INavigableIconGrid.EmulateRaycast => false; bool uGUI_INavigableIconGrid.SelectItemClosestToPosition(Vector3 worldPos) => false; uGUI_INavigableIconGrid uGUI_INavigableIconGrid.GetNavigableGridInDirection(int dirX, int dirY) => null; Graphic uGUI_INavigableIconGrid.GetSelectedIcon() => null; public void SelectItem(object item) { DeselectItem(); selectedServerItem = item as GameObject; if (!selectedServerItem) { return; } if (selectedServerItem.TryGetComponentInChildren(out mGUI_Change_Legend_On_Select componentInChildren)) { componentInChildren.SyncLegendBarToGUISelection(); } if (selectedServerItem == serverAreaContent.GetChild(0).gameObject) // Server Create Button { selectedServerItem.transform.Find("NewGameButton").GetComponent().sprite = SelectedSprite; } else { selectedServerItem.transform.Find("Load/NewGameButton").GetComponent().sprite = SelectedSprite; } selectedServerItem.GetComponentInChildren(); UIUtils.ScrollToShowItemInCenter(selectedServerItem.transform); RuntimeManager.PlayOneShot(HoverSound.path); } public void DeselectItem() { if (!selectedServerItem) { return; } if (selectedServerItem == serverAreaContent.GetChild(0).gameObject) // Server Create Button { selectedServerItem.transform.Find("NewGameButton").GetComponent().sprite = NormalSprite; } else { selectedServerItem.transform.Find("Load/NewGameButton").GetComponent().sprite = NormalSprite; } selectedServerItem.GetComponentInChildren().makeTextWhite(); selectedServerItem = null; } public void DeselectAllItems() { // Create ServerEntry button serverAreaContent.GetChild(0).Find("NewGameButton").GetComponent().sprite = NormalSprite; serverAreaContent.GetChild(0).GetComponentInChildren().makeTextWhite(); // Server buttons for (int i = 1; i < serverAreaContent.childCount; i++) { Transform child = serverAreaContent.GetChild(i); child.Find("Load/NewGameButton").GetComponent().sprite = NormalSprite; child.GetComponentInChildren().makeTextWhite(); child.GetComponent().ResetLoadDeleteView(); } } public bool SelectFirstItem() { MainMenuServerButton firstServerObject = serverAreaContent.GetComponentInChildren(); if (firstServerObject) { SelectItem(firstServerObject.gameObject); return true; } Transform serverCreationButton = serverAreaContent.GetChild(0); if (serverCreationButton && serverCreationButton.name == "NewServer") { SelectItem(serverCreationButton.gameObject); return true; } return false; } public bool SelectItemInDirection(int dirX, int dirY) { if (selectedServerItem) { return dirY != 0 && SelectItemInYDirection(GetSelectedIndex(), dirY); } return SelectFirstItem(); } public int GetSelectedIndex() => selectedServerItem ? selectedServerItem.transform.GetSiblingIndex() : -1; public bool SelectItemInYDirection(int selectedIndex, int dirY) { int dir = dirY > 0 ? 1 : -1; for (int newIndex = selectedIndex + dir; newIndex >= 0 && newIndex < serverAreaContent.childCount; newIndex += dir) { if (SelectItemByIndex(newIndex)) { return true; } } return false; } public bool SelectItemByIndex(int selectedIndex) { if (selectedIndex < serverAreaContent.childCount && selectedIndex >= 0) { SelectItem(serverAreaContent.GetChild(selectedIndex).gameObject); return true; } return false; } private void LoadSavedServers() { ServerList.Refresh(); foreach (ServerList.Entry entry in ServerList.Instance.Entries) { CreateServerButton(entry.Name, entry.Address, entry.Port); } } private IEnumerator FindLANServers() { void LateAddButton(IPEndPoint serverEndPoint) { if (!ServerList.Instance.Entries.Any(e => e.Address == serverEndPoint.Address.ToString() && e.Port == serverEndPoint.Port)) { Log.Info($"Adding LAN server: {serverEndPoint}"); // Add ServerList entry to keep indices in sync with servers UI, to enable removal by index ServerList.Instance.Add(new ServerList.Entry("LAN Server", serverEndPoint.Address, serverEndPoint.Port, false)); CreateServerButton("LAN Server", serverEndPoint.Address.ToString(), serverEndPoint.Port, true); } } using Task> searchTask = LANBroadcastClient.SearchAsync(); while (!searchTask.IsCompleted) { while (LANBroadcastClient.DiscoveredServers.TryDequeue(out IPEndPoint endPoint)) { LateAddButton(endPoint); } yield return null; } while (LANBroadcastClient.DiscoveredServers.TryDequeue(out IPEndPoint endPoint)) { LateAddButton(endPoint); } ServerList.Instance.Save(); } public GameObject CreateServerButton(string serverName, string address, int port, bool isReadOnly = false) { GameObject multiplayerButtonInst = Instantiate(multiplayerServerButtonRef, serverAreaContent, false); multiplayerButtonInst.name = $"NitroxServer_{serverAreaContent.childCount - 2}"; DestroyImmediate(multiplayerButtonInst.RequireGameObject("Load")); // Needs to be deleted before MainMenuServerButton.Init() below Destroy(multiplayerButtonInst.GetComponent()); GameObject multiplayerLoadButtonInst = Instantiate(multiplayerNewServerButtonRef, multiplayerButtonInst.transform, false); multiplayerLoadButtonInst.name = "Load"; MainMenuServerButton serverButton = multiplayerButtonInst.AddComponent(); serverButton.Init(serverName, address, port, isReadOnly); scrollBar.SetActive(serverAreaContent.childCount >= 4); foreach (EventTrigger eventTrigger in multiplayerButtonInst.GetComponentsInChildren(true)) { ForwardTriggerScrollToScrollRect(eventTrigger); } return multiplayerButtonInst; } private void CreateAddServerButton() { GameObject multiplayerButtonInst = Instantiate(multiplayerNewServerButtonRef, serverAreaContent, false); multiplayerButtonInst.name = "NewServer"; // "NewServer" is important, see OnConfirm() TextMeshProUGUI txt = multiplayerButtonInst.RequireTransform("NewGameButton/Text").GetComponent(); txt.text = "Nitrox_AddServer"; txt.fontSize *= 1.5f; txt.fontStyle = FontStyles.Bold; Button multiplayerButtonButton = multiplayerButtonInst.RequireTransform("NewGameButton").GetComponent