diff --git a/LightlessSync/Services/ModelDecimation/MdlDecimator.cs b/LightlessSync/Services/ModelDecimation/MdlDecimator.cs index 55b511c..4fcdbc0 100644 --- a/LightlessSync/Services/ModelDecimation/MdlDecimator.cs +++ b/LightlessSync/Services/ModelDecimation/MdlDecimator.cs @@ -1343,22 +1343,11 @@ internal static class MdlDecimator return false; } - return IsBodyMaterial(mdl.Materials[mesh.MaterialIndex]); + return ModelDecimationFilters.IsBodyMaterial(mdl.Materials[mesh.MaterialIndex]); } private static bool IsBodyMaterial(string materialPath) - { - if (string.IsNullOrWhiteSpace(materialPath)) - { - return false; - } - - var normalized = materialPath.Replace('\\', '/').ToLowerInvariant(); - var nameStart = normalized.LastIndexOf('/'); - var fileName = nameStart >= 0 ? normalized[(nameStart + 1)..] : normalized; - return fileName.Contains("_bibo", StringComparison.Ordinal) - || fileName.EndsWith("_a.mtrl", StringComparison.Ordinal); - } + => ModelDecimationFilters.IsBodyMaterial(materialPath); private sealed class BodyCollisionData { diff --git a/LightlessSync/Services/ModelDecimation/ModelDecimationFilters.cs b/LightlessSync/Services/ModelDecimation/ModelDecimationFilters.cs new file mode 100644 index 0000000..622410c --- /dev/null +++ b/LightlessSync/Services/ModelDecimation/ModelDecimationFilters.cs @@ -0,0 +1,126 @@ +namespace LightlessSync.Services.ModelDecimation; + +internal static class ModelDecimationFilters +{ + // MODELS ONLY HERE, NOT MATERIALS + internal static readonly string[] HairPaths = + [ + "/hair/", + "hir.mdl", + ]; + + internal static readonly string[] ClothingPaths = + [ + "chara/equipment/", + "/equipment/", + + "met.mdl", + "top.mdl", + "glv.mdl", + "dwn.mdl", + "sho.mdl", + ]; + + internal static readonly string[] AccessoryPaths = + [ + "/accessory/", + "chara/accessory/", + + "ear.mdl", + "nek.mdl", + "wrs.mdl", + "ril.mdl", + "rir.mdl", + ]; + + internal static readonly string[] BodyPaths = + [ + "/body/", + "chara/equipment/e0000/model/", + "chara/equipment/e9903/model/", + "chara/equipment/e9903/model/", + ]; + + internal static readonly string[] FaceHeadPaths = + [ + "/face/", + "/obj/face/", + "/head/", + "fac.mdl", + ]; + + internal static readonly string[] TailOrEarPaths = + [ + "/tail/", + "/obj/tail/", + "/zear/", + "/obj/zear/", + + "til.mdl", + "zer.mdl", + ]; + + // BODY MATERIALS ONLY, NOT MESHES + internal static readonly string[] BodyMaterials = + [ + "_bibo", + "_a.mtrl", + "_b.mtrl", + ]; + + internal static string NormalizePath(string path) + => path.Replace('\\', '/').ToLowerInvariant(); + + internal static bool IsHairPath(string normalizedPath) + => ContainsAny(normalizedPath, HairPaths); + + internal static bool IsClothingPath(string normalizedPath) + => ContainsAny(normalizedPath, ClothingPaths); + + internal static bool IsAccessoryPath(string normalizedPath) + => ContainsAny(normalizedPath, AccessoryPaths); + + + internal static bool IsBodyPath(string normalizedPath) + => ContainsAny(normalizedPath, BodyPaths); + + internal static bool IsFaceHeadPath(string normalizedPath) + => ContainsAny(normalizedPath, FaceHeadPaths); + + internal static bool IsTailOrEarPath(string normalizedPath) + => ContainsAny(normalizedPath, TailOrEarPaths); + + internal static bool ContainsAny(string normalizedPath, IReadOnlyList markers) + { + for (var i = 0; i < markers.Count; i++) + { + if (normalizedPath.Contains(markers[i], StringComparison.Ordinal)) + { + return true; + } + } + + return false; + } + + internal static bool IsBodyMaterial(string materialPath) + { + if (string.IsNullOrWhiteSpace(materialPath)) + { + return false; + } + + var normalized = NormalizePath(materialPath); + var nameStart = normalized.LastIndexOf('/'); + var fileName = nameStart >= 0 ? normalized[(nameStart + 1)..] : normalized; + foreach (var marker in BodyMaterials) + { + if (fileName.Contains(marker, StringComparison.Ordinal)) + { + return true; + } + } + + return false; + } +} diff --git a/LightlessSync/Services/ModelDecimation/ModelDecimationService.cs b/LightlessSync/Services/ModelDecimation/ModelDecimationService.cs index 00406f6..3caa070 100644 --- a/LightlessSync/Services/ModelDecimation/ModelDecimationService.cs +++ b/LightlessSync/Services/ModelDecimation/ModelDecimationService.cs @@ -348,46 +348,40 @@ public sealed class ModelDecimationService return true; } - var normalized = NormalizeGamePath(gamePath); - if (normalized.Contains("/hair/", StringComparison.Ordinal)) + var normalized = ModelDecimationFilters.NormalizePath(gamePath); + if (ModelDecimationFilters.IsHairPath(normalized)) { return false; } - if (normalized.Contains("/chara/equipment/", StringComparison.Ordinal)) + if (ModelDecimationFilters.IsClothingPath(normalized)) { return _performanceConfigService.Current.ModelDecimationAllowClothing; } - if (normalized.Contains("/chara/accessory/", StringComparison.Ordinal)) + if (ModelDecimationFilters.IsAccessoryPath(normalized)) { return _performanceConfigService.Current.ModelDecimationAllowAccessories; } - if (normalized.Contains("/chara/human/", StringComparison.Ordinal)) + if (ModelDecimationFilters.IsBodyPath(normalized)) { - if (normalized.Contains("/body/", StringComparison.Ordinal)) - { - return _performanceConfigService.Current.ModelDecimationAllowBody; - } + return _performanceConfigService.Current.ModelDecimationAllowBody; + } - if (normalized.Contains("/face/", StringComparison.Ordinal) || normalized.Contains("/head/", StringComparison.Ordinal)) - { - return _performanceConfigService.Current.ModelDecimationAllowFaceHead; - } + if (ModelDecimationFilters.IsFaceHeadPath(normalized)) + { + return _performanceConfigService.Current.ModelDecimationAllowFaceHead; + } - if (normalized.Contains("/tail/", StringComparison.Ordinal)) - { - return _performanceConfigService.Current.ModelDecimationAllowTail; - } + if (ModelDecimationFilters.IsTailOrEarPath(normalized)) + { + return _performanceConfigService.Current.ModelDecimationAllowTail; } return true; } - private static string NormalizeGamePath(string path) - => path.Replace('\\', '/').ToLowerInvariant(); - private bool TryGetDecimationSettings(out ModelDecimationSettings settings) { settings = new ModelDecimationSettings(