diff --git a/src/plugin/Edelstein.Plugin.Rue/Commands/AbstractTemplateCommand.cs b/src/plugin/Edelstein.Plugin.Rue/Commands/AbstractTemplateCommand.cs index e21f3192c..dc452883e 100644 --- a/src/plugin/Edelstein.Plugin.Rue/Commands/AbstractTemplateCommand.cs +++ b/src/plugin/Edelstein.Plugin.Rue/Commands/AbstractTemplateCommand.cs @@ -1,7 +1,7 @@ using System.Diagnostics; -using DotNet.Globbing; using Edelstein.Protocol.Gameplay.Game.Objects.User; using Edelstein.Protocol.Utilities.Templates; +using Gma.DataStructures.StringSearch; using PowerArgs; namespace Edelstein.Plugin.Rue.Commands; @@ -26,35 +26,51 @@ protected AbstractTemplateCommand(ITemplateManager templates) : base( } } -public abstract class AbstractTemplateCommand : AbstractCommand +public abstract class AbstractTemplateCommand : AbstractCommand, IIndexedCommand where TTemplate : class, ITemplate where TArgs : TemplateCommandArgs { private readonly ITemplateManager _templates; - private readonly GlobOptions _options = new() { Evaluation = { CaseInsensitive = true } }; + private readonly ITrie _trie; + private bool isIndexing; + private bool isIndexed; protected AbstractTemplateCommand( ITemplateManager templates ) { _templates = templates; + _trie = new UkkonenTrie(); } protected abstract Task> Indices(); protected abstract Task Execute(IFieldUser user, TTemplate template, TArgs args); + public async Task Index() + { + if (isIndexed || isIndexing) return; + isIndexing = true; + foreach (var index in await Indices()) + _trie.Add(index.SearchString.ToLower(), index); + isIndexing = false; + isIndexed = true; + } + protected override async Task Execute(IFieldUser user, TArgs args) { + if (isIndexing || !isIndexed) + { + await user.Message("Templates have not finished indexing yet, please try again later.."); + return; + } + var stopwatch = new Stopwatch(); await user.Message($"Searching for '{args.Search}', this might take awhile.."); stopwatch.Start(); - var glob = Glob.Parse(args.Search, _options); - var data = await Indices(); - - var results = data - .Where(d => glob.IsMatch(d.SearchString)) + var results = _trie + .Retrieve(args.Search.ToLower()) .DistinctBy(d => d.ID) .ToList(); var elapsed = stopwatch.Elapsed; @@ -91,7 +107,7 @@ protected override async Task Execute(IFieldUser user, TArgs args) if (currentPage < maxPage) menu.Add(-10, "#rNext page#k"); if (currentPage > minPage) menu.Add(-20, "#rPrevious page#k"); - var selection = target.AskMenu($"Found {results.Count} results for '{args.Search}' in {elapsed.TotalSeconds:F} seconds (page {currentPage} of {maxPage})", menu); + var selection = target.AskMenu($"Found {results.Count} results for '{args.Search}' in {elapsed.TotalMilliseconds:F2}ms (page {currentPage} of {maxPage})", menu); if (selection == -10) { currentPage++; continue; } if (selection == -20) { currentPage--; continue; } diff --git a/src/plugin/Edelstein.Plugin.Rue/Commands/IIndexedCommand.cs b/src/plugin/Edelstein.Plugin.Rue/Commands/IIndexedCommand.cs new file mode 100644 index 000000000..a3d2083bc --- /dev/null +++ b/src/plugin/Edelstein.Plugin.Rue/Commands/IIndexedCommand.cs @@ -0,0 +1,6 @@ +namespace Edelstein.Plugin.Rue.Commands; + +public interface IIndexedCommand : ICommand +{ + Task Index(); +} diff --git a/src/plugin/Edelstein.Plugin.Rue/Edelstein.Plugin.Rue.csproj b/src/plugin/Edelstein.Plugin.Rue/Edelstein.Plugin.Rue.csproj index b17d9275f..ea5f190c0 100644 --- a/src/plugin/Edelstein.Plugin.Rue/Edelstein.Plugin.Rue.csproj +++ b/src/plugin/Edelstein.Plugin.Rue/Edelstein.Plugin.Rue.csproj @@ -12,9 +12,9 @@ - + diff --git a/src/plugin/Edelstein.Plugin.Rue/Plugs/UserOnPacketCheckPasswordFlippedPlug.cs b/src/plugin/Edelstein.Plugin.Rue/Plugs/UserOnPacketCheckPasswordFlippedPlug.cs index bb1a897b0..1550b91ba 100644 --- a/src/plugin/Edelstein.Plugin.Rue/Plugs/UserOnPacketCheckPasswordFlippedPlug.cs +++ b/src/plugin/Edelstein.Plugin.Rue/Plugs/UserOnPacketCheckPasswordFlippedPlug.cs @@ -2,7 +2,6 @@ using Edelstein.Plugin.Rue.Contracts; using Edelstein.Protocol.Gameplay.Login.Contexts; using Edelstein.Protocol.Gameplay.Login.Contracts; -using Edelstein.Protocol.Services.Auth.Contracts; using Edelstein.Protocol.Utilities.Pipelines; using Microsoft.Extensions.Logging; diff --git a/src/plugin/Edelstein.Plugin.Rue/Plugs/UserOnPacketCreateSecurityHandleAutoRegisterPlug.cs b/src/plugin/Edelstein.Plugin.Rue/Plugs/UserOnPacketCreateSecurityHandleAutoRegisterPlug.cs index 2c35ff888..cd00deb16 100644 --- a/src/plugin/Edelstein.Plugin.Rue/Plugs/UserOnPacketCreateSecurityHandleAutoRegisterPlug.cs +++ b/src/plugin/Edelstein.Plugin.Rue/Plugs/UserOnPacketCreateSecurityHandleAutoRegisterPlug.cs @@ -1,6 +1,5 @@ using Edelstein.Plugin.Rue.Configs; using Edelstein.Plugin.Rue.Contracts; -using Edelstein.Protocol.Gameplay.Game.Contexts; using Edelstein.Protocol.Gameplay.Login.Contexts; using Edelstein.Protocol.Gameplay.Login.Contracts; using Edelstein.Protocol.Utilities.Pipelines; diff --git a/src/plugin/Edelstein.Plugin.Rue/RueGamePlugin.cs b/src/plugin/Edelstein.Plugin.Rue/RueGamePlugin.cs index db3242237..93c3a6031 100644 --- a/src/plugin/Edelstein.Plugin.Rue/RueGamePlugin.cs +++ b/src/plugin/Edelstein.Plugin.Rue/RueGamePlugin.cs @@ -1,4 +1,5 @@ -using Edelstein.Plugin.Rue.Commands; +using System.Diagnostics; +using Edelstein.Plugin.Rue.Commands; using Edelstein.Plugin.Rue.Commands.Admin; using Edelstein.Plugin.Rue.Commands.Common; using Edelstein.Plugin.Rue.Plugs; @@ -21,37 +22,49 @@ public Task OnInit(IPluginHost host, GameContext ctx) return Task.CompletedTask; } - public Task OnStart(IPluginHost host, GameContext ctx) + public async Task OnStart(IPluginHost host, GameContext ctx) { var commandManager = new CommandManager(); - commandManager.Insert(new HelpCommand(commandManager)); - commandManager.Insert(new AliasCommand(commandManager)); + await commandManager.Insert(new HelpCommand(commandManager)); + await commandManager.Insert(new AliasCommand(commandManager)); - commandManager.Insert(new FieldCommand( + await commandManager.Insert(new FieldCommand( ctx.Managers.Field, ctx.Templates.Field, ctx.Templates.FieldString )); - commandManager.Insert(new ItemCommand( + await commandManager.Insert(new ItemCommand( ctx.Templates.Item, ctx.Templates.ItemString )); - commandManager.Insert(new SkillCommand( + await commandManager.Insert(new SkillCommand( ctx.Templates.Skill, ctx.Templates.SkillString )); - commandManager.Insert(new QuestCommand( + await commandManager.Insert(new QuestCommand( ctx.Templates.Quest )); - commandManager.Insert(new EquipCommand()); - commandManager.Insert(new StatCommand()); - commandManager.Insert(new TemporaryStatCommand()); - commandManager.Insert(new MobTemporaryStatCommand()); - commandManager.Insert(new DebugCommand()); + await commandManager.Insert(new EquipCommand()); + await commandManager.Insert(new StatCommand()); + await commandManager.Insert(new TemporaryStatCommand()); + await commandManager.Insert(new MobTemporaryStatCommand()); + await commandManager.Insert(new DebugCommand()); ctx.Pipelines.FieldOnPacketUserChat.Add(PipelinePriority.High, new FieldOnPacketUserChatCommandPlug(commandManager)); - return Task.CompletedTask; + + _ = Task.Run(async () => + { + await Task.WhenAll((await commandManager.RetrieveAll()) + .OfType() + .Select(async c => + { + var stopwatch = new Stopwatch(); + stopwatch.Start(); + await c.Index(); + host.Logger.LogDebug("Finished indexing for command {Command} in {Elapsed:F2}ms", c.Name, stopwatch.Elapsed.TotalMilliseconds); + })); + }); } public Task OnStop()