2021-02-20 20:52:23 +00:00
using System.Collections.Generic ;
2021-02-20 22:56:55 +00:00
using System.Linq ;
2021-02-20 20:52:23 +00:00
using SanAndreasUnity.Net ;
using UnityEngine ;
namespace SanAndreasUnity.Commands
{
public class CommandManager : MonoBehaviour
{
public static CommandManager Singleton { get ; private set ; }
readonly Dictionary < string , CommandInfo > m_registeredCommands = new Dictionary < string , CommandInfo > ( ) ;
public IEnumerable < string > RegisteredCommands = > m_registeredCommands . Keys ;
public static string invalidSyntaxText = > "Invalid syntax" ;
[SerializeField] private List < string > m_forbiddenCommands = new List < string > ( ) ;
/// <summary> Forbidden commands can not be registered. </summary>
public List < string > ForbiddenCommands = > m_forbiddenCommands ;
[SerializeField] private bool m_registerHelpCommand = true ;
public struct CommandInfo
{
public string command ;
2021-02-22 14:50:43 +00:00
public string description ;
2021-02-20 20:52:23 +00:00
public System . Func < ProcessCommandContext , ProcessCommandResult > commandHandler ;
public bool allowToRunWithoutServerPermissions ;
2021-02-22 14:50:43 +00:00
public bool runOnlyOnServer ;
2021-02-20 20:52:23 +00:00
public CommandInfo ( string command , bool allowToRunWithoutServerPermissions )
2021-02-22 14:50:43 +00:00
: this ( )
2021-02-20 20:52:23 +00:00
{
this . command = command ;
this . allowToRunWithoutServerPermissions = allowToRunWithoutServerPermissions ;
2021-02-22 14:50:43 +00:00
}
public CommandInfo ( string command , string description , bool allowToRunWithoutServerPermissions , bool runOnlyOnServer )
: this ( )
{
this . command = command ;
this . description = description ;
this . allowToRunWithoutServerPermissions = allowToRunWithoutServerPermissions ;
this . runOnlyOnServer = runOnlyOnServer ;
2021-02-20 20:52:23 +00:00
}
}
public class ProcessCommandResult
{
public string response ;
public static ProcessCommandResult UnknownCommand = > new ProcessCommandResult { response = "Unknown command" } ;
public static ProcessCommandResult InvalidCommand = > new ProcessCommandResult { response = "Invalid command" } ;
public static ProcessCommandResult NoPermissions = > new ProcessCommandResult { response = "You don't have permissions to run this command" } ;
2021-02-22 14:50:43 +00:00
public static ProcessCommandResult CanOnlyRunOnServer = > new ProcessCommandResult { response = "This command can only run on server" } ;
public static ProcessCommandResult LimitInterval ( float interval ) = > new ProcessCommandResult { response = $"You must wait for {interval} seconds before running this command again" } ;
2021-02-20 20:52:23 +00:00
}
public class ProcessCommandContext
{
public string command ;
public bool hasServerPermissions ;
2021-02-20 23:46:48 +00:00
public Player player ;
2021-02-20 20:52:23 +00:00
}
void Awake ( )
{
if ( null = = Singleton )
Singleton = this ;
if ( m_registerHelpCommand )
RegisterCommand ( new CommandInfo { command = "help" , commandHandler = ProcessHelpCommand , allowToRunWithoutServerPermissions = true } ) ;
}
public bool RegisterCommand ( CommandInfo commandInfo )
{
commandInfo . command = commandInfo . command . Trim ( ) ;
if ( this . ForbiddenCommands . Contains ( commandInfo . command ) )
return false ;
if ( m_registeredCommands . ContainsKey ( commandInfo . command ) )
return false ;
m_registeredCommands . Add ( commandInfo . command , commandInfo ) ;
return true ;
}
public bool RemoveCommand ( string command )
{
return m_registeredCommands . Remove ( command ) ;
}
public static string [ ] SplitCommandIntoArguments ( string command )
{
// TODO: add support for arguments that have spaces, i.e. those enclosed with quotes
return command . Split ( new string [ ] { " " , "\t" } , System . StringSplitOptions . RemoveEmptyEntries ) ;
}
public static string GetRestOfTheCommand ( string command , int argumentIndex )
{
if ( argumentIndex < 0 )
return "" ;
string [ ] args = SplitCommandIntoArguments ( command ) ;
if ( argumentIndex > args . Length - 2 )
return "" ;
return string . Join ( " " , args , argumentIndex + 1 , args . Length - argumentIndex - 1 ) ;
}
2021-02-20 23:46:48 +00:00
ProcessCommandResult ProcessCommand ( ProcessCommandContext context )
2021-02-20 20:52:23 +00:00
{
2021-02-20 23:46:48 +00:00
if ( string . IsNullOrWhiteSpace ( context . command ) )
2021-02-20 20:52:23 +00:00
return ProcessCommandResult . UnknownCommand ;
2021-02-20 23:46:48 +00:00
string [ ] arguments = SplitCommandIntoArguments ( context . command ) ;
2021-02-20 20:52:23 +00:00
if ( 0 = = arguments . Length )
return ProcessCommandResult . InvalidCommand ;
if ( ! m_registeredCommands . TryGetValue ( arguments [ 0 ] , out CommandInfo commandInfo ) )
return ProcessCommandResult . UnknownCommand ;
2021-02-22 14:50:43 +00:00
if ( commandInfo . runOnlyOnServer & & ! NetStatus . IsServer )
return ProcessCommandResult . CanOnlyRunOnServer ;
2021-02-20 23:46:48 +00:00
if ( ! context . hasServerPermissions & & ! commandInfo . allowToRunWithoutServerPermissions )
2021-02-20 20:52:23 +00:00
return ProcessCommandResult . NoPermissions ;
return commandInfo . commandHandler ( context ) ;
}
public ProcessCommandResult ProcessCommandAsServer ( string command )
{
2021-02-20 23:46:48 +00:00
return ProcessCommand ( new ProcessCommandContext { command = command , hasServerPermissions = true } ) ;
2021-02-20 20:52:23 +00:00
}
public ProcessCommandResult ProcessCommandForPlayer ( Player player , string command )
{
bool hasServerPermissions = player = = Player . Local ;
2021-02-20 23:46:48 +00:00
return ProcessCommand ( new ProcessCommandContext
{
command = command ,
hasServerPermissions = hasServerPermissions ,
player = player ,
} ) ;
2021-02-20 20:52:23 +00:00
}
ProcessCommandResult ProcessHelpCommand ( ProcessCommandContext context )
{
2021-02-20 22:56:55 +00:00
string response = "List of available commands: " +
string . Join ( ", " , m_registeredCommands
. Where ( pair = > context . hasServerPermissions | | pair . Value . allowToRunWithoutServerPermissions )
. Select ( pair = > pair . Key ) ) ;
2021-02-20 20:52:23 +00:00
return new ProcessCommandResult { response = response } ;
}
public bool HasCommand ( string command )
{
return m_registeredCommands . ContainsKey ( command ) ;
}
}
}