From fe0e01b8fe610c0037b17aefc91ad143706ccd99 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Mon, 28 Nov 2022 15:30:37 +0100 Subject: [PATCH] Use compiled regex. --- Penumbra.GameData/Data/GamePathParser.cs | 118 ++++++++++------------- 1 file changed, 49 insertions(+), 69 deletions(-) diff --git a/Penumbra.GameData/Data/GamePathParser.cs b/Penumbra.GameData/Data/GamePathParser.cs index 58817c28..d784463a 100644 --- a/Penumbra.GameData/Data/GamePathParser.cs +++ b/Penumbra.GameData/Data/GamePathParser.cs @@ -1,7 +1,5 @@ using System; -using System.Collections.Generic; using System.IO; -using System.Linq; using System.Text; using System.Text.RegularExpressions; using Dalamud.Logging; @@ -80,62 +78,6 @@ internal class GamePathParser : IGamePathParser private const string WorldFolder1 = "bgcommon"; private const string WorldFolder2 = "bg"; - // @formatter:off - // language=regex - private readonly IReadOnlyDictionary>> _regexes = new Dictionary>>() - { - [FileType.Font] = new Dictionary> - { - [ObjectType.Font] = CreateRegexes(@"common/font/(?'fontname'.*)_(?'id'\d\d)(_lobby)?\.fdt"), - }, - [FileType.Texture] = new Dictionary> - { - [ObjectType.Icon] = CreateRegexes(@"ui/icon/(?'group'\d*)(/(?'lang'[a-z]{2}))?(/(?'hq'hq))?/(?'id'\d*)(?'hr'_hr1)?\.tex"), - [ObjectType.Map] = CreateRegexes(@"ui/map/(?'id'[a-z0-9]{4})/(?'variant'\d{2})/\k'id'\k'variant'(?'suffix'[a-z])?(_[a-z])?\.tex"), - [ObjectType.Weapon] = CreateRegexes(@"chara/weapon/w(?'id'\d{4})/obj/body/b(?'weapon'\d{4})/texture/v(?'variant'\d{2})_w\k'id'b\k'weapon'(_[a-z])?_[a-z]\.tex"), - [ObjectType.Monster] = CreateRegexes(@"chara/monster/m(?'monster'\d{4})/obj/body/b(?'id'\d{4})/texture/v(?'variant'\d{2})_m\k'monster'b\k'id'(_[a-z])?_[a-z]\.tex"), - [ObjectType.Equipment] = CreateRegexes(@"chara/equipment/e(?'id'\d{4})/texture/v(?'variant'\d{2})_c(?'race'\d{4})e\k'id'_(?'slot'[a-z]{3})(_[a-z])?_[a-z]\.tex"), - [ObjectType.DemiHuman] = CreateRegexes(@"chara/demihuman/d(?'id'\d{4})/obj/equipment/e(?'equip'\d{4})/texture/v(?'variant'\d{2})_d\k'id'e\k'equip'_(?'slot'[a-z]{3})(_[a-z])?_[a-z]\.tex"), - [ObjectType.Accessory] = CreateRegexes(@"chara/accessory/a(?'id'\d{4})/texture/v(?'variant'\d{2})_c(?'race'\d{4})a\k'id'_(?'slot'[a-z]{3})_[a-z]\.tex"), - [ObjectType.Character] = CreateRegexes( @"chara/human/c(?'race'\d{4})/obj/(?'type'[a-z]+)/(?'typeabr'[a-z])(?'id'\d{4})/texture/(?'minus'(--)?)(v(?'variant'\d{2})_)?c\k'race'\k'typeabr'\k'id'(_(?'slot'[a-z]{3}))?(_[a-z])?_[a-z]\.tex" - , @"chara/human/c(?'race'\d{4})/obj/(?'type'[a-z]+)/(?'typeabr'[a-z])(?'id'\d{4})/texture" - , @"chara/common/texture/skin(?'skin'.*)\.tex" - , @"chara/common/texture/(?'catchlight'catchlight)(.*)\.tex" - , @"chara/common/texture/decal_(?'location'[a-z]+)/[-_]?decal_(?'id'\d+).tex"), - }, - [FileType.Model] = new Dictionary> - { - [ObjectType.Weapon] = CreateRegexes(@"chara/weapon/w(?'id'\d{4})/obj/body/b(?'weapon'\d{4})/model/w\k'id'b\k'weapon'\.mdl"), - [ObjectType.Monster] = CreateRegexes(@"chara/monster/m(?'monster'\d{4})/obj/body/b(?'id'\d{4})/model/m\k'monster'b\k'id'\.mdl"), - [ObjectType.Equipment] = CreateRegexes(@"chara/equipment/e(?'id'\d{4})/model/c(?'race'\d{4})e\k'id'_(?'slot'[a-z]{3})\.mdl"), - [ObjectType.DemiHuman] = CreateRegexes(@"chara/demihuman/d(?'id'\d{4})/obj/equipment/e(?'equip'\d{4})/model/d\k'id'e\k'equip'_(?'slot'[a-z]{3})\.mdl"), - [ObjectType.Accessory] = CreateRegexes(@"chara/accessory/a(?'id'\d{4})/model/c(?'race'\d{4})a\k'id'_(?'slot'[a-z]{3})\.mdl"), - [ObjectType.Character] = CreateRegexes(@"chara/human/c(?'race'\d{4})/obj/(?'type'[a-z]+)/(?'typeabr'[a-z])(?'id'\d{4})/model/c\k'race'\k'typeabr'\k'id'_(?'slot'[a-z]{3})\.mdl"), - }, - [FileType.Material] = new Dictionary> - { - [ObjectType.Weapon] = CreateRegexes(@"chara/weapon/w(?'id'\d{4})/obj/body/b(?'weapon'\d{4})/material/v(?'variant'\d{4})/mt_w\k'id'b\k'weapon'_[a-z]+\.mtrl"), - [ObjectType.Monster] = CreateRegexes(@"chara/monster/m(?'monster'\d{4})/obj/body/b(?'id'\d{4})/material/v(?'variant'\d{4})/mt_m\k'monster'b\k'id'_[a-z]+\.mtrl"), - [ObjectType.Equipment] = CreateRegexes(@"chara/equipment/e(?'id'\d{4})/material/v(?'variant'\d{4})/mt_c(?'race'\d{4})e\k'id'_(?'slot'[a-z]{3})_[a-z]+\.mtrl"), - [ObjectType.DemiHuman] = CreateRegexes(@"chara/demihuman/d(?'id'\d{4})/obj/equipment/e(?'equip'\d{4})/material/v(?'variant'\d{4})/mt_d\k'id'e\k'equip'_(?'slot'[a-z]{3})_[a-z]+\.mtrl"), - [ObjectType.Accessory] = CreateRegexes(@"chara/accessory/a(?'id'\d{4})/material/v(?'variant'\d{4})/mt_c(?'race'\d{4})a\k'id'_(?'slot'[a-z]{3})_[a-z]+\.mtrl"), - [ObjectType.Character] = CreateRegexes(@"chara/human/c(?'race'\d{4})/obj/(?'type'[a-z]+)/(?'typeabr'[a-z])(?'id'\d{4})/material(/v(?'variant'\d{4}))?/mt_c\k'race'\k'typeabr'\k'id'(_(?'slot'[a-z]{3}))?_[a-z]+\.mtrl"), - }, - [FileType.Imc] = new Dictionary> - { - [ObjectType.Weapon] = CreateRegexes(@"chara/weapon/w(?'id'\d{4})/obj/body/b(?'weapon'\d{4})/b\k'weapon'\.imc"), - [ObjectType.Monster] = CreateRegexes(@"chara/monster/m(?'monster'\d{4})/obj/body/b(?'id'\d{4})/b\k'id'\.imc"), - [ObjectType.Equipment] = CreateRegexes(@"chara/equipment/e(?'id'\d{4})/e\k'id'\.imc"), - [ObjectType.DemiHuman] = CreateRegexes(@"chara/demihuman/d(?'id'\d{4})/obj/equipment/e(?'equip'\d{4})/e\k'equip'\.imc"), - [ObjectType.Accessory] = CreateRegexes(@"chara/accessory/a(?'id'\d{4})/a\k'id'\.imc"), - }, - }; - - private static IReadOnlyList CreateRegexes(params string[] regexes) - => regexes.Select(s => new Regex(s, RegexOptions.Compiled)).ToArray(); - // @formatter:on - - public ObjectType PathToObjectType(string path) { if (path.Length == 0) @@ -190,20 +132,58 @@ internal class GamePathParser : IGamePathParser var objectType = PathToObjectType(path); - if (!_regexes.TryGetValue(fileType, out var objectDict)) - return (fileType, objectType, null); - - if (!objectDict.TryGetValue(objectType, out var regexes)) - return (fileType, objectType, null); - - foreach (var regex in regexes) + static Match TestCharacterTextures(string path) { - var match = regex.Match(path); - if (match.Success) - return (fileType, objectType, match); + var regexes = new Regex[] + { + GamePathManager.Character.Tex.Regex(), + GamePathManager.Character.Tex.FolderRegex(), + GamePathManager.Character.Tex.SkinRegex(), + GamePathManager.Character.Tex.CatchlightRegex(), + GamePathManager.Character.Tex.DecalRegex(), + }; + foreach (var regex in regexes) + { + var match = regex.Match(path); + if (match.Success) + return match; + } + + return Match.Empty; } - return (fileType, objectType, null); + var match = (fileType, objectType) switch + { + (FileType.Font, ObjectType.Font) => GamePathManager.Font.Regex().Match(path), + (FileType.Imc, ObjectType.Weapon) => GamePathManager.Weapon.Imc.Regex().Match(path), + (FileType.Imc, ObjectType.Monster) => GamePathManager.Monster.Imc.Regex().Match(path), + (FileType.Imc, ObjectType.DemiHuman) => GamePathManager.DemiHuman.Imc.Regex().Match(path), + (FileType.Imc, ObjectType.Equipment) => GamePathManager.Equipment.Imc.Regex().Match(path), + (FileType.Imc, ObjectType.Accessory) => GamePathManager.Accessory.Imc.Regex().Match(path), + (FileType.Model, ObjectType.Weapon) => GamePathManager.Weapon.Mdl.Regex().Match(path), + (FileType.Model, ObjectType.Monster) => GamePathManager.Monster.Mdl.Regex().Match(path), + (FileType.Model, ObjectType.DemiHuman) => GamePathManager.DemiHuman.Mdl.Regex().Match(path), + (FileType.Model, ObjectType.Equipment) => GamePathManager.Equipment.Mdl.Regex().Match(path), + (FileType.Model, ObjectType.Accessory) => GamePathManager.Accessory.Mdl.Regex().Match(path), + (FileType.Model, ObjectType.Character) => GamePathManager.Character.Mdl.Regex().Match(path), + (FileType.Material, ObjectType.Weapon) => GamePathManager.Weapon.Mtrl.Regex().Match(path), + (FileType.Material, ObjectType.Monster) => GamePathManager.Monster.Mtrl.Regex().Match(path), + (FileType.Material, ObjectType.DemiHuman) => GamePathManager.DemiHuman.Mtrl.Regex().Match(path), + (FileType.Material, ObjectType.Equipment) => GamePathManager.Equipment.Mtrl.Regex().Match(path), + (FileType.Material, ObjectType.Accessory) => GamePathManager.Accessory.Mtrl.Regex().Match(path), + (FileType.Material, ObjectType.Character) => GamePathManager.Character.Mtrl.Regex().Match(path), + (FileType.Texture, ObjectType.Weapon) => GamePathManager.Weapon.Tex.Regex().Match(path), + (FileType.Texture, ObjectType.Monster) => GamePathManager.Monster.Tex.Regex().Match(path), + (FileType.Texture, ObjectType.DemiHuman) => GamePathManager.DemiHuman.Tex.Regex().Match(path), + (FileType.Texture, ObjectType.Equipment) => GamePathManager.Equipment.Tex.Regex().Match(path), + (FileType.Texture, ObjectType.Accessory) => GamePathManager.Accessory.Tex.Regex().Match(path), + (FileType.Texture, ObjectType.Character) => TestCharacterTextures(path), + (FileType.Texture, ObjectType.Icon) => GamePathManager.Icon.Regex().Match(path), + (FileType.Texture, ObjectType.Map) => GamePathManager.Map.Regex().Match(path), + _ => Match.Empty, + }; + + return (fileType, objectType, match.Success ? match : null); } private static GameObjectInfo HandleEquipment(FileType fileType, GroupCollection groups)