using System.Collections; using System.Collections.Generic; using System.Linq; using NitroxClient.Communication.Abstract; using NitroxClient.GameLogic.HUD.Components; using NitroxClient.GameLogic.PlayerLogic.PlayerModel.Abstract; using NitroxModel.Core; using TMPro; using UnityEngine; using UnityEngine.UI; using static NitroxClient.Unity.Helper.AssetBundleLoader; namespace NitroxClient.GameLogic.HUD.PdaTabs; /// /// The component containing a new PDA tab based on ping manager tab /// public class uGUI_PlayerListTab : uGUI_PingTab { private NitroxPDATabManager nitroxPDATabManager; private PlayerManager playerManager; private LocalPlayer localPlayer; private IPacketSender packetSender; private readonly Dictionary assets = new(); public bool FinishedLoadingAssets { get; private set; } private new readonly Dictionary entries = new(); private PrefabPool pool; private new readonly Dictionary tempSort = new(); public override void Awake() { // Copied from uGUI_PingTab.Awake but we don't want it to be executed because it creates a PrefabPool selectableVisibilityToggle = new SelectableWrapper(visibilityToggle, delegate (GameInput.Button button) { if (button == GameInput.Button.UISubmit) { visibilityToggle.isOn = !visibilityToggle.isOn; return true; } return false; }); nitroxPDATabManager = NitroxServiceLocator.LocateService(); playerManager = NitroxServiceLocator.LocateService(); localPlayer = NitroxServiceLocator.LocateService(); packetSender = NitroxServiceLocator.LocateService(); // Need to reassign manually these variables and get rid of the objects we don't need content = gameObject.FindChild("Content").GetComponent(); pingManagerLabel = gameObject.GetComponentInChildren(); scrollRect = gameObject.GetComponentInChildren(); pingCanvas = (RectTransform)content.transform.Find("ScrollView/Viewport/ScrollCanvas"); pool = new PrefabPool(prefabEntry, pingCanvas, 8, 4, delegate (uGUI_PlayerPingEntry entry) { entry.Uninitialize(); }, delegate (uGUI_PlayerPingEntry entry) { entry.Uninitialize(); }); } public IEnumerator Start() { Transform buttonAll = content.transform.Find("ButtonAll"); DestroyImmediate(buttonAll.gameObject); yield return LoadAllAssets(NitroxAssetBundle.PLAYER_LIST_TAB); foreach (Object asset in NitroxAssetBundle.PLAYER_LIST_TAB.LoadedAssets) { if (asset is Sprite sprite) { if (asset.name.Equals("player_list_tab@3x")) { nitroxPDATabManager.AddTabSprite(asset.name, new Atlas.Sprite(sprite)); } assets.Add(asset.name, sprite); } } FinishedLoadingAssets = true; _isDirty = true; } public Sprite GetSprite(string assetName) { if (assets.TryGetValue(assetName, out Sprite sprite)) { return sprite; } return Sprite.Create(new Texture2D(100, 100), new Rect(0, 0, 100, 100), new Vector2(50, 50), 100); } public new void OnEnable() { // Enter events for player join and disconnect playerManager.OnCreate += OnAdd; playerManager.OnRemove += OnRemove; } public new void OnDestroy() { playerManager.OnCreate -= OnAdd; playerManager.OnRemove -= OnRemove; } public override void OnLanguageChanged() { pingManagerLabel.text = Language.main.Get("Nitrox_PlayerListTabName"); entries.Values.ForEach(entry => entry.OnLanguageChanged()); } public override void OnLateUpdate(bool _) { UpdateEntries(); } public new void UpdateEntries() { if (!_isDirty) { return; } _isDirty = false; Dictionary players = playerManager.GetAll().ToDictionary(player => player.PlayerId.ToString(), player => player); players.Add(localPlayer.PlayerId.ToString(), localPlayer); foreach (KeyValuePair entry in players) { if (!entries.ContainsKey(entry.Key)) { // Sets up a new entry for the player AddNewEntry(entry.Key, entry.Value); } } // Sort the items by alphabetical order (based on SN's code) tempSort.Clear(); foreach (KeyValuePair entry in entries) { if (!entry.Value.IsLocalPlayer) { tempSort.Add(entry.Value.PlayerName, entry.Value); } } List sorted = new(tempSort.Keys); sorted.Sort(); entries[localPlayer.PlayerId.ToString()].rectTransform.SetSiblingIndex(0); for (int j = 0; j < sorted.Count; j++) { string id = tempSort[sorted[j]].id; entries[id].rectTransform.SetSiblingIndex(j + 1); } } public uGUI_PlayerPingEntry GetEntry() { uGUI_PlayerPingEntry uGUI_PlayerEntry; if (pool.pool.Count == 0) { for (int i = 0; i < 4; i++) { uGUI_PlayerEntry = Instantiate(prefabEntry).GetComponent(); uGUI_PlayerEntry.rectTransform.SetParent(pingCanvas, false); uGUI_PlayerEntry.Uninitialize(); pool.pool.Add(uGUI_PlayerEntry); } } int index = pool.pool.Count - 1; uGUI_PlayerEntry = pool.pool[index]; pool.pool.RemoveAt(index); return uGUI_PlayerEntry; } public void MakePrefab(GameObject basePrefab) { // We need to instantiate the prefab as we cannot directly make modifications in it GameObject newPrefab = Instantiate(basePrefab); newPrefab.name = "PlayerEntry"; // We never want this to appear DestroyImmediate(newPrefab.FindChild("ColorToggle")); // Need to modify the pingTab's script from uGUI_PingEntry to uGUI_PlayerEntry uGUI_PingEntry pingEntry = newPrefab.GetComponent(); uGUI_PlayerPingEntry playerEntry = newPrefab.AddComponent(); playerEntry.visibility = pingEntry.visibility; playerEntry.visibilityIcon = pingEntry.visibilityIcon; playerEntry.icon = pingEntry.icon; playerEntry.label = pingEntry.label; playerEntry._rectTransform = pingEntry._rectTransform; playerEntry.id = pingEntry.id; playerEntry.spriteVisible = pingEntry.spriteVisible; playerEntry.spriteHidden = pingEntry.spriteHidden; DestroyImmediate(pingEntry); // Make buttons for mute, kick, tp Transform container = newPrefab.transform; playerEntry.ShowObject = newPrefab.FindChild("ButtonVisibility"); playerEntry.ShowObject.AddComponent(); playerEntry.MuteObject = Instantiate(playerEntry.ShowObject, container); playerEntry.KickObject = Instantiate(playerEntry.ShowObject, container); playerEntry.TeleportToObject = Instantiate(playerEntry.ShowObject, container); playerEntry.TeleportToMeObject = Instantiate(playerEntry.ShowObject, container); playerEntry.MuteObject.name = "MuteObject"; playerEntry.KickObject.name = "KickObject"; playerEntry.TeleportToObject.name = "TeleportToObject"; playerEntry.TeleportToMeObject.name = "TeleportToMeObject"; prefabEntry = newPrefab; } private void AddNewEntry(string playerId, INitroxPlayer player) { uGUI_PlayerPingEntry entry = GetEntry(); entry.Initialize(playerId, player.PlayerName, this); entry.UpdateEntryForNewPlayer(player, localPlayer, packetSender); entries.Add(playerId, entry); } private void OnAdd(ushort playerId, RemotePlayer remotePlayer) { _isDirty = true; } private void OnRemove(ushort playerId, RemotePlayer remotePlayers) { string playerIdString = playerId.ToString(); if (!entries.ContainsKey(playerIdString)) { return; } uGUI_PlayerPingEntry entry = entries[playerIdString]; entries.Remove(playerIdString); pool.Release(entry); _isDirty = true; } }