Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 87 additions & 1 deletion Source/Common/ChatCommands.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Linq;

namespace Multiplayer.Common;

Expand All @@ -18,11 +19,41 @@ public void Handle(IChatSource source, string cmd)
}
else
{
source.SendMsg("Invalid command");
source.SendMsg("Invalid command. Use help or ? to list available commands.");
}
}

public void AddCommandHandler(string name, ChatCmdHandler handler) => handlers[name] = handler;

public IEnumerable<string> GetCommandNames() => handlers.Keys.OrderBy(name => name);

public IEnumerable<ChatCmdInfo> GetCommandInfos()
{
return handlers
.GroupBy(entry => entry.Value)
.Select(group => new ChatCmdInfo(group.Key, group.Select(entry => entry.Key).ToArray()))
.OrderBy(info => info.PrimaryName);
}

public bool TryGetCommandInfo(string name, out ChatCmdInfo info)
{
if (handlers.TryGetValue(name, out var handler))
{
info = new ChatCmdInfo(handler, handlers.Where(entry => entry.Value == handler).Select(entry => entry.Key).ToArray());
return true;
}

info = null!;
return false;
}
}

public sealed class ChatCmdInfo(ChatCmdHandler handler, string[] names)
{
public ChatCmdHandler Handler { get; } = handler;
public string[] Names { get; } = names;
public string PrimaryName => Names.First();
public string DisplayNames => string.Join(", ", Names);
}

public abstract class ChatCmdHandler
Expand All @@ -31,6 +62,9 @@ public abstract class ChatCmdHandler

public MultiplayerServer Server => MultiplayerServer.instance!;

public virtual string Description => string.Empty;
public virtual string Usage => string.Empty;

public abstract void Handle(IChatSource source, string[] args);

public void SendNoPermission(ServerPlayer player)
Expand All @@ -46,6 +80,9 @@ public void SendNoPermission(ServerPlayer player)

public class ChatCmdJoinPoint : ChatCmdHandler
{
public override string Description => "Create a fresh join point immediately.";
public override string Usage => "joinpoint";

public ChatCmdJoinPoint()
{
requiresHost = true;
Expand All @@ -58,8 +95,54 @@ public override void Handle(IChatSource source, string[] args)
}
}

public class ChatCmdHelp : ChatCmdHandler
{
public override string Description => "Show available commands or detailed help for one command.";
public override string Usage => "help [command]";

public override void Handle(IChatSource source, string[] args)
{
if (args.Length > 0)
{
if (Server.chatCmdManager.TryGetCommandInfo(args[0], out var command))
{
source.SendMsg($"Command: {command.DisplayNames}");

if (!string.IsNullOrEmpty(command.Handler.Description))
source.SendMsg($"Description: {command.Handler.Description}");

if (!string.IsNullOrEmpty(command.Handler.Usage))
source.SendMsg($"Usage: {command.Handler.Usage}");

if (command.Handler.requiresHost)
source.SendMsg("Requires host permissions.");

return;
}

source.SendMsg($"Unknown command '{args[0]}'. Use help to list available commands.");
return;
}

source.SendMsg("Available commands:");
foreach (var command in Server.chatCmdManager.GetCommandInfos())
{
var summary = command.Handler.Description;
if (command.Handler.requiresHost)
summary = string.IsNullOrEmpty(summary) ? "Requires host permissions." : $"{summary} Requires host permissions.";

source.SendMsg($"- {command.DisplayNames}: {summary}");
}

source.SendMsg("Use help <command> for detailed usage.");
}
}

public class ChatCmdKick : ChatCmdHandler
{
public override string Description => "Disconnect a player by username.";
public override string Usage => "kick <username>";

public ChatCmdKick()
{
requiresHost = true;
Expand Down Expand Up @@ -92,6 +175,9 @@ public override void Handle(IChatSource source, string[] args)

public class ChatCmdStop : ChatCmdHandler
{
public override string Description => "Stop the standalone server.";
public override string Usage => "stop";

public ChatCmdStop()
{
requiresHost = true;
Expand Down
3 changes: 3 additions & 0 deletions Source/Common/MultiplayerServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ public MultiplayerServer(ServerSettings settings)
chatCmdManager = new ChatCmdManager();
playerManager = new PlayerManager(this);

var helpCmd = new ChatCmdHelp();
RegisterChatCmd("help", helpCmd);
RegisterChatCmd("?", helpCmd);
RegisterChatCmd("joinpoint", new ChatCmdJoinPoint());
RegisterChatCmd("kick", new ChatCmdKick());
RegisterChatCmd("stop", new ChatCmdStop());
Expand Down
Loading