Sistema de comando simple -- # camp codereview Relacionados El problema

Simple Command system


1
vote

problema

Español

A continuación, he codificado un sistema de comando simple que pasa una cadena a un método y verifica si la primera palabra dividida por ('') es una clave en el diccionario de comandos registrados, si es así, ejecuta la clase que se almacena como el valor de la entrada del diccionario.

Pocos mensajes de lo que se escribe para los comandos

  @mycommand hello :ohnicecommand John .setamount 10000   

commandohandller.cs:

  using System; using System.Collections.Generic;  namespace Sirius.Base.Game.Habbo.Commands {     using Commands;     using Commands.Habbo;     using Other.GameClients;      internal class CommandHandler     {         private readonly Dictionary<string, ICommand> _commandsRegistered;          internal CommandHandler()         {             _commandsRegistered = new Dictionary<string, ICommand>();              RegisterCommands();         }          private void RegisterCommands()         {             RegisterCommand(":info", new InfoCommand());         }          public bool IsCommandInput(Player player, string input)         {             ICommand command;              var cmdString = input.Split(' ')[0];              if (!_commandsRegistered.TryGetValue(cmdString, out command))             {                 return false;             }              if (command.PermissionRequired != "" && !player.GetPlayerData().GetPermissions().HasCommand(command.PermissionRequired))             {                 return false;             }              if (command.NumberOfParameters < input.Split(' ').Length)             {                 player.SendWhisper("Invalid command syntax -- " + cmdString + " " + command.CommandParameters);                 return true;             }              DateTime lastExecuted;              if (player.GetPlayerData()._commandCooldowns.TryGetValue(cmdString, out lastExecuted))             {                 var commandSpan = DateTime.Now - lastExecuted;                  if (command.CommandCooldown && commandSpan.TotalSeconds < (command.CommandCooldownMs / 1000))                 {                     player.SendNotification("You're cooling down from this command! [" + commandSpan.TotalSeconds + "/" + (command.CommandCooldownMs / 1000) + "]");                     return true;                 }             }             else             {                 player.GetPlayerData()._commandCooldowns.Add(cmdString, DateTime.Now);             }              command.ProcessCommand(player);              return true;         }          private void RegisterCommand(string commandName, ICommand command)         {             _commandsRegistered.Add(commandName, command);         }     } }   

icommand:

  namespace Sirius.Base.Game.Habbo.Commands.Commands {     using Other.GameClients;      internal interface ICommand     {         void ProcessCommand(Player player);         string PermissionRequired { get; }         int NumberOfParameters { get; }         string CommandParameters { get; }         string CommandDescription { get; }         bool CommandCooldown { get; }         int CommandCooldownMs { get; }     } }   

