first commit
This commit is contained in:
@@ -0,0 +1,292 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using FMODUnity;
|
||||
using NitroxClient.Unity.Helper;
|
||||
using NitroxModel.Serialization;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace NitroxClient.MonoBehaviours.Gui.MainMenu.ServersList;
|
||||
|
||||
public class MainMenuCreateServerPanel : MonoBehaviour, uGUI_INavigableIconGrid, uGUI_IButtonReceiver
|
||||
{
|
||||
public const string NAME = "MultiplayerCreateServer";
|
||||
private const string DEFAULT_PORT = "11000";
|
||||
|
||||
private TMP_InputField serverNameInput, serverAddressInput, serverPortInput;
|
||||
private mGUI_Change_Legend_On_Select legendChange;
|
||||
|
||||
private GameObject selectedItem;
|
||||
private GameObject[] selectableItems;
|
||||
|
||||
public void Setup(GameObject savedGamesRef)
|
||||
{
|
||||
GameObject multiplayerButtonRef = savedGamesRef.RequireGameObject("Scroll View/Viewport/SavedGameAreaContent/NewGame");
|
||||
GameObject generalTextRef = multiplayerButtonRef.GetComponentInChildren<TextMeshProUGUI>().gameObject;
|
||||
|
||||
GameObject inputFieldRef = GameObject.Find("/Menu canvas/Panel/MainMenu/RightSide/Home/EmailBox/InputField");
|
||||
GameObject inputFieldBlueprint = Instantiate(inputFieldRef, transform, false);
|
||||
|
||||
inputFieldBlueprint.GetComponent<RectTransform>().sizeDelta = new Vector2(300, 40);
|
||||
TMP_InputField inputFieldBlueprintInput = inputFieldBlueprint.GetComponent<TMP_InputField>();
|
||||
inputFieldBlueprintInput.characterValidation = TMP_InputField.CharacterValidation.None;
|
||||
inputFieldBlueprintInput.onSubmit = new TMP_InputField.SubmitEvent();
|
||||
inputFieldBlueprintInput.onSubmit.AddListener(_ => { SelectItemInDirection(0, 1); });
|
||||
|
||||
GameObject serverName = Instantiate(inputFieldBlueprint, transform, false);
|
||||
serverName.transform.localPosition = new Vector3(-160, 300, 0);
|
||||
serverNameInput = serverName.GetComponent<TMP_InputField>();
|
||||
serverNameInput.placeholder.GetComponent<TranslationLiveUpdate>().translationKey = Language.main.Get("Nitrox_AddServer_NamePlaceholder");
|
||||
GameObject serverNameDesc = Instantiate(generalTextRef, serverName.transform, false);
|
||||
serverNameDesc.transform.localPosition = new Vector3(-200, 0, 0);
|
||||
serverNameDesc.GetComponent<TextMeshProUGUI>().text = Language.main.Get("Nitrox_AddServer_NameDescription");
|
||||
|
||||
GameObject serverAddress = Instantiate(inputFieldBlueprint, transform, false);
|
||||
serverAddress.transform.localPosition = new Vector3(-160, 225, 0);
|
||||
serverAddressInput = serverAddress.GetComponent<TMP_InputField>();
|
||||
serverAddressInput.placeholder.GetComponent<TranslationLiveUpdate>().translationKey = Language.main.Get("Nitrox_AddServer_AddressPlaceholder");
|
||||
GameObject serverAddressDesc = Instantiate(generalTextRef, serverAddress.transform, false);
|
||||
serverAddressDesc.transform.localPosition = new Vector3(-200, 0, 0);
|
||||
serverAddressDesc.GetComponent<TextMeshProUGUI>().text = Language.main.Get("Nitrox_AddServer_AddressDescription");
|
||||
|
||||
GameObject serverPort = Instantiate(inputFieldBlueprint, transform, false);
|
||||
serverPort.transform.localPosition = new Vector3(-160, 150, 0);
|
||||
serverPortInput = serverPort.GetComponent<TMP_InputField>();
|
||||
serverPortInput.characterValidation = TMP_InputField.CharacterValidation.Integer;
|
||||
serverPortInput.placeholder.GetComponent<TranslationLiveUpdate>().translationKey = Language.main.Get("Nitrox_AddServer_PortPlaceholder");
|
||||
serverPortInput.text = DEFAULT_PORT;
|
||||
GameObject serverPortDesc = Instantiate(generalTextRef, serverPort.transform, false);
|
||||
serverPortDesc.transform.localPosition = new Vector3(-200, 0, 0);
|
||||
serverPortDesc.GetComponent<TextMeshProUGUI>().text = Language.main.Get("Nitrox_AddServer_PortDescription");
|
||||
|
||||
GameObject confirmButton = Instantiate(multiplayerButtonRef, transform, false);
|
||||
confirmButton.transform.localPosition = new Vector3(-200, 90, 0);
|
||||
confirmButton.transform.GetChild(0).GetComponent<RectTransform>().sizeDelta = new Vector2(200, 40);
|
||||
confirmButton.GetComponentInChildren<TextMeshProUGUI>().text = Language.main.Get("Nitrox_AddServer_Confirm");
|
||||
Button confirmButtonButton = confirmButton.RequireTransform("NewGameButton").GetComponent<Button>();
|
||||
confirmButtonButton.onClick = new Button.ButtonClickedEvent();
|
||||
confirmButtonButton.onClick.AddListener(SaveServer);
|
||||
|
||||
GameObject backButton = Instantiate(multiplayerButtonRef, transform, false);
|
||||
backButton.transform.localPosition = new Vector3(-200, 40, 0);
|
||||
backButton.transform.GetChild(0).GetComponent<RectTransform>().sizeDelta = new Vector2(200, 40);
|
||||
backButton.GetComponentInChildren<TextMeshProUGUI>().text = Language.main.Get("Nitrox_Cancel");
|
||||
Button backButtonButton = backButton.RequireTransform("NewGameButton").GetComponent<Button>();
|
||||
backButtonButton.onClick = new Button.ButtonClickedEvent();
|
||||
backButtonButton.onClick.AddListener(OnBack);
|
||||
|
||||
selectableItems = [serverName, serverAddress, serverPort, confirmButton, backButton];
|
||||
Destroy(inputFieldBlueprint);
|
||||
Destroy(transform.Find("Scroll View").gameObject);
|
||||
|
||||
legendChange = gameObject.AddComponent<mGUI_Change_Legend_On_Select>();
|
||||
legendChange.legendButtonConfiguration = confirmButtonButton.GetComponent<mGUI_Change_Legend_On_Select>().legendButtonConfiguration.Take(2).ToArray();
|
||||
}
|
||||
|
||||
private void SaveServer()
|
||||
{
|
||||
string serverNameText = serverNameInput.text.Trim();
|
||||
string serverHostText = serverAddressInput.text.Trim();
|
||||
string serverPortText = serverPortInput.text.Trim();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(serverNameText) ||
|
||||
string.IsNullOrWhiteSpace(serverHostText) ||
|
||||
string.IsNullOrWhiteSpace(serverPortText) ||
|
||||
!int.TryParse(serverPortText, out int serverPort))
|
||||
{
|
||||
Log.InGame(Language.main.Get("Nitrox_AddServer_InvalidInput"));
|
||||
return;
|
||||
}
|
||||
|
||||
GameObject newEntry = MainMenuServerListPanel.Main.CreateServerButton(serverNameText, serverHostText, serverPort);
|
||||
ServerList.Instance.Add(new ServerList.Entry(serverNameText, serverHostText, serverPort));
|
||||
ServerList.Instance.Save();
|
||||
OnBack();
|
||||
MainMenuServerListPanel.Main.StartCoroutine(DelayedScrollToNewEntry());
|
||||
Log.InGame(Language.main.Get("Nitrox_AddServer_CreatedSuccessful"));
|
||||
return;
|
||||
|
||||
IEnumerator DelayedScrollToNewEntry()
|
||||
{
|
||||
yield return new WaitForEndOfFrame();
|
||||
UIUtils.ScrollToShowItemInCenter(newEntry.transform);
|
||||
}
|
||||
}
|
||||
|
||||
public bool OnButtonDown(GameInput.Button button)
|
||||
{
|
||||
switch (button)
|
||||
{
|
||||
case GameInput.Button.UISubmit:
|
||||
OnConfirm();
|
||||
return true;
|
||||
case GameInput.Button.UICancel:
|
||||
OnBack();
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (GameInput.GetKeyDown(KeyCode.Tab))
|
||||
{
|
||||
if (GameInput.GetKey(KeyCode.LeftShift))
|
||||
{
|
||||
SelectItemInDirection(-1, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectItemInDirection(1, 0);
|
||||
}
|
||||
}
|
||||
else if (selectedItem && GameInput.GetKeyDown(KeyCode.Return))
|
||||
{
|
||||
OnConfirm();
|
||||
}
|
||||
}
|
||||
|
||||
public void OnBack()
|
||||
{
|
||||
serverNameInput.text = string.Empty;
|
||||
serverAddressInput.text = string.Empty;
|
||||
serverPortInput.text = string.Empty;
|
||||
DeselectAllItems();
|
||||
MainMenuRightSide.main.OpenGroup(MainMenuServerListPanel.NAME);
|
||||
}
|
||||
|
||||
public void OnConfirm()
|
||||
{
|
||||
if (selectedItem.TryGetComponentInChildren(out TMP_InputField inputField))
|
||||
{
|
||||
inputField.ActivateInputField();
|
||||
}
|
||||
|
||||
if (selectedItem.TryGetComponentInChildren(out Button button))
|
||||
{
|
||||
button.onClick.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
object uGUI_INavigableIconGrid.GetSelectedItem() => selectedItem;
|
||||
|
||||
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();
|
||||
selectedItem = item as GameObject;
|
||||
|
||||
legendChange.SyncLegendBarToGUISelection();
|
||||
|
||||
if (!selectedItem)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedItem.TryGetComponent(out TMP_InputField selectedInputField))
|
||||
{
|
||||
selectedInputField.Select();
|
||||
}
|
||||
else // Button
|
||||
{
|
||||
selectedItem.transform.GetChild(0).GetComponent<Image>().sprite = MainMenuServerListPanel.SelectedSprite;
|
||||
selectedItem.GetComponentInChildren<uGUI_BasicColorSwap>().makeTextBlack();
|
||||
}
|
||||
|
||||
if (!EventSystem.current.alreadySelecting)
|
||||
{
|
||||
EventSystem.current.SetSelectedGameObject(selectedItem);
|
||||
}
|
||||
|
||||
RuntimeManager.PlayOneShot(MainMenuServerListPanel.HoverSound.path);
|
||||
}
|
||||
|
||||
public void DeselectItem()
|
||||
{
|
||||
if (!selectedItem)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedItem.TryGetComponent(out TMP_InputField selectedInputField))
|
||||
{
|
||||
selectedInputField.DeactivateInputField();
|
||||
selectedInputField.ReleaseSelection();
|
||||
}
|
||||
else // Button
|
||||
{
|
||||
selectedItem.transform.GetChild(0).GetComponent<Image>().sprite = MainMenuServerListPanel.NormalSprite;
|
||||
selectedItem.transform.GetChild(0).GetComponent<uGUI_BasicColorSwap>().makeTextWhite();
|
||||
}
|
||||
|
||||
if (!EventSystem.current.alreadySelecting)
|
||||
{
|
||||
EventSystem.current.SetSelectedGameObject(null);
|
||||
}
|
||||
|
||||
selectedItem = null;
|
||||
}
|
||||
|
||||
public void DeselectAllItems()
|
||||
{
|
||||
foreach (GameObject child in selectableItems)
|
||||
{
|
||||
selectedItem = child;
|
||||
DeselectItem();
|
||||
}
|
||||
}
|
||||
|
||||
public bool SelectFirstItem()
|
||||
{
|
||||
SelectItem(selectableItems[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SelectItemInDirection(int dirX, int dirY)
|
||||
{
|
||||
if (!selectedItem)
|
||||
{
|
||||
return SelectFirstItem();
|
||||
}
|
||||
|
||||
if (dirX == dirY)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int dir = dirX + dirY > 0 ? 1 : -1;
|
||||
for (int newIndex = GetSelectedIndex() + dir; newIndex >= 0 && newIndex < selectableItems.Length; newIndex += dir)
|
||||
{
|
||||
if (SelectItemByIndex(newIndex))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private int GetSelectedIndex() => selectedItem ? Array.IndexOf(selectableItems, selectedItem) : -1;
|
||||
|
||||
private bool SelectItemByIndex(int selectedIndex)
|
||||
{
|
||||
if (selectedIndex >= 0 && selectedIndex < selectableItems.Length)
|
||||
{
|
||||
SelectItem(selectableItems[selectedIndex]);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
namespace NitroxClient.MonoBehaviours.Gui.MainMenu.ServersList;
|
||||
|
||||
public class MainMenuDeleteServer : uGUI_NavigableControlGrid, uGUI_IButtonReceiver
|
||||
{
|
||||
public MainMenuServerButton serverButton;
|
||||
|
||||
private void Start() => interGridNavigation = new uGUI_InterGridNavigation();
|
||||
|
||||
public bool OnButtonDown(GameInput.Button button)
|
||||
{
|
||||
if (button != GameInput.Button.UICancel)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
OnBack();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnBack() => serverButton.CancelDelete();
|
||||
}
|
@@ -0,0 +1,220 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NitroxClient.GameLogic.Settings;
|
||||
using NitroxClient.MonoBehaviours.Gui.MainMenu.ServerJoin;
|
||||
using NitroxClient.Unity.Helper;
|
||||
using NitroxModel.Serialization;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace NitroxClient.MonoBehaviours.Gui.MainMenu.ServersList;
|
||||
|
||||
public class MainMenuServerButton : MonoBehaviour
|
||||
{
|
||||
private static MainMenuLoadButton loadButtonRef;
|
||||
private static LegendButtonData[] confirmButtonLegendData;
|
||||
private static GameObject deleteButtonRef;
|
||||
|
||||
private CanvasGroup loadCg;
|
||||
private CanvasGroup deleteCg;
|
||||
private Button cancelDeleteButton;
|
||||
|
||||
private string joinIp;
|
||||
private int joinPort;
|
||||
private string joinServerName;
|
||||
|
||||
public static void Setup(MainMenuLoadButton _loadButtonRef)
|
||||
{
|
||||
loadButtonRef = _loadButtonRef;
|
||||
confirmButtonLegendData = _loadButtonRef.GetComponent<mGUI_Change_Legend_On_Select>().legendButtonConfiguration;
|
||||
deleteButtonRef = _loadButtonRef.deleteButton;
|
||||
}
|
||||
|
||||
public void Init(string serverName, string ip, int port, bool isReadOnly)
|
||||
{
|
||||
joinIp = ip;
|
||||
joinPort = port;
|
||||
joinServerName = serverName;
|
||||
|
||||
Transform loadTransform = this.RequireTransform("Load");
|
||||
loadCg = loadTransform.gameObject.AddComponent<CanvasGroup>();
|
||||
Transform newGameButtonTransform = loadTransform.RequireTransform("NewGameButton");
|
||||
|
||||
TextMeshProUGUI tmp = newGameButtonTransform.RequireTransform("Text").GetComponent<TextMeshProUGUI>();
|
||||
Destroy(tmp.GetComponent<TranslationLiveUpdate>());
|
||||
StringBuilder buttonText = new(Language.main.Get("Nitrox_ConnectTo"));
|
||||
buttonText.Append(" <b>").Append(serverName).AppendLine("</b>");
|
||||
if (NitroxPrefs.HideIp.Value)
|
||||
{
|
||||
buttonText.AppendLine("***.***.***.***:*****");
|
||||
}
|
||||
else
|
||||
{
|
||||
buttonText.Append(ip[^Math.Min(ip.Length, 25)..]).Append(':').Append(port);
|
||||
}
|
||||
tmp.text = buttonText.ToString();
|
||||
|
||||
Button multiplayerJoinButton = newGameButtonTransform.GetComponent<Button>();
|
||||
multiplayerJoinButton.onClick = new Button.ButtonClickedEvent();
|
||||
multiplayerJoinButton.onClick.AddListener(() => _ = OnJoinButtonClicked());
|
||||
|
||||
gameObject.GetComponent<mGUI_Change_Legend_On_Select>().legendButtonConfiguration = confirmButtonLegendData;
|
||||
|
||||
// We don't want servers that are discovered automatically to be deleted
|
||||
if (isReadOnly)
|
||||
{
|
||||
Destroy(transform.Find("Delete").gameObject);
|
||||
return;
|
||||
}
|
||||
|
||||
GameObject delete = Instantiate(deleteButtonRef, loadTransform, false);
|
||||
Button deleteButtonButton = delete.GetComponent<Button>();
|
||||
deleteButtonButton.onClick = new Button.ButtonClickedEvent();
|
||||
deleteButtonButton.onClick.AddListener(RequestDelete);
|
||||
|
||||
Transform deleteTransform = this.RequireTransform("Delete");
|
||||
Destroy(deleteTransform.GetComponent<MainMenuDeleteGame>());
|
||||
Destroy(deleteTransform.GetComponent<TranslationLiveUpdate>());
|
||||
deleteCg = deleteTransform.GetComponent<CanvasGroup>();
|
||||
cancelDeleteButton = deleteTransform.RequireTransform("DeleteCancelButton").GetComponent<Button>();
|
||||
cancelDeleteButton.onClick = new Button.ButtonClickedEvent();
|
||||
cancelDeleteButton.onClick.AddListener(CancelDelete);
|
||||
Button confirmDeleteButton = deleteTransform.RequireTransform("DeleteConfirmButton").GetComponent<Button>();
|
||||
confirmDeleteButton.onClick = new Button.ButtonClickedEvent();
|
||||
confirmDeleteButton.onClick.AddListener(Delete);
|
||||
|
||||
deleteTransform.gameObject.AddComponent<MainMenuDeleteServer>().serverButton = this;
|
||||
TextMeshProUGUI warningTmp = deleteTransform.RequireTransform("DeleteWarningText").GetComponent<TextMeshProUGUI>();
|
||||
warningTmp.text = Language.main.Get("Nitrox_ServerEntry_DeleteWarning");
|
||||
}
|
||||
|
||||
public void RequestDelete()
|
||||
{
|
||||
uGUI_MainMenu.main.OnRightSideOpened(deleteCg.gameObject);
|
||||
uGUI_LegendBar.ClearButtons();
|
||||
uGUI_LegendBar.ChangeButton(0, uGUI.FormatButton(GameInput.Button.UICancel, gamePadOnly: true), Language.main.GetFormat("Back"));
|
||||
uGUI_LegendBar.ChangeButton(1, uGUI.FormatButton(GameInput.Button.UISubmit, gamePadOnly: true), Language.main.GetFormat("ItemSelectorSelect"));
|
||||
StartCoroutine(loadButtonRef.ShiftAlpha(loadCg, 0.0f, loadButtonRef.animTime, loadButtonRef.alphaPower, false));
|
||||
StartCoroutine(loadButtonRef.ShiftAlpha(deleteCg, 1f, loadButtonRef.animTime, loadButtonRef.alphaPower, true, cancelDeleteButton));
|
||||
StartCoroutine(loadButtonRef.ShiftPos(loadCg, MainMenuLoadButton.target.left, MainMenuLoadButton.target.centre, loadButtonRef.animTime, loadButtonRef.posPower));
|
||||
StartCoroutine(loadButtonRef.ShiftPos(deleteCg, MainMenuLoadButton.target.centre, MainMenuLoadButton.target.right, loadButtonRef.animTime, loadButtonRef.posPower));
|
||||
}
|
||||
|
||||
public void CancelDelete()
|
||||
{
|
||||
MainMenuRightSide.main.OpenGroup(MainMenuServerListPanel.NAME);
|
||||
if (GameInput.IsPrimaryDeviceGamepad())
|
||||
MainMenuServerListPanel.Main.SelectItemByIndex(MainMenuServerListPanel.Main.GetSelectedIndex());
|
||||
StartCoroutine(loadButtonRef.ShiftAlpha(loadCg, 1f, loadButtonRef.animTime, loadButtonRef.alphaPower, true));
|
||||
StartCoroutine(loadButtonRef.ShiftAlpha(deleteCg, 0.0f, loadButtonRef.animTime, loadButtonRef.alphaPower, false));
|
||||
StartCoroutine(loadButtonRef.ShiftPos(loadCg, MainMenuLoadButton.target.centre, MainMenuLoadButton.target.left, loadButtonRef.animTime, loadButtonRef.posPower));
|
||||
StartCoroutine(loadButtonRef.ShiftPos(deleteCg, MainMenuLoadButton.target.right, MainMenuLoadButton.target.centre, loadButtonRef.animTime, loadButtonRef.posPower));
|
||||
}
|
||||
|
||||
public void ResetLoadDeleteView()
|
||||
{
|
||||
loadCg.alpha = 1;
|
||||
loadCg.interactable = loadCg.blocksRaycasts = true;
|
||||
|
||||
RectTransform loadTransform = loadCg.GetComponent<RectTransform>();
|
||||
float loadPosX = loadTransform.sizeDelta.x * 0.5f;
|
||||
loadTransform.localPosition = new Vector3(loadPosX, loadTransform.localPosition.y, 0);
|
||||
|
||||
if (deleteCg) // Read only server entries
|
||||
{
|
||||
RectTransform deleteTransform = deleteCg.GetComponent<RectTransform>();
|
||||
float deletePosX = deleteTransform.sizeDelta.x * 0.5f;
|
||||
deleteTransform.localPosition = new Vector3(deletePosX, deleteTransform.localPosition.y, 0);
|
||||
|
||||
deleteCg.alpha = 0;
|
||||
deleteCg.interactable = deleteCg.blocksRaycasts = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void Delete()
|
||||
{
|
||||
MainMenuRightSide.main.OpenGroup(MainMenuServerListPanel.NAME);
|
||||
int scrollIndex = MainMenuServerListPanel.Main.GetSelectedIndex();
|
||||
if (GameInput.IsPrimaryDeviceGamepad() && !MainMenuServerListPanel.Main.SelectItemInYDirection(scrollIndex, 1))
|
||||
{
|
||||
MainMenuServerListPanel.Main.SelectItemInYDirection(scrollIndex, -1);
|
||||
}
|
||||
StartCoroutine(loadButtonRef.ShiftPos(deleteCg, MainMenuLoadButton.target.left, MainMenuLoadButton.target.centre, loadButtonRef.animTime, loadButtonRef.posPower));
|
||||
StartCoroutine(loadButtonRef.ShiftAlpha(deleteCg, 0.0f, loadButtonRef.animTime, loadButtonRef.alphaPower, false));
|
||||
|
||||
ServerList.Instance.RemoveAt(transform.GetSiblingIndex() - 1);
|
||||
ServerList.Instance.Save();
|
||||
|
||||
Destroy(gameObject);
|
||||
}
|
||||
|
||||
public async Task OnJoinButtonClicked()
|
||||
{
|
||||
if (MainMenuServerListPanel.Main.IsJoining)
|
||||
{
|
||||
return; // Do not attempt to join multiple servers.
|
||||
}
|
||||
|
||||
MainMenuServerListPanel.Main.IsJoining = true;
|
||||
MainMenuServerListPanel.Main.DeselectAllItems();
|
||||
await OpenJoinServerMenuAsync(joinIp, joinPort).ContinueWith(_ => { MainMenuServerListPanel.Main.IsJoining = false; });
|
||||
MainMenuJoinServerPanel.Instance.UpdatePanelValues(joinServerName);
|
||||
}
|
||||
|
||||
public static async Task OpenJoinServerMenuAsync(string serverIp, int serverPort)
|
||||
{
|
||||
if (!MainMenuServerListPanel.Main)
|
||||
{
|
||||
Log.Error("MainMenuServerListPanel is not instantiated although OpenJoinServerMenuAsync is called.");
|
||||
return;
|
||||
}
|
||||
|
||||
IPEndPoint endpoint = ResolveIPEndPoint(serverIp, serverPort);
|
||||
if (endpoint == null)
|
||||
{
|
||||
Log.InGame($"{Language.main.Get("Nitrox_UnableToConnect")}: {serverIp}:{serverPort}");
|
||||
return;
|
||||
}
|
||||
|
||||
MainMenuNotificationPanel.ShowLoading();
|
||||
await JoinServerBackend.StartMultiplayerClientAsync(endpoint.Address, endpoint.Port);
|
||||
}
|
||||
|
||||
private static IPEndPoint ResolveIPEndPoint(string serverIp, int serverPort)
|
||||
{
|
||||
UriHostNameType hostType = Uri.CheckHostName(serverIp);
|
||||
IPAddress address;
|
||||
switch (hostType)
|
||||
{
|
||||
case UriHostNameType.IPv4:
|
||||
case UriHostNameType.IPv6:
|
||||
IPAddress.TryParse(serverIp, out address);
|
||||
break;
|
||||
case UriHostNameType.Dns:
|
||||
address = ResolveHostName(serverIp, serverPort);
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
return address != null ? new IPEndPoint(address, serverPort) : null;
|
||||
|
||||
static IPAddress ResolveHostName(string hostname, int serverPort)
|
||||
{
|
||||
try
|
||||
{
|
||||
IPHostEntry hostEntry = Dns.GetHostEntry(hostname);
|
||||
return hostEntry.AddressList[0];
|
||||
}
|
||||
catch (SocketException ex)
|
||||
{
|
||||
Log.ErrorSensitive(ex, "Unable to resolve the address {hostname}:{serverPort}", hostname, serverPort);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,355 @@
|
||||
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<MainMenuLoadMenu>();
|
||||
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<GridLayoutGroup>().spacing = new Vector2(0, 5);
|
||||
|
||||
scrollRect = transform.RequireGameObject("Scroll View").GetComponent<ScrollRect>();
|
||||
scrollBar = scrollRect.RequireGameObject("Scrollbar");
|
||||
|
||||
multiplayerServerButtonRef = savedGamesRef.GetComponent<MainMenuLoadPanel>().saveInstance;
|
||||
MainMenuServerButton.Setup(multiplayerServerButtonRef.GetComponent<MainMenuLoadButton>());
|
||||
|
||||
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<Image>().sprite = SelectedSprite;
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedServerItem.transform.Find("Load/NewGameButton").GetComponent<Image>().sprite = SelectedSprite;
|
||||
}
|
||||
|
||||
selectedServerItem.GetComponentInChildren<uGUI_BasicColorSwap>();
|
||||
|
||||
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<Image>().sprite = NormalSprite;
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedServerItem.transform.Find("Load/NewGameButton").GetComponent<Image>().sprite = NormalSprite;
|
||||
}
|
||||
|
||||
selectedServerItem.GetComponentInChildren<uGUI_BasicColorSwap>().makeTextWhite();
|
||||
selectedServerItem = null;
|
||||
}
|
||||
|
||||
public void DeselectAllItems()
|
||||
{
|
||||
// Create ServerEntry button
|
||||
serverAreaContent.GetChild(0).Find("NewGameButton").GetComponent<Image>().sprite = NormalSprite;
|
||||
serverAreaContent.GetChild(0).GetComponentInChildren<uGUI_BasicColorSwap>().makeTextWhite();
|
||||
|
||||
// Server buttons
|
||||
for (int i = 1; i < serverAreaContent.childCount; i++)
|
||||
{
|
||||
Transform child = serverAreaContent.GetChild(i);
|
||||
child.Find("Load/NewGameButton").GetComponent<Image>().sprite = NormalSprite;
|
||||
child.GetComponentInChildren<uGUI_BasicColorSwap>().makeTextWhite();
|
||||
child.GetComponent<MainMenuServerButton>().ResetLoadDeleteView();
|
||||
}
|
||||
}
|
||||
|
||||
public bool SelectFirstItem()
|
||||
{
|
||||
MainMenuServerButton firstServerObject = serverAreaContent.GetComponentInChildren<MainMenuServerButton>();
|
||||
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<IEnumerable<IPEndPoint>> 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<MainMenuLoadButton>());
|
||||
|
||||
GameObject multiplayerLoadButtonInst = Instantiate(multiplayerNewServerButtonRef, multiplayerButtonInst.transform, false);
|
||||
multiplayerLoadButtonInst.name = "Load";
|
||||
|
||||
MainMenuServerButton serverButton = multiplayerButtonInst.AddComponent<MainMenuServerButton>();
|
||||
serverButton.Init(serverName, address, port, isReadOnly);
|
||||
|
||||
scrollBar.SetActive(serverAreaContent.childCount >= 4);
|
||||
foreach (EventTrigger eventTrigger in multiplayerButtonInst.GetComponentsInChildren<EventTrigger>(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<TextMeshProUGUI>();
|
||||
txt.text = "Nitrox_AddServer";
|
||||
txt.fontSize *= 1.5f;
|
||||
txt.fontStyle = FontStyles.Bold;
|
||||
|
||||
Button multiplayerButtonButton = multiplayerButtonInst.RequireTransform("NewGameButton").GetComponent<Button>();
|
||||
multiplayerButtonButton.onClick = new Button.ButtonClickedEvent();
|
||||
multiplayerButtonButton.onClick.AddListener(OpenAddServerGroup);
|
||||
|
||||
ForwardTriggerScrollToScrollRect(multiplayerButtonButton.GetComponent<EventTrigger>());
|
||||
}
|
||||
|
||||
private void ForwardTriggerScrollToScrollRect(EventTrigger eventTrigger)
|
||||
{
|
||||
eventTrigger.triggers.RemoveAll(trigger => trigger.eventID == EventTriggerType.Scroll);
|
||||
|
||||
EventTrigger.TriggerEvent callback = new();
|
||||
callback.AddListener(x => scrollRect.Scroll(((PointerEventData)x).scrollDelta.y, 5f));
|
||||
|
||||
eventTrigger.triggers.Add(new EventTrigger.Entry
|
||||
{
|
||||
eventID = EventTriggerType.Scroll,
|
||||
callback = callback
|
||||
});
|
||||
}
|
||||
|
||||
public void OpenAddServerGroup()
|
||||
{
|
||||
DeselectAllItems();
|
||||
MainMenuRightSide.main.OpenGroup(MainMenuCreateServerPanel.NAME);
|
||||
}
|
||||
|
||||
public void RefreshServerEntries()
|
||||
{
|
||||
if (!serverAreaContent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (Transform child in serverAreaContent)
|
||||
{
|
||||
Destroy(child.gameObject);
|
||||
}
|
||||
|
||||
CreateAddServerButton();
|
||||
LoadSavedServers();
|
||||
CoroutineHost.StartCoroutine(FindLANServers());
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user