-
-
Notifications
You must be signed in to change notification settings - Fork 78
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add some class for parsing command arguments
- Loading branch information
1 parent
ff01e1d
commit 414db37
Showing
13 changed files
with
498 additions
and
57 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
33 changes: 33 additions & 0 deletions
33
src/MineCase.Server.Interfaces/Game/Commands/CommandMap.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Text; | ||
|
||
namespace MineCase.Server.Game.Commands | ||
{ | ||
public class CommandMap | ||
{ | ||
private readonly Dictionary<string, ICommand> _commandMap = new Dictionary<string, ICommand>(); | ||
|
||
public void RegisterCommand(ICommand command) | ||
{ | ||
_commandMap.Add(command.Name, command); | ||
} | ||
|
||
public bool Dispatch(ICommandSender sender, string commandContent) | ||
{ | ||
var (commandName, args) = CommandParser.ParseCommand(commandContent); | ||
|
||
try | ||
{ | ||
return _commandMap.TryGetValue(commandName, out var command) && | ||
(command.NeededPermission == null || sender.HasPermission(command.NeededPermission).Result) && | ||
command.Execute(sender, args); | ||
} | ||
catch (CommandException e) | ||
{ | ||
sender.SendMessage($"在执行指令 {commandName} 之时发生指令相关的异常 {e}"); | ||
return false; | ||
} | ||
} | ||
} | ||
} |
87 changes: 87 additions & 0 deletions
87
src/MineCase.Server.Interfaces/Game/Commands/CommandParser.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Diagnostics; | ||
using System.Diagnostics.Contracts; | ||
using System.Linq; | ||
using System.Text; | ||
|
||
namespace MineCase.Server.Game.Commands | ||
{ | ||
/// <summary> | ||
/// 未解析参数 | ||
/// </summary> | ||
/// <remarks>用于参数无法解析或当前不需要已解析的形式的情形</remarks> | ||
public class UnresolvedArgument : ICommandArgument | ||
{ | ||
public string RawContent { get; } | ||
|
||
public UnresolvedArgument(string rawContent) | ||
{ | ||
if (rawContent == null) | ||
{ | ||
throw new ArgumentNullException(nameof(rawContent)); | ||
} | ||
|
||
if (rawContent.Length <= 0) | ||
{ | ||
throw new ArgumentException($"{nameof(rawContent)} 不得为空", nameof(rawContent)); | ||
} | ||
|
||
RawContent = rawContent; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// 命令分析器 | ||
/// </summary> | ||
public static class CommandParser | ||
{ | ||
/// <summary> | ||
/// 分析命令 | ||
/// </summary> | ||
/// <param name="input">输入,即作为命令被分析的文本</param> | ||
/// <returns>命令名及命令的参数</returns> | ||
public static (string, IList<ICommandArgument>) ParseCommand(string input) | ||
{ | ||
if (input == null || input.Length < 2) | ||
{ | ||
throw new ArgumentException("输入不合法", nameof(input)); | ||
} | ||
|
||
var splitResult = input.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); | ||
if (splitResult.Length == 0) | ||
{ | ||
throw new ArgumentException($"输入 ({input}) 不合法"); | ||
} | ||
|
||
return (splitResult[0], ParseCommandArgument(splitResult.Skip(1))); | ||
} | ||
|
||
// 参数必须保持有序,因此返回值使用 IList 而不是 IEnumerable | ||
private static IList<ICommandArgument> ParseCommandArgument(IEnumerable<string> input) | ||
{ | ||
var result = new List<ICommandArgument>(); | ||
|
||
foreach (var arg in input) | ||
{ | ||
Contract.Assert(arg != null && arg.Length > 1); | ||
|
||
// TODO: 使用更加具有可扩展性的方法 | ||
switch (arg[0]) | ||
{ | ||
case '@': | ||
result.Add(new TargetSelectorArgument(arg)); | ||
break; | ||
case '{': | ||
result.Add(new DataTagArgument(arg)); | ||
break; | ||
default: | ||
result.Add(new UnresolvedArgument(arg)); | ||
break; | ||
} | ||
} | ||
|
||
return result; | ||
} | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
src/MineCase.Server.Interfaces/Game/Commands/DataTagArgument.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Text; | ||
using MineCase.Nbt.Tags; | ||
|
||
namespace MineCase.Server.Game.Commands | ||
{ | ||
public class DataTagArgument : UnresolvedArgument | ||
{ | ||
public NbtCompound Tag { get; } | ||
|
||
public DataTagArgument(string rawContent) | ||
: base(rawContent) | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Threading.Tasks; | ||
|
||
namespace MineCase.Server.Game.Commands | ||
{ | ||
/// <summary> | ||
/// 命令参数接口 | ||
/// </summary> | ||
public interface ICommandArgument | ||
{ | ||
/// <summary> | ||
/// Gets 命令参数的原本内容 | ||
/// </summary> | ||
string RawContent { get; } | ||
} | ||
|
||
/// <summary> | ||
/// 命令接口 | ||
/// </summary> | ||
public interface ICommand | ||
{ | ||
/// <summary> | ||
/// Gets 该命令的名称 | ||
/// </summary> | ||
string Name { get; } | ||
|
||
/// <summary> | ||
/// Gets 该命令的描述,可为 null | ||
/// </summary> | ||
string Description { get; } | ||
|
||
/// <summary> | ||
/// Gets 要执行此命令需要的权限,可为 null | ||
/// </summary> | ||
Permission NeededPermission { get; } | ||
|
||
/// <summary> | ||
/// Gets 该命令的别名,可为 null | ||
/// </summary> | ||
IEnumerable<string> Aliases { get; } | ||
|
||
/// <summary> | ||
/// 执行该命令 | ||
/// </summary> | ||
/// <param name="commandSender">发送命令者</param> | ||
/// <param name="args">命令的参数</param> | ||
/// <returns>执行是否成功,如果成功则返回 true</returns> | ||
/// <exception cref="CommandException">可能抛出派生自 <see cref="CommandException"/> 的异常</exception> | ||
bool Execute(ICommandSender commandSender, IList<ICommandArgument> args); | ||
} | ||
|
||
/// <summary> | ||
/// 命令执行过程中可能发生的异常的基类 | ||
/// </summary> | ||
/// <remarks>派生自此类的异常在 <see cref="CommandMap.Dispatch(ICommandSender, string)"/> 中将会被吃掉,不会传播到外部</remarks> | ||
public class CommandException : Exception | ||
{ | ||
public ICommand Command { get; } | ||
|
||
public CommandException(ICommand command = null, string content = null, Exception innerException = null) | ||
: base(content, innerException) | ||
{ | ||
Command = command; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// 表示命令的使用方式错误的异常 | ||
/// </summary> | ||
public class CommandWrongUsageException : CommandException | ||
{ | ||
public CommandWrongUsageException(ICommand command, string content = null, Exception innerException = null) | ||
: base(command, content, innerException) | ||
{ | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// 可发送命令者接口 | ||
/// </summary> | ||
public interface ICommandSender : IPermissible | ||
{ | ||
/// <summary> | ||
/// 向可发送命令者发送(一般为反馈)特定的信息 | ||
/// </summary> | ||
/// <param name="msg">要发送的信息</param> | ||
Task SendMessage(string msg); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.