Files
Nitrox/NitroxClient/GameLogic/HUD/PdaTabs/uGUI_PlayerListTab.cs
2025-07-06 00:23:46 +02:00

245 lines
8.6 KiB
C#

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;
/// <summary>
/// The component containing a new PDA tab based on ping manager tab
/// </summary>
public class uGUI_PlayerListTab : uGUI_PingTab
{
private NitroxPDATabManager nitroxPDATabManager;
private PlayerManager playerManager;
private LocalPlayer localPlayer;
private IPacketSender packetSender;
private readonly Dictionary<string, Sprite> assets = new();
public bool FinishedLoadingAssets { get; private set; }
private new readonly Dictionary<string, uGUI_PlayerPingEntry> entries = new();
private PrefabPool<uGUI_PlayerPingEntry> pool;
private new readonly Dictionary<string, uGUI_PlayerPingEntry> 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<NitroxPDATabManager>();
playerManager = NitroxServiceLocator.LocateService<PlayerManager>();
localPlayer = NitroxServiceLocator.LocateService<LocalPlayer>();
packetSender = NitroxServiceLocator.LocateService<IPacketSender>();
// Need to reassign manually these variables and get rid of the objects we don't need
content = gameObject.FindChild("Content").GetComponent<CanvasGroup>();
pingManagerLabel = gameObject.GetComponentInChildren<TextMeshProUGUI>();
scrollRect = gameObject.GetComponentInChildren<ScrollRect>();
pingCanvas = (RectTransform)content.transform.Find("ScrollView/Viewport/ScrollCanvas");
pool = new PrefabPool<uGUI_PlayerPingEntry>(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<string, INitroxPlayer> players = playerManager.GetAll().ToDictionary<RemotePlayer, string, INitroxPlayer>(player => player.PlayerId.ToString(), player => player);
players.Add(localPlayer.PlayerId.ToString(), localPlayer);
foreach (KeyValuePair<string, INitroxPlayer> 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<string, uGUI_PlayerPingEntry> entry in entries)
{
if (!entry.Value.IsLocalPlayer)
{
tempSort.Add(entry.Value.PlayerName, entry.Value);
}
}
List<string> 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_PlayerPingEntry>();
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_PingEntry>();
uGUI_PlayerPingEntry playerEntry = newPrefab.AddComponent<uGUI_PlayerPingEntry>();
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<ButtonTooltip>();
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;
}
}