From d2db4fb74ce3ee6e63313f944f0a13a74badc8ab Mon Sep 17 00:00:00 2001 From: linkpuff Date: Thu, 4 Mar 2021 11:20:05 +0000 Subject: [PATCH] Commands.Core: Compliance with Impostor 1.3.0 (Announcement Server is now disabled by default) BlackTea:Naming scheme fixes Plugin.Test: Compliance with Impostor 1.3.0 --- .../Networking/BlackTeaTransport.cs | 8 +- .../Impostor.Commands.Core/Class.cs | 724 +++++++++--------- .../Impostor.Commands.Core.csproj | 2 +- .../Impostor.Commands.Core/Structures.cs | 2 + ImpostorHQ.Command/Plugin.Test/MainClass.cs | 4 +- 5 files changed, 385 insertions(+), 355 deletions(-) diff --git a/ImpostorHQ.Command/Impostor.Commands.Core.Client/Networking/BlackTeaTransport.cs b/ImpostorHQ.Command/Impostor.Commands.Core.Client/Networking/BlackTeaTransport.cs index 7e4e6ab..aa982f1 100644 --- a/ImpostorHQ.Command/Impostor.Commands.Core.Client/Networking/BlackTeaTransport.cs +++ b/ImpostorHQ.Command/Impostor.Commands.Core.Client/Networking/BlackTeaTransport.cs @@ -11,7 +11,7 @@ namespace Impostor.Commands.Core.Client public class BlackTeaTransport { public ClientWebSocket Socket { get; private set; } - private BlackTeaSharp cryptographicFunction { get; set; } + private BlackTeaSharp CryptographicFunction { get; set; } public string Key { get; private set; } public Action OnReceived { get; set; } private ArraySegment ReceiveBuffer { get; set; } @@ -20,7 +20,7 @@ public class BlackTeaTransport public BlackTeaTransport(ClientWebSocket socket, string key, Action received) { this.Socket = socket; - this.cryptographicFunction = new BlackTeaSharp(); + this.CryptographicFunction = new BlackTeaSharp(); this.Key = key; this.OnReceived = received; this.ReceiveBuffer = new ArraySegment(new byte[1024]); @@ -50,7 +50,7 @@ private async Task ReadCallback() { while (ContinueReading) { - var received = cryptographicFunction.Decrypt(await Read().ConfigureAwait(false),Key); + var received = CryptographicFunction.Decrypt(await Read().ConfigureAwait(false),Key); OnReceived?.Invoke(JsonSerializer.Deserialize(received)); } } @@ -70,7 +70,7 @@ private async Task Read() } public void SendAsync(string message) { - Socket.SendAsync(Encoding.UTF8.GetBytes(cryptographicFunction.Encrypt(message,Key)),WebSocketMessageType.Text,true,CancellationToken.None).ConfigureAwait(false); + Socket.SendAsync(Encoding.UTF8.GetBytes(CryptographicFunction.Encrypt(message,Key)),WebSocketMessageType.Text,true,CancellationToken.None).ConfigureAwait(false); } public static ulong GetTime() diff --git a/ImpostorHQ.Command/Impostor.Commands.Core/Class.cs b/ImpostorHQ.Command/Impostor.Commands.Core/Class.cs index 2410753..3c7ba63 100644 --- a/ImpostorHQ.Command/Impostor.Commands.Core/Class.cs +++ b/ImpostorHQ.Command/Impostor.Commands.Core/Class.cs @@ -25,11 +25,13 @@ using Impostor.Api.Plugins; using Impostor.Api.Games.Managers; using Impostor.Api.Events.Managers; +using Impostor.Api.Events.Announcements; +using Impostor.Api.Events; #endregion namespace Impostor.Commands.Core { - [ImpostorPlugin("ImpostorHQ","Impostor HeadQuarters API","anti, Dimaguy","0.0.7 stable")] + [ImpostorPlugin("ImpostorHQ", "Impostor HeadQuarters API", "anti, Dimaguy", "0.0.7 stable")] public class Class : PluginBase { // this is used by the plugin loader. @@ -63,7 +65,7 @@ public class Class : PluginBase //provides MessageWriters. Not used for anything, yet. public IMessageWriterProvider MessageWriterProvider { get; private set; } public GameCommandChatInterface ChatInterface { get; set; } - public IEventManager EventManager{ get; set; } + public IEventManager EventManager { get; set; } private ParallelOptions Options { get; set; } public IClientManager ClientManager { get; set; } @@ -73,7 +75,7 @@ public class Class : PluginBase //our lovely log manager! public SpatiallyEfficientLogFileManager LogManager { get; private set; } public AnnouncementServer AnnouncementManager { get; private set; } - public QuodEratDemonstrandum.QuiteElegantDirectory QED{ get; private set; } + public QuodEratDemonstrandum.QuiteElegantDirectory QED { get; private set; } public PluginLoader PluginLoader { get; private set; } public QuiteExtendableDirectInterface QEDi { get; set; } public QuiteEffectiveDetector QEDetector { get; private set; } @@ -85,7 +87,7 @@ public class Class : PluginBase /// The global event manager. /// The global game manager. /// A provider for MessageWriters (not used yet). - public Class(ILogger logger, IEventManager manager, IGameManager gameManager,IMessageWriterProvider provider,IClientManager clientManager) + public Class(ILogger logger, IEventManager manager, IGameManager gameManager, IMessageWriterProvider provider, IClientManager clientManager) { this.GameManager = gameManager; this.Logger = logger; @@ -124,14 +126,17 @@ public override ValueTask DisableAsync() Configuration.SaveTo(ConfigPath); ChatCommandCfg.SaveTo(ChatConfigPath); LogManager.Finish(); - AnnouncementManager.Shutdown(); + if (Configuration.LegacyAnnouncement) + { + AnnouncementManager.Shutdown(); + } QED.Shutdown(); PluginLoader.Shutdown(); QEDetector.Shutdown(); return default; } #endregion - + /// /// Our main thread. This executes all our code. /// @@ -225,24 +230,32 @@ private void InitializeServers() var errorMimeHtml = File.ReadAllText(Path.Combine("dashboard", "mime.html")); //we initialize our servers and set up the events. CertificateAuthority.CertificateSynthesizer synth = new CertificateAuthority.CertificateSynthesizer(); - this.ApiServer = new WebApiServer(Configuration.WebApiPort, Configuration.ListenInterface, Configuration.ApiKeys.ToArray(), Logger,GameManager,this,QEDetector,Configuration.UseSsl,synth.GetHttpsCert("anti.the-great.exterminator")); - this.DashboardServer = new HttpServer(Configuration.ListenInterface, Configuration.WebsitePort, ClientHTML, error404Html, errorMimeHtml,this,ApiServer,QEDetector, Configuration.UseSsl, synth.GetHttpsCert("anti.the-great.exterminator")); + this.ApiServer = new WebApiServer(Configuration.WebApiPort, Configuration.ListenInterface, Configuration.ApiKeys.ToArray(), Logger, GameManager, this, QEDetector, Configuration.UseSsl, synth.GetHttpsCert("anti.the-great.exterminator")); + this.DashboardServer = new HttpServer(Configuration.ListenInterface, Configuration.WebsitePort, ClientHTML, error404Html, errorMimeHtml, this, ApiServer, QEDetector, Configuration.UseSsl, synth.GetHttpsCert("anti.the-great.exterminator")); Logger.LogInformation($"ImpostorHQ : API Server listening on: {Configuration.ListenInterface}:{Configuration.WebApiPort}. Dashboard listening on: {Configuration.ListenInterface}:{Configuration.WebsitePort}/client.html"); - this.AnnouncementManager = new AnnouncementServer(this,"configs"); + if (Configuration.LegacyAnnouncement) + { + this.AnnouncementManager = new AnnouncementServer(this, "configs"); + Logger.LogInformation($"ImpostorHQ : Legacy Announcement Server Enabled!"); + } + ApiServer.OnMessageReceived += DashboardCommandReceived; ApiServer.RegisterCommand(Structures.DashboardCommands.HelpMessage, "=> will display the help message."); ApiServer.RegisterCommand(Structures.DashboardCommands.ServerWideBroadcast, " : => will send a message to all lobbies."); ApiServer.RegisterCommand(Structures.DashboardCommands.ListColors, "=> will list all the colors accepted by the /broadcast commands."); - ApiServer.RegisterCommand(Structures.DashboardCommands.ListKeys,"=> will list all registered API keys."); - ApiServer.RegisterCommand(Structures.DashboardCommands.AddKey,"=> will register the selected key."); - ApiServer.RegisterCommand(Structures.DashboardCommands.DeleteKey,"=> will delete the API key, if it is valid."); - ApiServer.RegisterCommand(Structures.DashboardCommands.PlayerInfo," => this will show information about a player."); - ApiServer.RegisterCommand(Structures.DashboardCommands.ListLogs,"=> will list the logs that you can then fetch."); + ApiServer.RegisterCommand(Structures.DashboardCommands.ListKeys, "=> will list all registered API keys."); + ApiServer.RegisterCommand(Structures.DashboardCommands.AddKey, "=> will register the selected key."); + ApiServer.RegisterCommand(Structures.DashboardCommands.DeleteKey, "=> will delete the API key, if it is valid."); + ApiServer.RegisterCommand(Structures.DashboardCommands.PlayerInfo, " => this will show information about a player."); + ApiServer.RegisterCommand(Structures.DashboardCommands.ListLogs, "=> will list the logs that you can then fetch."); ApiServer.RegisterCommand(Structures.DashboardCommands.FetchLog, " => will download the log in CSV format. They will be converted to CSV on-demand, so don't spam this command, because it will use up CPU time."); - ApiServer.RegisterCommand(Structures.DashboardCommands.AnnouncementMultiCommand," set => will set that announcement, clear => will clear the message and delete it from the disk."); + if (Configuration.LegacyAnnouncement) + { + ApiServer.RegisterCommand(Structures.DashboardCommands.AnnouncementMultiCommand, " set => will set that announcement, clear => will clear the message and delete it from the disk."); + } } - + /// /// This is the default player command handler, which also handles commands for plugins. /// @@ -256,108 +269,108 @@ private void GameEventListener_OnPlayerCommandReceived(string command, string da ChatInterface.SafeMultiMessage(source.Game, ChatInterface.GenerateDocs(), Structures.BroadcastType.Information, destination: source.ClientPlayer); return; } - + switch (command) { case Structures.PlayerCommands.MapChange: - { - if (string.IsNullOrEmpty(data)) { - ChatInterface.SafeMultiMessage(source.Game, "Invalid command data. Please use /help for more information.", Structures.BroadcastType.Error, destination: source.ClientPlayer); - return; - } - if (!source.ClientPlayer.IsHost) - { - ChatInterface.SafeMultiMessage(source.Game, "You are not the host.", Structures.BroadcastType.Error, destination: source.ClientPlayer); + if (string.IsNullOrEmpty(data)) + { + ChatInterface.SafeMultiMessage(source.Game, "Invalid command data. Please use /help for more information.", Structures.BroadcastType.Error, destination: source.ClientPlayer); + return; + } + if (!source.ClientPlayer.IsHost) + { + ChatInterface.SafeMultiMessage(source.Game, "You are not the host.", Structures.BroadcastType.Error, destination: source.ClientPlayer); + break; + } + var map = data.ToLower(); + if (!Structures.Maps.Contains(map)) + { + ChatInterface.SafeMultiMessage(source.Game, "Invalid map. Accepted values: Skeld, MiraHQ, Polus.", Structures.BroadcastType.Error, destination: source.ClientPlayer); + } + else + { + var flag = MapTypes.Skeld; + switch (map) + { + case "polus": + { + flag = MapTypes.Polus; + break; + } + case "mirahq": + { + flag = MapTypes.MiraHQ; + break; + } + } + + source.Game.Options.Map = flag; + source.Game.SyncSettingsAsync(); + } break; } - var map = data.ToLower(); - if (!Structures.Maps.Contains(map)) - { - ChatInterface.SafeMultiMessage(source.Game, "Invalid map. Accepted values: Skeld, MiraHQ, Polus.", Structures.BroadcastType.Error, destination: source.ClientPlayer); - } - else + case Structures.PlayerCommands.MaxPlayersChange: { - var flag = MapTypes.Skeld; - switch (map) + if (string.IsNullOrEmpty(data)) + { + ChatInterface.SafeMultiMessage(source.Game, "Invalid command data. Please use /help for more information.", Structures.BroadcastType.Error, destination: source.ClientPlayer); + return; + } + if (!source.ClientPlayer.IsHost) { - case "polus": + ChatInterface.SafeMultiMessage(source.Game, "You are not the host.", Structures.BroadcastType.Error, destination: source.ClientPlayer); + break; + } + if (Byte.TryParse(data, out byte num)) + { + if (!Structures.MaxPlayers.Contains(num)) { - flag = MapTypes.Polus; - break; + ChatInterface.SafeMultiMessage(source.Game, "Invalid number of players. Accepted numbers: 10, 8, 6, 4.", Structures.BroadcastType.Error, destination: source.ClientPlayer); } - case "mirahq": + else { - flag = MapTypes.MiraHQ; - break; + source.Game.Options.MaxPlayers = num; + source.Game.SyncSettingsAsync(); } } - - source.Game.Options.Map = flag; - source.Game.SyncSettingsAsync(); - } - break; - } - case Structures.PlayerCommands.MaxPlayersChange: - { - if (string.IsNullOrEmpty(data)) - { - ChatInterface.SafeMultiMessage(source.Game, "Invalid command data. Please use /help for more information.", Structures.BroadcastType.Error, destination: source.ClientPlayer); - return; - } - if (!source.ClientPlayer.IsHost) - { - ChatInterface.SafeMultiMessage(source.Game, "You are not the host.", Structures.BroadcastType.Error, destination: source.ClientPlayer); + else + { + ChatInterface.SafeMultiMessage(source.Game, "Invalid syntax. Please use \"/players <10,8,6,4>.", Structures.BroadcastType.Error, destination: source.ClientPlayer); + } break; } - if (Byte.TryParse(data, out byte num)) + case Structures.PlayerCommands.ImpostorChange: { - if (!Structures.MaxPlayers.Contains(num)) + if (string.IsNullOrEmpty(data)) { - ChatInterface.SafeMultiMessage(source.Game, "Invalid number of players. Accepted numbers: 10, 8, 6, 4.", Structures.BroadcastType.Error, destination: source.ClientPlayer); + ChatInterface.SafeMultiMessage(source.Game, "Invalid command data. Please use /help for more information.", Structures.BroadcastType.Error, destination: source.ClientPlayer); + return; } - else + if (!source.ClientPlayer.IsHost) { - source.Game.Options.MaxPlayers = num; - source.Game.SyncSettingsAsync(); + ChatInterface.SafeMultiMessage(source.Game, "You are not the host.", Structures.BroadcastType.Error, destination: source.ClientPlayer); + break; } - } - else - { - ChatInterface.SafeMultiMessage(source.Game,"Invalid syntax. Please use \"/players <10,8,6,4>.",Structures.BroadcastType.Error,destination:source.ClientPlayer); - } - break; - } - case Structures.PlayerCommands.ImpostorChange: - { - if (string.IsNullOrEmpty(data)) - { - ChatInterface.SafeMultiMessage(source.Game, "Invalid command data. Please use /help for more information.", Structures.BroadcastType.Error, destination: source.ClientPlayer); - return; - } - if (!source.ClientPlayer.IsHost) - { - ChatInterface.SafeMultiMessage(source.Game, "You are not the host.", Structures.BroadcastType.Error, destination: source.ClientPlayer); - break; - } - if (Byte.TryParse(data, out byte num)) - { - if (!Structures.MaxImpostors.Contains(num)) + if (Byte.TryParse(data, out byte num)) { - ChatInterface.SafeMultiMessage(source.Game, "Invalid number of impostors. Accepted numbers: 3, 2, 1.", Structures.BroadcastType.Error, destination: source.ClientPlayer); + if (!Structures.MaxImpostors.Contains(num)) + { + ChatInterface.SafeMultiMessage(source.Game, "Invalid number of impostors. Accepted numbers: 3, 2, 1.", Structures.BroadcastType.Error, destination: source.ClientPlayer); + } + else + { + source.Game.Options.NumImpostors = num; + source.Game.SyncSettingsAsync(); + } } else { - source.Game.Options.NumImpostors = num; - source.Game.SyncSettingsAsync(); + ChatInterface.SafeMultiMessage(source.Game, "Invalid syntax. Please use \"/impostors <3,2,1>.", Structures.BroadcastType.Error, destination: source.ClientPlayer); } + break; } - else - { - ChatInterface.SafeMultiMessage(source.Game, "Invalid syntax. Please use \"/impostors <3,2,1>.", Structures.BroadcastType.Error, destination: source.ClientPlayer); - } - break; - } } } /// @@ -381,7 +394,7 @@ private void GameEventListener_OnPlayerLeft(IPlayerDestroyedEvent evt) /// /// The network transport containing the data. /// The client that executed the command. - private void DashboardCommandReceived(Structures.BaseMessage message,IWebSocketConnection client) + private void DashboardCommandReceived(Structures.BaseMessage message, IWebSocketConnection client) { //this indicates if the command was successfully parsed. bool commandHandled = true; @@ -419,326 +432,336 @@ private void DashboardCommandReceived(Structures.BaseMessage message,IWebSocketC switch (cmd) { case Structures.DashboardCommands.ServerWideBroadcast: - { - if (isSingle) { - //a broadcast command must contain some data to broadcast. - commandHandled = false; - break; - } + if (isSingle) + { + //a broadcast command must contain some data to broadcast. + commandHandled = false; + break; + } - isSingle = true; //we may get errors. - if (!message.Text.Contains(':')) - { - ApiServer.PushTo("Invalid structure. Please use: /broadcast :", - Structures.ServerSources.DebugSystem, Structures.MessageFlag.ConsoleLogMessage, client); - break; - } + isSingle = true; //we may get errors. + if (!message.Text.Contains(':')) + { + ApiServer.PushTo("Invalid structure. Please use: /broadcast :", + Structures.ServerSources.DebugSystem, Structures.MessageFlag.ConsoleLogMessage, client); + break; + } - var sides = message.Text.Split(':'); - if (string.IsNullOrEmpty(sides[0]) || string.IsNullOrEmpty(sides[1])) - { - ApiServer.PushTo( - "Please specify a color and a message. Example: /broadcast green:Greetings to all players!", - Structures.ServerSources.DebugSystem, Structures.MessageFlag.ConsoleLogMessage, client); - break; - } + var sides = message.Text.Split(':'); + if (string.IsNullOrEmpty(sides[0]) || string.IsNullOrEmpty(sides[1])) + { + ApiServer.PushTo( + "Please specify a color and a message. Example: /broadcast green:Greetings to all players!", + Structures.ServerSources.DebugSystem, Structures.MessageFlag.ConsoleLogMessage, client); + break; + } - if (!KnownColors.Contains(sides[0])) - { - ApiServer.PushTo("Unknown color. Please use /broadcastcolors to list all colors.", - Structures.ServerSources.DebugSystem, Structures.MessageFlag.ConsoleLogMessage, client); - break; - } + if (!KnownColors.Contains(sides[0])) + { + ApiServer.PushTo("Unknown color. Please use /broadcastcolors to list all colors.", + Structures.ServerSources.DebugSystem, Structures.MessageFlag.ConsoleLogMessage, client); + break; + } - isSingle = - false; //no errors. That means we need to inform the user that the broadcast is running. - lock (GameManager.Games) - { - //we broadcast to all games. - //to do this, we compile a list, then broadcast the message in parallel. - Task[] tasks = new Task[GameManager.Games.Count()]; - if (tasks.Length == 0) break; //no lobbies. - int index = 0; - foreach (var game in GameManager.Games) - { - var col = ParseColor(sides[0]); - tasks[index] = ExternalCallback == null - ? ChatInterface.SafeAsyncBroadcast(game, col + sides[1], - Structures.BroadcastType.Manual) - : new Task(() => - ExternalCallback(game, sides[1], Structures.BroadcastType.Information)); - } - - //if this does not return, our server is not working. - var t = new Thread(() => ParallelExecuteBroadcast(tasks)); - t.Start(); - } + isSingle = + false; //no errors. That means we need to inform the user that the broadcast is running. + lock (GameManager.Games) + { + //we broadcast to all games. + //to do this, we compile a list, then broadcast the message in parallel. + Task[] tasks = new Task[GameManager.Games.Count()]; + if (tasks.Length == 0) break; //no lobbies. + int index = 0; + foreach (var game in GameManager.Games) + { + var col = ParseColor(sides[0]); + tasks[index] = ExternalCallback == null + ? ChatInterface.SafeAsyncBroadcast(game, col + sides[1], + Structures.BroadcastType.Manual) + : new Task(() => + ExternalCallback(game, sides[1], Structures.BroadcastType.Information)); + } + + //if this does not return, our server is not working. + var t = new Thread(() => ParallelExecuteBroadcast(tasks)); + t.Start(); + } - break; - } - case Structures.DashboardCommands.ListColors: - { - if (!isSingle) - { - commandHandled = false; break; } - - string response = "Broadcast colors:\n"; - foreach (var color in KnownColors) + case Structures.DashboardCommands.ListColors: { - response += $" {color}\n"; - } + if (!isSingle) + { + commandHandled = false; + break; + } - ApiServer.PushTo(response, Structures.ServerSources.SystemInfo, - Structures.MessageFlag.ConsoleLogMessage, client); - break; - } - case Structures.DashboardCommands.HelpMessage: - { - if (!isSingle) - { - //we actually reject data, because the user might be confused. - //if we accept his command, we might increase his level of confusion. - commandHandled = false; + string response = "Broadcast colors:\n"; + foreach (var color in KnownColors) + { + response += $" {color}\n"; + } + + ApiServer.PushTo(response, Structures.ServerSources.SystemInfo, + Structures.MessageFlag.ConsoleLogMessage, client); break; } - - var helpstr = "Dashboard commands : \n"; - foreach (var command in ApiServer.Commands) + case Structures.DashboardCommands.HelpMessage: { - helpstr += " " + command.Key + " " + command.Value + "\n"; - } + if (!isSingle) + { + //we actually reject data, because the user might be confused. + //if we accept his command, we might increase his level of confusion. + commandHandled = false; + break; + } - ApiServer.PushTo(helpstr, Structures.ServerSources.SystemInfo, - Structures.MessageFlag.ConsoleLogMessage, client); - break; - } - case Structures.DashboardCommands.ListKeys: - { - if (!isSingle) - { - commandHandled = false; + var helpstr = "Dashboard commands : \n"; + foreach (var command in ApiServer.Commands) + { + helpstr += " " + command.Key + " " + command.Value + "\n"; + } + + ApiServer.PushTo(helpstr, Structures.ServerSources.SystemInfo, + Structures.MessageFlag.ConsoleLogMessage, client); break; } - - string response = "Api keys:\n"; - lock (ApiServer.ApiKeys) + case Structures.DashboardCommands.ListKeys: { - foreach (var key in ApiServer.ApiKeys) + if (!isSingle) { - response += $" \"{key}\"\n"; + commandHandled = false; + break; } - } - ApiServer.PushTo(response, Structures.ServerSources.SystemInfo, - Structures.MessageFlag.ConsoleLogMessage, client); - break; - } - case Structures.DashboardCommands.AddKey: - { - if (isSingle) - { - commandHandled = false; + string response = "Api keys:\n"; + lock (ApiServer.ApiKeys) + { + foreach (var key in ApiServer.ApiKeys) + { + response += $" \"{key}\"\n"; + } + } + + ApiServer.PushTo(response, Structures.ServerSources.SystemInfo, + Structures.MessageFlag.ConsoleLogMessage, client); break; } - - lock (ApiServer.ApiKeys) + case Structures.DashboardCommands.AddKey: { - if (!AddApiKey(message.Text)) + if (isSingle) { - ApiServer.PushTo("Cannot add key: the key already exists.", - Structures.ServerSources.DebugSystem, Structures.MessageFlag.ConsoleLogMessage, - client); - isSingle = true; //we inhibit it from sending 'Command executed successfully' + commandHandled = false; + break; } - else + + lock (ApiServer.ApiKeys) { - isSingle = true; //we inhibit it from sending 'Command executed successfully' - ApiServer.PushTo($"The key \"{message.Text}\" is now valid and can be used.", - Structures.ServerSources.CommandSystem, Structures.MessageFlag.ConsoleLogMessage, - client); + if (!AddApiKey(message.Text)) + { + ApiServer.PushTo("Cannot add key: the key already exists.", + Structures.ServerSources.DebugSystem, Structures.MessageFlag.ConsoleLogMessage, + client); + isSingle = true; //we inhibit it from sending 'Command executed successfully' + } + else + { + isSingle = true; //we inhibit it from sending 'Command executed successfully' + ApiServer.PushTo($"The key \"{message.Text}\" is now valid and can be used.", + Structures.ServerSources.CommandSystem, Structures.MessageFlag.ConsoleLogMessage, + client); + } } - } - break; - } - case Structures.DashboardCommands.DeleteKey: - { - if (isSingle) - { - commandHandled = false; break; } + case Structures.DashboardCommands.DeleteKey: + { + if (isSingle) + { + commandHandled = false; + break; + } - lock (ApiServer.ApiKeys) - if (ApiServer.ApiKeys.Count == 1) + lock (ApiServer.ApiKeys) + if (ApiServer.ApiKeys.Count == 1) + { + isSingle = true; + ApiServer.PushTo( + $"The key \"{message.Text}\" cannot be removed, because it is the only remaining key. In order to remove it, please add another key, then execute this command.", + Structures.ServerSources.CommandSystem, Structures.MessageFlag.ConsoleLogMessage, + client); + break; + } + + if (RemoveKey(message.Text)) { isSingle = true; - ApiServer.PushTo( - $"The key \"{message.Text}\" cannot be removed, because it is the only remaining key. In order to remove it, please add another key, then execute this command.", + ApiServer.ApiKeys.Remove(message.Text); + ApiServer.PushTo($"The key \"{message.Text}\" is now gone.", + Structures.ServerSources.CommandSystem, Structures.MessageFlag.ConsoleLogMessage, + client); + } + else + { + isSingle = true; + ApiServer.PushTo($"Cannot delete the key \"{message.Text}\". It is not registered.", Structures.ServerSources.CommandSystem, Structures.MessageFlag.ConsoleLogMessage, client); - break; } - if (RemoveKey(message.Text)) - { - isSingle = true; - ApiServer.ApiKeys.Remove(message.Text); - ApiServer.PushTo($"The key \"{message.Text}\" is now gone.", - Structures.ServerSources.CommandSystem, Structures.MessageFlag.ConsoleLogMessage, - client); - } - else - { - isSingle = true; - ApiServer.PushTo($"Cannot delete the key \"{message.Text}\". It is not registered.", - Structures.ServerSources.CommandSystem, Structures.MessageFlag.ConsoleLogMessage, - client); + break; } - - break; - } case Structures.DashboardCommands.PlayerInfo: - { - if (isSingle) { - commandHandled = false; - break; - } + if (isSingle) + { + commandHandled = false; + break; + } - StringBuilder response = new StringBuilder(); - response.Append("Players matching request: "); - bool matches = false; - foreach (var player in GetPlayers()) - { - if (player.Character == null) continue; - if (player.Character.PlayerInfo.PlayerName.Contains(message.Text, - StringComparison.InvariantCultureIgnoreCase)) + StringBuilder response = new StringBuilder(); + response.Append("Players matching request: "); + bool matches = false; + foreach (var player in GetPlayers()) { - if (!matches) + if (player.Character == null) continue; + if (player.Character.PlayerInfo.PlayerName.Contains(message.Text, + StringComparison.InvariantCultureIgnoreCase)) { - matches = true; - response.Append("\n"); + if (!matches) + { + matches = true; + response.Append("\n"); + } + + response.AppendLine( + $" {player.Character.PlayerInfo.PlayerName}, Address: {player.Client.Connection.EndPoint.Address}:"); + response.AppendLine($" Lobby: {player.Game.Code.Code}"); + response.AppendLine($" Dead: {player.Character.PlayerInfo.IsDead}"); + response.AppendLine($" Impostor: {player.Character.PlayerInfo.IsImpostor}"); + response.AppendLine( + $" Color: {(Structures.PlayerColor)player.Character.PlayerInfo.Color}"); + response.AppendLine( + $" Hat: {(Structures.HatId)player.Character.PlayerInfo.Hat}"); + response.AppendLine( + $" Pet: {(Structures.PetId)player.Character.PlayerInfo.Pet}"); + response.AppendLine( + $" Skin: {(Structures.SkinId)player.Character.PlayerInfo.Skin}"); } - - response.AppendLine( - $" {player.Character.PlayerInfo.PlayerName}, Address: {player.Client.Connection.EndPoint.Address}:"); - response.AppendLine($" Lobby: {player.Game.Code.Code}"); - response.AppendLine($" Dead: {player.Character.PlayerInfo.IsDead}"); - response.AppendLine($" Impostor: {player.Character.PlayerInfo.IsImpostor}"); - response.AppendLine( - $" Color: {(Structures.PlayerColor) player.Character.PlayerInfo.ColorId}"); - response.AppendLine( - $" Hat: {(Structures.HatId) player.Character.PlayerInfo.HatId}"); - response.AppendLine( - $" Pet: {(Structures.PetId) player.Character.PlayerInfo.PetId}"); - response.AppendLine( - $" Skin: {(Structures.SkinId) player.Character.PlayerInfo.SkinId}"); } - } - if (!matches) response.Append("No matches."); - ApiServer.PushTo(response.ToString(), Structures.ServerSources.SystemInfo, - Structures.MessageFlag.ConsoleLogMessage, client); - isSingle = true; - break; - } - case Structures.DashboardCommands.ListLogs: - { - if (!isSingle) - { - commandHandled = false; - break; - } - - isSingle = true; - var logs = LogManager.GetLogNames(); - if (logs == null || logs.Length == 0) - { - ApiServer.PushTo("There are no logs, which might be a server error.", - Structures.ServerSources.DebugSystemCritical, Structures.MessageFlag.ConsoleLogMessage, - client); + if (!matches) response.Append("No matches."); + ApiServer.PushTo(response.ToString(), Structures.ServerSources.SystemInfo, + Structures.MessageFlag.ConsoleLogMessage, client); + isSingle = true; break; } - else + case Structures.DashboardCommands.ListLogs: { - var response = "Log dates:\n"; - foreach (var log in logs) + if (!isSingle) { - response += Path.GetFileNameWithoutExtension(log) + '\n'; + commandHandled = false; + break; } - ApiServer.PushTo(response, Structures.ServerSources.SystemInfo, - Structures.MessageFlag.ConsoleLogMessage, client); - } - - break; - } - case Structures.DashboardCommands.FetchLog: - { - if (isSingle) - { - commandHandled = false; - break; - } + isSingle = true; + var logs = LogManager.GetLogNames(); + if (logs == null || logs.Length == 0) + { + ApiServer.PushTo("There are no logs, which might be a server error.", + Structures.ServerSources.DebugSystemCritical, Structures.MessageFlag.ConsoleLogMessage, + client); + break; + } + else + { + var response = "Log dates:\n"; + foreach (var log in logs) + { + response += Path.GetFileNameWithoutExtension(log) + '\n'; + } - isSingle = true; - var logs = LogManager.GetLogNames(); - var log = Path.Combine("hqlogs", message.Text + ".self"); + ApiServer.PushTo(response, Structures.ServerSources.SystemInfo, + Structures.MessageFlag.ConsoleLogMessage, client); + } - if (!logs.Contains(log)) - { - ApiServer.PushTo("", "", Structures.MessageFlag.FetchLogs, client, new float[] {0}); + break; } - else + case Structures.DashboardCommands.FetchLog: { - ApiServer.PushTo(message.Text + ".csv", "", Structures.MessageFlag.FetchLogs, client, - new float[] {1}); - } + if (isSingle) + { + commandHandled = false; + break; + } - break; - } - case Structures.DashboardCommands.AnnouncementMultiCommand: - { - if (isSingle) - { isSingle = true; - ApiServer.PushTo("Invalid syntax. Please use \"/announcement (set ... /clear).\"! Example: \"/announcement set Greetings to all!\"", - Structures.ServerSources.DebugSystem, Structures.MessageFlag.ConsoleLogMessage, client); - break; - } + var logs = LogManager.GetLogNames(); + var log = Path.Combine("hqlogs", message.Text + ".self"); + + if (!logs.Contains(log)) + { + ApiServer.PushTo("", "", Structures.MessageFlag.FetchLogs, client, new float[] { 0 }); + } + else + { + ApiServer.PushTo(message.Text + ".csv", "", Structures.MessageFlag.FetchLogs, client, + new float[] { 1 }); + } - if (message.Text.StartsWith("clear")) - { - isSingle = false; //inform that it was executed. - AnnouncementManager.DisableAnnouncement(); break; } - else if (message.Text.StartsWith("set ")) - { - message.Text = message.Text.Replace("set ", ""); - isSingle = true; - AnnouncementManager.SetMessage(message.Text); - ApiServer.PushTo($"The announcement has been set: \"{message.Text}\"!", - Structures.ServerSources.DebugSystem, Structures.MessageFlag.ConsoleLogMessage, client); - } - else + case Structures.DashboardCommands.AnnouncementMultiCommand: { - commandHandled = false; - } + if (isSingle) + { + isSingle = true; + ApiServer.PushTo("Invalid syntax. Please use \"/announcement (set ... /clear).\"! Example: \"/announcement set Greetings to all!\"", + Structures.ServerSources.DebugSystem, Structures.MessageFlag.ConsoleLogMessage, client); + break; + } - break; + if (message.Text.StartsWith("clear")) + { + isSingle = false; //inform that it was executed. + if (Configuration.LegacyAnnouncement) + { + AnnouncementManager.DisableAnnouncement(); + } + else + { + + } + break; + } + else if (message.Text.StartsWith("set ")) + { + message.Text = message.Text.Replace("set ", ""); + isSingle = true; + if (Configuration.LegacyAnnouncement) + { + AnnouncementManager.SetMessage(message.Text); + } + ApiServer.PushTo($"The announcement has been set: \"{message.Text}\"!", + Structures.ServerSources.DebugSystem, Structures.MessageFlag.ConsoleLogMessage, client); + } + else + { + commandHandled = false; + } - } + break; + + } default: - OnExternalCommandInvoked?.Invoke(cmd,message.Text,isSingle,client); + OnExternalCommandInvoked?.Invoke(cmd, message.Text, isSingle, client); isSingle = true; //inhibit 'Command executed successfully'. break; - + } if (commandHandled) @@ -760,7 +783,7 @@ private void DashboardCommandReceived(Structures.BaseMessage message,IWebSocketC { } - catch(Exception ex) + catch (Exception ex) { LogManager.LogError(ex.ToString(), Shared.ErrorLocation.DashboardCommandHandler); } @@ -774,7 +797,7 @@ private void ParallelExecuteBroadcast(Task[] targets) //this should take care of some issues. Parallel.ForEach(targets, Options, (broadcastTask) => { - Task.Run(()=>broadcastTask); + Task.Run(() => broadcastTask); }); } /// @@ -868,7 +891,7 @@ private string ParseColor(string input) /// The message to log. public void LogPlugin(string sourcePluginName, string message) { - LogManager.LogPlugin(sourcePluginName,message); + LogManager.LogPlugin(sourcePluginName, message); } /// /// This is an old function, and can be used by plugins to log warnings to the console. @@ -893,5 +916,10 @@ public delegate void DelDashboardCommandInvoked(string command, string data, boo /// This is called when an external player command (a command registered by a plugin) is called. /// public event DelDashboardCommandInvoked OnExternalCommandInvoked; + + /// + /// This is called when an announcement is requested + /// + } } \ No newline at end of file diff --git a/ImpostorHQ.Command/Impostor.Commands.Core/Impostor.Commands.Core.csproj b/ImpostorHQ.Command/Impostor.Commands.Core/Impostor.Commands.Core.csproj index 5bf0e6b..7089ba3 100644 --- a/ImpostorHQ.Command/Impostor.Commands.Core/Impostor.Commands.Core.csproj +++ b/ImpostorHQ.Command/Impostor.Commands.Core/Impostor.Commands.Core.csproj @@ -16,7 +16,7 @@ - + diff --git a/ImpostorHQ.Command/Impostor.Commands.Core/Structures.cs b/ImpostorHQ.Command/Impostor.Commands.Core/Structures.cs index 44abb49..8ec8983 100644 --- a/ImpostorHQ.Command/Impostor.Commands.Core/Structures.cs +++ b/ImpostorHQ.Command/Impostor.Commands.Core/Structures.cs @@ -94,6 +94,7 @@ public class PluginConfiguration public ushort WebApiPort { get; set; } public ushort WebsitePort { get; set; } public string ListenInterface { get; set; } + public bool LegacyAnnouncement { get; set; } #endregion public static PluginConfiguration GetDefaultConfig() { @@ -104,6 +105,7 @@ public static PluginConfiguration GetDefaultConfig() cfg.WebApiPort = 22023; cfg.WebsitePort = 22024; cfg.ListenInterface = "0.0.0.0"; + cfg.LegacyAnnouncement = false; #endregion return cfg; } diff --git a/ImpostorHQ.Command/Plugin.Test/MainClass.cs b/ImpostorHQ.Command/Plugin.Test/MainClass.cs index f1a87a3..cec716c 100644 --- a/ImpostorHQ.Command/Plugin.Test/MainClass.cs +++ b/ImpostorHQ.Command/Plugin.Test/MainClass.cs @@ -24,7 +24,7 @@ public void Load(QuiteExtendableDirectInterface reference,PluginFileSystem pfs) public Dictionary HijackedPlayers = new Dictionary(); private void MyFunction() { - PluginBase.UnsafeDirectReference.ConsolePluginStatus("Greetings from the test plugin!"); + PluginBase.UnsafeDirectReference.ConsolePluginStatus("Greetings from the test plugin! Warning: This should not be used in production environments!"); PluginBase.ApiServer.RegisterCommand("/greet", "=> A test command, added by the test plugin."); //this is a 'low level' hook, showing how to make your own handler. //Please use the default OnDashboardCommandReceived event if your structure corresponds to the default one. @@ -70,7 +70,7 @@ private void MyFunction() if(clientPlayer.Character==null) continue; if (clientPlayer.Character.PlayerInfo.PlayerName.ToLower().Equals(data)) { - await clientPlayer.Character.SetMurderedAsync().ConfigureAwait(false); + await clientPlayer.Character.MurderPlayerAsync(clientPlayer.Character).ConfigureAwait(false); return; } }