Skip to content

Commit

Permalink
feat: Add /help command (#2984)
Browse files Browse the repository at this point in the history
* feat: implement help command and refac commands creation

* fix: tweak command descriptions, formatting, and hide internal ones

* feat: print help intro command on start
  • Loading branch information
mihakrajnc authored Dec 12, 2024
1 parent cf3e6d5 commit 3b35332
Show file tree
Hide file tree
Showing 16 changed files with 90 additions and 49 deletions.
18 changes: 7 additions & 11 deletions Explorer/Assets/DCL/Chat/ChatCommandsHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,22 @@ public class ChatCommandsHandler
{
private const string CHAT_COMMAND_CHAR = "/";

private readonly Dictionary<Regex, IChatCommand> commandsCache = new ();
private readonly IReadOnlyDictionary<Regex, Func<IChatCommand>> commandsFactory;
private readonly IReadOnlyList<IChatCommand> commands;

public ChatCommandsHandler(IReadOnlyDictionary<Regex, Func<IChatCommand>> commandsFactory)
public ChatCommandsHandler(IReadOnlyList<IChatCommand> commands)
{
this.commandsFactory = commandsFactory;
this.commands = commands;
}

public bool TryGetChatCommand(in string message, ref (IChatCommand command, Match match) commandTuple)
{
foreach (Regex? commandRegex in commandsFactory.Keys)
foreach (IChatCommand cmd in commands)
{
commandTuple.match = commandRegex.Match(message);
commandTuple.match = cmd.Regex.Match(message);

if (!commandTuple.match.Success) continue;

if (!commandsCache.TryGetValue(commandRegex, out commandTuple.command))
{
commandTuple.command = commandsFactory[commandRegex]();
commandsCache[commandRegex] = commandTuple.command;
}
commandTuple.command = cmd;

return true;
}
Expand Down
3 changes: 3 additions & 0 deletions Explorer/Assets/DCL/Chat/ChatController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@ protected override void OnViewInstantiated()
viewInstance.ChatBubblesToggle.Toggle.SetIsOnWithoutNotify(nametagsData.showChatBubbles);
OnToggleChatBubblesValueChanged(nametagsData.showChatBubbles);
OnFocus();

// Intro message
chatHistory.AddMessage(ChatMessage.NewFromSystem("Type /help for available commands."));
}

protected override void OnViewShow()
Expand Down
2 changes: 2 additions & 0 deletions Explorer/Assets/DCL/Chat/Commands/IChatCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ namespace DCL.Chat.Commands
{
public interface IChatCommand
{
Regex Regex { get; }

string Description { get; }

UniTask<string> ExecuteAsync(Match match, CancellationToken ct);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ public class CommandsHandleChatMessageBus : IChatMessagesBus

public event Action<ChatMessage>? MessageAdded;

public CommandsHandleChatMessageBus(IChatMessagesBus origin, IReadOnlyDictionary<Regex, Func<IChatCommand>> commandsFactory)
public CommandsHandleChatMessageBus(IChatMessagesBus origin, IReadOnlyList<IChatCommand> commands)
{
this.origin = origin;
this.chatCommandsHandler = new ChatCommandsHandler(commandsFactory);
this.chatCommandsHandler = new ChatCommandsHandler(commands);
origin.MessageAdded += OriginOnOnMessageAdded;
}

Expand Down
4 changes: 2 additions & 2 deletions Explorer/Assets/DCL/Chat/MessageBus/IChatMessagesBus.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ void CreateTestChatEntry()
return messagesBus;
}

public static IChatMessagesBus WithCommands(this IChatMessagesBus messagesBus, IReadOnlyDictionary<Regex, Func<IChatCommand>> commandsFactory) =>
new CommandsHandleChatMessageBus(messagesBus, commandsFactory);
public static IChatMessagesBus WithCommands(this IChatMessagesBus messagesBus, IReadOnlyList<IChatCommand> commands) =>
new CommandsHandleChatMessageBus(messagesBus, commands);

public static IChatMessagesBus WithIgnoreSymbols(this IChatMessagesBus messagesBus) =>
new IgnoreWithSymbolsChatMessageBus(messagesBus);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@ public class ChangeRealmChatCommand : IChatCommand
// Parameters to URL mapping
private readonly Dictionary<string, string> paramUrls;

public static readonly Regex REGEX =
public Regex Regex { get; } =
new (
$@"^/({COMMAND_WORLD}|{ChatCommandsUtils.COMMAND_GOTO})\s+((?!-?\d+\s*,\s*-?\d+$).+?)(?:\s+(-?\d+)\s*,\s*(-?\d+))?$",
RegexOptions.Compiled);
public string Description => "<b>/world <i><world></i></b> - Teleport to a different realm";

private readonly URLDomain worldDomain = URLDomain.FromString(IRealmNavigator.WORLDS_DOMAIN);

private readonly Dictionary<string, URLAddress> worldAddressesCaches = new ();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ namespace Global.Dynamic.ChatCommands
{
public class ClearChatCommand : IChatCommand
{
public static readonly Regex REGEX = new ($@"^/(clear).*", RegexOptions.Compiled);
public Regex Regex { get; } = new ("^/(clear).*", RegexOptions.Compiled);
public string Description => "<b>/clear</b> - Clear the chat";

private readonly IChatHistory chatHistory;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ namespace Global.Dynamic.ChatCommands
{
public class DebugPanelChatCommand : IChatCommand
{
public static readonly Regex REGEX = new (@"^/debug(?:\s+(\w+))?$", RegexOptions.Compiled);
public Regex Regex { get; } = new (@"^/debug(?:\s+(\w+))?$", RegexOptions.Compiled);
public string Description => "<b>/debug</b> - Toggle debug panel";

private readonly IDebugContainerBuilder debugContainerBuilder;
private readonly ConnectionStatusPanelPlugin connectionStatusPanelPlugin;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ public class GoToChatCommand : IChatCommand
private const string COMMAND_GOTO_LOCAL = "goto-local";
private const string PARAMETER_RANDOM = "random";

public static readonly Regex REGEX =
public Regex Regex { get; } =
new (
$@"^/({ChatCommandsUtils.COMMAND_GOTO}|{COMMAND_GOTO_LOCAL})\s+(?:(-?\d+)\s*,\s*(-?\d+)|{PARAMETER_RANDOM})$",
RegexOptions.Compiled);
public string Description => "<b>/goto <i><world | x,y | random></i></b> - Teleport to a specific location.";

private readonly IRealmNavigator realmNavigator;

private int x;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using Cysharp.Threading.Tasks;
using DCL.Chat.Commands;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;

namespace Global.Dynamic.ChatCommands
{
public class HelpChatCommand : IChatCommand
{
public Regex Regex { get; } = new ("^/(help).*", RegexOptions.Compiled);
public string Description => "<b>/help</b> - Shows this help message";

private readonly List<IChatCommand> commands;

public HelpChatCommand(List<IChatCommand> commands)
{
this.commands = commands;
}

public UniTask<string> ExecuteAsync(Match match, CancellationToken ct)
{
var sb = new StringBuilder();

sb.AppendLine("Available commands:\n");

foreach (IChatCommand cmd in commands)
{
if (string.IsNullOrEmpty(cmd.Description)) continue;

sb.AppendLine(cmd.Description);
}

return UniTask.FromResult(sb.ToString());
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using DCL.Chat.Commands;
using DCL.FeatureFlags;
using PortableExperiences.Controller;
using System;
using System.Text.RegularExpressions;
using System.Threading;

Expand All @@ -17,7 +18,8 @@ public class KillPortableExperienceChatCommand : IChatCommand
private static readonly string COMMAND_PATTERN = $"^/(?<command>{Regex.Escape(COMMAND_PX)})";
private static readonly string OPTIONAL_SUFFIX_PATTERN = $"(?<suffix>{Regex.Escape(ENS_SUFFIX)})?";

public static readonly Regex REGEX = new($"{COMMAND_PATTERN}{NAME_PATTERN}{OPTIONAL_SUFFIX_PATTERN}$", RegexOptions.Compiled);
public Regex Regex { get; } = new($"{COMMAND_PATTERN}{NAME_PATTERN}{OPTIONAL_SUFFIX_PATTERN}$", RegexOptions.Compiled);
public string Description => string.Empty; // Internal command, don't advertise it in /help

private readonly IPortableExperiencesController portableExperiencesController;
private readonly FeatureFlagsCache featureFlagsCache;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ public class LoadPortableExperienceChatCommand : IChatCommand
private static readonly string COMMAND_PATTERN = $"^/(?<command>{Regex.Escape(COMMAND_PX)})";
private static readonly string OPTIONAL_SUFFIX_PATTERN = $"(?<suffix>{Regex.Escape(ENS_SUFFIX)})?";

public static readonly Regex REGEX = new($"{COMMAND_PATTERN}{NAME_PATTERN}{OPTIONAL_SUFFIX_PATTERN}$", RegexOptions.Compiled);
public Regex Regex { get; } = new($"{COMMAND_PATTERN}{NAME_PATTERN}{OPTIONAL_SUFFIX_PATTERN}$", RegexOptions.Compiled);
public string Description => string.Empty; // Internal command, don't advertise it in /help

private readonly IPortableExperiencesController portableExperiencesController;
private readonly FeatureFlagsCache featureFlagsCache;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@
using Cysharp.Threading.Tasks;
using DCL.Chat.Commands;
using ECS.SceneLifeCycle;
using ECS.SceneLifeCycle.Systems;
using System;

namespace Global.Dynamic.ChatCommands
{
public class ReloadSceneChatCommand : IChatCommand
{
public static readonly Regex REGEX = new (@"^/reload(?:\s+(\w+))?$", RegexOptions.Compiled);
public Regex Regex { get; } = new (@"^/reload(?:\s+(\w+))?$", RegexOptions.Compiled);
public string Description => "<b>/reload</b> - Reload the current scene";

private readonly ECSReloadScene reloadScene;

Expand All @@ -23,6 +22,7 @@ public async UniTask<string> ExecuteAsync(Match match, CancellationToken ct)
{
if (await reloadScene.TryReloadSceneAsync(ct))
return "🟢 Current scene has been reloaded";

return "🔴 You need to be in a SDK7 scene to reload it.";
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ public class ShowEntityInfoChatCommand : IChatCommand
private const string COMMAND_SHOW = "show-entity-components";
private const string EXAMPLE = "/show-entity-components scene_name entity_id";

public static readonly Regex REGEX = new ($@"^/({COMMAND_SHOW}).*", RegexOptions.Compiled);
public Regex Regex { get; } = new ($"^/({COMMAND_SHOW}).*", RegexOptions.Compiled);
public string Description => "<b>/show <i><entity></i></b> - Show entity components info";

private readonly IWorldInfoHub worldInfoHub;

Expand Down
37 changes: 13 additions & 24 deletions Explorer/Assets/Scripts/Global/Dynamic/DynamicWorldContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,6 @@ IMultiPool MultiPoolFactory() =>
staticContainer.WebRequestsContainer.WebRequestController
);


bool localSceneDevelopment = !string.IsNullOrEmpty(dynamicWorldParams.LocalSceneDevelopmentRealm);

container.RealmController = new RealmController(
Expand Down Expand Up @@ -419,34 +418,24 @@ IMultiPool MultiPoolFactory() =>
var currentSceneInfo = new CurrentSceneInfo();
var connectionStatusPanelPlugin = new ConnectionStatusPanelPlugin(container.UserInAppInAppInitializationFlow, container.MvcManager, mainUIView, roomsStatus, currentSceneInfo, container.reloadSceneController, globalWorld, playerEntity, debugBuilder);

var chatCommandsFactory = new Dictionary<Regex, Func<IChatCommand>>
var chatCommands = new List<IChatCommand>
{
{ GoToChatCommand.REGEX, () => new GoToChatCommand(realmNavigator) },
{
ChangeRealmChatCommand.REGEX,
() => new ChangeRealmChatCommand(realmNavigator, bootstrapContainer.DecentralandUrlsSource,
new EnvironmentValidator(bootstrapContainer.Environment))
},
{ DebugPanelChatCommand.REGEX, () => new DebugPanelChatCommand(debugBuilder, connectionStatusPanelPlugin) },
{ ShowEntityInfoChatCommand.REGEX, () => new ShowEntityInfoChatCommand(worldInfoHub) },
{ ClearChatCommand.REGEX, () => new ClearChatCommand(chatHistory) },
{ ReloadSceneChatCommand.REGEX, () => new ReloadSceneChatCommand(container.reloadSceneController) },
{
LoadPortableExperienceChatCommand.REGEX,
() => new LoadPortableExperienceChatCommand(staticContainer.PortableExperiencesController,
staticContainer.FeatureFlagsCache)
},
{
KillPortableExperienceChatCommand.REGEX,
() => new KillPortableExperienceChatCommand(staticContainer.PortableExperiencesController,
staticContainer.FeatureFlagsCache)
}
new GoToChatCommand(realmNavigator),
new ChangeRealmChatCommand(realmNavigator, bootstrapContainer.DecentralandUrlsSource, new EnvironmentValidator(bootstrapContainer.Environment)),
new DebugPanelChatCommand(debugBuilder, connectionStatusPanelPlugin),
new ShowEntityInfoChatCommand(worldInfoHub),
new ClearChatCommand(chatHistory),
new ReloadSceneChatCommand(container.reloadSceneController),
new LoadPortableExperienceChatCommand(staticContainer.PortableExperiencesController, staticContainer.FeatureFlagsCache),
new KillPortableExperienceChatCommand(staticContainer.PortableExperiencesController, staticContainer.FeatureFlagsCache),
};

chatCommands.Add(new HelpChatCommand(chatCommands));

IChatMessagesBus coreChatMessageBus = new MultiplayerChatMessagesBus(container.MessagePipesHub, container.ProfileRepository, new MessageDeduplication<double>())
.WithSelfResend(identityCache, container.ProfileRepository)
.WithIgnoreSymbols()
.WithCommands(chatCommandsFactory)
.WithCommands(chatCommands)
.WithDebugPanel(debugBuilder);

container.ChatMessagesBus = dynamicWorldParams.EnableAnalytics
Expand Down Expand Up @@ -627,7 +616,7 @@ IMultiPool MultiPoolFactory() =>
assetsProvisioner,
container.MvcManager,
dclCursor,
realmUrl => container.ChatMessagesBus.Send($"/{ChatCommandsUtils.COMMAND_GOTO} {realmUrl}", "RestrictedActionAPI")),
realmUrl => container.ChatMessagesBus.Send($"/{ChatCommandsUtils.COMMAND_GOTO} {realmUrl}", "RestrictedActionAPI")),
new NftPromptPlugin(assetsProvisioner, webBrowser, container.MvcManager, nftInfoAPIClient, staticContainer.WebRequestsContainer.WebRequestController, dclCursor),
staticContainer.CharacterContainer.CreateGlobalPlugin(),
staticContainer.QualityContainer.CreatePlugin(),
Expand Down

0 comments on commit 3b35332

Please sign in to comment.