diff --git a/README.md b/README.md index d7f4696..4e372f2 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ HMM使用基于CSV变种的HMM格式文件,便于阅读,以行为单位, ## 对比/补丁文件 -作为专业的地图数据维护工具,HMM支持对地图文件进行对比,查看数据中更改过的地方,选择性的合并数据,并能将变更内容到处为.hmp补丁文件。 +作为专业的地图数据维护工具,HMM支持对地图文件进行对比,查看数据中更改过的地方,选择性的合并数据,并能将变更内容导出为.hmp补丁文件。 ![地图对比](doc/images/diff.png) diff --git a/code/HellMapManager/Assets/translate.xaml b/code/HellMapManager/Assets/translate.xaml index 325b7b1..eb7252f 100644 --- a/code/HellMapManager/Assets/translate.xaml +++ b/code/HellMapManager/Assets/translate.xaml @@ -25,4 +25,10 @@ {0}个文件已经存在,您是否想替换它? + 使用英文逗号分隔多个关键字。 +可以使用 类型=来进行精确匹配,例如 name=入口 表示只匹配名称完全等于“入口”的项目。 +类型为空可以进行全类型精确匹配。 +前置英文感叹号表示排除。 +支持的类型为:key|name|desc|tag|group|to|command|message|misc。 +支持用\进行转义。 diff --git a/code/HellMapManager/Cores/MapDatabase.API.cs b/code/HellMapManager/Cores/MapDatabase.API.cs index ff8e25a..9cfc512 100644 --- a/code/HellMapManager/Cores/MapDatabase.API.cs +++ b/code/HellMapManager/Cores/MapDatabase.API.cs @@ -741,13 +741,15 @@ public void APIRemoveVariables(List keys) _lock.ExitWriteLock(); } } - public QueryResult? APIQueryPathAny(List from, List target, Context context, MapperOptions options) + public QueryResult? APIQueryPathAny(List from, List target, Context? context, MapperOptions? options) { _lock.EnterReadLock(); try { if (Current != null) { + context ??= new Context(); + options ??= new MapperOptions(); return new Walking(new Mapper(Current, context, options)).QueryPathAny(from, target, 0).SuccessOrNull(); } } @@ -758,13 +760,15 @@ public void APIRemoveVariables(List keys) return null; } - public QueryResult? APIQueryPathAll(string start, List target, Context context, MapperOptions options) + public QueryResult? APIQueryPathAll(string start, List target, Context? context, MapperOptions? options) { _lock.EnterReadLock(); try { if (Current != null) { + context ??= new Context(); + options ??= new MapperOptions(); return new Walking(new Mapper(Current, context, options)).QueryPathAll(start, target).SuccessOrNull(); } } @@ -774,13 +778,15 @@ public void APIRemoveVariables(List keys) } return null; } - public QueryResult? APIQueryPathOrdered(string start, List target, Context context, MapperOptions options) + public QueryResult? APIQueryPathOrdered(string start, List target, Context? context, MapperOptions? options) { _lock.EnterReadLock(); try { if (Current != null) { + context ??= new Context(); + options ??= new MapperOptions(); return new Walking(new Mapper(Current, context, options)).QueryPathOrdered(start, target).SuccessOrNull(); } } @@ -848,13 +854,15 @@ public List APIQueryRegionRooms(string key) return []; } - public List APIDilate(List src, int iterations, Context context, MapperOptions options) + public List APIDilate(List src, int iterations, Context? context, MapperOptions? options) { _lock.EnterReadLock(); try { if (Current != null) { + context ??= new Context(); + options ??= new MapperOptions(); return new Walking(new Mapper(Current, context, options)).Dilate(src, iterations); } } @@ -864,13 +872,15 @@ public List APIDilate(List src, int iterations, Context context, } return []; } - public string APITrackExit(string start, string command, Context context, MapperOptions options) + public string APITrackExit(string start, string command, Context? context, MapperOptions? options) { _lock.EnterReadLock(); try { if (Current != null) { + context ??= new Context(); + options ??= new MapperOptions(); var mapper = new Mapper(Current, context, options); var room = mapper.GetRoom(start); if (room is not null) @@ -911,13 +921,15 @@ public string APIGetVariable(string key) } return ""; } - public Room? APIGetRoom(string key, Context context, MapperOptions options) + public Room? APIGetRoom(string key, Context? context, MapperOptions? options) { _lock.EnterReadLock(); try { if (Current != null) { + context ??= new Context(); + options ??= new MapperOptions(); return new Mapper(Current, context, options).GetRoom(key); } } @@ -1147,13 +1159,15 @@ public void APIGroupRoom(string key, string group) _lock.ExitWriteLock(); } } - public List APIGetRoomExits(string key, Context context, MapperOptions options) + public List APIGetRoomExits(string key, Context? context, MapperOptions? options) { _lock.EnterReadLock(); try { if (Current != null) { + context ??= new Context(); + options ??= new MapperOptions(); var mapper = new Mapper(Current, context, options); var room = mapper.GetRoom(key); if (room is not null) diff --git a/code/HellMapManager/Cores/MapDatabase.cs b/code/HellMapManager/Cores/MapDatabase.cs index 1e78a0d..42f6eca 100644 --- a/code/HellMapManager/Cores/MapDatabase.cs +++ b/code/HellMapManager/Cores/MapDatabase.cs @@ -8,7 +8,7 @@ namespace HellMapManager.Cores; public partial class MapDatabase() { public ReaderWriterLockSlim _lock = new(); - public const int Version = 1003; + public const int Version = 1004; public MapFile? Current; public Settings Settings = new(); diff --git a/code/HellMapManager/Helpers/FilterHelper.cs b/code/HellMapManager/Helpers/FilterHelper.cs new file mode 100644 index 0000000..338c7e3 --- /dev/null +++ b/code/HellMapManager/Helpers/FilterHelper.cs @@ -0,0 +1,75 @@ + +using System; +using System.Collections.Generic; +using System.Linq; +using HellMapManager.Models; +using HellMapManager.Utils.ControlCode; + +namespace HellMapManager.Helpers; + +public class FilterHelper +{ + const string TypeKey = "key"; + const string TypeName = "name"; + const string TypeTo = "to"; + const string TypeTag = "tag"; + const string TypeCommand = "command"; + const string TypeGroup = "group"; + const string TypeType = "type"; + const string TypeValue = "value"; + const string TypeDesc = "desc"; + const string TypeMisc = "misc"; + + const string TypeMessage = "message"; + static readonly ControlCode escaper = new ControlCode(). + WithCommand(new Command("\\", "0", "\\\\")). + WithCommand(new Command("\n", "1", "\\n")). + WithCommand(new Command(",", "2", "\\,")). + WithCommand(new Command("=", "3", "\\=")). + WithCommand(new Command(" ", "4", "\\ ")). + WithCommand(new Command("!", "5", "\\!")); + + public static FilterKeyword ParseKeyword(string unpacked) + { + var keyword = new FilterKeyword(); + if (unpacked.StartsWith("!")) + { + keyword.Not = true; + unpacked = unpacked[1..]; + } + var data = unpacked.Split(['='], 2); + if (data.Length > 1) + { + keyword.Type = escaper.Decode(data[0].Trim()) switch + { + "" => FilterKeywordType.Any, + TypeKey => FilterKeywordType.Key, + TypeName => FilterKeywordType.Name, + TypeTo => FilterKeywordType.To, + TypeTag => FilterKeywordType.Tag, + TypeCommand => FilterKeywordType.Command, + TypeGroup => FilterKeywordType.Group, + TypeMisc => FilterKeywordType.Misc, + TypeType => FilterKeywordType.Type, + TypeDesc => FilterKeywordType.Desc, + TypeValue => FilterKeywordType.Value, + TypeMessage => FilterKeywordType.Message, + _ => FilterKeywordType.Wrong, + }; + keyword.Value = escaper.Decode(data[1]); + keyword.PartialMatch = false; + } + else + { + keyword.Value = escaper.Decode(data[0]); + keyword.PartialMatch = true; + } + return keyword; + } + public static List ParseKeywords(string filter) + { + return escaper.Unpack(filter).Split(",", StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries).ToList().ConvertAll(r => ParseKeyword(r)); + } + +} + diff --git a/code/HellMapManager/Misc/AppVersion.cs b/code/HellMapManager/Misc/AppVersion.cs index b7b579f..fd9013d 100644 --- a/code/HellMapManager/Misc/AppVersion.cs +++ b/code/HellMapManager/Misc/AppVersion.cs @@ -2,7 +2,7 @@ namespace HellMapManager.Misc; public class AppVersion(int major, int minor, int patch) { - public static AppVersion Current { get; } = new(0, 20260101, 0); + public static AppVersion Current { get; } = new(0, 20260116, 0); public int Major { get; } = major; public int Minor { get; } = minor; public int Patch { get; } = patch; diff --git a/code/HellMapManager/Misc/Links.cs b/code/HellMapManager/Misc/Links.cs index de3f21e..c43342f 100644 --- a/code/HellMapManager/Misc/Links.cs +++ b/code/HellMapManager/Misc/Links.cs @@ -8,5 +8,5 @@ public class Links public const string ScriptInro = "https://github.com/hellclient-scripts/hellmapmanager/blob/main/doc/script/index.md"; public const string API = "https://github.com/hellclient-scripts/hellmapmanager/blob/main/doc/api/index.md"; public const string BestPractices = "https://github.com/hellclient-scripts/hellmapmanager/blob/main/doc/bestpractices/index.md"; - + public const string Forum = "https://forum.hellclient.com/"; } \ No newline at end of file diff --git a/code/HellMapManager/Models/Context.cs b/code/HellMapManager/Models/Context.cs index 51b0216..d42f2e8 100644 --- a/code/HellMapManager/Models/Context.cs +++ b/code/HellMapManager/Models/Context.cs @@ -187,18 +187,21 @@ public bool IsBlocked(string from, string to) { return BlockedLinks.ContainsKey(from) && BlockedLinks[from].ContainsKey(to); } - public static Context FromEnvironment(Environment env) + public static Context FromEnvironment(Environment? env) { var context = new Context(); - context.WithTags(env.Tags); - context.WithRoomConditions(env.RoomConditions); - context.WithRooms(env.Rooms); - context.WithWhitelist(env.Whitelist); - context.WithBlacklist(env.Blacklist); - context.WithShortcuts(env.Shortcuts); - context.WithPaths(env.Paths); - context.WithBlockedLinks(env.BlockedLinks); - context.WithCommandCosts(env.CommandCosts); + if (env != null) + { + context.WithTags(env.Tags); + context.WithRoomConditions(env.RoomConditions); + context.WithRooms(env.Rooms); + context.WithWhitelist(env.Whitelist); + context.WithBlacklist(env.Blacklist); + context.WithShortcuts(env.Shortcuts); + context.WithPaths(env.Paths); + context.WithBlockedLinks(env.BlockedLinks); + context.WithCommandCosts(env.CommandCosts); + } return context; } public Environment ToEnvironment() diff --git a/code/HellMapManager/Models/FilterKeyword.cs b/code/HellMapManager/Models/FilterKeyword.cs new file mode 100644 index 0000000..1ae6496 --- /dev/null +++ b/code/HellMapManager/Models/FilterKeyword.cs @@ -0,0 +1,37 @@ +using System; +using System.Text.RegularExpressions; + +namespace HellMapManager.Models; + +public enum FilterKeywordType +{ + Any, + Wrong, + Misc, + Message, + Key, + Name, + To, + Tag, + Command, + Group, + Type, + + Desc, + Value, +} +public class FilterKeyword +{ + public FilterKeywordType Type = FilterKeywordType.Any; + public bool Not = false; + public bool PartialMatch = true; + public string Value = ""; + public bool Match(string target, FilterKeywordType type) + { + if (Type != FilterKeywordType.Any && Type != type) + { + return false; + } + return Not != (PartialMatch ? target.Contains(Value) : target == Value); + } +} \ No newline at end of file diff --git a/code/HellMapManager/Models/Landmark.cs b/code/HellMapManager/Models/Landmark.cs index 05bbae5..b8c4971 100644 --- a/code/HellMapManager/Models/Landmark.cs +++ b/code/HellMapManager/Models/Landmark.cs @@ -80,9 +80,9 @@ public static void Sort(List list) public partial class Landmark { - public bool Filter(string filter) + public bool Filter(FilterKeyword keyword) { - if (Key.Contains(filter) || Type.Contains(filter) || Value.Contains(filter) || Group.Contains(filter) || Desc.Contains(filter)) + if (keyword.Match(Key, FilterKeywordType.Key) || keyword.Match(Type, FilterKeywordType.Type) || keyword.Match(Value, FilterKeywordType.Value) || keyword.Match(Group, FilterKeywordType.Group) || keyword.Match(Desc, FilterKeywordType.Desc)) { return true; } diff --git a/code/HellMapManager/Models/Marker.cs b/code/HellMapManager/Models/Marker.cs index 4d5fea2..8661659 100644 --- a/code/HellMapManager/Models/Marker.cs +++ b/code/HellMapManager/Models/Marker.cs @@ -62,13 +62,13 @@ public static void Sort(List list) } public partial class Marker { - public bool Filter(string val) + public bool Filter(FilterKeyword keyword) { - if (Key.Contains(val) || - Value.Contains(val) || - Desc.Contains(val) || - Group.Contains(val) || - Message.Contains(val) + if (keyword.Match(Key, FilterKeywordType.Key) || + keyword.Match(Value, FilterKeywordType.Value) || + keyword.Match(Desc, FilterKeywordType.Desc) || + keyword.Match(Group, FilterKeywordType.Group) || + keyword.Match(Message, FilterKeywordType.Message) ) { return true; diff --git a/code/HellMapManager/Models/Region.cs b/code/HellMapManager/Models/Region.cs index 631fd4e..108ee9d 100644 --- a/code/HellMapManager/Models/Region.cs +++ b/code/HellMapManager/Models/Region.cs @@ -107,18 +107,19 @@ public static void Sort(List list) public partial class Region { - public bool Filter(string val) + public bool Filter(FilterKeyword keyword) { - if (Key.Contains(val) || - Desc.Contains(val) || - Group.Contains(val) || - Message.Contains(val)) + + if (keyword.Match(Key, FilterKeywordType.Key) || + keyword.Match(Desc, FilterKeywordType.Desc) || + keyword.Match(Group, FilterKeywordType.Group) || + keyword.Match(Message, FilterKeywordType.Message)) { return true; } foreach (var item in Items) { - if (item.Value.Contains(val)) + if (keyword.Match(item.Value, FilterKeywordType.To)) { return true; } diff --git a/code/HellMapManager/Models/Room.cs b/code/HellMapManager/Models/Room.cs index 84f91b5..f2d9713 100644 --- a/code/HellMapManager/Models/Room.cs +++ b/code/HellMapManager/Models/Room.cs @@ -322,38 +322,38 @@ public void Arrange() Tags.Sort((x, y) => x.Key.CompareTo(y.Key)); Exits.ForEach(e => e.Arrange()); } - public bool Filter(string val) + public bool Filter(FilterKeyword keyword) { - if (Key.Contains(val) || - Name.Contains(val) || - Desc.Contains(val) || - Group.Contains(val)) + if (keyword.Match(Key, FilterKeywordType.Key) || + keyword.Match(Name, FilterKeywordType.Name) || + keyword.Match(Desc, FilterKeywordType.Desc) || + keyword.Match(Group, FilterKeywordType.Group)) { return true; } foreach (var tag in Tags) { - if (tag.Key.Contains(val)) + if (keyword.Match(tag.Key, FilterKeywordType.Tag)) { return true; } } foreach (var data in Data) { - if (data.Key.Contains(val) || data.Value.Contains(val)) + if (keyword.Match(data.Key, FilterKeywordType.Misc) || keyword.Match(data.Value, FilterKeywordType.Misc)) { return true; } } foreach (var exit in Exits) { - if (exit.Command.Contains(val) || exit.To.Contains(val)) + if (keyword.Match(exit.Command, FilterKeywordType.Command) || keyword.Match(exit.To, FilterKeywordType.To)) { return true; } foreach(var cond in exit.Conditions) { - if (cond.Key.Contains(val)) + if (keyword.Match(cond.Key, FilterKeywordType.Tag)) { return true; } diff --git a/code/HellMapManager/Models/Route.cs b/code/HellMapManager/Models/Route.cs index 8f21ce3..f6101f6 100644 --- a/code/HellMapManager/Models/Route.cs +++ b/code/HellMapManager/Models/Route.cs @@ -82,18 +82,18 @@ public string RoomsList return string.Join("\n", Rooms); } } - public bool Filter(string val) + public bool Filter(FilterKeyword keyword) { - if (Key.Contains(val) || - Desc.Contains(val) || - Group.Contains(val) || - Message.Contains(val)) + if (keyword.Match(Key, FilterKeywordType.Key) || + keyword.Match(Desc, FilterKeywordType.Desc) || + keyword.Match(Group, FilterKeywordType.Group) || + keyword.Match(Message, FilterKeywordType.Message)) { return true; } foreach (var room in Rooms) { - if (room.Contains(val)) + if (keyword.Match(room, FilterKeywordType.To)) { return true; } diff --git a/code/HellMapManager/Models/Shortcut.cs b/code/HellMapManager/Models/Shortcut.cs index de5521a..eb8f95d 100644 --- a/code/HellMapManager/Models/Shortcut.cs +++ b/code/HellMapManager/Models/Shortcut.cs @@ -63,22 +63,26 @@ public static Shortcut Decode(string val) result.Cost = HMMFormatter.UnescapeIntAt(list, 7, 0); return result; } - public bool Filter(string val) + public bool Filter(FilterKeyword keyword) { - if (Key.Contains(val) || Command.Contains(val) || To.Contains(val) || Group.Contains(val) || Desc.Contains(val)) + if (keyword.Match(Key, FilterKeywordType.Key) || + keyword.Match(Command, FilterKeywordType.Command) || + keyword.Match(To, FilterKeywordType.To) || + keyword.Match(Group, FilterKeywordType.Group) || + keyword.Match(Desc, FilterKeywordType.Desc)) { return true; } foreach (var cond in Conditions) { - if (cond.Key.Contains(val)) + if (keyword.Match(cond.Key, FilterKeywordType.Tag)) { return true; } } foreach (var cond in RoomConditions) { - if (cond.Key.Contains(val)) + if (keyword.Match(cond.Key, FilterKeywordType.Tag)) { return true; } diff --git a/code/HellMapManager/Models/Snapshot.cs b/code/HellMapManager/Models/Snapshot.cs index a490f65..0c2bcba 100644 --- a/code/HellMapManager/Models/Snapshot.cs +++ b/code/HellMapManager/Models/Snapshot.cs @@ -87,9 +87,12 @@ public Snapshot Clone() Count = Count, }; } - public bool Filter(string filter) + public bool Filter(FilterKeyword keyword) { - if (Key.Contains(filter) || Type.Contains(filter) || Value.Contains(filter) || Group.Contains(filter)) + if (keyword.Match(Key, FilterKeywordType.Key) || + keyword.Match(Type, FilterKeywordType.Type) || + keyword.Match(Value, FilterKeywordType.Value) || + keyword.Match(Group, FilterKeywordType.Group)) { return true; } diff --git a/code/HellMapManager/Models/Trace.cs b/code/HellMapManager/Models/Trace.cs index 1c3d201..b9dff75 100644 --- a/code/HellMapManager/Models/Trace.cs +++ b/code/HellMapManager/Models/Trace.cs @@ -84,18 +84,18 @@ public void AddLocations(List loctions) } Arrange(); } - public bool Filter(string val) + public bool Filter(FilterKeyword keyword) { - if (Key.Contains(val) || - Desc.Contains(val) || - Group.Contains(val) || - Message.Contains(val)) + if (keyword.Match(Key, FilterKeywordType.Key) || + keyword.Match(Desc, FilterKeywordType.Desc) || + keyword.Match(Group, FilterKeywordType.Group) || + keyword.Match(Message, FilterKeywordType.Message)) { return true; } foreach (var room in Locations) { - if (room.Contains(val)) + if (keyword.Match(room, FilterKeywordType.To)) { return true; } diff --git a/code/HellMapManager/Models/Variable.cs b/code/HellMapManager/Models/Variable.cs index 680ce56..44e5d1c 100644 --- a/code/HellMapManager/Models/Variable.cs +++ b/code/HellMapManager/Models/Variable.cs @@ -1,4 +1,5 @@ namespace HellMapManager.Models; + using System.Collections.Generic; @@ -47,21 +48,12 @@ public Variable Clone() Desc = Desc, }; } - public bool Filter(string filter) + public bool Filter(FilterKeyword keyword) { - if (Key.Contains(filter)) - { - return true; - } - if (Value.Contains(filter)) - { - return true; - } - if (Group.Contains(filter)) - { - return true; - } - if (Desc.Contains(filter)) + if (keyword.Match(Key, FilterKeywordType.Key) || + keyword.Match(Value, FilterKeywordType.Value) || + keyword.Match(Group, FilterKeywordType.Group) || + keyword.Match(Desc, FilterKeywordType.Desc)) { return true; } diff --git a/code/HellMapManager/Services/API/API.cs b/code/HellMapManager/Services/API/API.cs index c90f537..3814153 100644 --- a/code/HellMapManager/Services/API/API.cs +++ b/code/HellMapManager/Services/API/API.cs @@ -331,7 +331,7 @@ public async Task APIQueryPathAny(HttpContext ctx) await InvalidJSONRequest(ctx); return; } - var result = Database.APIQueryPathAny(query.From, query.Target, Context.FromEnvironment(query.Environment.ToEnvironment()), query.Options.ToMapperOptions()); + var result = Database.APIQueryPathAny(query.From, query.Target, Context.FromEnvironment(query?.Environment?.ToEnvironment()), query?.Options?.ToMapperOptions()); await WriteJSON(ctx, QueryResultModel.FromQueryResult(result)); } public async Task APIQueryPathAll(HttpContext ctx) @@ -342,7 +342,7 @@ public async Task APIQueryPathAll(HttpContext ctx) await InvalidJSONRequest(ctx); return; } - var result = Database.APIQueryPathAll(query.Start, query.Target, Context.FromEnvironment(query.Environment.ToEnvironment()), query.Options.ToMapperOptions()); + var result = Database.APIQueryPathAll(query.Start, query.Target, Context.FromEnvironment(query?.Environment?.ToEnvironment()), query?.Options?.ToMapperOptions()); await WriteJSON(ctx, QueryResultModel.FromQueryResult(result)); } public async Task APIQueryPathOrdered(HttpContext ctx) @@ -353,7 +353,7 @@ public async Task APIQueryPathOrdered(HttpContext ctx) await InvalidJSONRequest(ctx); return; } - var result = Database.APIQueryPathOrdered(query.Start, query.Target, Context.FromEnvironment(query.Environment.ToEnvironment()), query.Options.ToMapperOptions()); + var result = Database.APIQueryPathOrdered(query.Start, query.Target, Context.FromEnvironment(query?.Environment?.ToEnvironment()), query?.Options?.ToMapperOptions()); await WriteJSON(ctx, QueryResultModel.FromQueryResult(result)); } public async Task APIDilate(HttpContext ctx) @@ -364,7 +364,7 @@ public async Task APIDilate(HttpContext ctx) await InvalidJSONRequest(ctx); return; } - var output = Database.APIDilate(input.Source, input.Iterations, Context.FromEnvironment(input.Environment.ToEnvironment()), input.Options.ToMapperOptions()); + var output = Database.APIDilate(input.Source, input.Iterations, Context.FromEnvironment(input?.Environment?.ToEnvironment()), input?.Options?.ToMapperOptions()); await WriteJSON(ctx, output); } public async Task APITrackExit(HttpContext ctx) @@ -375,7 +375,7 @@ public async Task APITrackExit(HttpContext ctx) await InvalidJSONRequest(ctx); return; } - var output = Database.APITrackExit(input.Start, input.Command, Context.FromEnvironment(input.Environment.ToEnvironment()), input.Options.ToMapperOptions()); + var output = Database.APITrackExit(input.Start, input.Command, Context.FromEnvironment(input?.Environment?.ToEnvironment()), input?.Options?.ToMapperOptions()); await WriteJSON(ctx, output); } public async Task APIGetVariable(HttpContext ctx) @@ -408,7 +408,7 @@ public async Task APIGetRoom(HttpContext ctx) await InvalidJSONRequest(ctx); return; } - var room = Database.APIGetRoom(input.Key, Context.FromEnvironment(input.Environment.ToEnvironment()), input.Options.ToMapperOptions()); + var room = Database.APIGetRoom(input.Key, Context.FromEnvironment(input?.Environment?.ToEnvironment()), input?.Options?.ToMapperOptions()); await WriteJSON(ctx, RoomModel.From(room)); } public async Task APIClearSnapshots(HttpContext ctx) @@ -524,7 +524,7 @@ public async Task APIGetRoomExits(HttpContext ctx) await InvalidJSONRequest(ctx); return; } - var exits = Database.APIGetRoomExits(input.Key, Context.FromEnvironment(input.Environment.ToEnvironment()), input.Options.ToMapperOptions()); + var exits = Database.APIGetRoomExits(input.Key, Context.FromEnvironment(input?.Environment?.ToEnvironment()), input?.Options?.ToMapperOptions()); await WriteJSON(ctx, ExitModel.FromList(exits)); } } \ No newline at end of file diff --git a/code/HellMapManager/Services/API/Models.cs b/code/HellMapManager/Services/API/Models.cs index 2ec1dd8..33b118f 100644 --- a/code/HellMapManager/Services/API/Models.cs +++ b/code/HellMapManager/Services/API/Models.cs @@ -1356,8 +1356,8 @@ public class InputQueryPathAny() } public List From { get; set; } = []; public List Target { get; set; } = []; - public EnvironmentModel Environment { get; set; } = new(); - public MapperOptionsModel Options { get; set; } = new(); + public EnvironmentModel? Environment { get; set; } = new(); + public MapperOptionsModel? Options { get; set; } = new(); } public class InputQueryPath() @@ -1379,8 +1379,8 @@ public class InputQueryPath() } public string Start { get; set; } = ""; public List Target { get; set; } = []; - public EnvironmentModel Environment { get; set; } = new(); - public MapperOptionsModel Options { get; set; } = new(); + public EnvironmentModel? Environment { get; set; } = new(); + public MapperOptionsModel? Options { get; set; } = new(); } public class InputDilate() @@ -1401,8 +1401,8 @@ public class InputDilate() } public List Source { get; set; } = []; public int Iterations { get; set; } = 1; - public EnvironmentModel Environment { get; set; } = new(); - public MapperOptionsModel Options { get; set; } = new(); + public EnvironmentModel? Environment { get; set; } = new(); + public MapperOptionsModel? Options { get; set; } = new(); } public class InputTrackExit() { @@ -1422,8 +1422,8 @@ public class InputTrackExit() } public string Start { get; set; } = ""; public string Command { get; set; } = ""; - public EnvironmentModel Environment { get; set; } = new(); - public MapperOptionsModel Options { get; set; } = new(); + public EnvironmentModel? Environment { get; set; } = new(); + public MapperOptionsModel? Options { get; set; } = new(); } public class InputKey() { @@ -1461,8 +1461,8 @@ public class InputGetRoom() return null; } public string Key { get; set; } = ""; - public EnvironmentModel Environment { get; set; } = new(); - public MapperOptionsModel Options { get; set; } = new(); + public EnvironmentModel? Environment { get; set; } = new(); + public MapperOptionsModel? Options { get; set; } = new(); } diff --git a/code/HellMapManager/Utils/Filter.cs b/code/HellMapManager/Utils/Filter.cs deleted file mode 100644 index 64a2d09..0000000 --- a/code/HellMapManager/Utils/Filter.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace HellMapManager.Utils; - -public class FilterUtil -{ - public static List SplitFilter(string filter) - { - var parts = filter.Split(",", StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); - return new List(parts); - } -} \ No newline at end of file diff --git a/code/HellMapManager/ViewModels/MainWindowViewModel.Landmarks.cs b/code/HellMapManager/ViewModels/MainWindowViewModel.Landmarks.cs index 6a393df..9cc6cb4 100644 --- a/code/HellMapManager/ViewModels/MainWindowViewModel.Landmarks.cs +++ b/code/HellMapManager/ViewModels/MainWindowViewModel.Landmarks.cs @@ -27,7 +27,7 @@ public ObservableCollection FilteredLandmarks var models = AppKernel.MapDatabase.Current.Map.Landmarks; if (!string.IsNullOrEmpty(LandmarksFilter)) { - HellMapManager.Utils.FilterUtil.SplitFilter(LandmarksFilter).ForEach(filter => + HellMapManager.Helpers.FilterHelper.ParseKeywords(LandmarksFilter).ForEach(filter => { models = models.FindAll(r => r.Filter(filter)); }); diff --git a/code/HellMapManager/ViewModels/MainWindowViewModel.Markers.cs b/code/HellMapManager/ViewModels/MainWindowViewModel.Markers.cs index 90460ec..5b8c193 100644 --- a/code/HellMapManager/ViewModels/MainWindowViewModel.Markers.cs +++ b/code/HellMapManager/ViewModels/MainWindowViewModel.Markers.cs @@ -27,7 +27,7 @@ public ObservableCollection FilteredMarkers var models = AppKernel.MapDatabase.Current.Map.Markers; if (!string.IsNullOrEmpty(MarkersFilter)) { - HellMapManager.Utils.FilterUtil.SplitFilter(MarkersFilter).ForEach(filter => + HellMapManager.Helpers.FilterHelper.ParseKeywords(MarkersFilter).ForEach(filter => { models = models.FindAll(r => r.Filter(filter)); }); diff --git a/code/HellMapManager/ViewModels/MainWindowViewModel.Regions.cs b/code/HellMapManager/ViewModels/MainWindowViewModel.Regions.cs index ccc3f41..3887c27 100644 --- a/code/HellMapManager/ViewModels/MainWindowViewModel.Regions.cs +++ b/code/HellMapManager/ViewModels/MainWindowViewModel.Regions.cs @@ -27,7 +27,7 @@ public ObservableCollection FilteredRegions var models = AppKernel.MapDatabase.Current.Map.Regions; if (!string.IsNullOrEmpty(RegionsFilter)) { - HellMapManager.Utils.FilterUtil.SplitFilter(RegionsFilter).ForEach(filter => + HellMapManager.Helpers.FilterHelper.ParseKeywords(RegionsFilter).ForEach(filter => { models = models.FindAll(r => r.Filter(filter)); }); diff --git a/code/HellMapManager/ViewModels/MainWindowViewModel.Rooms.cs b/code/HellMapManager/ViewModels/MainWindowViewModel.Rooms.cs index 9620765..dbdf9ac 100644 --- a/code/HellMapManager/ViewModels/MainWindowViewModel.Rooms.cs +++ b/code/HellMapManager/ViewModels/MainWindowViewModel.Rooms.cs @@ -27,7 +27,7 @@ public ObservableCollection FilteredRooms var models = AppKernel.MapDatabase.Current.Map.Rooms; if (!string.IsNullOrEmpty(RoomsFilter)) { - HellMapManager.Utils.FilterUtil.SplitFilter(RoomsFilter).ForEach(filter => + HellMapManager.Helpers.FilterHelper.ParseKeywords(RoomsFilter).ForEach(filter => { models = models.FindAll(r => r.Filter(filter)); }); diff --git a/code/HellMapManager/ViewModels/MainWindowViewModel.Routes.cs b/code/HellMapManager/ViewModels/MainWindowViewModel.Routes.cs index 73c822b..87094c2 100644 --- a/code/HellMapManager/ViewModels/MainWindowViewModel.Routes.cs +++ b/code/HellMapManager/ViewModels/MainWindowViewModel.Routes.cs @@ -27,7 +27,7 @@ public ObservableCollection FilteredRoutes var models = AppKernel.MapDatabase.Current.Map.Routes; if (!string.IsNullOrEmpty(RoutesFilter)) { - HellMapManager.Utils.FilterUtil.SplitFilter(RoutesFilter).ForEach(filter => + HellMapManager.Helpers.FilterHelper.ParseKeywords(RoutesFilter).ForEach(filter => { models = models.FindAll(r => r.Filter(filter)); }); diff --git a/code/HellMapManager/ViewModels/MainWindowViewModel.Snapshot.cs b/code/HellMapManager/ViewModels/MainWindowViewModel.Snapshot.cs index 866a2d7..e75d48d 100644 --- a/code/HellMapManager/ViewModels/MainWindowViewModel.Snapshot.cs +++ b/code/HellMapManager/ViewModels/MainWindowViewModel.Snapshot.cs @@ -27,7 +27,7 @@ public ObservableCollection FilteredSnapshots var models = AppKernel.MapDatabase.Current.Map.Snapshots; if (!string.IsNullOrEmpty(SnapshotsFilter)) { - HellMapManager.Utils.FilterUtil.SplitFilter(SnapshotsFilter).ForEach(filter => + HellMapManager.Helpers.FilterHelper.ParseKeywords(SnapshotsFilter).ForEach(filter => { models = models.FindAll(r => r.Filter(filter)); }); diff --git a/code/HellMapManager/ViewModels/MainWindowViewModel.Traces.cs b/code/HellMapManager/ViewModels/MainWindowViewModel.Traces.cs index c96bd9c..23be918 100644 --- a/code/HellMapManager/ViewModels/MainWindowViewModel.Traces.cs +++ b/code/HellMapManager/ViewModels/MainWindowViewModel.Traces.cs @@ -27,7 +27,7 @@ public ObservableCollection FilteredTraces var models = AppKernel.MapDatabase.Current.Map.Traces; if (!string.IsNullOrEmpty(TracesFilter)) { - HellMapManager.Utils.FilterUtil.SplitFilter(TracesFilter).ForEach(filter => + HellMapManager.Helpers.FilterHelper.ParseKeywords(TracesFilter).ForEach(filter => { models = models.FindAll(r => r.Filter(filter)); }); diff --git a/code/HellMapManager/ViewModels/MainWindowViewModel.Variables.cs b/code/HellMapManager/ViewModels/MainWindowViewModel.Variables.cs index 6fce5d2..e20f390 100644 --- a/code/HellMapManager/ViewModels/MainWindowViewModel.Variables.cs +++ b/code/HellMapManager/ViewModels/MainWindowViewModel.Variables.cs @@ -27,7 +27,7 @@ public ObservableCollection FilteredVariables var models = AppKernel.MapDatabase.Current.Map.Variables; if (!string.IsNullOrEmpty(VariablesFilter)) { - HellMapManager.Utils.FilterUtil.SplitFilter(VariablesFilter).ForEach(filter => + HellMapManager.Helpers.FilterHelper.ParseKeywords(VariablesFilter).ForEach(filter => { models = models.FindAll(r => r.Filter(filter)); }); diff --git a/code/HellMapManager/ViewModels/MainWindowViewModel.Welcome.cs b/code/HellMapManager/ViewModels/MainWindowViewModel.Welcome.cs index e0495b5..28fe096 100644 --- a/code/HellMapManager/ViewModels/MainWindowViewModel.Welcome.cs +++ b/code/HellMapManager/ViewModels/MainWindowViewModel.Welcome.cs @@ -14,4 +14,11 @@ public static ObservableCollection HelpLinks new ExternalLink("最佳实践", Misc.Links.API,"了解使用HMM的最佳实践。"), ]; } + public static ObservableCollection CommunityLinks + { + get => [ + new ExternalLink("Github", Misc.Links.Homepage,"访问HMM的GitHub主页,获取最新版本和发布信息。"), + new ExternalLink("社区", Misc.Links.Forum,"加入HellClient社区,参与讨论并获取帮助。"), + ]; + } } \ No newline at end of file diff --git a/code/HellMapManager/ViewModels/MainWindowViewModel.shortcuts.cs b/code/HellMapManager/ViewModels/MainWindowViewModel.shortcuts.cs index 9c432c0..64f725d 100644 --- a/code/HellMapManager/ViewModels/MainWindowViewModel.shortcuts.cs +++ b/code/HellMapManager/ViewModels/MainWindowViewModel.shortcuts.cs @@ -27,7 +27,7 @@ public ObservableCollection FilteredShortcuts var models = AppKernel.MapDatabase.Current.Map.Shortcuts; if (!string.IsNullOrEmpty(ShortcutsFilter)) { - HellMapManager.Utils.FilterUtil.SplitFilter(ShortcutsFilter).ForEach(filter => + HellMapManager.Helpers.FilterHelper.ParseKeywords(ShortcutsFilter).ForEach(filter => { models = models.FindAll(r => r.Filter(filter)); }); diff --git a/code/HellMapManager/Views/MainWindow.axaml b/code/HellMapManager/Views/MainWindow.axaml index cc9cbdd..e50d05d 100644 --- a/code/HellMapManager/Views/MainWindow.axaml +++ b/code/HellMapManager/Views/MainWindow.axaml @@ -64,7 +64,10 @@ - + @@ -81,6 +84,8 @@ + + diff --git a/code/HellMapManager/Views/MainWindow.axaml.cs b/code/HellMapManager/Views/MainWindow.axaml.cs index 5d6dab3..c96522b 100644 --- a/code/HellMapManager/Views/MainWindow.axaml.cs +++ b/code/HellMapManager/Views/MainWindow.axaml.cs @@ -114,6 +114,11 @@ public void OpenURLHomepage(object? sender, RoutedEventArgs args) { TopLevel.GetTopLevel(this)!.Launcher.LaunchUriAsync(new Uri(Links.Homepage)); } + public void OpenURLForum(object? sender, RoutedEventArgs args) + { + TopLevel.GetTopLevel(this)!.Launcher.LaunchUriAsync(new Uri(Links.Forum)); + } + public void OpenURLTerm(object? sender, RoutedEventArgs args) { TopLevel.GetTopLevel(this)!.Launcher.LaunchUriAsync(new Uri(Links.Term)); diff --git a/code/HellMapManager/Views/Mapfile/Landmarks/Landmarks.axaml b/code/HellMapManager/Views/Mapfile/Landmarks/Landmarks.axaml index bb5c33a..005bec8 100644 --- a/code/HellMapManager/Views/Mapfile/Landmarks/Landmarks.axaml +++ b/code/HellMapManager/Views/Mapfile/Landmarks/Landmarks.axaml @@ -55,7 +55,7 @@ DockPanel.Dock="Right" Text="{Binding LandmarksFilter}" TextChanged="OnFilter" - Watermark="过滤,逗号分隔关键字" /> + Watermark="过滤"> + Watermark="过滤"> + Watermark="过滤"> + Watermark="过滤"> + Watermark="过滤"> + Watermark="过滤"> + Watermark="过滤"> + Watermark="过滤"> + Watermark="过滤"> + 沟通 + + + + + + + + + + + + + + 入门 diff --git a/code/HellMapManager/Windows/PatchWindow/Landmarks.axaml b/code/HellMapManager/Windows/PatchWindow/Landmarks.axaml index 73d0741..c59cf9e 100644 --- a/code/HellMapManager/Windows/PatchWindow/Landmarks.axaml +++ b/code/HellMapManager/Windows/PatchWindow/Landmarks.axaml @@ -26,7 +26,7 @@ DockPanel.Dock="Right" Text="{Binding LandmarksFilter}" TextChanged="OnFilter" - Watermark="过滤,逗号分隔关键字" /> + Watermark="过滤"> + Watermark="过滤"> FilteredLandmarks var models = Patch.Landmarks.Items; if (!string.IsNullOrEmpty(LandmarksFilter)) { - HellMapManager.Utils.FilterUtil.SplitFilter(LandmarksFilter).ForEach(filter => + HellMapManager.Helpers.FilterHelper.ParseKeywords(LandmarksFilter).ForEach(filter => { models = models.FindAll(r => { diff --git a/code/HellMapManager/Windows/PatchWindow/PatchWindowViewModel.Markers.cs b/code/HellMapManager/Windows/PatchWindow/PatchWindowViewModel.Markers.cs index a016b3f..56dd82f 100644 --- a/code/HellMapManager/Windows/PatchWindow/PatchWindowViewModel.Markers.cs +++ b/code/HellMapManager/Windows/PatchWindow/PatchWindowViewModel.Markers.cs @@ -25,7 +25,7 @@ public ObservableCollection FilteredMarkers var models = Patch.Markers.Items; if (!string.IsNullOrEmpty(MarkersFilter)) { - HellMapManager.Utils.FilterUtil.SplitFilter(MarkersFilter).ForEach(filter => + HellMapManager.Helpers.FilterHelper.ParseKeywords(MarkersFilter).ForEach(filter => { models = models.FindAll(r => { diff --git a/code/HellMapManager/Windows/PatchWindow/PatchWindowViewModel.Regions.cs b/code/HellMapManager/Windows/PatchWindow/PatchWindowViewModel.Regions.cs index a0df843..eaa5138 100644 --- a/code/HellMapManager/Windows/PatchWindow/PatchWindowViewModel.Regions.cs +++ b/code/HellMapManager/Windows/PatchWindow/PatchWindowViewModel.Regions.cs @@ -25,7 +25,7 @@ public ObservableCollection FilteredRegions var models = Patch.Regions.Items; if (!string.IsNullOrEmpty(RegionsFilter)) { - HellMapManager.Utils.FilterUtil.SplitFilter(RegionsFilter).ForEach(filter => + HellMapManager.Helpers.FilterHelper.ParseKeywords(RegionsFilter).ForEach(filter => { models = models.FindAll(r => { diff --git a/code/HellMapManager/Windows/PatchWindow/PatchWindowViewModel.Rooms.cs b/code/HellMapManager/Windows/PatchWindow/PatchWindowViewModel.Rooms.cs index 6bddd7f..b2416af 100644 --- a/code/HellMapManager/Windows/PatchWindow/PatchWindowViewModel.Rooms.cs +++ b/code/HellMapManager/Windows/PatchWindow/PatchWindowViewModel.Rooms.cs @@ -25,7 +25,7 @@ public ObservableCollection FilteredRooms var models = Patch.Rooms.Items; if (!string.IsNullOrEmpty(RoomsFilter)) { - HellMapManager.Utils.FilterUtil.SplitFilter(RoomsFilter).ForEach(filter => + HellMapManager.Helpers.FilterHelper.ParseKeywords(RoomsFilter).ForEach(filter => { models = models.FindAll(r => { diff --git a/code/HellMapManager/Windows/PatchWindow/PatchWindowViewModel.Routes.cs b/code/HellMapManager/Windows/PatchWindow/PatchWindowViewModel.Routes.cs index a318f65..5aa2f38 100644 --- a/code/HellMapManager/Windows/PatchWindow/PatchWindowViewModel.Routes.cs +++ b/code/HellMapManager/Windows/PatchWindow/PatchWindowViewModel.Routes.cs @@ -25,7 +25,7 @@ public ObservableCollection FilteredRoutes var models = Patch.Routes.Items; if (!string.IsNullOrEmpty(RoutesFilter)) { - HellMapManager.Utils.FilterUtil.SplitFilter(RoutesFilter).ForEach(filter => + HellMapManager.Helpers.FilterHelper.ParseKeywords(RoutesFilter).ForEach(filter => { models = models.FindAll(r => { diff --git a/code/HellMapManager/Windows/PatchWindow/PatchWindowViewModel.Shortcuts.cs b/code/HellMapManager/Windows/PatchWindow/PatchWindowViewModel.Shortcuts.cs index b6e57b9..2fcd68e 100644 --- a/code/HellMapManager/Windows/PatchWindow/PatchWindowViewModel.Shortcuts.cs +++ b/code/HellMapManager/Windows/PatchWindow/PatchWindowViewModel.Shortcuts.cs @@ -25,7 +25,7 @@ public ObservableCollection FilteredShortcuts var models = Patch.Shortcuts.Items; if (!string.IsNullOrEmpty(ShortcutsFilter)) { - HellMapManager.Utils.FilterUtil.SplitFilter(ShortcutsFilter).ForEach(filter => + HellMapManager.Helpers.FilterHelper.ParseKeywords(ShortcutsFilter).ForEach(filter => { models = models.FindAll(r => { diff --git a/code/HellMapManager/Windows/PatchWindow/PatchWindowViewModel.Snapshot.cs b/code/HellMapManager/Windows/PatchWindow/PatchWindowViewModel.Snapshot.cs index 1e6b011..37267e2 100644 --- a/code/HellMapManager/Windows/PatchWindow/PatchWindowViewModel.Snapshot.cs +++ b/code/HellMapManager/Windows/PatchWindow/PatchWindowViewModel.Snapshot.cs @@ -25,7 +25,7 @@ public ObservableCollection FilteredSnapshots var models = Patch.Snapshots.Items; if (!string.IsNullOrEmpty(SnapshotsFilter)) { - HellMapManager.Utils.FilterUtil.SplitFilter(SnapshotsFilter).ForEach(filter => + HellMapManager.Helpers.FilterHelper.ParseKeywords(SnapshotsFilter).ForEach(filter => { models = models.FindAll(r => { diff --git a/code/HellMapManager/Windows/PatchWindow/PatchWindowViewModel.Traces.cs b/code/HellMapManager/Windows/PatchWindow/PatchWindowViewModel.Traces.cs index f460cb7..aac296f 100644 --- a/code/HellMapManager/Windows/PatchWindow/PatchWindowViewModel.Traces.cs +++ b/code/HellMapManager/Windows/PatchWindow/PatchWindowViewModel.Traces.cs @@ -25,7 +25,7 @@ public ObservableCollection FilteredTraces var models = Patch.Traces.Items; if (!string.IsNullOrEmpty(TracesFilter)) { - HellMapManager.Utils.FilterUtil.SplitFilter(TracesFilter).ForEach(filter => + HellMapManager.Helpers.FilterHelper.ParseKeywords(TracesFilter).ForEach(filter => { models = models.FindAll(r => { diff --git a/code/HellMapManager/Windows/PatchWindow/PatchWindowViewModel.Variable.cs b/code/HellMapManager/Windows/PatchWindow/PatchWindowViewModel.Variable.cs index 4d39708..cf9caad 100644 --- a/code/HellMapManager/Windows/PatchWindow/PatchWindowViewModel.Variable.cs +++ b/code/HellMapManager/Windows/PatchWindow/PatchWindowViewModel.Variable.cs @@ -25,7 +25,7 @@ public ObservableCollection FilteredVariables var models = Patch.Variables.Items; if (!string.IsNullOrEmpty(VariablesFilter)) { - HellMapManager.Utils.FilterUtil.SplitFilter(VariablesFilter).ForEach(filter => + HellMapManager.Helpers.FilterHelper.ParseKeywords(VariablesFilter).ForEach(filter => { models = models.FindAll(r => { diff --git a/code/HellMapManager/Windows/PatchWindow/Regions.axaml b/code/HellMapManager/Windows/PatchWindow/Regions.axaml index 82d2576..527deb0 100644 --- a/code/HellMapManager/Windows/PatchWindow/Regions.axaml +++ b/code/HellMapManager/Windows/PatchWindow/Regions.axaml @@ -26,7 +26,7 @@ DockPanel.Dock="Right" Text="{Binding RegionsFilter}" TextChanged="OnFilter" - Watermark="过滤,逗号分隔关键字" /> + Watermark="过滤"> + Watermark="过滤"> + Watermark="过滤"> + Watermark="过滤"> + Watermark="过滤"> + Watermark="过滤"> + Watermark="过滤"> + Watermark="过滤"> diff --git a/code/HellMapManager/Windows/PickRoomWindow/PickRoomWindowViewModel.cs b/code/HellMapManager/Windows/PickRoomWindow/PickRoomWindowViewModel.cs index 1773c57..c5d8637 100644 --- a/code/HellMapManager/Windows/PickRoomWindow/PickRoomWindowViewModel.cs +++ b/code/HellMapManager/Windows/PickRoomWindow/PickRoomWindowViewModel.cs @@ -25,7 +25,7 @@ public ObservableCollection FilteredRooms var models = AppKernel.MapDatabase.Current.Map.Rooms; if (!string.IsNullOrEmpty(RoomsFilter)) { - HellMapManager.Utils.FilterUtil.SplitFilter(RoomsFilter).ForEach(filter => + HellMapManager.Helpers.FilterHelper.ParseKeywords(RoomsFilter).ForEach(filter => { models = models.FindAll(r => r.Filter(filter)); }); diff --git a/code/TestProject/APIServerTest.cs b/code/TestProject/APIServerTest.cs index f80953d..eed4c09 100644 --- a/code/TestProject/APIServerTest.cs +++ b/code/TestProject/APIServerTest.cs @@ -37,7 +37,7 @@ public async Task TestVersion() Assert.Equal(MapDatabase.Version, mapDatabase.APIVersion()); var resp = await Post($"http://localhost:{server.Port}" + "/api/version", typeof(string), ""); var result = JsonSerializer.Deserialize(resp, typeof(int), APIJsonSerializerContext.Default) as int?; - Assert.Equal(1003, result); + Assert.Equal(1004, result); await server.Stop(); } [Fact] diff --git a/code/TestProject/FilterHelperTest.cs b/code/TestProject/FilterHelperTest.cs new file mode 100644 index 0000000..e1353bc --- /dev/null +++ b/code/TestProject/FilterHelperTest.cs @@ -0,0 +1,86 @@ +namespace TestProject; + +using HellMapManager.Helpers; +using HellMapManager.Models; +public class FilterHelperTest +{ + [Fact] + public void TestKeyword() + { + var keyword = new FilterKeyword + { + Type = FilterKeywordType.Key, + Value = "abc", + PartialMatch = false, + }; + Assert.True(keyword.Match("abc", FilterKeywordType.Key)); + Assert.False(keyword.Match("abcd", FilterKeywordType.Key)); + Assert.False(keyword.Match("abc", FilterKeywordType.Type)); + keyword.Type = FilterKeywordType.Any; + Assert.True(keyword.Match("abc", FilterKeywordType.Key)); + Assert.False(keyword.Match("abcd", FilterKeywordType.Key)); + keyword.PartialMatch = true; + Assert.True(keyword.Match("abcd", FilterKeywordType.Key)); + keyword.Not = true; + Assert.False(keyword.Match("abcd", FilterKeywordType.Key)); + keyword.PartialMatch = false; + Assert.True(keyword.Match("abcd", FilterKeywordType.Key)); + Assert.False(keyword.Match("abc", FilterKeywordType.Key)); + } + [Fact] + public void TestFilter() + { + //分词 + var input = "abc"; + var result = FilterHelper.ParseKeywords(input); + Assert.Equal(new List { "abc" }, result.ConvertAll(x => x.Value)); + input = ""; + result = FilterHelper.ParseKeywords(input); + Assert.Equal(new List { }, result.ConvertAll(x => x.Value)); + input = " "; + result = FilterHelper.ParseKeywords(input); + Assert.Equal(new List { }, result.ConvertAll(x => x.Value)); + input = "abc,def"; + result = FilterHelper.ParseKeywords(input); + Assert.Equal(new List { "abc", "def" }, result.ConvertAll(x => x.Value)); + input = "abc ,, , def,h ij "; + result = FilterHelper.ParseKeywords(input); + Assert.Equal(new List { "abc", "def", "h ij" }, result.ConvertAll(x => x.Value)); + + //转义 + input = @"abc\,def"; + result = FilterHelper.ParseKeywords(input); + Assert.Equal(new List { "abc,def" }, result.ConvertAll(x => x.Value)); + input = @"abc\ \,, ,\ def,h ij\ "; + result = FilterHelper.ParseKeywords(input); + Assert.Equal(new List { "abc ,", " def", "h ij " }, result.ConvertAll(x => x.Value)); + input = @"\\\n\=\,\ \!"; + result = FilterHelper.ParseKeywords(input); + Assert.Equal(new List { "\\\n=, !" }, result.ConvertAll(x => x.Value)); + input = @"search"; + var keyword = FilterHelper.ParseKeyword(input); + Assert.Equal(FilterKeywordType.Any, keyword.Type); + Assert.Equal("search", keyword.Value); + Assert.True(keyword.PartialMatch); + Assert.False(keyword.Not); + input = @"!name=example, notexists=!=value , search"; + result = FilterHelper.ParseKeywords(input); + Assert.Equal(3, result.Count); + keyword = result[0]; + Assert.Equal(FilterKeywordType.Name, keyword.Type); + Assert.Equal("example", keyword.Value); + Assert.False(keyword.PartialMatch); + Assert.True(keyword.Not); + keyword = result[1]; + Assert.Equal(FilterKeywordType.Wrong, keyword.Type); + Assert.Equal("!=value", keyword.Value); + Assert.False(keyword.PartialMatch); + Assert.False(keyword.Not); + keyword = result[2]; + Assert.Equal(FilterKeywordType.Any, keyword.Type); + Assert.Equal("search", keyword.Value); + Assert.True(keyword.PartialMatch); + Assert.False(keyword.Not); + + } +} \ No newline at end of file diff --git a/code/TestProject/FilterUtilTest.cs b/code/TestProject/FilterUtilTest.cs deleted file mode 100644 index d684a3d..0000000 --- a/code/TestProject/FilterUtilTest.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace TestProject; - -using HellMapManager.Utils; - -public class FilterUtilTest -{ - [Fact] - public void TestFilter() - { - var keywords = "abc"; - var result = FilterUtil.SplitFilter(keywords); - Assert.Equal(new List { "abc" }, result); - keywords = ""; - result = FilterUtil.SplitFilter(keywords); - Assert.Equal(new List { }, result); - keywords = " "; - result = FilterUtil.SplitFilter(keywords); - Assert.Equal(new List { }, result); - keywords = "abc,def"; - result = FilterUtil.SplitFilter(keywords); - Assert.Equal(new List { "abc", "def" }, result); - keywords = "abc ,, , def,h ij"; - result = FilterUtil.SplitFilter(keywords); - Assert.Equal(new List { "abc", "def", "h ij" }, result); - } -} \ No newline at end of file diff --git a/code/TestProject/MapTest.cs b/code/TestProject/MapTest.cs index cca7efc..8243680 100644 --- a/code/TestProject/MapTest.cs +++ b/code/TestProject/MapTest.cs @@ -517,7 +517,7 @@ public void TestMap() rooms = mapDatabase.APIDilate(["key6"], 1, ctx, opt); rooms.Sort(); Assert.Equal("key1;key3;key6", string.Join(";", rooms)); - opt.WithCommandWhitelist(["1>2","1>3","2>1","2>3","3>1","3>3","3>4","4>3","4>5","5>3","6>3","A>6C"]); + opt.WithCommandWhitelist(["1>2", "1>3", "2>1", "2>3", "3>1", "3>3", "3>4", "4>3", "4>5", "5>3", "6>3", "A>6C"]); exit = mapDatabase.APITrackExit("key6", "A>1", ctx, opt); Assert.Equal("", exit); qr = mapDatabase.APIQueryPathAll("key6", ["key1", "key5"], ctx, opt); @@ -534,4 +534,70 @@ public void TestMap() Assert.Equal("key3;key6", string.Join(";", rooms)); } + [Fact] + public void TestNullableAPI() + { + var mapDatabase = new MapDatabase(); + var ctx = new Context(); + var opt = new MapperOptions(); + var qr = mapDatabase.APIQueryPathAll("key1", ["key2"], ctx, opt); + Assert.Null(qr); + qr = mapDatabase.APIQueryPathAny(["key1"], ["key2"], ctx, opt); + Assert.Null(qr); + qr = mapDatabase.APIQueryPathOrdered("key1", ["key2"], ctx, opt); + Assert.Null(qr); + var rooms = mapDatabase.APIDilate(["key1", "key6"], 2, ctx, opt); + Assert.Empty(rooms); + var exit = mapDatabase.APITrackExit("key1", "1>2", ctx, opt); + Assert.Equal("", exit); + qr = mapDatabase.APIQueryPathAll("key1", ["key2"], null, null); + Assert.Null(qr); + qr = mapDatabase.APIQueryPathAny(["key1"], ["key2"], null, null); + Assert.Null(qr); + qr = mapDatabase.APIQueryPathOrdered("key1", ["key2"], null, null); + Assert.Null(qr); + rooms = mapDatabase.APIDilate(["key1", "key6"], 2, null, null); + Assert.Empty(rooms); + exit = mapDatabase.APITrackExit("key1", "1>2", null, null); + Assert.Equal("", exit); + InitMapDatabase(mapDatabase); + qr = mapDatabase.APIQueryPathAll("key1", ["key2"], ctx, opt); + Assert.NotNull(qr); + Assert.Equal("1>2", Step.JoinCommands(";", qr.Steps)); + qr = mapDatabase.APIQueryPathAny(["key1"], ["key2"], ctx, opt); + Assert.NotNull(qr); + Assert.Equal("1>2", Step.JoinCommands(";", qr.Steps)); + qr = mapDatabase.APIQueryPathOrdered("key1", ["key2"], ctx, opt); + Assert.NotNull(qr); + Assert.Equal("1>2", Step.JoinCommands(";", qr.Steps)); + rooms = mapDatabase.APIDilate(["key1", "key6"], 2, ctx, opt); + rooms.Sort(); + Assert.Equal("key1;key2;key3;key4", string.Join(";", rooms)); + exit = mapDatabase.APITrackExit("key1", "1>2", ctx, opt); + Assert.Equal("key2", exit); + exit = mapDatabase.APITrackExit("notfound", "1>2", ctx, opt); + Assert.Equal("", exit); + exit = mapDatabase.APITrackExit("key1", "notfound", ctx, opt); + Assert.Equal("", exit); + + qr = mapDatabase.APIQueryPathAll("key1", ["key2"], null, null); + Assert.NotNull(qr); + Assert.Equal("1>2", Step.JoinCommands(";", qr.Steps)); + qr = mapDatabase.APIQueryPathAny(["key1"], ["key2"], null, null); + Assert.NotNull(qr); + Assert.Equal("1>2", Step.JoinCommands(";", qr.Steps)); + qr = mapDatabase.APIQueryPathOrdered("key1", ["key2"], null, null); + Assert.NotNull(qr); + Assert.Equal("1>2", Step.JoinCommands(";", qr.Steps)); + rooms = mapDatabase.APIDilate(["key1", "key6"], 2, null, null); + rooms.Sort(); + Assert.Equal("key1;key2;key3;key4", string.Join(";", rooms)); + exit = mapDatabase.APITrackExit("key1", "1>2", null, null); + Assert.Equal("key2", exit); + exit = mapDatabase.APITrackExit("notfound", "1>2", null, null); + Assert.Equal("", exit); + exit = mapDatabase.APITrackExit("key1", "notfound", null, null); + Assert.Equal("", exit); + + } } \ No newline at end of file diff --git a/code/TestProject/ModelTest.cs b/code/TestProject/ModelTest.cs index 8f4d3fd..e268d5a 100644 --- a/code/TestProject/ModelTest.cs +++ b/code/TestProject/ModelTest.cs @@ -1,3 +1,4 @@ +using HellMapManager.Helpers; using HellMapManager.Models; namespace TestProject; @@ -363,16 +364,34 @@ public void TestRoom() Assert.Equal("", room.GetData("notfound")); Room room2; - Assert.False(room.Filter("unknow")); - Assert.True(room.Filter("key")); - Assert.True(room.Filter("name")); - Assert.True(room.Filter("group")); - Assert.True(room.Filter("tag1")); - Assert.True(room.Filter("dkey1")); - Assert.True(room.Filter("dval2")); - Assert.True(room.Filter("command1")); - Assert.True(room.Filter("to2")); - Assert.True(room.Filter("on1")); + Assert.False(room.Filter(FilterHelper.ParseKeyword("unknow"))); + Assert.True(room.Filter(FilterHelper.ParseKeyword("key"))); + Assert.False(room.Filter(FilterHelper.ParseKeyword("key=ke"))); + Assert.True(room.Filter(FilterHelper.ParseKeyword("key=key"))); + Assert.True(room.Filter(FilterHelper.ParseKeyword("name"))); + Assert.False(room.Filter(FilterHelper.ParseKeyword("name=nam"))); + Assert.True(room.Filter(FilterHelper.ParseKeyword("name=name"))); + Assert.True(room.Filter(FilterHelper.ParseKeyword("group"))); + Assert.False(room.Filter(FilterHelper.ParseKeyword("group=gro"))); + Assert.True(room.Filter(FilterHelper.ParseKeyword("group=group"))); + Assert.True(room.Filter(FilterHelper.ParseKeyword("tag1"))); + Assert.False(room.Filter(FilterHelper.ParseKeyword("tag=tag"))); + Assert.True(room.Filter(FilterHelper.ParseKeyword("tag=tag1"))); + Assert.True(room.Filter(FilterHelper.ParseKeyword("dkey1"))); + Assert.False(room.Filter(FilterHelper.ParseKeyword("misc=dkey"))); + Assert.True(room.Filter(FilterHelper.ParseKeyword("misc=dkey1"))); + Assert.True(room.Filter(FilterHelper.ParseKeyword("dval2"))); + Assert.False(room.Filter(FilterHelper.ParseKeyword("misc=dval"))); + Assert.True(room.Filter(FilterHelper.ParseKeyword("misc=dval2"))); + Assert.True(room.Filter(FilterHelper.ParseKeyword("command1"))); + Assert.False(room.Filter(FilterHelper.ParseKeyword("command=command"))); + Assert.True(room.Filter(FilterHelper.ParseKeyword("command=command1"))); + Assert.True(room.Filter(FilterHelper.ParseKeyword("to2"))); + Assert.False(room.Filter(FilterHelper.ParseKeyword("to=to"))); + Assert.True(room.Filter(FilterHelper.ParseKeyword("to=to2"))); + Assert.True(room.Filter(FilterHelper.ParseKeyword("on1"))); + Assert.False(room.Filter(FilterHelper.ParseKeyword("tag=con"))); + Assert.True(room.Filter(FilterHelper.ParseKeyword("tag=con1"))); Assert.Equal(2, room.ExitsCount); Assert.Equal("tag1,tag2", room.AllTags); @@ -536,12 +555,22 @@ public void TestMarker() }; - Assert.True(marker.Filter("key")); - Assert.True(marker.Filter("value")); - Assert.True(marker.Filter("group")); - Assert.True(marker.Filter("desc")); - Assert.True(marker.Filter("message")); - Assert.False(marker.Filter("notfound")); + Assert.True(marker.Filter(FilterHelper.ParseKeyword("key"))); + Assert.False(marker.Filter(FilterHelper.ParseKeyword("key=key"))); + Assert.True(marker.Filter(FilterHelper.ParseKeyword("key=key1"))); + Assert.True(marker.Filter(FilterHelper.ParseKeyword("value"))); + Assert.False(marker.Filter(FilterHelper.ParseKeyword("value=value"))); + Assert.True(marker.Filter(FilterHelper.ParseKeyword("value=value1"))); + Assert.True(marker.Filter(FilterHelper.ParseKeyword("group"))); + Assert.False(marker.Filter(FilterHelper.ParseKeyword("group=group"))); + Assert.True(marker.Filter(FilterHelper.ParseKeyword("group=group1"))); + Assert.True(marker.Filter(FilterHelper.ParseKeyword("desc"))); + Assert.False(marker.Filter(FilterHelper.ParseKeyword("desc=desc"))); + Assert.True(marker.Filter(FilterHelper.ParseKeyword("desc=desc1"))); + Assert.True(marker.Filter(FilterHelper.ParseKeyword("message"))); + Assert.False(marker.Filter(FilterHelper.ParseKeyword("message=message"))); + Assert.True(marker.Filter(FilterHelper.ParseKeyword("message=message1"))); + Assert.False(marker.Filter(FilterHelper.ParseKeyword("notfound"))); Marker marker2; marker2 = marker.Clone(); Assert.True(marker2.Validated()); @@ -583,12 +612,22 @@ public void TestRoute() }; Assert.Equal("rid1a\nrid1b", route.RoomsList); - Assert.True(route.Filter("key")); - Assert.True(route.Filter("rid1")); - Assert.True(route.Filter("desc")); - Assert.True(route.Filter("group")); - Assert.True(route.Filter("message")); - Assert.False(route.Filter("NotFound")); + Assert.True(route.Filter(FilterHelper.ParseKeyword("key"))); + Assert.False(route.Filter(FilterHelper.ParseKeyword("key=key"))); + Assert.True(route.Filter(FilterHelper.ParseKeyword("key=key1"))); + Assert.True(route.Filter(FilterHelper.ParseKeyword("rid1"))); + Assert.False(route.Filter(FilterHelper.ParseKeyword("to=rid"))); + Assert.True(route.Filter(FilterHelper.ParseKeyword("to=rid1a"))); + Assert.True(route.Filter(FilterHelper.ParseKeyword("desc"))); + Assert.False(route.Filter(FilterHelper.ParseKeyword("desc=desc"))); + Assert.True(route.Filter(FilterHelper.ParseKeyword("desc=desc1"))); + Assert.True(route.Filter(FilterHelper.ParseKeyword("group"))); + Assert.False(route.Filter(FilterHelper.ParseKeyword("group=group"))); + Assert.True(route.Filter(FilterHelper.ParseKeyword("group=group1"))); + Assert.True(route.Filter(FilterHelper.ParseKeyword("message"))); + Assert.False(route.Filter(FilterHelper.ParseKeyword("message=message"))); + Assert.True(route.Filter(FilterHelper.ParseKeyword("message=message1"))); + Assert.False(route.Filter(FilterHelper.ParseKeyword("NotFound"))); Assert.Equal("rid1a;rid1b", route.AllRooms); Assert.Equal(2, route.RoomsCount); @@ -632,12 +671,22 @@ public void TestTrace() Message = "message1", }; Assert.Equal("rid1\nrid2", trace.LocationList); - Assert.True(trace.Filter("key")); - Assert.True(trace.Filter("rid")); - Assert.True(trace.Filter("desc")); - Assert.True(trace.Filter("group")); - Assert.True(trace.Filter("message")); - Assert.False(trace.Filter("NotFound")); + Assert.True(trace.Filter(FilterHelper.ParseKeyword("key"))); + Assert.False(trace.Filter(FilterHelper.ParseKeyword("key=key"))); + Assert.True(trace.Filter(FilterHelper.ParseKeyword("key=key1"))); + Assert.True(trace.Filter(FilterHelper.ParseKeyword("rid"))); + Assert.False(trace.Filter(FilterHelper.ParseKeyword("to=rid"))); + Assert.True(trace.Filter(FilterHelper.ParseKeyword("to=rid1"))); + Assert.True(trace.Filter(FilterHelper.ParseKeyword("desc"))); + Assert.False(trace.Filter(FilterHelper.ParseKeyword("desc=desc"))); + Assert.True(trace.Filter(FilterHelper.ParseKeyword("desc=desc1"))); + Assert.True(trace.Filter(FilterHelper.ParseKeyword("group"))); + Assert.False(trace.Filter(FilterHelper.ParseKeyword("group=group"))); + Assert.True(trace.Filter(FilterHelper.ParseKeyword("group=group1"))); + Assert.True(trace.Filter(FilterHelper.ParseKeyword("message"))); + Assert.False(trace.Filter(FilterHelper.ParseKeyword("message=message"))); + Assert.True(trace.Filter(FilterHelper.ParseKeyword("message=message1"))); + Assert.False(trace.Filter(FilterHelper.ParseKeyword("NotFound"))); Assert.Equal(2, trace.LocationsCount); @@ -686,13 +735,25 @@ public void TestRegion() Message = "message1", Items = [new RegionItem(RegionItemType.Room, "room1", false), new RegionItem(RegionItemType.Zone, "zone1", true)] }; - Assert.True(region.Filter("key")); - Assert.True(region.Filter("room")); - Assert.True(region.Filter("zone")); - Assert.True(region.Filter("desc")); - Assert.True(region.Filter("group")); - Assert.True(region.Filter("message")); - Assert.False(region.Filter("NotFound")); + Assert.True(region.Filter(FilterHelper.ParseKeyword("key"))); + Assert.False(region.Filter(FilterHelper.ParseKeyword("key=key"))); + Assert.True(region.Filter(FilterHelper.ParseKeyword("key=key1"))); + Assert.True(region.Filter(FilterHelper.ParseKeyword("room"))); + Assert.False(region.Filter(FilterHelper.ParseKeyword("to=room"))); + Assert.True(region.Filter(FilterHelper.ParseKeyword("to=room1"))); + Assert.True(region.Filter(FilterHelper.ParseKeyword("zone"))); + Assert.False(region.Filter(FilterHelper.ParseKeyword("to=zone"))); + Assert.True(region.Filter(FilterHelper.ParseKeyword("to=zone1"))); + Assert.True(region.Filter(FilterHelper.ParseKeyword("desc"))); + Assert.False(region.Filter(FilterHelper.ParseKeyword("desc=desc"))); + Assert.True(region.Filter(FilterHelper.ParseKeyword("desc=desc1"))); + Assert.True(region.Filter(FilterHelper.ParseKeyword("group"))); + Assert.False(region.Filter(FilterHelper.ParseKeyword("group=group"))); + Assert.True(region.Filter(FilterHelper.ParseKeyword("group=group1"))); + Assert.True(region.Filter(FilterHelper.ParseKeyword("message"))); + Assert.False(region.Filter(FilterHelper.ParseKeyword("message=message"))); + Assert.True(region.Filter(FilterHelper.ParseKeyword("message=message1"))); + Assert.False(region.Filter(FilterHelper.ParseKeyword("NotFound"))); Assert.Equal(2, region.ItemsCount); Region region2; @@ -771,12 +832,22 @@ public void TestLandmark() Group = "group1", Desc = "desc1" }; - Assert.True(lm.Filter("key")); - Assert.True(lm.Filter("type")); - Assert.True(lm.Filter("value")); - Assert.True(lm.Filter("group")); - Assert.True(lm.Filter("desc")); - Assert.False(lm.Filter("NotFound")); + Assert.True(lm.Filter(FilterHelper.ParseKeyword("key"))); + Assert.True(lm.Filter(FilterHelper.ParseKeyword("key=key1"))); + Assert.False(lm.Filter(FilterHelper.ParseKeyword("key=key"))); + Assert.True(lm.Filter(FilterHelper.ParseKeyword("type"))); + Assert.True(lm.Filter(FilterHelper.ParseKeyword("type=type1"))); + Assert.False(lm.Filter(FilterHelper.ParseKeyword("type=type"))); + Assert.True(lm.Filter(FilterHelper.ParseKeyword("value"))); + Assert.True(lm.Filter(FilterHelper.ParseKeyword("value=value1"))); + Assert.False(lm.Filter(FilterHelper.ParseKeyword("value=value"))); + Assert.True(lm.Filter(FilterHelper.ParseKeyword("group"))); + Assert.True(lm.Filter(FilterHelper.ParseKeyword("group=group1"))); + Assert.False(lm.Filter(FilterHelper.ParseKeyword("group=group"))); + Assert.True(lm.Filter(FilterHelper.ParseKeyword("desc"))); + Assert.True(lm.Filter(FilterHelper.ParseKeyword("desc=desc1"))); + Assert.False(lm.Filter(FilterHelper.ParseKeyword("desc=desc"))); + Assert.False(lm.Filter(FilterHelper.ParseKeyword("NotFound"))); Landmark lm2; lm2 = lm.Clone(); @@ -822,14 +893,28 @@ public void TestShortcut() RoomConditions = [new ValueCondition("con1", 1, false), new ValueCondition("con2", 1, true)], Conditions = [new ValueCondition("con3", 1, false), new ValueCondition("con4", 1, true)] }; - Assert.True(sc.Filter("key")); - Assert.True(sc.Filter("command")); - Assert.True(sc.Filter("to")); - Assert.True(sc.Filter("group")); - Assert.True(sc.Filter("desc")); - Assert.True(sc.Filter("on1")); - Assert.True(sc.Filter("on3")); - Assert.False(sc.Filter("NotFound")); + Assert.True(sc.Filter(FilterHelper.ParseKeyword("key"))); + Assert.True(sc.Filter(FilterHelper.ParseKeyword("key=key1"))); + Assert.False(sc.Filter(FilterHelper.ParseKeyword("key=key"))); + Assert.True(sc.Filter(FilterHelper.ParseKeyword("command"))); + Assert.True(sc.Filter(FilterHelper.ParseKeyword("command=command1"))); + Assert.False(sc.Filter(FilterHelper.ParseKeyword("command=command"))); + Assert.True(sc.Filter(FilterHelper.ParseKeyword("to"))); + Assert.True(sc.Filter(FilterHelper.ParseKeyword("to=to1"))); + Assert.False(sc.Filter(FilterHelper.ParseKeyword("to=to"))); + Assert.True(sc.Filter(FilterHelper.ParseKeyword("group"))); + Assert.True(sc.Filter(FilterHelper.ParseKeyword("group=group1"))); + Assert.False(sc.Filter(FilterHelper.ParseKeyword("group=group"))); + Assert.True(sc.Filter(FilterHelper.ParseKeyword("desc"))); + Assert.True(sc.Filter(FilterHelper.ParseKeyword("desc=desc1"))); + Assert.False(sc.Filter(FilterHelper.ParseKeyword("desc=desc"))); + Assert.True(sc.Filter(FilterHelper.ParseKeyword("on1"))); + Assert.True(sc.Filter(FilterHelper.ParseKeyword("tag=con1"))); + Assert.False(sc.Filter(FilterHelper.ParseKeyword("tag=con"))); + Assert.True(sc.Filter(FilterHelper.ParseKeyword("on3"))); + Assert.True(sc.Filter(FilterHelper.ParseKeyword("tag=con3"))); + Assert.False(sc.Filter(FilterHelper.ParseKeyword("tag=con"))); + Assert.False(sc.Filter(FilterHelper.ParseKeyword("NotFound"))); Shortcut sc2; sc2 = sc.Clone(); Assert.True(sc.Equal(sc2)); @@ -885,11 +970,19 @@ public void TestVariable() Group = "group1", Desc = "desc1" }; - Assert.True(var1.Filter("key")); - Assert.True(var1.Filter("value")); - Assert.True(var1.Filter("group")); - Assert.True(var1.Filter("desc")); - Assert.False(var1.Filter("NotFound")); + Assert.True(var1.Filter(FilterHelper.ParseKeyword("key"))); + Assert.True(var1.Filter(FilterHelper.ParseKeyword("key=key1"))); + Assert.False(var1.Filter(FilterHelper.ParseKeyword("key=key"))); + Assert.True(var1.Filter(FilterHelper.ParseKeyword("value"))); + Assert.True(var1.Filter(FilterHelper.ParseKeyword("value=value1"))); + Assert.False(var1.Filter(FilterHelper.ParseKeyword("value=value"))); + Assert.True(var1.Filter(FilterHelper.ParseKeyword("group"))); + Assert.True(var1.Filter(FilterHelper.ParseKeyword("group=group1"))); + Assert.False(var1.Filter(FilterHelper.ParseKeyword("group=group"))); + Assert.True(var1.Filter(FilterHelper.ParseKeyword("desc"))); + Assert.True(var1.Filter(FilterHelper.ParseKeyword("desc=desc1"))); + Assert.False(var1.Filter(FilterHelper.ParseKeyword("desc=desc"))); + Assert.False(var1.Filter(FilterHelper.ParseKeyword("NotFound"))); Variable var2; var2 = var1.Clone(); @@ -922,11 +1015,19 @@ public void TestSnapshot() Group = "group1", Timestamp = 1234567890 }; - Assert.True(snapshot.Filter("key")); - Assert.True(snapshot.Filter("type")); - Assert.True(snapshot.Filter("value")); - Assert.True(snapshot.Filter("group")); - Assert.False(snapshot.Filter("NotFound")); + Assert.True(snapshot.Filter(FilterHelper.ParseKeyword("key"))); + Assert.True(snapshot.Filter(FilterHelper.ParseKeyword("key=key1"))); + Assert.False(snapshot.Filter(FilterHelper.ParseKeyword("key=key"))); + Assert.True(snapshot.Filter(FilterHelper.ParseKeyword("type"))); + Assert.True(snapshot.Filter(FilterHelper.ParseKeyword("type=type1"))); + Assert.False(snapshot.Filter(FilterHelper.ParseKeyword("type=type"))); + Assert.True(snapshot.Filter(FilterHelper.ParseKeyword("value"))); + Assert.True(snapshot.Filter(FilterHelper.ParseKeyword("value=value1"))); + Assert.False(snapshot.Filter(FilterHelper.ParseKeyword("value=value"))); + Assert.True(snapshot.Filter(FilterHelper.ParseKeyword("group"))); + Assert.True(snapshot.Filter(FilterHelper.ParseKeyword("group=group1"))); + Assert.False(snapshot.Filter(FilterHelper.ParseKeyword("group=group"))); + Assert.False(snapshot.Filter(FilterHelper.ParseKeyword("NotFound"))); Assert.True(snapshot.Validated()); Snapshot snapshot2; @@ -1805,7 +1906,7 @@ public void TestSnapshotSearch() ss.Keywords = ["value3", "value4", "value"]; ss.Any = false; Assert.False(ss.Validate(snapshot)); - ss.MaxNoise=2; + ss.MaxNoise = 2; Assert.True(ss.Validate(snapshot)); } [Fact] diff --git a/doc/api/history.md b/doc/api/history.md index 112d2e9..bd98fd4 100644 --- a/doc/api/history.md +++ b/doc/api/history.md @@ -1,5 +1,10 @@ # API变更记录 + +## Version 1004 + +与hellmapmanager.ts的代码同步,对接口无影响。 + ## Version 1003 * SearchSnapshots 接口加入MaxNoise diff --git a/doc/tutorials/manual.md b/doc/tutorials/manual.md index 6a36c57..c9d7290 100644 --- a/doc/tutorials/manual.md +++ b/doc/tutorials/manual.md @@ -24,10 +24,10 @@ * 名称: 大镇街 * 分组: 佛山 * 出口: - * 目标:???? 指令 n - * 目标:???? 指令 e - * 目标:???? 指令 s - * 目标:???? 指令 e + * 目标:? 指令 n + * 目标:? 指令 e + * 目标:? 指令 s + * 目标:? 指令 e * 描述: Landmark 大镇街 结果如图 @@ -39,7 +39,7 @@ * 主键设置为不带业务数据的值。为了防止编码问题,建议使用字母数字的组合。 * 名称一般就是房间名,便于管理。 * 分组就是房间的地区。 -* 出口 的目标由于都不知道对应房间的信息,先都设为????,便于之后查遗补缺。 +* 出口 的目标由于都不知道对应房间的信息,先都设为?,便于之后查遗补缺。 * 描述是觉得这个房间可能可以用来定位,先标记下。 添加结束后,应该在房间列表中出现一个单独的房间,如下图 @@ -70,7 +70,7 @@ * 名称:北门 * 分组:佛山 * 出口: - * 目标 ???? 指令 n + * 目标 ? 指令 n * 目标 foshan-dazhenjie 指令 s 很明显,由于我们知道 s 对应的是之前的房间,所以,可以直接在新建出口窗口里点击 目标右侧的 选取按钮,在选取窗口里选择 房间(或者你手输/复制粘贴也可以): @@ -89,11 +89,11 @@ 回到大镇街,点击 左下方的编辑按钮,编辑n那个出口,指向北门 -保存后,会发现关系地图里两个地图 有了双向箭头 +保存后,会发现关系地图里两个房间有了双向箭头 ![关系地图3](../images/tutorials/manual-rmap3.png) -这时候双击那个不是????到foshan-beimen的n出口,或者双击地图上的 那个北门\(foshan-beimen\)/佛山的房间,关系地图就跳到北门了。 +这时候双击那个不是?到foshan-beimen的n出口,或者双击地图上的 那个北门\(foshan-beimen\)/佛山的房间,关系地图就跳到北门了。 这时候我们发现,北门也变成双向连接了。 @@ -101,7 +101,7 @@ 很好,干得好,下一步,就是继续把这个区域的房间都登记进去了。 -这时候,可不用急着把所有出口都维护正确,这是下一步的工作。 +这时候,并不用急着把所有出口都维护正确,这是下一步的工作。 ## 全面检查出口关系 @@ -115,19 +115,19 @@ 这时候我们开始继续了。 -还记得我们之前用了很多????的出口吗? +还记得我们之前用了很多?的出口吗? 然我们搜索下 ``` -佛山,???? +佛山,to=? ``` 用逗号分割2个关键字,就能找到佛山分组下所有未更新的出口了 ![列表](../images/tutorials/manual-list3.png) -嗯,发现明显有问题,感觉把这些出口的修复正确。 +嗯,发现明显有问题,赶紧把这些出口修复正确。 ## 更新定位 @@ -194,4 +194,12 @@ curl -X POST -d '{"From":["foshan-dazhenjie"],"Target":["foshan-linjiandao7"]}' 各种描述,地图,npc等,可以抓取快照。 -手动绘制的部分只是主干,通过代码同步更新的部分才是逐渐生产出来的血肉。 \ No newline at end of file +手动绘制的部分只是主干,通过代码同步更新的部分才是逐渐生产出来的血肉。 + +## 修订记录 + +由于mapper加入了高级关键字搜索功能。 + +原教程中的????目标改为?目标 + +搜索的 佛山,???? 改为 佛山,to=? \ No newline at end of file