various thingies
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
using PlayerRoles;
|
||||
using LabApi.Features;
|
||||
using LabApi.Features.Wrappers;
|
||||
|
||||
namespace VisibleSpectators;
|
||||
|
||||
/// <summary>
|
||||
/// Utility for formatting player display names and color mapping.
|
||||
/// </summary>
|
||||
public static class PlayerDisplayUtil
|
||||
{
|
||||
private static readonly Dictionary<string, string> ColorMap = new()
|
||||
{
|
||||
{ "DEFAULT", "FFFFFF" },
|
||||
{ "PUMPKIN", "EE7600" },
|
||||
{ "ARMY_GREEN", "4B5320" },
|
||||
{ "MINT", "98FB98" },
|
||||
{ "NICKEL", "727472" },
|
||||
{ "CARMINE", "960018" },
|
||||
{ "EMERALD", "50C878" },
|
||||
{ "GREEN", "228B22" },
|
||||
{ "LIME", "BFFF00" },
|
||||
{ "POLICE_BLUE", "002DB3" },
|
||||
{ "ORANGE", "FF9966" },
|
||||
{ "SILVER_BLUE", "666699" },
|
||||
{ "BLUE_GREEN", "4DFFB8" },
|
||||
{ "MAGENTA", "FF0090" },
|
||||
{ "YELLOW", "FAFF86" },
|
||||
{ "TOMATO", "FF6448" },
|
||||
{ "DEEP_PINK", "FF1493" },
|
||||
{ "AQUA", "00FFFF" },
|
||||
{ "CYAN", "00B7EB" },
|
||||
{ "CRIMSON", "DC143C" },
|
||||
{ "LIGHT_GREEN", "32CD32" },
|
||||
{ "SILVER", "A0A0A0" },
|
||||
{ "BROWN", "944710" },
|
||||
{ "RED", "C50000" },
|
||||
{ "PINK", "FF96DE" },
|
||||
{ "LIGHT_RED", "FD8272" },
|
||||
{ "PURPLE", "8137CE" },
|
||||
{ "BLUE", "005EBC" },
|
||||
{ "TEAL", "008080" },
|
||||
{ "GOLD", "EFC01A" }
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Returns a formatted display string for a player, with color.
|
||||
/// </summary>
|
||||
public static string PlayerToDisplay(Player player)
|
||||
{
|
||||
if (player is not { IsReady: true }) return string.Empty;
|
||||
const string defaultColor = "FFFFFF";
|
||||
try
|
||||
{
|
||||
var groupColor = player.GroupColor;
|
||||
if (string.IsNullOrEmpty(groupColor))
|
||||
return $"<color=#{defaultColor}FF>{player.DisplayName}</color>";
|
||||
return ColorMap.TryGetValue(groupColor.ToUpper(), out var color)
|
||||
? $"<color=#{color}FF>{player.DisplayName}</color>"
|
||||
: $"<color=#{defaultColor}FF>{player.DisplayName}</color>";
|
||||
}
|
||||
catch
|
||||
{
|
||||
return $"<color=#{defaultColor}FF>{player.DisplayName}</color>";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the player is not Overwatch.
|
||||
/// </summary>
|
||||
public static bool IsNotOverwatch(Player player)
|
||||
{
|
||||
return player != null && player.Role != RoleTypeId.Overwatch;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using LabApi.Loader.Features.Plugins;
|
||||
using LabApi.Features;
|
||||
using LabApi.Events.Handlers;
|
||||
using LabApi.Events.Arguments.PlayerEvents;
|
||||
using LabApi.Features.Console;
|
||||
using MEC;
|
||||
|
||||
namespace VisibleSpectators;
|
||||
|
||||
/// <summary>
|
||||
/// Main entry point for the VisibleSpectators plugin.
|
||||
/// </summary>
|
||||
public class Plugin : Plugin<SpectatorConfig>
|
||||
{
|
||||
private SpectatorManager _spectatorManager;
|
||||
public override string Name => "VisibleSpectators";
|
||||
public override string Author => "Code002Lover";
|
||||
public override Version Version { get; } = new(1, 0, 0);
|
||||
public override string Description => "See your spectators";
|
||||
public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion);
|
||||
|
||||
public override void Enable()
|
||||
{
|
||||
Logger.Debug("starting...");
|
||||
_spectatorManager = new SpectatorManager(Config);
|
||||
PlayerEvents.ChangedSpectator += _spectatorManager.OnSpectate;
|
||||
PlayerEvents.Joined += _spectatorManager.OnJoin;
|
||||
Timing.RunCoroutine(_spectatorManager.KeepUpdatingSpectators());
|
||||
}
|
||||
|
||||
public override void Disable()
|
||||
{
|
||||
Logger.Debug("unloading...");
|
||||
PlayerEvents.Joined -= _spectatorManager.OnJoin;
|
||||
PlayerEvents.ChangedSpectator -= _spectatorManager.OnSpectate;
|
||||
_spectatorManager = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace VisibleSpectators;
|
||||
|
||||
/// <summary>
|
||||
/// Configuration for the VisibleSpectators plugin.
|
||||
/// </summary>
|
||||
public class SpectatorConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// Header message shown above the spectator list.
|
||||
/// </summary>
|
||||
public string HeaderMessage { get; set; } = "Spectators:";
|
||||
/// <summary>
|
||||
/// Message shown when there are no spectators.
|
||||
/// </summary>
|
||||
public string NoSpectatorsMessage { get; set; } = "No spectators";
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
using HintServiceMeow.Core.Enum;
|
||||
using HintServiceMeow.Core.Models.Hints;
|
||||
using HintServiceMeow.Core.Utilities;
|
||||
using LabApi.Events.Arguments.PlayerEvents;
|
||||
using LabApi.Features;
|
||||
using LabApi.Features.Console;
|
||||
using LabApi.Features.Wrappers;
|
||||
using MEC;
|
||||
using PlayerRoles;
|
||||
|
||||
namespace VisibleSpectators;
|
||||
|
||||
/// <summary>
|
||||
/// Handles spectator hint management and updates for players.
|
||||
/// </summary>
|
||||
public class SpectatorManager
|
||||
{
|
||||
private readonly SpectatorConfig _config;
|
||||
private readonly Dictionary<Player, Hint> _spectatorHints = new();
|
||||
public int YCoordinate { get; set; } = 100;
|
||||
|
||||
public SpectatorManager(SpectatorConfig config)
|
||||
{
|
||||
_config = config;
|
||||
}
|
||||
|
||||
public IEnumerator<float> KeepUpdatingSpectators()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
UpdateSpectators();
|
||||
yield return Timing.WaitForSeconds(1);
|
||||
}
|
||||
// ReSharper disable once IteratorNeverReturns
|
||||
}
|
||||
|
||||
public void OnSpectate(PlayerChangedSpectatorEventArgs ev)
|
||||
{
|
||||
UpdateSpectators(ev.OldTarget);
|
||||
UpdateSpectators(ev.NewTarget);
|
||||
UpdateSpectators(ev.Player);
|
||||
}
|
||||
|
||||
public void OnJoin(PlayerJoinedEventArgs ev)
|
||||
{
|
||||
AddPlayerHint(ev.Player);
|
||||
}
|
||||
|
||||
private void UpdateSpectators()
|
||||
{
|
||||
foreach (var player in GetPlayers())
|
||||
UpdateSpectators(player);
|
||||
}
|
||||
|
||||
private void AddPlayerHint(Player player)
|
||||
{
|
||||
var hint = new Hint
|
||||
{
|
||||
Text = $"{_config.HeaderMessage}\n{_config.NoSpectatorsMessage}",
|
||||
Alignment = HintAlignment.Right,
|
||||
YCoordinate = YCoordinate,
|
||||
Hide = true
|
||||
};
|
||||
var playerDisplay = PlayerDisplay.Get(player);
|
||||
playerDisplay.AddHint(hint);
|
||||
_spectatorHints[player] = hint;
|
||||
}
|
||||
|
||||
private void UpdateSpectators(Player player)
|
||||
{
|
||||
if (player == null) return;
|
||||
if (!_spectatorHints.ContainsKey(player)) AddPlayerHint(player);
|
||||
var spectators = _config.NoSpectatorsMessage;
|
||||
try
|
||||
{
|
||||
spectators = string.Join("\n", player.CurrentSpectators.Where(PlayerDisplayUtil.IsNotOverwatch).Select(PlayerDisplayUtil.PlayerToDisplay));
|
||||
if (player.Role == RoleTypeId.Spectator)
|
||||
spectators = player.CurrentlySpectating == null
|
||||
? _config.NoSpectatorsMessage
|
||||
: string.Join("\n",
|
||||
player.CurrentlySpectating?.CurrentSpectators.Where(PlayerDisplayUtil.IsNotOverwatch)
|
||||
.Select(PlayerDisplayUtil.PlayerToDisplay) ?? Array.Empty<string>());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error(e);
|
||||
}
|
||||
if (spectators.Length < 2) spectators = _config.NoSpectatorsMessage;
|
||||
_spectatorHints[player].Text = $"{_config.HeaderMessage}\n{spectators}";
|
||||
_spectatorHints[player].Hide = player.Role is RoleTypeId.Destroyed or RoleTypeId.None;
|
||||
_spectatorHints[player].YCoordinate = YCoordinate + player.CurrentSpectators.Count * 10;
|
||||
}
|
||||
|
||||
private static Player[] GetPlayers()
|
||||
{
|
||||
return Player.ReadyList.Where(PlayerDisplayUtil.IsNotOverwatch).Where(x => x != null).ToArray();
|
||||
}
|
||||
}
|
||||
@@ -1,194 +0,0 @@
|
||||
using HintServiceMeow.Core.Enum;
|
||||
using HintServiceMeow.Core.Models.Hints;
|
||||
using HintServiceMeow.Core.Utilities;
|
||||
using LabApi.Events.Arguments.PlayerEvents;
|
||||
using LabApi.Events.Handlers;
|
||||
using LabApi.Features;
|
||||
using LabApi.Features.Console;
|
||||
using LabApi.Features.Wrappers;
|
||||
using LabApi.Loader.Features.Plugins;
|
||||
using PlayerRoles;
|
||||
using Timer = System.Timers.Timer;
|
||||
|
||||
namespace VisibleSpectators;
|
||||
|
||||
public class Plugin : Plugin<SpectatorConfig>
|
||||
{
|
||||
private static Plugin _singleton;
|
||||
|
||||
private static readonly Dictionary<string, string> GetColorMap = new()
|
||||
{
|
||||
{ "DEFAULT", "FFFFFF" },
|
||||
{ "PUMPKIN", "EE7600" },
|
||||
{ "ARMY_GREEN", "4B5320" },
|
||||
{ "MINT", "98FB98" },
|
||||
{ "NICKEL", "727472" },
|
||||
{ "CARMINE", "960018" },
|
||||
{ "EMERALD", "50C878" },
|
||||
{ "GREEN", "228B22" },
|
||||
{ "LIME", "BFFF00" },
|
||||
{ "POLICE_BLUE", "002DB3" },
|
||||
{ "ORANGE", "FF9966" },
|
||||
{ "SILVER_BLUE", "666699" },
|
||||
{ "BLUE_GREEN", "4DFFB8" },
|
||||
{ "MAGENTA", "FF0090" },
|
||||
{ "YELLOW", "FAFF86" },
|
||||
{ "TOMATO", "FF6448" },
|
||||
{ "DEEP_PINK", "FF1493" },
|
||||
{ "AQUA", "00FFFF" },
|
||||
{ "CYAN", "00B7EB" },
|
||||
{ "CRIMSON", "DC143C" },
|
||||
{ "LIGHT_GREEN", "32CD32" },
|
||||
{ "SILVER", "A0A0A0" },
|
||||
{ "BROWN", "944710" },
|
||||
{ "RED", "C50000" },
|
||||
{ "PINK", "FF96DE" },
|
||||
{ "LIGHT_RED", "FD8272" },
|
||||
{ "PURPLE", "8137CE" },
|
||||
{ "BLUE", "005EBC" },
|
||||
{ "TEAL", "008080" },
|
||||
{ "GOLD", "EFC01A" }
|
||||
};
|
||||
|
||||
private readonly Dictionary<Player, Hint> _spectatorHints = new();
|
||||
private Timer _timer;
|
||||
public override string Name => "VisibleSpectators";
|
||||
public override string Author => "Code002Lover";
|
||||
public override Version Version { get; } = new(1, 0, 0);
|
||||
public override string Description => "See your spectators";
|
||||
public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion);
|
||||
|
||||
public int YCoordinate { get; set; } = 100;
|
||||
|
||||
public override void Enable()
|
||||
{
|
||||
Logger.Debug("starting...");
|
||||
_singleton = this;
|
||||
|
||||
PlayerEvents.ChangedSpectator += OnSpectate;
|
||||
PlayerEvents.Joined += OnJoin;
|
||||
|
||||
_timer = new Timer(1000);
|
||||
_timer.Elapsed += (_, _) => UpdateSpectators();
|
||||
_timer.Start();
|
||||
}
|
||||
|
||||
public override void Disable()
|
||||
{
|
||||
Logger.Debug("unloading...");
|
||||
|
||||
_timer.Stop();
|
||||
_timer.Dispose();
|
||||
_timer = null;
|
||||
|
||||
PlayerEvents.Joined -= OnJoin;
|
||||
PlayerEvents.ChangedSpectator -= OnSpectate;
|
||||
|
||||
_singleton = null;
|
||||
}
|
||||
|
||||
private void UpdateSpectators()
|
||||
{
|
||||
foreach (var player in GetPlayers()) UpdateSpectators(player);
|
||||
}
|
||||
|
||||
private void AddPlayerHint(Player player)
|
||||
{
|
||||
var hint = new Hint
|
||||
{
|
||||
Text = $"{Config!.HeaderMessage}\n{Config!.NoSpectatorsMessage}",
|
||||
Alignment = HintAlignment.Right,
|
||||
YCoordinate = YCoordinate,
|
||||
Hide = true
|
||||
};
|
||||
|
||||
var playerDisplay = PlayerDisplay.Get(player);
|
||||
playerDisplay.AddHint(hint);
|
||||
|
||||
_spectatorHints[player] = hint;
|
||||
}
|
||||
|
||||
private static string PlayerToDisplay(Player player)
|
||||
{
|
||||
if (player == null) return "";
|
||||
if (!player.IsReady) return "";
|
||||
|
||||
// Default color if GroupColor is null or not found in the map
|
||||
const string defaultColor = "FFFFFF";
|
||||
|
||||
try
|
||||
{
|
||||
var groupColor = player.GroupColor;
|
||||
if (string.IsNullOrEmpty(groupColor))
|
||||
return $"<color=#{defaultColor}FF>{player.DisplayName}</color>";
|
||||
|
||||
return GetColorMap.TryGetValue(groupColor.ToUpper(), out var color)
|
||||
? $"<color=#{color}FF>{player.DisplayName}</color>"
|
||||
: $"<color=#{defaultColor}FF>{player.DisplayName}</color>";
|
||||
}
|
||||
catch
|
||||
{
|
||||
return $"<color=#{defaultColor}FF>{player.DisplayName}</color>";
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsNotOverwatch(Player player)
|
||||
{
|
||||
return player != null && player.Role != RoleTypeId.Overwatch;
|
||||
}
|
||||
|
||||
private void UpdateSpectators(Player player)
|
||||
{
|
||||
// Safety check - if player doesn't have a hint, create one
|
||||
if (!_spectatorHints.ContainsKey(player)) AddPlayerHint(player);
|
||||
|
||||
var spectators = Config!.NoSpectatorsMessage;
|
||||
|
||||
try
|
||||
{
|
||||
spectators = string.Join("\n", player.CurrentSpectators.Where(IsNotOverwatch).Select(PlayerToDisplay));
|
||||
if (player.Role == RoleTypeId.Spectator)
|
||||
spectators = player.CurrentlySpectating == null
|
||||
? Config!.NoSpectatorsMessage
|
||||
: string.Join("\n",
|
||||
player.CurrentlySpectating?.CurrentSpectators.Where(IsNotOverwatch)
|
||||
.Select(PlayerToDisplay) ?? Array.Empty<string>());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error(e);
|
||||
}
|
||||
|
||||
if (spectators.Length < 2) spectators = Config!.NoSpectatorsMessage;
|
||||
|
||||
|
||||
_spectatorHints[player].Text = $"{Config!.HeaderMessage}\n{spectators}";
|
||||
|
||||
_spectatorHints[player].Hide = player.Role is RoleTypeId.Destroyed or RoleTypeId.None;
|
||||
|
||||
_spectatorHints[player].YCoordinate = YCoordinate + player.CurrentSpectators.Count * 10;
|
||||
}
|
||||
|
||||
private static Player[] GetPlayers()
|
||||
{
|
||||
return Player.ReadyList.Where(IsNotOverwatch).ToArray();
|
||||
}
|
||||
|
||||
private static void OnSpectate(PlayerChangedSpectatorEventArgs ev)
|
||||
{
|
||||
_singleton.UpdateSpectators(ev.OldTarget);
|
||||
_singleton.UpdateSpectators(ev.NewTarget);
|
||||
_singleton.UpdateSpectators(ev.Player);
|
||||
}
|
||||
|
||||
private void OnJoin(PlayerJoinedEventArgs ev)
|
||||
{
|
||||
AddPlayerHint(ev.Player);
|
||||
}
|
||||
}
|
||||
|
||||
public class SpectatorConfig
|
||||
{
|
||||
public string HeaderMessage { get; set; } = "Spectators:";
|
||||
public string NoSpectatorsMessage { get; set; } = "No spectators";
|
||||
}
|
||||
Reference in New Issue
Block a user