diff --git a/EvoSC.sln b/EvoSC.sln index 2ec61fa13..767003d64 100644 --- a/EvoSC.sln +++ b/EvoSC.sln @@ -84,7 +84,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MatchTrackerModule", "src\M EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MatchReadyModule", "src\Modules\MatchReadyModule\MatchReadyModule.csproj", "{0538B9AB-B556-45BF-8230-53087BA9D353}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Scoreboard", "src\Modules\Scoreboard\Scoreboard.csproj", "{CD032D37-3BC8-4DE8-8C5B-45A0DE36932E}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScoreboardModule", "src\Modules\ScoreboardModule\ScoreboardModule.csproj", "{CD032D37-3BC8-4DE8-8C5B-45A0DE36932E}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NextMapModule", "src\Modules\NextMapModule\NextMapModule.csproj", "{64688FA7-136C-4BB9-B716-4E96DD0AA82F}" EndProject diff --git a/src/EvoSC/EvoSC.csproj b/src/EvoSC/EvoSC.csproj index 844ecefc8..86b39b074 100644 --- a/src/EvoSC/EvoSC.csproj +++ b/src/EvoSC/EvoSC.csproj @@ -34,7 +34,7 @@ - + diff --git a/src/EvoSC/InternalModules.cs b/src/EvoSC/InternalModules.cs index a7fa2c43b..5b5c3b2f7 100644 --- a/src/EvoSC/InternalModules.cs +++ b/src/EvoSC/InternalModules.cs @@ -20,7 +20,7 @@ using EvoSC.Modules.Official.OpenPlanetModule; using EvoSC.Modules.Official.Player; using EvoSC.Modules.Official.PlayerRecords; -using EvoSC.Modules.Official.Scoreboard; +using EvoSC.Modules.Official.ScoreboardModule; using EvoSC.Modules.Official.ServerManagementModule; using EvoSC.Modules.Official.SetName; using EvoSC.Modules.Official.SpectatorCamModeModule; diff --git a/src/Modules/Scoreboard/Controllers/ScoreboardCommandsController.cs b/src/Modules/Scoreboard/Controllers/ScoreboardCommandsController.cs deleted file mode 100644 index e36e18395..000000000 --- a/src/Modules/Scoreboard/Controllers/ScoreboardCommandsController.cs +++ /dev/null @@ -1,17 +0,0 @@ -using EvoSC.Commands.Attributes; -using EvoSC.Commands.Interfaces; -using EvoSC.Common.Controllers; -using EvoSC.Common.Controllers.Attributes; -using EvoSC.Modules.Official.Scoreboard.Interfaces; - -namespace EvoSC.Modules.Official.Scoreboard.Controllers; - -[Controller] -public class ScoreboardCommandsController(IScoreboardService scoreboardService) : EvoScController -{ - [ChatCommand("scoreboard", "[Command.ShowScoreboard]")] - public async Task ShowScoreboardAsync() - { - await scoreboardService.ShowScoreboardAsync(Context.Player); - } -} diff --git a/src/Modules/Scoreboard/Controllers/ScoreboardEventController.cs b/src/Modules/Scoreboard/Controllers/ScoreboardEventController.cs deleted file mode 100644 index 466a5545f..000000000 --- a/src/Modules/Scoreboard/Controllers/ScoreboardEventController.cs +++ /dev/null @@ -1,37 +0,0 @@ -using EvoSC.Common.Controllers; -using EvoSC.Common.Controllers.Attributes; -using EvoSC.Common.Events.Attributes; -using EvoSC.Common.Interfaces.Controllers; -using EvoSC.Common.Remote; -using EvoSC.Common.Remote.EventArgsModels; -using EvoSC.Modules.Official.MatchManagerModule.Events; -using EvoSC.Modules.Official.MatchManagerModule.Events.EventArgObjects; -using EvoSC.Modules.Official.Scoreboard.Interfaces; -using GbxRemoteNet.Events; - -namespace EvoSC.Modules.Official.Scoreboard.Controllers; - -[Controller] -public class ScoreboardEventController(IScoreboardService scoreboardService) : EvoScController -{ - [Subscribe(GbxRemoteEvent.BeginMap)] - public async Task OnBeginMapAsync(object sender, MapGbxEventArgs args) - { - await scoreboardService.LoadAndSendRequiredAdditionalInfoAsync(); - await scoreboardService.ShowScoreboardToAllAsync(); - } - - [Subscribe(MatchSettingsEvent.MatchSettingsLoaded)] - public async Task OnMatchSettingsLoadedAsync(object sender, MatchSettingsLoadedEventArgs args) - { - await scoreboardService.LoadAndSendRequiredAdditionalInfoAsync(); - await scoreboardService.ShowScoreboardToAllAsync(); - } - - [Subscribe(ModeScriptEvent.StartRoundStart)] - public async Task OnRoundStartAsync(object sender, RoundEventArgs args) - { - scoreboardService.SetCurrentRound(args.Count); - await scoreboardService.SendRequiredAdditionalInfoAsync(); - } -} diff --git a/src/Modules/Scoreboard/Controllers/ScoreboardManialinkController.cs b/src/Modules/Scoreboard/Controllers/ScoreboardManialinkController.cs deleted file mode 100644 index 70be12211..000000000 --- a/src/Modules/Scoreboard/Controllers/ScoreboardManialinkController.cs +++ /dev/null @@ -1,11 +0,0 @@ -using EvoSC.Common.Controllers.Attributes; -using EvoSC.Manialinks; -using EvoSC.Modules.Official.Scoreboard.Interfaces; - -namespace EvoSC.Modules.Official.Scoreboard.Controllers; - -[Controller] -public class ScoreboardManialinkController(IScoreboardService scoreboardService) : ManialinkController -{ - public Task ResendScoreboardAsync() => scoreboardService.ShowScoreboardAsync(Context.Player); -} diff --git a/src/Modules/Scoreboard/Interfaces/IScoreboardService.cs b/src/Modules/Scoreboard/Interfaces/IScoreboardService.cs deleted file mode 100644 index 2e6a4d11f..000000000 --- a/src/Modules/Scoreboard/Interfaces/IScoreboardService.cs +++ /dev/null @@ -1,41 +0,0 @@ -using EvoSC.Common.Interfaces.Models; - -namespace EvoSC.Modules.Official.Scoreboard.Interfaces; - -public interface IScoreboardService -{ - /// - /// Sends the scoreboard manialink to all players. - /// - public Task ShowScoreboardToAllAsync(); - - /// - /// Sends the scoreboard manialink to a specific players. - /// - public Task ShowScoreboardAsync(IPlayer playerLogin); - - /// - /// Hide the default game scoreboard. - /// - public Task HideNadeoScoreboardAsync(); - - /// - /// Shows the default game scoreboard. - /// - public Task ShowNadeoScoreboardAsync(); - - /// - /// Sends the manialink with additional values used by the scoreboard. - /// - public Task SendRequiredAdditionalInfoAsync(); - - /// - /// Refreshes the additionally required data and sends the manialink. - /// - public Task LoadAndSendRequiredAdditionalInfoAsync(); - - /// - /// Sets the current round. - /// - public void SetCurrentRound(int round); -} diff --git a/src/Modules/Scoreboard/Interfaces/IScoreboardTrackerService.cs b/src/Modules/Scoreboard/Interfaces/IScoreboardTrackerService.cs deleted file mode 100644 index c00c7d63a..000000000 --- a/src/Modules/Scoreboard/Interfaces/IScoreboardTrackerService.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace EvoSC.Modules.Official.Scoreboard.Interfaces; - -public interface IScoreboardTrackerService -{ - public int RoundsPerMap { get; set; } - - public int PointsLimit { get; set; } - - public int CurrentRound { get; set; } - - public int MaxPlayers { get; set; } -} diff --git a/src/Modules/Scoreboard/ScoreboardModule.cs b/src/Modules/Scoreboard/ScoreboardModule.cs deleted file mode 100644 index 95bf6804a..000000000 --- a/src/Modules/Scoreboard/ScoreboardModule.cs +++ /dev/null @@ -1,22 +0,0 @@ -using EvoSC.Modules.Attributes; -using EvoSC.Modules.Interfaces; -using EvoSC.Modules.Official.Scoreboard.Interfaces; - -namespace EvoSC.Modules.Official.Scoreboard; - -[Module(IsInternal = true)] -public class ScoreboardModule(IScoreboardService scoreboardService) : EvoScModule, IToggleable -{ - public Task EnableAsync() - { - scoreboardService.LoadAndSendRequiredAdditionalInfoAsync(); - scoreboardService.HideNadeoScoreboardAsync(); - - return scoreboardService.ShowScoreboardToAllAsync(); - } - - public Task DisableAsync() - { - return scoreboardService.ShowNadeoScoreboardAsync(); - } -} diff --git a/src/Modules/Scoreboard/Services/ScoreboardTrackerService.cs b/src/Modules/Scoreboard/Services/ScoreboardTrackerService.cs deleted file mode 100644 index bbf52a0e6..000000000 --- a/src/Modules/Scoreboard/Services/ScoreboardTrackerService.cs +++ /dev/null @@ -1,97 +0,0 @@ -using EvoSC.Common.Services.Attributes; -using EvoSC.Common.Services.Models; -using EvoSC.Modules.Official.Scoreboard.Interfaces; - -namespace EvoSC.Modules.Official.Scoreboard.Services; - -[Service(LifeStyle = ServiceLifeStyle.Singleton)] -public class ScoreboardTrackerService : IScoreboardTrackerService -{ - private int _roundsPerMap = -1; - private readonly object _roundsPerMapLock = new(); - - private int _pointsLimit = -1; - private readonly object _pointsLimitLock = new(); - - private int _currentRound = -1; - private readonly object _currentRoundLock = new(); - - private int _maxPlayers = -1; - private readonly object _maxPlayersLock = new(); - - public int RoundsPerMap - { - get - { - lock (_roundsPerMapLock) - { - return _roundsPerMap; - } - } - - set - { - lock (_roundsPerMapLock) - { - _roundsPerMap = value; - } - } - } - - public int PointsLimit - { - get - { - lock (_pointsLimitLock) - { - return _pointsLimit; - } - } - - set - { - lock (_pointsLimitLock) - { - _pointsLimit = value; - } - } - } - - public int CurrentRound - { - get - { - lock (_currentRoundLock) - { - return _currentRound; - } - } - - set - { - lock (_currentRoundLock) - { - _currentRound = value; - } - } - } - - public int MaxPlayers - { - get - { - lock (_maxPlayersLock) - { - return _maxPlayers; - } - } - - set - { - lock (_maxPlayersLock) - { - _maxPlayers = value; - } - } - } -} diff --git a/src/Modules/Scoreboard/Templates/Components/BackgroundBox.mt b/src/Modules/Scoreboard/Templates/Components/BackgroundBox.mt deleted file mode 100644 index 55fbe511d..000000000 --- a/src/Modules/Scoreboard/Templates/Components/BackgroundBox.mt +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/src/Modules/Scoreboard/Templates/Components/PlayerRow/CustomLabelBackground.mt b/src/Modules/Scoreboard/Templates/Components/PlayerRow/CustomLabelBackground.mt deleted file mode 100644 index c21412bdf..000000000 --- a/src/Modules/Scoreboard/Templates/Components/PlayerRow/CustomLabelBackground.mt +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/src/Modules/Scoreboard/Templates/Components/PlayerRow/Framemodel.mt b/src/Modules/Scoreboard/Templates/Components/PlayerRow/Framemodel.mt deleted file mode 100644 index 37cdafd0d..000000000 --- a/src/Modules/Scoreboard/Templates/Components/PlayerRow/Framemodel.mt +++ /dev/null @@ -1,195 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Modules/Scoreboard/Templates/Components/PlayerRow/PlayerRowBackground.mt b/src/Modules/Scoreboard/Templates/Components/PlayerRow/PlayerRowBackground.mt deleted file mode 100644 index ad4154156..000000000 --- a/src/Modules/Scoreboard/Templates/Components/PlayerRow/PlayerRowBackground.mt +++ /dev/null @@ -1,139 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/src/Modules/Scoreboard/Templates/Components/PlayerRow/PointsBox.mt b/src/Modules/Scoreboard/Templates/Components/PlayerRow/PointsBox.mt deleted file mode 100644 index fcabef295..000000000 --- a/src/Modules/Scoreboard/Templates/Components/PlayerRow/PointsBox.mt +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Modules/Scoreboard/Templates/Components/PlayerRow/PositionBox.mt b/src/Modules/Scoreboard/Templates/Components/PlayerRow/PositionBox.mt deleted file mode 100644 index 9af6a75eb..000000000 --- a/src/Modules/Scoreboard/Templates/Components/PlayerRow/PositionBox.mt +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Modules/Scoreboard/Templates/Components/ScoreboardHeader.mt b/src/Modules/Scoreboard/Templates/Components/ScoreboardHeader.mt deleted file mode 100644 index 3ddbd19e8..000000000 --- a/src/Modules/Scoreboard/Templates/Components/ScoreboardHeader.mt +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/src/Modules/Scoreboard/Templates/Components/Scrollbar.mt b/src/Modules/Scoreboard/Templates/Components/Scrollbar.mt deleted file mode 100644 index 61d55dddb..000000000 --- a/src/Modules/Scoreboard/Templates/Components/Scrollbar.mt +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Modules/Scoreboard/Themes/DefaultScoreboardTheme.cs b/src/Modules/Scoreboard/Themes/DefaultScoreboardTheme.cs deleted file mode 100644 index e9a88b652..000000000 --- a/src/Modules/Scoreboard/Themes/DefaultScoreboardTheme.cs +++ /dev/null @@ -1,49 +0,0 @@ -using EvoSC.Common.Interfaces.Themes; -using EvoSC.Common.Themes; -using EvoSC.Common.Themes.Attributes; -using EvoSC.Common.Util; - -namespace EvoSC.Modules.Official.Scoreboard.Themes; - -[Theme(Name = "Scoreboard", Description = "Default theme for the scoreboard.")] -public class DefaultScoreboardTheme(IThemeManager theme) : Theme -{ - private readonly dynamic _theme = theme.Theme; - - public override Task ConfigureAsync() - { - Set("ScoreboardModule.BackgroundBox.BgHeader").To(_theme.UI_BgPrimary); - Set("ScoreboardModule.BackgroundBox.BgHeaderGrad").To(ColorUtils.Darken(_theme.UI_BgPrimary)); - Set("ScoreboardModule.BackgroundBox.BgList").To(_theme.UI_BgHighlight); - - Set("ScoreboardModule.ScoreboardHeader.Text").To(_theme.UI_TextPrimary); - Set("ScoreboardModule.ScoreboardHeader.Logo").To(_theme.UI_LogoLight); - - Set("ScoreboardModule.ClubTag.Bg").To(_theme.UI_BgHighlight); - - Set("ScoreboardModule.PlayerRow.Text").To(_theme.UI_TextPrimary); - Set("ScoreboardModule.PlayerRow.CustomLabelBackground.Bg").To(_theme.Black); - - Set("ScoreboardModule.PlayerRow.PlayerActions.BgHighlight").To(_theme.UI_BgHighlight); - - Set("ScoreboardModule.PlayerRow.PlayerRowBackground.Bg").To(ColorUtils.Lighten(_theme.UI_BgHighlight)); - Set("ScoreboardModule.PlayerRow.PlayerRowBackground.BgHighlight").To(ColorUtils.SetLightness(_theme.UI_BgHighlight, 70)); - - Set("ScoreboardModule.PlayerRow.PointsBox.Bg").To(ColorUtils.SetLightness(_theme.UI_BgHighlight, 70)); - Set("ScoreboardModule.PlayerRow.PointsBox.Text").To(ColorUtils.SetLightness(_theme.UI_BgHighlight, 20)); - - Set("ScoreboardModule.PlayerRow.PositionBox.Bg").To(_theme.UI_BgHighlight); - - Set("ScoreboardModule.PlayerRow.FrameModel.Bg").To(_theme.UI_BgHighlight); - - Set("ScoreboardModule.PlayerRow.FrameModel.Text").To(_theme.UI_TextPrimary); - Set("ScoreboardModule.PlayerRow.FrameModel.BgRow").To(_theme.UI_BgHighlight); - Set("ScoreboardModule.PlayerRow.FrameModel.TextRoundPoints").To(_theme.UI_TextSecondary); - - Set("ScoreboardModule.Scoreboard.BgPosition").To(_theme.UI_BgHighlight); - - Set("ScoreboardModule.Settings.Text").To(_theme.UI_TextPrimary); - - return Task.CompletedTask; - } -} diff --git a/src/Modules/ScoreboardModule/Config/IScoreboardSettings.cs b/src/Modules/ScoreboardModule/Config/IScoreboardSettings.cs new file mode 100644 index 000000000..60b50627b --- /dev/null +++ b/src/Modules/ScoreboardModule/Config/IScoreboardSettings.cs @@ -0,0 +1,15 @@ +using System.ComponentModel; +using Config.Net; +using EvoSC.Modules.Attributes; + +namespace EvoSC.Modules.Official.ScoreboardModule.Config; + +[Settings] +public interface IScoreboardSettings +{ + [Option(DefaultValue = 160.0), Description("Sets the width of the scoreboard.")] + public double Width { get; } + + [Option(DefaultValue = 80.0), Description("Sets the height of the scoreboard.")] + public double Height { get; } +} diff --git a/src/Modules/ScoreboardModule/Controllers/ScoreboardEventController.cs b/src/Modules/ScoreboardModule/Controllers/ScoreboardEventController.cs new file mode 100644 index 000000000..9943a7af6 --- /dev/null +++ b/src/Modules/ScoreboardModule/Controllers/ScoreboardEventController.cs @@ -0,0 +1,28 @@ +using EvoSC.Common.Controllers; +using EvoSC.Common.Controllers.Attributes; +using EvoSC.Common.Events.Attributes; +using EvoSC.Common.Interfaces.Controllers; +using EvoSC.Common.Remote; +using EvoSC.Modules.Official.ScoreboardModule.Interfaces; +using GbxRemoteNet.Events; + +namespace EvoSC.Modules.Official.ScoreboardModule.Controllers; + +[Controller] +public class ScoreboardEventController( + IScoreboardService scoreboardService, + IScoreboardNicknamesService nicknamesService +) + : EvoScController +{ + [Subscribe(GbxRemoteEvent.PlayerConnect)] + public Task OnPlayerConnectAsync(object sender, PlayerGbxEventArgs args) => + nicknamesService.AddNicknameByLoginAsync(args.Login); + + [Subscribe(GbxRemoteEvent.BeginMap)] + public async Task OnBeginMapAsync(object sender, MapGbxEventArgs args) + { + await nicknamesService.LoadNicknamesAsync(); + await scoreboardService.SendScoreboardAsync(); + } +} diff --git a/src/Modules/ScoreboardModule/Interfaces/IScoreboardNicknamesService.cs b/src/Modules/ScoreboardModule/Interfaces/IScoreboardNicknamesService.cs new file mode 100644 index 000000000..a3023558b --- /dev/null +++ b/src/Modules/ScoreboardModule/Interfaces/IScoreboardNicknamesService.cs @@ -0,0 +1,50 @@ +namespace EvoSC.Modules.Official.ScoreboardModule.Interfaces; + +public interface IScoreboardNicknamesService +{ + /// + /// Gets the online player by login and then sets their custom nickname in the repo. + /// + /// + /// + public Task AddNicknameByLoginAsync(string login); + + /// + /// Clears the nicknames repo. + /// + /// + public Task ClearNicknamesAsync(); + + /// + /// Gets all online players and sets their custom nicknames in the repo. + /// + /// + public Task LoadNicknamesAsync(); + + /// + /// Sends the manialink containing the nicknames in the repo. + /// + /// + public Task SendNicknamesManialinkAsync(); + + /// + /// Converts the nickname repo to a ManiaScript array. + /// + /// + /// + public string ToManiaScriptArray(Dictionary nicknameMap); + + /// + /// Converts an entry of the nickname repo to a ManiaScript array entry. + /// + /// + /// + public string ToManiaScriptArrayEntry(KeyValuePair loginNickname); + + /// + /// Escapes a nickname to be safely inserted into a XMl comment. + /// + /// + /// + public string EscapeNickname(string nickname); +} diff --git a/src/Modules/ScoreboardModule/Interfaces/IScoreboardService.cs b/src/Modules/ScoreboardModule/Interfaces/IScoreboardService.cs new file mode 100644 index 000000000..9dc5c0624 --- /dev/null +++ b/src/Modules/ScoreboardModule/Interfaces/IScoreboardService.cs @@ -0,0 +1,19 @@ +namespace EvoSC.Modules.Official.ScoreboardModule.Interfaces; + +public interface IScoreboardService +{ + /// + /// Sends the scoreboard manialink to all players. + /// + public Task SendScoreboardAsync(); + + /// + /// Hide the default game scoreboard. + /// + public Task HideNadeoScoreboardAsync(); + + /// + /// Shows the default game scoreboard. + /// + public Task ShowNadeoScoreboardAsync(); +} diff --git a/src/Modules/Scoreboard/Localization.resx b/src/Modules/ScoreboardModule/Localization.resx similarity index 100% rename from src/Modules/Scoreboard/Localization.resx rename to src/Modules/ScoreboardModule/Localization.resx diff --git a/src/Modules/ScoreboardModule/ScoreboardModule.cs b/src/Modules/ScoreboardModule/ScoreboardModule.cs new file mode 100644 index 000000000..6d8235ca3 --- /dev/null +++ b/src/Modules/ScoreboardModule/ScoreboardModule.cs @@ -0,0 +1,20 @@ +using EvoSC.Modules.Attributes; +using EvoSC.Modules.Interfaces; +using EvoSC.Modules.Official.ScoreboardModule.Interfaces; + +namespace EvoSC.Modules.Official.ScoreboardModule; + +[Module(IsInternal = true)] +public class ScoreboardModule(IScoreboardService scoreboardService, IScoreboardNicknamesService nicknamesService) + : EvoScModule, IToggleable +{ + public async Task EnableAsync() + { + await nicknamesService.LoadNicknamesAsync(); + await scoreboardService.HideNadeoScoreboardAsync(); + await scoreboardService.SendScoreboardAsync(); + } + + public Task DisableAsync() => + scoreboardService.ShowNadeoScoreboardAsync(); +} diff --git a/src/Modules/Scoreboard/Scoreboard.csproj b/src/Modules/ScoreboardModule/ScoreboardModule.csproj similarity index 93% rename from src/Modules/Scoreboard/Scoreboard.csproj rename to src/Modules/ScoreboardModule/ScoreboardModule.csproj index b1ff40dea..456dbbf3f 100644 --- a/src/Modules/Scoreboard/Scoreboard.csproj +++ b/src/Modules/ScoreboardModule/ScoreboardModule.csproj @@ -4,7 +4,7 @@ net8.0 enable enable - EvoSC.Modules.Official.Scoreboard + EvoSC.Modules.Official.ScoreboardModule diff --git a/src/Modules/ScoreboardModule/Services/ScoreboardNicknamesService.cs b/src/Modules/ScoreboardModule/Services/ScoreboardNicknamesService.cs new file mode 100644 index 000000000..7619688c8 --- /dev/null +++ b/src/Modules/ScoreboardModule/Services/ScoreboardNicknamesService.cs @@ -0,0 +1,68 @@ +using EvoSC.Common.Interfaces.Services; +using EvoSC.Common.Services.Attributes; +using EvoSC.Common.Services.Models; +using EvoSC.Common.Util; +using EvoSC.Manialinks.Interfaces; +using EvoSC.Modules.Official.ScoreboardModule.Interfaces; + +namespace EvoSC.Modules.Official.ScoreboardModule.Services; + +[Service(LifeStyle = ServiceLifeStyle.Singleton)] +public class ScoreboardNicknamesService( + IPlayerManagerService playerManagerService, + IManialinkManager manialinkManager +) : IScoreboardNicknamesService +{ + private readonly Dictionary _nicknames = new(); + + public async Task AddNicknameByLoginAsync(string login) + { + var player = await playerManagerService.GetOnlinePlayerAsync(PlayerUtils.ConvertLoginToAccountId(login)); + + if (player.NickName == player.UbisoftName) + { + return; + } + + _nicknames[login] = player.NickName; + } + + public Task ClearNicknamesAsync() + { + _nicknames.Clear(); + + return Task.CompletedTask; + } + + public async Task LoadNicknamesAsync() + { + var onlinePlayers = await playerManagerService.GetOnlinePlayersAsync(); + foreach (var player in onlinePlayers.Where(player => player.NickName != player.UbisoftName)) + { + _nicknames[player.GetLogin()] = player.NickName; + } + } + + public Task SendNicknamesManialinkAsync() => + manialinkManager.SendPersistentManialinkAsync("ScoreboardModule.PlayerNicknames", + new { nicknames = ToManiaScriptArray(_nicknames) }); + + public string ToManiaScriptArray(Dictionary nicknameMap) + { + var entriesList = nicknameMap.Select(ToManiaScriptArrayEntry).ToList(); + var joinedEntries = string.Join(",\n", entriesList); + + return $"[{joinedEntries}]"; + } + + public string ToManiaScriptArrayEntry(KeyValuePair loginNickname) + { + return $"\"{loginNickname.Key}\" => \"{EscapeNickname(loginNickname.Value)}\""; + } + + public string EscapeNickname(string nickname) + { + return nickname.Replace("-->", "-\u2192", StringComparison.OrdinalIgnoreCase) + .Replace("\"", "\\\"", StringComparison.OrdinalIgnoreCase); + } +} diff --git a/src/Modules/ScoreboardModule/Services/ScoreboardService.cs b/src/Modules/ScoreboardModule/Services/ScoreboardService.cs new file mode 100644 index 000000000..941f496fc --- /dev/null +++ b/src/Modules/ScoreboardModule/Services/ScoreboardService.cs @@ -0,0 +1,58 @@ +using EvoSC.Common.Interfaces; +using EvoSC.Common.Services.Attributes; +using EvoSC.Common.Services.Models; +using EvoSC.Manialinks.Interfaces; +using EvoSC.Modules.Official.GameModeUiModule.Enums; +using EvoSC.Modules.Official.GameModeUiModule.Interfaces; +using EvoSC.Modules.Official.ScoreboardModule.Config; +using EvoSC.Modules.Official.ScoreboardModule.Interfaces; + +namespace EvoSC.Modules.Official.ScoreboardModule.Services; + +[Service(LifeStyle = ServiceLifeStyle.Transient)] +public class ScoreboardService( + IManialinkManager manialinks, + IServerClient server, + IScoreboardNicknamesService nicknamesService, + IScoreboardSettings settings, + IGameModeUiModuleService gameModeUiModuleService +) + : IScoreboardService +{ + private const string ScoreboardTemplate = "ScoreboardModule.Scoreboard"; + + public async Task SendScoreboardAsync() + { + await manialinks.SendPersistentManialinkAsync(ScoreboardTemplate, await GetDataAsync()); + await nicknamesService.SendNicknamesManialinkAsync(); + } + + private async Task GetDataAsync() + { + var currentNextMaxPlayers = await server.Remote.GetMaxPlayersAsync(); + var currentNextMaxSpectators = await server.Remote.GetMaxSpectatorsAsync(); + + return new + { + settings, MaxPlayers = currentNextMaxPlayers.CurrentValue + currentNextMaxSpectators.CurrentValue + }; + } + + public Task HideNadeoScoreboardAsync() => + gameModeUiModuleService.ApplyComponentSettingsAsync( + GameModeUiComponents.ScoresTable, + false, + 0.0, + 0.0, + 1.0 + ); + + public Task ShowNadeoScoreboardAsync() => + gameModeUiModuleService.ApplyComponentSettingsAsync( + GameModeUiComponents.ScoresTable, + true, + 0.0, + 0.0, + 1.0 + ); +} diff --git a/src/Modules/ScoreboardModule/Templates/Components/Body/Legend.mt b/src/Modules/ScoreboardModule/Templates/Components/Body/Legend.mt new file mode 100644 index 000000000..b0ad6e0a8 --- /dev/null +++ b/src/Modules/ScoreboardModule/Templates/Components/Body/Legend.mt @@ -0,0 +1,86 @@ + + + + + + + + + + + + diff --git a/src/Modules/ScoreboardModule/Templates/Components/Header/HeaderBackground.mt b/src/Modules/ScoreboardModule/Templates/Components/Header/HeaderBackground.mt new file mode 100644 index 000000000..78adc18e1 --- /dev/null +++ b/src/Modules/ScoreboardModule/Templates/Components/Header/HeaderBackground.mt @@ -0,0 +1,11 @@ + + + + + + diff --git a/src/Modules/ScoreboardModule/Templates/Components/Header/HeaderContent.mt b/src/Modules/ScoreboardModule/Templates/Components/Header/HeaderContent.mt new file mode 100644 index 000000000..728922584 --- /dev/null +++ b/src/Modules/ScoreboardModule/Templates/Components/Header/HeaderContent.mt @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + diff --git a/src/Modules/ScoreboardModule/Templates/Components/Header/Logo.mt b/src/Modules/ScoreboardModule/Templates/Components/Header/Logo.mt new file mode 100644 index 000000000..c1a8ad19a --- /dev/null +++ b/src/Modules/ScoreboardModule/Templates/Components/Header/Logo.mt @@ -0,0 +1,14 @@ + + + + + + diff --git a/src/Modules/ScoreboardModule/Templates/Components/Row/CustomLabelBackground.mt b/src/Modules/ScoreboardModule/Templates/Components/Row/CustomLabelBackground.mt new file mode 100644 index 000000000..74cf71d74 --- /dev/null +++ b/src/Modules/ScoreboardModule/Templates/Components/Row/CustomLabelBackground.mt @@ -0,0 +1,20 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/Modules/ScoreboardModule/Templates/Components/Row/Flag.mt b/src/Modules/ScoreboardModule/Templates/Components/Row/Flag.mt new file mode 100644 index 000000000..a53876481 --- /dev/null +++ b/src/Modules/ScoreboardModule/Templates/Components/Row/Flag.mt @@ -0,0 +1,11 @@ + + + + + diff --git a/src/Modules/ScoreboardModule/Templates/Components/Row/Framemodel.mt b/src/Modules/ScoreboardModule/Templates/Components/Row/Framemodel.mt new file mode 100644 index 000000000..e38ae2fbe --- /dev/null +++ b/src/Modules/ScoreboardModule/Templates/Components/Row/Framemodel.mt @@ -0,0 +1,244 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Modules/Scoreboard/Templates/Components/PlayerRow/PlayerActions.mt b/src/Modules/ScoreboardModule/Templates/Components/Row/PlayerActions.mt similarity index 59% rename from src/Modules/Scoreboard/Templates/Components/PlayerRow/PlayerActions.mt rename to src/Modules/ScoreboardModule/Templates/Components/Row/PlayerActions.mt index 58ad3f4de..45d13b8a1 100644 --- a/src/Modules/Scoreboard/Templates/Components/PlayerRow/PlayerActions.mt +++ b/src/Modules/ScoreboardModule/Templates/Components/Row/PlayerActions.mt @@ -2,36 +2,36 @@ - - + diff --git a/src/Modules/ScoreboardModule/Templates/Components/Row/PlayerRowBackground.mt b/src/Modules/ScoreboardModule/Templates/Components/Row/PlayerRowBackground.mt new file mode 100644 index 000000000..8499ed831 --- /dev/null +++ b/src/Modules/ScoreboardModule/Templates/Components/Row/PlayerRowBackground.mt @@ -0,0 +1,57 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Modules/ScoreboardModule/Templates/Components/Row/PositionBox.mt b/src/Modules/ScoreboardModule/Templates/Components/Row/PositionBox.mt new file mode 100644 index 000000000..9286387b3 --- /dev/null +++ b/src/Modules/ScoreboardModule/Templates/Components/Row/PositionBox.mt @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + diff --git a/src/Modules/ScoreboardModule/Templates/Components/ScoreboardBg.mt b/src/Modules/ScoreboardModule/Templates/Components/ScoreboardBg.mt new file mode 100644 index 000000000..edf86e156 --- /dev/null +++ b/src/Modules/ScoreboardModule/Templates/Components/ScoreboardBg.mt @@ -0,0 +1,13 @@ + + + + + + diff --git a/src/Modules/ScoreboardModule/Templates/Components/ScoreboardBody.mt b/src/Modules/ScoreboardModule/Templates/Components/ScoreboardBody.mt new file mode 100644 index 000000000..403d4b037 --- /dev/null +++ b/src/Modules/ScoreboardModule/Templates/Components/ScoreboardBody.mt @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + diff --git a/src/Modules/ScoreboardModule/Templates/Components/ScoreboardHeader.mt b/src/Modules/ScoreboardModule/Templates/Components/ScoreboardHeader.mt new file mode 100644 index 000000000..1f726082d --- /dev/null +++ b/src/Modules/ScoreboardModule/Templates/Components/ScoreboardHeader.mt @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/src/Modules/Scoreboard/Templates/Components/Settings/Form.mt b/src/Modules/ScoreboardModule/Templates/Components/Settings/Form.mt similarity index 100% rename from src/Modules/Scoreboard/Templates/Components/Settings/Form.mt rename to src/Modules/ScoreboardModule/Templates/Components/Settings/Form.mt diff --git a/src/Modules/Scoreboard/Templates/Components/Settings/Wrapper.mt b/src/Modules/ScoreboardModule/Templates/Components/Settings/Wrapper.mt similarity index 100% rename from src/Modules/Scoreboard/Templates/Components/Settings/Wrapper.mt rename to src/Modules/ScoreboardModule/Templates/Components/Settings/Wrapper.mt diff --git a/src/Modules/ScoreboardModule/Templates/PlayerNicknames.mt b/src/Modules/ScoreboardModule/Templates/PlayerNicknames.mt new file mode 100644 index 000000000..5a252187d --- /dev/null +++ b/src/Modules/ScoreboardModule/Templates/PlayerNicknames.mt @@ -0,0 +1,10 @@ + + +