infocommand (solo 1 de muchos comandos)

  using System; using System.Text;  namespace Sirius.Base.Game.Habbo.Commands.Commands.Habbo {     using Other.Communication.Packets.Outgoing.Notifications;     using Other.GameClients;      internal sealed class InfoCommand : ICommand     {         public string PermissionRequired => "";         public int NumberOfParameters => 0;         public string CommandParameters => "";         public string CommandDescription => "Lets you view information about the server.";         public bool CommandCooldown => true;         public int CommandCooldownMs => 5000;          public void ProcessCommand(Player player)         {             // do what ever you want the command to do here...         }     } }   
Original en ingles

Below I have coded a simple command system that passes a string to a method and checks if the first word split by (' ') is a key in the registered commands dictionary, if it is, it executes the class that is stored as the dictionary entry's value.

few examles of what is typed for commands

@mycommand hello :ohnicecommand John .setamount 10000 

CommandHandler.cs:

using System; using System.Collections.Generic;  namespace Sirius.Base.Game.Habbo.Commands {     using Commands;     using Commands.Habbo;     using Other.GameClients;      internal class CommandHandler     {         private readonly Dictionary<string, ICommand> _commandsRegistered;          internal CommandHandler()         {             _commandsRegistered = new Dictionary<string, ICommand>();              RegisterCommands();         }          private void RegisterCommands()         {             RegisterCommand(":info", new InfoCommand());         }          public bool IsCommandInput(Player player, string input)         {             ICommand command;              var cmdString = input.Split(' ')[0];              if (!_commandsRegistered.TryGetValue(cmdString, out command))             {                 return false;             }              if (command.PermissionRequired != "" && !player.GetPlayerData().GetPermissions().HasCommand(command.PermissionRequired))             {                 return false;             }              if (command.NumberOfParameters < input.Split(' ').Length)             {                 player.SendWhisper("Invalid command syntax -- " + cmdString + " " + command.CommandParameters);                 return true;             }              DateTime lastExecuted;              if (player.GetPlayerData()._commandCooldowns.TryGetValue(cmdString, out lastExecuted))             {                 var commandSpan = DateTime.Now - lastExecuted;                  if (command.CommandCooldown && commandSpan.TotalSeconds < (command.CommandCooldownMs / 1000))                 {                     player.SendNotification("You're cooling down from this command! [" + commandSpan.TotalSeconds + "/" + (command.CommandCooldownMs / 1000) + "]");                     return true;                 }             }             else             {                 player.GetPlayerData()._commandCooldowns.Add(cmdString, DateTime.Now);             }              command.ProcessCommand(player);              return true;         }          private void RegisterCommand(string commandName, ICommand command)         {             _commandsRegistered.Add(commandName, command);         }     } } 

ICommand:

namespace Sirius.Base.Game.Habbo.Commands.Commands {     using Other.GameClients;      internal interface ICommand     {         void ProcessCommand(Player player);         string PermissionRequired { get; }         int NumberOfParameters { get; }         string CommandParameters { get; }         string CommandDescription { get; }         bool CommandCooldown { get; }         int CommandCooldownMs { get; }     } } 

InfoCommand (just 1 of many commands)

using System; using System.Text;  namespace Sirius.Base.Game.Habbo.Commands.Commands.Habbo {     using Other.Communication.Packets.Outgoing.Notifications;     using Other.GameClients;      internal sealed class InfoCommand : ICommand     {         public string PermissionRequired => "";         public int NumberOfParameters => 0;         public string CommandParameters => "";         public string CommandDescription => "Lets you view information about the server.";         public bool CommandCooldown => true;         public int CommandCooldownMs => 5000;          public void ProcessCommand(Player player)         {             // do what ever you want the command to do here...         }     } } 
  
   
   

Lista de respuestas

6
 
vote
vote
La mejor respuesta
 

El mayor problema que veo es que tiene que manualmente registrarse cada uno y cada uno . ¿Por qué molestarse? ¿Por qué no solo obtener una lista de todos los comandos que implementan ICommand a través de la reflexión? La velocidad no debe ser un problema enorme porque asumo que usted hace esto en algún tipo de inicio.

  var baseCommandInterface = typeof(ICommand); var commands = AppDomain.CurrentDomain.GetAssemblies()     .SelectMany(s => s.GetTypes())     .Where(p => baseCommandInterface.IsAssignableFrom(p));   

Ahora solo enumere commands y eche y opera en ellos. La vida debe ser mucho más fácil de esta manera.


Siguiente, ¿por qué molestarse con un bool y int4 para enfriar hacia abajo? Simplemente use un int? , si es null No hay enfriamiento hacia abajo, si es 9988776655544337 , entonces es el tiempo de infrecente. Bastante simple.


Usted usa el término Command demasiadas veces para mis gustos.

  internal interface ICommand {     void Process(Player player);     string PermissionRequired { get; }     int NumberOfParameters { get; }     string Parameters { get; }     string Description { get; }     int? CooldownMs { get; } }   

Incluso entonces, 99887766555443310 es verdaderamente innecesario. Apuesto a que hay un separador de algún tipo entre los comandos en la cadena var baseCommandInterface = typeof(ICommand); var commands = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(s => s.GetTypes()) .Where(p => baseCommandInterface.IsAssignableFrom(p)); 1

  var baseCommandInterface = typeof(ICommand); var commands = AppDomain.CurrentDomain.GetAssemblies()     .SelectMany(s => s.GetTypes())     .Where(p => baseCommandInterface.IsAssignableFrom(p)); 2 

luego var baseCommandInterface = typeof(ICommand); var commands = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(s => s.GetTypes()) .Where(p => baseCommandInterface.IsAssignableFrom(p)); 3 se convierte en un var baseCommandInterface = typeof(ICommand); var commands = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(s => s.GetTypes()) .Where(p => baseCommandInterface.IsAssignableFrom(p)); 4 que significa que puede usar var baseCommandInterface = typeof(ICommand); var commands = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(s => s.GetTypes()) .Where(p => baseCommandInterface.IsAssignableFrom(p)); 5 en lugar de var baseCommandInterface = typeof(ICommand); var commands = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(s => s.GetTypes()) .Where(p => baseCommandInterface.IsAssignableFrom(p)); 6 . Este también significa que puede extrapolar más y definir una clase abstracta para esto, y agregar un método 998877766555443317 :

  var baseCommandInterface = typeof(ICommand); var commands = AppDomain.CurrentDomain.GetAssemblies()     .SelectMany(s => s.GetTypes())     .Where(p => baseCommandInterface.IsAssignableFrom(p)); 8  

entonces en un comando real:

  var baseCommandInterface = typeof(ICommand); var commands = AppDomain.CurrentDomain.GetAssemblies()     .SelectMany(s => s.GetTypes())     .Where(p => baseCommandInterface.IsAssignableFrom(p)); 9  

Luego, creó su propio sistema que requiere código de placa de calderilla, y extraí el código de la placa de la caldera.

 

The biggest issue I see is you have to manually register each and every command. Why bother? Why not just get a list of all commands that implement ICommand through Reflection? Speed shouldn't be a huge problem because I assume you do this on some sort of start-up.

var baseCommandInterface = typeof(ICommand); var commands = AppDomain.CurrentDomain.GetAssemblies()     .SelectMany(s => s.GetTypes())     .Where(p => baseCommandInterface.IsAssignableFrom(p)); 

Now just enumerate commands and cast and operate on them. Life should be a lot easier this way.


Next, why bother with a bool and int for cool downs? Just use an int?, if it's null then there's no cool down, if its >0 then that's the cool down time. Pretty simple.


You use the term Command way too many times for my tastes.

internal interface ICommand {     void Process(Player player);     string PermissionRequired { get; }     int NumberOfParameters { get; }     string Parameters { get; }     string Description { get; }     int? CooldownMs { get; } } 

Even then, NumberOfParameters is truly unnecessary. I'd bet there is a separator of some sort between commands in the Parameters string, which really shouldn't be a string, but should be something like the following:

public class CommandParameter {     public string Name { get; set; }     public Type Type { get; set; }     public string Description { get; set; } } 

Then Parameters becomes an IEnumerable<CommandParameter> which means you can use Parameters.Count in place of NumberOfParameters. This also means you can extrapolate further and define an abstract class for this, and add a CanProcess(Player player) method:

public abstract class BaseCommand : ICommand {     private List<CommandParameter> _parameters = new List<CommandParameter>();     public IEnumerable<CommandParameter> Parameters => _parameters;      public int? Cooldown { get; protected set; }     public string Description { get; protected set; }     public string PermissionRequired { get; protected set; }      public abstract void ProcessCommand(Player player);      public bool CanProcess(Player player)     {         // Check cool down, permissions, ban list, etc.     } } 

Then in an actual command:

public class InfoCommand : BaseCommand {     public InfoCommand()     {         Cooldown = 5000;         Description = "Lets you view information about the server.";     }      public override void ProcessCommand(Player player)     {         if (!CanProcess(player))         {             // I'm throwing an exception, but you could just `return` and send a message or whatever             throw new InvalidOperationException("You have either exceeded the cool down, do not have permissions, or are banned. Please try again later.");         }          // Process our command here     } } 

Then you created your own system that requires boilerplate code, and extracted that boilerplate code away.

 
 
     
     

Relacionados problema

0  Creación de múltiples objetos del extracto de SQL Server  ( Creating multiple objects from sql server extract ) 
He creado una solución prototipo simplificada como una especie de prueba de concepto antes de comenzar un programa más grande. Aquí están los datos de prueb...

7  Versión LINQ del algoritmo de recocido simulado  ( Linq version of the simulated annealing algorithm ) 
Decidí intentarlo e implementar (una versión de) la recocido simulado algoritmo usando solo linq , solo para ver si pudiera. Me encantaría si alguien pudi...

35  Demasiados bucles en la aplicación de dibujo  ( Too many loops in drawing app ) 
Tengo un método que tiene muchos bucles: #ifndef __RUNES_STRUCTURES_H #define __RUNES_STRUCTURES_H /* Runes structures. */ struct Game { char board[2...

6  ¿Está mi delegado definió la forma correcta y necesita transformarse en una mariposa bonita?  ( Is my delegate defined the right way and does it need to transform to a pretty e ) 
He leído tantos Historias de tiempo de cama e inserciones de cómo < fuertes> delegados trabajo y por qué eventos deben ser reemplazados por los delegado...

3  Mientras que el bucle usa variables adicionales, ¿se puede limpiar esto?  ( While loop uses extra variables can this be cleaned up ) 
Una pieza de mi programa permite que se utilice el bucle y la incremento de una entidad seleccionada en un bucle de tiempo en otro lugar. Aquí hay una muestra...

6  PRIGO DE PODER TICTACTOO EN C #  ( Command prompt tictactoe in c ) 
Escribí un juego básico de comando TIC TAC TOE juego. Quiero saber qué se puede mejorar en términos de modelado y qué errores he hecho (si corresponde). vo...

3  Genéricos anulables - implementando secuencialSearchst en C #  ( Nullable generics implementing sequentialsearchst in c ) 
Para fines de aprendizaje, estoy implementando cierto código de SEDEDWICK & AMP; Los algoritmos de Wayne, cuarta edición . Debido a las características del...

3  Generador de imágenes de Mandelbrot con iteración paralela  ( Mandelbrot image generator with parallel iteration ) 
Actualmente estoy tratando de optimizar esta clase que tengo para la generación fractal. La ecuación está destinada a ser conectable; He usado z => z*z + c ...

7  Colecciones vacías en caché  ( Cached empty collections ) 
A menudo necesito devolver las colecciones vacías. Uno de esos días, escribí lo siguiente para devolver una instancia en caché: public static class Array<...

1  TPL HILO FUGA Y FUGA DE MEMORIA  ( Tpl thread leak and memory leak ) 
Estoy tratando de rastrear lo que supongo que debo ser una pérdida de memoria / hilo en uno de mis programas. Mi programa usa una función para cargar un arc...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos