diff --git a/AssemblyRemapper/Commands/CommandProcessor.cs b/AssemblyRemapper/Commands/CommandProcessor.cs index 5eb5d16..6915370 100644 --- a/AssemblyRemapper/Commands/CommandProcessor.cs +++ b/AssemblyRemapper/Commands/CommandProcessor.cs @@ -1,4 +1,4 @@ -using AssemblyRemapper.Reflection; +using AssemblyRemapper.Remapper; using AssemblyRemapper.Utils; namespace AssemblyRemapper.Commands @@ -23,7 +23,7 @@ namespace AssemblyRemapper.Commands { if (command == "remap" || command == "Remap") { - var remapper = new Remapper(); + var remapper = new Remapper.Remapper(); DataProvider.LoadMappingFile(); DataProvider.LoadAssemblyDefinition(); diff --git a/AssemblyRemapper/Enums/EFailureReason.cs b/AssemblyRemapper/Enums/EFailureReason.cs index 9d597c0..ebed52c 100644 --- a/AssemblyRemapper/Enums/EFailureReason.cs +++ b/AssemblyRemapper/Enums/EFailureReason.cs @@ -13,6 +13,7 @@ internal enum EFailureReason HasGenericParameters, HasAttribute, IsAttribute, + Constructor, HasMethods, HasFields, HasProperties, diff --git a/AssemblyRemapper/Enums/EMatchResult.cs b/AssemblyRemapper/Enums/EMatchResult.cs index b1457f2..3f9bc07 100644 --- a/AssemblyRemapper/Enums/EMatchResult.cs +++ b/AssemblyRemapper/Enums/EMatchResult.cs @@ -2,8 +2,7 @@ internal enum EMatchResult { - NoMatch = -1, Disabled = 0, - SearchedNoResult = 1, + NoMatch = 1, Match = 2, } \ No newline at end of file diff --git a/AssemblyRemapper/Models/RemapModel.cs b/AssemblyRemapper/Models/RemapModel.cs index 0e32a7c..970d9de 100644 --- a/AssemblyRemapper/Models/RemapModel.cs +++ b/AssemblyRemapper/Models/RemapModel.cs @@ -14,9 +14,6 @@ internal class RemapModel [JsonIgnore] public EFailureReason FailureReason { get; set; } - [JsonIgnore] - public HashSet Scores { get; set; } = []; - public string NewTypeName { get; set; } = string.Empty; public string OriginalTypeName { get; set; } = string.Empty; @@ -31,18 +28,39 @@ internal class RemapModel /// internal class SearchParams { + #region BOOL_PARAMS + public bool? IsPublic { get; set; } = null; public bool? IsAbstract { get; set; } = null; public bool? IsInterface { get; set; } = null; public bool? IsEnum { get; set; } = null; public bool? IsNested { get; set; } = null; - public string? ParentName { get; set; } = null; public bool? IsSealed { get; set; } = null; public bool? HasAttribute { get; set; } = null; public bool? IsDerived { get; set; } = null; public bool? HasGenericParameters { get; set; } = null; - public string MatchBaseClass { get; set; } - public string IgnoreBaseClass { get; set; } + + #endregion BOOL_PARAMS + + #region STR_PARAMS + + public string? ParentName { get; set; } = null; + public string? MatchBaseClass { get; set; } = null; + public string? IgnoreBaseClass { get; set; } = null; + + #endregion STR_PARAMS + + #region INT_PARAMS + + public int? ConstructorParameterCount { get; set; } = null; + public int? MethodCount { get; set; } = null; + public int? FieldCount { get; set; } = null; + public int? PropertyCount { get; set; } = null; + + #endregion INT_PARAMS + + #region LISTS + public List MatchMethods { get; set; } public List IgnoreMethods { get; set; } public List MatchFields { get; set; } @@ -52,6 +70,8 @@ internal class SearchParams public List MatchNestedTypes { get; set; } public List IgnoreNestedTypes { get; set; } + #endregion LISTS + public SearchParams() { } diff --git a/AssemblyRemapper/Reflection/Publicizer.cs b/AssemblyRemapper/Remapper/Publicizer.cs similarity index 97% rename from AssemblyRemapper/Reflection/Publicizer.cs rename to AssemblyRemapper/Remapper/Publicizer.cs index 777090e..70abae2 100644 --- a/AssemblyRemapper/Reflection/Publicizer.cs +++ b/AssemblyRemapper/Remapper/Publicizer.cs @@ -1,6 +1,6 @@ using AssemblyRemapper.Utils; -namespace AssemblyRemapper.Reflection; +namespace AssemblyRemapper.Remapper; internal static class Publicizer { diff --git a/AssemblyRemapper/Reflection/Remapper.cs b/AssemblyRemapper/Remapper/Remapper.cs similarity index 97% rename from AssemblyRemapper/Reflection/Remapper.cs rename to AssemblyRemapper/Remapper/Remapper.cs index 6b5cfd4..871de3d 100644 --- a/AssemblyRemapper/Reflection/Remapper.cs +++ b/AssemblyRemapper/Remapper/Remapper.cs @@ -1,9 +1,10 @@ using AssemblyRemapper.Enums; using AssemblyRemapper.Models; +using AssemblyRemapper.Remapper.Search; using AssemblyRemapper.Utils; using Mono.Cecil; -namespace AssemblyRemapper.Reflection; +namespace AssemblyRemapper.Remapper; internal class Remapper { @@ -148,6 +149,12 @@ internal class Remapper return EFailureReason.HasAttribute; } + if (type.MatchConstructors(remap.SearchParams, score) == EMatchResult.NoMatch) + { + remap.FailureReason = EFailureReason.Constructor; + return EFailureReason.Constructor; + } + if (type.MatchMethods(remap.SearchParams, score) == EMatchResult.NoMatch) { remap.FailureReason = EFailureReason.HasMethods; diff --git a/AssemblyRemapper/Reflection/Renamer.cs b/AssemblyRemapper/Remapper/Renamer.cs similarity index 98% rename from AssemblyRemapper/Reflection/Renamer.cs rename to AssemblyRemapper/Remapper/Renamer.cs index a6e5dbd..48b0c9b 100644 --- a/AssemblyRemapper/Reflection/Renamer.cs +++ b/AssemblyRemapper/Remapper/Renamer.cs @@ -3,7 +3,7 @@ using AssemblyRemapper.Utils; using Mono.Cecil; using Mono.Collections.Generic; -namespace AssemblyRemapper.Reflection; +namespace AssemblyRemapper.Remapper; internal static class Renamer { diff --git a/AssemblyRemapper/Remapper/Search/Constructors.cs b/AssemblyRemapper/Remapper/Search/Constructors.cs new file mode 100644 index 0000000..0d3fd08 --- /dev/null +++ b/AssemblyRemapper/Remapper/Search/Constructors.cs @@ -0,0 +1,36 @@ +using AssemblyRemapper.Enums; +using AssemblyRemapper.Models; +using Mono.Cecil; +using Mono.Cecil.Rocks; + +namespace AssemblyRemapper.Remapper.Search; + +internal static class Constructors +{ + /// + /// Search for types with a constructor of a given length + /// + /// + /// + /// Match if constructor parameters matches + public static EMatchResult GetTypeByParameterCount(TypeDefinition type, SearchParams parms, ScoringModel score) + { + if (parms.ConstructorParameterCount is null) + { + return EMatchResult.Disabled; + } + + var constructors = type.GetConstructors(); + + foreach (var constructor in constructors) + { + if (constructor.Parameters.Count == parms.ConstructorParameterCount) + { + score.Score++; + return EMatchResult.Match; + } + } + + return EMatchResult.NoMatch; + } +} \ No newline at end of file diff --git a/AssemblyRemapper/Remapper/Search/Fields.cs b/AssemblyRemapper/Remapper/Search/Fields.cs new file mode 100644 index 0000000..c13f4a4 --- /dev/null +++ b/AssemblyRemapper/Remapper/Search/Fields.cs @@ -0,0 +1,5 @@ +namespace AssemblyRemapper.Remapper.Search; + +internal static class Fields +{ +} \ No newline at end of file diff --git a/AssemblyRemapper/Remapper/Search/Methods.cs b/AssemblyRemapper/Remapper/Search/Methods.cs new file mode 100644 index 0000000..30af909 --- /dev/null +++ b/AssemblyRemapper/Remapper/Search/Methods.cs @@ -0,0 +1,99 @@ +using AssemblyRemapper.Enums; +using AssemblyRemapper.Models; +using Mono.Cecil; +using Mono.Cecil.Rocks; + +namespace AssemblyRemapper.Remapper.Search; + +internal static class Methods +{ + /// + /// returns a match on all types with the specified methods + /// + /// + /// + /// + /// Match if type contains any supplied methods + public static EMatchResult GetTypeWithMethods(TypeDefinition type, SearchParams parms, ScoringModel score) + { + var matchCount = 0; + + // Handle match methods + foreach (var method in type.Methods) + { + foreach (var name in parms.MatchMethods) + { + // Method name match + if (method.Name == name) + { + matchCount += 1; + score.Score++; + } + } + } + + return matchCount > 0 + ? EMatchResult.Match + : EMatchResult.NoMatch; + } + + /// + /// Returns a match on all types without methods + /// + /// + /// + /// + /// Match if type has no methods + public static EMatchResult GetTypeWithoutMethods(TypeDefinition type, SearchParams parms, ScoringModel score) + { + if (parms.IgnoreMethods is null) return EMatchResult.Disabled; + + var skippAll = parms.IgnoreMethods.Contains("*"); + var methodCount = type.Methods.Count - type.GetConstructors().Count(); + + // Subtract method count from constructor count to check for real methods + if (methodCount is 0 && skippAll is true) + { + score.Score++; + return EMatchResult.Match; + } + + return EMatchResult.NoMatch; + } + + /// + /// Get all types without the specified method + /// + /// + /// + /// + /// + public static EMatchResult GetTypeWithNoMethods(TypeDefinition type, SearchParams parms, ScoringModel score) + { + if (parms.IgnoreMethods is null) { return EMatchResult.Disabled; } + + foreach (var method in type.Methods) + { + if (parms.IgnoreMethods.Contains(method.Name)) + { + return EMatchResult.NoMatch; + } + } + + score.Score++; + return EMatchResult.Match; + } + + public static EMatchResult GetTypeByNumberOfMethods(TypeDefinition type, SearchParams parms, ScoringModel score) + { + if (parms.MethodCount is null) { return EMatchResult.Disabled; } + + if (type.Methods.Count == parms.MethodCount) + { + score.Score++; + return EMatchResult.Match; + } + + return EMatchResult.NoMatch; + } +} \ No newline at end of file diff --git a/AssemblyRemapper/Remapper/Search/NestedTypes.cs b/AssemblyRemapper/Remapper/Search/NestedTypes.cs new file mode 100644 index 0000000..18d090d --- /dev/null +++ b/AssemblyRemapper/Remapper/Search/NestedTypes.cs @@ -0,0 +1,5 @@ +namespace AssemblyRemapper.Remapper.Search; + +internal class NestedTypes +{ +} \ No newline at end of file diff --git a/AssemblyRemapper/Remapper/Search/Properties.cs b/AssemblyRemapper/Remapper/Search/Properties.cs new file mode 100644 index 0000000..7d794ce --- /dev/null +++ b/AssemblyRemapper/Remapper/Search/Properties.cs @@ -0,0 +1,6 @@ +namespace AssemblyRemapper.Remapper.Search +{ + internal class Properties + { + } +} \ No newline at end of file diff --git a/AssemblyRemapper/Reflection/SearchExtentions.cs b/AssemblyRemapper/Remapper/Search/TypeDefExtensions.cs similarity index 83% rename from AssemblyRemapper/Reflection/SearchExtentions.cs rename to AssemblyRemapper/Remapper/Search/TypeDefExtensions.cs index 5c09407..36de9c2 100644 --- a/AssemblyRemapper/Reflection/SearchExtentions.cs +++ b/AssemblyRemapper/Remapper/Search/TypeDefExtensions.cs @@ -1,11 +1,12 @@ using AssemblyRemapper.Enums; using AssemblyRemapper.Models; +using AssemblyRemapper.Utils; using Mono.Cecil; using Mono.Cecil.Rocks; -namespace AssemblyRemapper.Reflection; +namespace AssemblyRemapper.Remapper.Search; -internal static class SearchExtentions +internal static class TypeDefExtensions { public static EMatchResult MatchIsAbstract(this TypeDefinition type, SearchParams parms, ScoringModel score) { @@ -181,52 +182,56 @@ internal static class SearchExtentions return EMatchResult.NoMatch; } + public static EMatchResult MatchConstructors(this TypeDefinition type, SearchParams parms, ScoringModel score) + { + var matches = new List { }; + + if (parms.ConstructorParameterCount is not null) + { + matches.Add(Constructors.GetTypeByParameterCount(type, parms, score)); + } + + return matches.GetMatch(); + } + + /// + /// Handle running all method matching routines + /// + /// Match if any search criteria met public static EMatchResult MatchMethods(this TypeDefinition type, SearchParams parms, ScoringModel score) { - // We're not searching for methods and this type contains methods - if (parms.MatchMethods.Count is 0 && parms.IgnoreMethods.Count is 0) + var matches = new List { }; + + if (parms.MatchMethods.Count > 0 && parms.IgnoreMethods.Contains("*") is true) { - return EMatchResult.Disabled; + Logger.Log($"Cannot both ignore all methods and search for a method on {score.ProposedNewName}.", ConsoleColor.Red); + return EMatchResult.NoMatch; + } + else if (parms.MatchMethods.Count > 0) + { + matches.Add(Methods.GetTypeWithMethods(type, parms, score)); } - var skippAll = parms.IgnoreMethods.Contains("*"); - var methodCount = type.Methods.Count - type.GetConstructors().Count(); - - // Subtract method count from constructor count to check for real methods - if (methodCount is 0 && skippAll is true) + if (parms.IgnoreMethods.Count > 0) { - return EMatchResult.Match; + Logger.Log("TypeWithoutMethods"); + matches.Add(Methods.GetTypeWithoutMethods(type, parms, score)); } - // Handle Ignore methods - foreach (var method in type.Methods) + if (parms.IgnoreMethods.Contains("*")) { - if (parms.IgnoreMethods.Contains(method.Name)) - { - // Contains blacklisted method, no match - score.FailureReason = EFailureReason.HasMethods; - score.Score--; - return EMatchResult.NoMatch; - } + Logger.Log("TypeWithNoMethods"); + matches.Add(Methods.GetTypeWithNoMethods(type, parms, score)); } - var matchCount = 0; - - // Handle match methods - foreach (var method in type.Methods) + if (parms.MethodCount > 0) { - foreach (var name in parms.MatchMethods) - { - // Method name match - if (method.Name == name) - { - matchCount += 1; - score.Score++; - } - } + Logger.Log("TypeByNumberOfMethods"); + matches.Add(Methods.GetTypeByNumberOfMethods(type, parms, score)); } - return matchCount > 0 ? EMatchResult.Match : EMatchResult.NoMatch; + // return match if any condition matched + return matches.GetMatch(); } public static EMatchResult MatchFields(this TypeDefinition type, SearchParams parms, ScoringModel score) @@ -241,6 +246,7 @@ internal static class SearchExtentions // Type has fields, we dont want any if (type.HasFields is false && skippAll is true) { + score.Score++; return EMatchResult.Match; } diff --git a/AssemblyRemapper/Utils/EnumHelpers.cs b/AssemblyRemapper/Utils/EnumHelpers.cs new file mode 100644 index 0000000..c7b4d5e --- /dev/null +++ b/AssemblyRemapper/Utils/EnumHelpers.cs @@ -0,0 +1,23 @@ +using AssemblyRemapper.Enums; + +namespace AssemblyRemapper.Utils; + +internal static class EnumExtensions +{ + /// + /// Returns a match from a list of match results + /// + /// + /// highest EMatchResult + public static EMatchResult GetMatch(this List matches) + { + if (matches.Contains(EMatchResult.Disabled)) { return EMatchResult.Disabled; } + + if (matches.Contains(EMatchResult.NoMatch)) { return EMatchResult.NoMatch; } + + if (matches.Contains(EMatchResult.Match)) { return EMatchResult.Match; } + + // default to disabled + return EMatchResult.Disabled; + } +} \ No newline at end of file diff --git a/Templates/MappingTemplate.jsonc b/Templates/MappingTemplate.jsonc index 11b6126..575bd71 100644 --- a/Templates/MappingTemplate.jsonc +++ b/Templates/MappingTemplate.jsonc @@ -1,23 +1,40 @@ [ // TEMPLATE - // NOTE: You only need to add the properties you need inside of `SearchParams` + // NOTE: Only add the properties you need inside of `SearchParams` + // The remapper will take any and all consideration you give it + // it uses any input you give it its matching, so only use parameters you need. + // Tldr; The remapper is a giant state machine, you get what you ask for { "NewTypeName": "TEMPLATE", // This is the name we want to change it to "OriginalTypeName": "", // This is the name of the object in the assembly, Can be used to store what type you're changing as its not read unless "UseDirectRename" is true, it is also written to after remapping "UseForceRename": false, // If this is true, directly remap using the name in the assembly from the above property "SearchParams": { // null means disabled - "IsPublic": null, // Is the Type public? (bool) - "IsAbstract": null, // Is the Type Abstract? (bool) - "IsInterface": null, // Is the Type an Interface? (bool) - "IsEnum": null, // Is the Type an Enum? (bool) - "IsNested": null, // Is the Type Nested? (bool) - "ParentName": "", // The Name of the parent type if it is nested, can be left empty (string) - "IsSealed": null, // Is the Type Sealed? (bool) - "HasAttribute": null, // Does the Type have an attribute? (bool) - "IsDerived": null, // Does the Type inherit from another Type? (bool) + + // Bool parameters + + "IsPublic": false, // Is the Type public? + "IsAbstract": false, // Is the Type Abstract? + "IsInterface": false, // Is the Type an Interface? + "IsEnum": false, // Is the Type an Enum? + "IsNested": false, // Is the Type Nested? + "IsSealed": false, // Is the Type Sealed? + "HasAttribute": false, // Does the Type have an attribute? + "IsDerived": false, // Does the Type inherit from another Type? + "HasGenericParameters": false, // Does the type have generic parameters? + + // String parameters + + "ParentName": "", // The Name of the parent type (IsNested must be enabled) "MatchBaseClass": "", // Base class to match (IsDerived must be enabled) "IgnoreBaseClass": "", // Base class to ignore (IsDerived must be enabled) - "HasGenericParameters": null, // Does the type have generic parameters? (bool) + + // Integer parameters + + "ConstructorParameterCount": 0, // Match types that have a constructor parameter of this length + "MethodCount": 0, // Match types that have a method count this length + "FieldCount": 0, // Match types that have a method count this length + "PropertyCount": 0, // Match types that have a method count this length + // Note: // - You can can filter the ignore list with a wild card '*' to match all types that have none of that search parameter // - These are all lists of strings