first commit
This commit is contained in:
17
NitroxClient/GameLogic/HUD/Components/ButtonTooltip.cs
Normal file
17
NitroxClient/GameLogic/HUD/Components/ButtonTooltip.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.GameLogic.HUD.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Shows the ToolipText when hovering the GameObject containg this component
|
||||
/// </summary>
|
||||
public class ButtonTooltip : MonoBehaviour, ITooltip
|
||||
{
|
||||
public string TooltipText { get; set; }
|
||||
public bool showTooltipOnDrag => false;
|
||||
|
||||
public void GetTooltip(TooltipData tooltip)
|
||||
{
|
||||
tooltip.prefix.Append(TooltipText);
|
||||
}
|
||||
}
|
39
NitroxClient/GameLogic/HUD/NitroxPDATab.cs
Normal file
39
NitroxClient/GameLogic/HUD/NitroxPDATab.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
namespace NitroxClient.GameLogic.HUD;
|
||||
|
||||
public abstract class NitroxPDATab
|
||||
{
|
||||
/// <summary>
|
||||
/// Text showing up when hovering the tab icon
|
||||
/// </summary>
|
||||
public abstract string ToolbarTip { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Asset name for the tab's icon sprite
|
||||
/// </summary>
|
||||
public abstract string TabIconAssetName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Base game tab from which we will take the icon as a placeholder
|
||||
/// </summary>
|
||||
public abstract PDATab FallbackTabIcon { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The uGUI_PDATab component that will be used in-game
|
||||
/// </summary>
|
||||
public abstract uGUI_PDATab uGUI_PDATab { get;}
|
||||
|
||||
/// <summary>
|
||||
/// Should be a new int value that isn't currently used by default game (>7) nor by another custom tab
|
||||
/// </summary>
|
||||
public abstract PDATab PDATabId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create uGUI_PDATab component thanks to the now existing uGUI_PDA component
|
||||
/// </summary>
|
||||
public abstract void OnInitializePDA(uGUI_PDA uGUI_PDA);
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not to render the pings images over the PDA when this PDA tab is open
|
||||
/// </summary>
|
||||
public abstract bool KeepPingsVisible { get; }
|
||||
}
|
43
NitroxClient/GameLogic/HUD/NitroxPDATabManager.cs
Normal file
43
NitroxClient/GameLogic/HUD/NitroxPDATabManager.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace NitroxClient.GameLogic.HUD;
|
||||
|
||||
public class NitroxPDATabManager
|
||||
{
|
||||
public readonly Dictionary<PDATab, NitroxPDATab> CustomTabs = new();
|
||||
|
||||
private readonly Dictionary<string, Atlas.Sprite> tabSpritesByName = new();
|
||||
private readonly Dictionary<string, TabSpriteLoadedEvent> spriteLoadedCallbackByName = new();
|
||||
|
||||
public NitroxPDATabManager()
|
||||
{
|
||||
void RegisterTab(NitroxPDATab nitroxTab)
|
||||
{
|
||||
CustomTabs.Add(nitroxTab.PDATabId, nitroxTab);
|
||||
}
|
||||
|
||||
RegisterTab(new PlayerListTab());
|
||||
}
|
||||
|
||||
public void AddTabSprite(string spriteName, Atlas.Sprite sprite)
|
||||
{
|
||||
tabSpritesByName.Add(spriteName, sprite);
|
||||
if (spriteLoadedCallbackByName.TryGetValue(spriteName, out TabSpriteLoadedEvent spriteLoadedEvent))
|
||||
{
|
||||
spriteLoadedEvent.Invoke(sprite);
|
||||
spriteLoadedCallbackByName.Remove(spriteName);
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryGetTabSprite(string spriteName, out Atlas.Sprite sprite) => tabSpritesByName.TryGetValue(spriteName, out sprite);
|
||||
|
||||
public delegate void TabSpriteLoadedEvent(Atlas.Sprite sprite);
|
||||
|
||||
public void SetSpriteLoadedCallback(string tabName, TabSpriteLoadedEvent callback)
|
||||
{
|
||||
if (!spriteLoadedCallbackByName.ContainsKey(tabName))
|
||||
{
|
||||
spriteLoadedCallbackByName.Add(tabName, callback);
|
||||
}
|
||||
}
|
||||
}
|
244
NitroxClient/GameLogic/HUD/PdaTabs/uGUI_PlayerListTab.cs
Normal file
244
NitroxClient/GameLogic/HUD/PdaTabs/uGUI_PlayerListTab.cs
Normal file
@@ -0,0 +1,244 @@
|
||||
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;
|
||||
}
|
||||
}
|
244
NitroxClient/GameLogic/HUD/PdaTabs/uGUI_PlayerPingEntry.cs
Normal file
244
NitroxClient/GameLogic/HUD/PdaTabs/uGUI_PlayerPingEntry.cs
Normal file
@@ -0,0 +1,244 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using NitroxClient.Communication.Abstract;
|
||||
using NitroxClient.Communication.Packets.Processors;
|
||||
using NitroxClient.GameLogic.HUD.Components;
|
||||
using NitroxClient.GameLogic.PlayerLogic.PlayerModel.Abstract;
|
||||
using NitroxClient.MonoBehaviours.Gui.Modals;
|
||||
using NitroxModel_Subnautica.DataStructures;
|
||||
using NitroxModel.Core;
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxModel.Packets;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UWE;
|
||||
|
||||
namespace NitroxClient.GameLogic.HUD.PdaTabs;
|
||||
|
||||
public class uGUI_PlayerPingEntry : uGUI_PingEntry
|
||||
{
|
||||
private uGUI_PlayerListTab parent;
|
||||
private INitroxPlayer player;
|
||||
|
||||
public string PlayerName => player?.PlayerName ?? string.Empty;
|
||||
public bool IsLocalPlayer => player is LocalPlayer;
|
||||
private bool showPing;
|
||||
|
||||
private bool muted
|
||||
{
|
||||
get
|
||||
{
|
||||
if (player is RemotePlayer remotePlayer && remotePlayer.PlayerContext != null)
|
||||
{
|
||||
return remotePlayer.PlayerContext.IsMuted;
|
||||
}
|
||||
// By default we don't care about the local state
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public GameObject ShowObject;
|
||||
public GameObject MuteObject;
|
||||
public GameObject KickObject;
|
||||
public GameObject TeleportToObject;
|
||||
public GameObject TeleportToMeObject;
|
||||
|
||||
public Sprite MutedSprite;
|
||||
public Sprite UnmutedSprite;
|
||||
public Sprite KickSprite;
|
||||
public Sprite TeleportToSprite;
|
||||
public Sprite TeleportToMeSprite;
|
||||
|
||||
public new void Awake()
|
||||
{
|
||||
NitroxServiceLocator.LocateService<MutePlayerProcessor>().OnPlayerMuted += (playerId, _) =>
|
||||
{
|
||||
if (player is RemotePlayer remotePlayer && remotePlayer.PlayerId == playerId)
|
||||
{
|
||||
RefreshMuteButton();
|
||||
}
|
||||
};
|
||||
NitroxServiceLocator.LocateService<PermsChangedProcessor>().OnPermissionsChanged += (perms) => RefreshButtonsVisibility();
|
||||
}
|
||||
|
||||
public IEnumerator Start()
|
||||
{
|
||||
// We must one frame so that the UI elements are initialized properly
|
||||
yield return null;
|
||||
// This action must happen after the yield so that they're correctly placed
|
||||
UpdateButtonsPosition();
|
||||
// We trigger it at least once so that the localizations are updated with the PlayerName
|
||||
OnLanguageChanged();
|
||||
}
|
||||
|
||||
public void Initialize(string id, string name, uGUI_PlayerListTab parent)
|
||||
{
|
||||
this.id = id;
|
||||
this.parent = parent;
|
||||
|
||||
gameObject.SetActive(true);
|
||||
visibilityIcon.sprite = spriteVisible;
|
||||
icon.SetForegroundSprite(SpriteManager.Get(SpriteManager.Group.Tab, "TabInventory"));
|
||||
showPing = true;
|
||||
|
||||
UpdateLabel(name);
|
||||
OnLanguageChanged();
|
||||
|
||||
CoroutineHost.StartCoroutine(AssignSprites());
|
||||
}
|
||||
|
||||
public void OnLanguageChanged()
|
||||
{
|
||||
GetTooltip(ShowObject).TooltipText = GetLocalizedText(showPing ? "Nitrox_HidePing" : "Nitrox_ShowPing");
|
||||
GetTooltip(MuteObject).TooltipText = GetLocalizedText(muted ? "Nitrox_Unmute" : "Nitrox_Mute");
|
||||
GetTooltip(KickObject).TooltipText = GetLocalizedText("Nitrox_Kick");
|
||||
GetTooltip(TeleportToObject).TooltipText = GetLocalizedText("Nitrox_TeleportTo");
|
||||
GetTooltip(TeleportToMeObject).TooltipText = GetLocalizedText("Nitrox_TeleportToMe");
|
||||
}
|
||||
|
||||
public new void Uninitialize()
|
||||
{
|
||||
base.Uninitialize();
|
||||
player = null;
|
||||
}
|
||||
|
||||
public void UpdateLabel(string text)
|
||||
{
|
||||
label.text = text;
|
||||
}
|
||||
|
||||
public void UpdateEntryForNewPlayer(INitroxPlayer newPlayer, LocalPlayer localPlayer, IPacketSender packetSender)
|
||||
{
|
||||
player = newPlayer;
|
||||
|
||||
UpdateLabel(player.PlayerName);
|
||||
Color playerColor = player.PlayerSettings.PlayerColor.ToUnity();
|
||||
icon.SetColors(playerColor, playerColor, playerColor);
|
||||
RefreshMuteButton();
|
||||
|
||||
// We need to update each button's listener whether or not they have enough perms because they may become OP during playtime
|
||||
ClearButtonListeners();
|
||||
|
||||
GetToggle(ShowObject).onValueChanged.AddListener(delegate (bool toggled)
|
||||
{
|
||||
if (player is RemotePlayer remotePlayer)
|
||||
{
|
||||
PingInstance pingInstance = remotePlayer.PlayerModel.GetComponentInChildren<PingInstance>();
|
||||
pingInstance.SetVisible(toggled);
|
||||
GetTooltip(ShowObject).TooltipText = GetLocalizedText(toggled ? "Nitrox_HidePing" : "Nitrox_ShowPing");
|
||||
visibilityIcon.sprite = toggled ? spriteVisible : spriteHidden;
|
||||
}
|
||||
});
|
||||
// Each of those clicks involves a confirmation modal
|
||||
GetToggle(MuteObject).onValueChanged.AddListener(delegate (bool toggled)
|
||||
{
|
||||
Modal.Get<ConfirmModal>()?.Show(GetLocalizedText(muted ? "Nitrox_Unmute" : "Nitrox_Mute", true), () =>
|
||||
{
|
||||
GetToggle(MuteObject).SetIsOnWithoutNotify(!toggled);
|
||||
if (player is RemotePlayer remotePlayer)
|
||||
{
|
||||
packetSender.Send(new ServerCommand($"{(toggled ? "" : "un")}mute {player.PlayerName}"));
|
||||
}
|
||||
});
|
||||
});
|
||||
GetToggle(KickObject).onValueChanged.AddListener(delegate (bool toggled)
|
||||
{
|
||||
Modal.Get<ConfirmModal>()?.Show(GetLocalizedText("Nitrox_Kick", true), () =>
|
||||
{
|
||||
packetSender.Send(new ServerCommand($"kick {player.PlayerName}"));
|
||||
});
|
||||
});
|
||||
GetToggle(TeleportToObject).onValueChanged.AddListener(delegate (bool toggled)
|
||||
{
|
||||
Modal.Get<ConfirmModal>()?.Show(GetLocalizedText("Nitrox_TeleportTo", true), () =>
|
||||
{
|
||||
packetSender.Send(new ServerCommand($"warp {player.PlayerName}"));
|
||||
});
|
||||
});
|
||||
GetToggle(TeleportToMeObject).onValueChanged.AddListener(delegate (bool toggled)
|
||||
{
|
||||
Modal.Get<ConfirmModal>()?.Show(GetLocalizedText("Nitrox_TeleportToMe", true), () =>
|
||||
{
|
||||
packetSender.Send(new ServerCommand($"warp {player.PlayerName} {localPlayer.PlayerName}"));
|
||||
});
|
||||
});
|
||||
|
||||
RefreshButtonsVisibility();
|
||||
}
|
||||
|
||||
private string GetLocalizedText(string key, bool isQuestion = false)
|
||||
{
|
||||
return Language.main.Get(isQuestion ? $"{key}Question" : key).Replace("{PLAYER}", PlayerName);
|
||||
}
|
||||
|
||||
public void UpdateButtonsPosition()
|
||||
{
|
||||
float OFFSET = 0f;
|
||||
List<GameObject> buttonsToAlign = new() { MuteObject, KickObject, TeleportToObject, TeleportToMeObject };
|
||||
foreach (GameObject buttonObject in buttonsToAlign)
|
||||
{
|
||||
RectTransform buttonRect = buttonObject.GetComponent<RectTransform>();
|
||||
buttonRect.anchoredPosition = new Vector2(rectTransform.anchoredPosition.x, 0f);
|
||||
buttonRect.localPosition = new Vector2(OFFSET, 0);
|
||||
OFFSET += 80f;
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearButtonListeners()
|
||||
{
|
||||
GetToggle(MuteObject).onValueChanged = new Toggle.ToggleEvent();
|
||||
GetToggle(KickObject).onValueChanged = new Toggle.ToggleEvent();
|
||||
GetToggle(TeleportToObject).onValueChanged = new Toggle.ToggleEvent();
|
||||
GetToggle(TeleportToMeObject).onValueChanged = new Toggle.ToggleEvent();
|
||||
}
|
||||
|
||||
private IEnumerator AssignSprites()
|
||||
{
|
||||
yield return new WaitUntil(() => parent.FinishedLoadingAssets);
|
||||
|
||||
// NB: Those textures MUST be exported with a Texture Type of "Sprite (2D and UI)", else they will look blurry not matter what
|
||||
// NB 2: Those textures for the buttons are scaled 68x61 but the image inside but not hit the borders to have a better render
|
||||
MutedSprite = parent.GetSprite("muted@3x");
|
||||
UnmutedSprite = parent.GetSprite("unmuted@3x");
|
||||
KickSprite = parent.GetSprite("kick@3x");
|
||||
TeleportToSprite = parent.GetSprite("teleport_to@3x");
|
||||
TeleportToMeSprite = parent.GetSprite("teleport_to_me@3x");
|
||||
|
||||
MuteObject.FindChild("Eye").GetComponent<Image>().sprite = muted ? MutedSprite : UnmutedSprite;
|
||||
KickObject.FindChild("Eye").GetComponent<Image>().sprite = KickSprite;
|
||||
TeleportToObject.FindChild("Eye").GetComponent<Image>().sprite = TeleportToSprite;
|
||||
TeleportToMeObject.FindChild("Eye").GetComponent<Image>().sprite = TeleportToMeSprite;
|
||||
}
|
||||
|
||||
private void RefreshMuteButton()
|
||||
{
|
||||
GetToggle(MuteObject).SetIsOnWithoutNotify(muted);
|
||||
GetTooltip(MuteObject).TooltipText = GetLocalizedText(muted ? "Nitrox_Unmute" : "Nitrox_Mute");
|
||||
MuteObject.FindChild("Eye").GetComponent<Image>().sprite = muted ? MutedSprite : UnmutedSprite;
|
||||
}
|
||||
|
||||
private void RefreshButtonsVisibility()
|
||||
{
|
||||
LocalPlayer localPlayer = NitroxServiceLocator.LocateService<LocalPlayer>();
|
||||
|
||||
bool isNotLocalPlayer = !IsLocalPlayer;
|
||||
// We don't want any control buttons to appear for the local player
|
||||
ShowObject.SetActive(isNotLocalPlayer);
|
||||
|
||||
// The perms here should be the same as the perm each command asks for
|
||||
MuteObject.SetActive(isNotLocalPlayer && localPlayer.Permissions >= Perms.MODERATOR);
|
||||
KickObject.SetActive(isNotLocalPlayer && localPlayer.Permissions >= Perms.MODERATOR);
|
||||
TeleportToObject.SetActive(isNotLocalPlayer && localPlayer.Permissions >= Perms.MODERATOR);
|
||||
TeleportToMeObject.SetActive(isNotLocalPlayer && localPlayer.Permissions >= Perms.MODERATOR);
|
||||
}
|
||||
|
||||
private Toggle GetToggle(GameObject gameObject)
|
||||
{
|
||||
return gameObject.GetComponent<Toggle>();
|
||||
}
|
||||
|
||||
private ButtonTooltip GetTooltip(GameObject gameObject)
|
||||
{
|
||||
return gameObject.GetComponent<ButtonTooltip>();
|
||||
}
|
||||
}
|
42
NitroxClient/GameLogic/HUD/PlayerListTab.cs
Normal file
42
NitroxClient/GameLogic/HUD/PlayerListTab.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using NitroxClient.GameLogic.HUD.PdaTabs;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.GameLogic.HUD;
|
||||
|
||||
public class PlayerListTab : NitroxPDATab
|
||||
{
|
||||
private uGUI_PDATab tab;
|
||||
|
||||
public override string ToolbarTip => "Nitrox_PlayerListTabName";
|
||||
|
||||
public override string TabIconAssetName => "player_list_tab@3x";
|
||||
|
||||
public override PDATab FallbackTabIcon => PDATab.Inventory;
|
||||
|
||||
public override uGUI_PDATab uGUI_PDATab => tab;
|
||||
|
||||
public override PDATab PDATabId => (PDATab)8;
|
||||
|
||||
public override void OnInitializePDA(uGUI_PDA uGUI_PDA)
|
||||
{
|
||||
// We need to copy the ping manager tab which is the closest to what we want
|
||||
GameObject pdaScreen = uGUI_PDA.gameObject;
|
||||
uGUI_PingTab pingTab = pdaScreen.GetComponentInChildren<uGUI_PingTab>();
|
||||
GameObject pingTabObject = pingTab.gameObject;
|
||||
|
||||
GameObject tabCopy = GameObject.Instantiate(pingTabObject, pdaScreen.transform.Find("Content"));
|
||||
tabCopy.name = "PlayerListTab";
|
||||
|
||||
// Set the tab inactive to suppress the uGUI_PlayerListTab awake(). We first need to set the
|
||||
// prefab, which is used inside the awake method and the base class awake method.
|
||||
tabCopy.SetActive(false);
|
||||
uGUI_PlayerListTab newTab = tabCopy.AddComponent<uGUI_PlayerListTab>();
|
||||
newTab.MakePrefab(pingTab.prefabEntry);
|
||||
GameObject.DestroyImmediate(tabCopy.GetComponent<uGUI_PingTab>());
|
||||
tabCopy.SetActive(true);
|
||||
|
||||
tab = newTab;
|
||||
}
|
||||
|
||||
public override bool KeepPingsVisible => true;
|
||||
}
|
33
NitroxClient/GameLogic/HUD/PlayerVitalsManager.cs
Normal file
33
NitroxClient/GameLogic/HUD/PlayerVitalsManager.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System.Collections.Generic;
|
||||
using NitroxClient.MonoBehaviours.Gui.HUD;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.GameLogic.HUD;
|
||||
|
||||
public class PlayerVitalsManager
|
||||
{
|
||||
private readonly Dictionary<ushort, RemotePlayerVitals> vitalsByPlayerId = new();
|
||||
|
||||
public RemotePlayerVitals CreateOrFindForPlayer(RemotePlayer remotePlayer)
|
||||
{
|
||||
if (!vitalsByPlayerId.TryGetValue(remotePlayer.PlayerId, out RemotePlayerVitals vitals))
|
||||
{
|
||||
vitalsByPlayerId[remotePlayer.PlayerId] = vitals = RemotePlayerVitals.CreateForPlayer(remotePlayer);
|
||||
}
|
||||
return vitals;
|
||||
}
|
||||
|
||||
public void RemoveForPlayer(ushort playerId)
|
||||
{
|
||||
if (vitalsByPlayerId.TryGetValue(playerId, out RemotePlayerVitals vitals))
|
||||
{
|
||||
vitalsByPlayerId.Remove(playerId);
|
||||
Object.Destroy(vitals.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryFindForPlayer(ushort playerId, out RemotePlayerVitals vitals)
|
||||
{
|
||||
return vitalsByPlayerId.TryGetValue(playerId, out vitals);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user