Dnlib refactor

* First compiling build

* fix out path

* fix hollow

* Traditional loops in favor of linq for clarity

* Start refactor

* Refactor part 2

* Rename variable

* Better error reason handling

* Clean up enum

* Refactor part 3

* Use combo boxes in favor of updowns

* Update tooltips

* fix is nested tree view display

* Capitialization

* Refactor part ??

* remove unused methods

* Expanded IsNested Check

* TypeFilter class + Fix CLI bug

* Remove reflection, change IsDerived and IsNested checks

* Remove optional out for IsPublic

* Remove nullable from IsPublic

* fix logger not resetting color

* actually fix it...

* remove redundant if else on IsPublic check

* Add logging to indicate all types have been filtered out

* Default IsPublic to true

* remove duplicate method call

* Refactor logger to be on its own thread

* Multithread remapping and grouped logging for threads

* 5 more filters

* Finish migrating to the new system

* bug fixes

* Add empty string validation to text fields

* re-enable renamer

* restore renamer

* Multi threaded renaming, still broken

* Basis for method renaming

* More renamer work, might get a passing build now?

* Re-enable publicizer

* Rework logging

* re-enable mapping updates

* fix hollow

* Iterate over all types instead of just one to re-link fields

* Add reference list command

---------

Co-authored-by: clodan <clodan@clodan.com>
This commit is contained in:
CJ-SPT 2024-06-26 14:45:54 -04:00 committed by GitHub
parent 4a24c914f6
commit d33f1f3c9b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
40 changed files with 1793 additions and 1407 deletions

View File

@ -17,7 +17,7 @@
"viewState": {
"x": -1324.3333740234375,
"y": -365.66656494140625,
"zoom": 0
"zoom": -0.6666666666666666
}
}
}

View File

@ -1,7 +1,12 @@
{
"nodes":[
{"id":"ffede66903965668","x":-1260,"y":-740,"width":660,"height":300,"color":"4","type":"text","text":"ReCodeIt Cross Compiler\n\n- "},
{"id":"4116b6bff3d9eb35","x":-2020,"y":-740,"width":250,"height":460,"type":"text","text":"ReCodeItCrossCompiler\n\n"}
{"id":"02cecbc06ca4e27e","x":-2460,"y":-840,"width":680,"height":440,"type":"text","text":"Re-Mapper overhaul\n\n- More required parameters for better searches\n - Is Asbstract\n - Is Interface\n - Is Public"},
{"id":"ef843881ce9f25ca","x":-1410,"y":-680,"width":170,"height":60,"type":"text","text":"Is Abstract"},
{"id":"d0995cf4fa4e7306","x":-1194,"y":-840,"width":120,"height":60,"type":"text","text":"IsPublic"},
{"id":"ef16782e8346c662","type":"text","text":"Is Interface","x":-1208,"y":-676,"width":149,"height":56}
],
"edges":[]
"edges":[
{"id":"3e2076115efebf6f","fromNode":"d0995cf4fa4e7306","fromSide":"bottom","toNode":"ef843881ce9f25ca","toSide":"top"},
{"id":"a7c1e1576f14002e","fromNode":"d0995cf4fa4e7306","fromSide":"bottom","toNode":"ef16782e8346c662","toSide":"top"}
]
}

View File

@ -26,6 +26,10 @@ public class Build : ICommand
if (isRemote) { return; }
await UseLastLoadedProject(console);
// Wait for log termination
Logger.Terminate();
while(Logger.IsRunning()) {}
}
private async Task<bool> UseLocalProject(IConsole console)

View File

@ -30,9 +30,12 @@ public class BuildRef : ICommand
CrossCompiler.StartRemap();
DataProvider.SaveAppSettings();
return default;
}
// Wait for log termination
Logger.Terminate();
while(Logger.IsRunning()) {}
return default;
}

View File

@ -23,6 +23,10 @@ public class DeObfuscate : ICommand
Logger.Log("Complete", ConsoleColor.Green);
// Wait for log termination
Logger.Terminate();
while(Logger.IsRunning()) {}
return default;
}
}

View File

@ -0,0 +1,108 @@
using CliFx;
using CliFx.Attributes;
using CliFx.Infrastructure;
using dnlib.DotNet;
namespace ReCodeIt.Commands;
[Command("GenRefCountList", Description = "Generates a print out of the most used classes. Useful to prioritize remap targets")]
public class GenRefList : ICommand
{
[CommandParameter(0, IsRequired = true, Description = "The absolute path to your de-obfuscated dll, remapped dll.")]
public string AssemblyPath { get; init; }
private static readonly List<string> Match = new()
{
"Class",
"GClass",
"GInterface",
"Interface",
"GStruct"
};
public ValueTask ExecuteAsync(IConsole console)
{
var references = CountTypeReferences(AssemblyPath);
// Sort and display the top 10 most referenced types
foreach (var pair in references.OrderByDescending(p => p.Value).Take(100))
{
Console.WriteLine($"{pair.Key}: {pair.Value}");
}
return default;
}
public static Dictionary<string, int> CountTypeReferences(string assemblyPath)
{
var typeReferenceCounts = new Dictionary<string, int>();
using (var module = ModuleDefMD.Load(assemblyPath))
{
foreach (var type in module.GetTypes())
{
CountReferencesInType(type, typeReferenceCounts);
}
}
return typeReferenceCounts;
}
private static void CountReferencesInType(TypeDef type, Dictionary<string, int> counts)
{
foreach (var method in type.Methods)
{
if (Match.Any(item => method.ReturnType.TypeName.StartsWith(item))) IncrementCount(method.ReturnType.TypeName, counts);
CountReferencesInMethod(method, counts);
}
foreach (var field in type.Fields)
{
if (field.FieldType.IsValueType || field.FieldType.IsPrimitive) continue;
if (!Match.Any(item => field.FieldType.TypeName.StartsWith(item))) continue;
IncrementCount(field.FieldType.FullName, counts);
}
foreach (var property in type.Properties)
{
if (property.PropertySig.RetType.IsValueType || property.PropertySig.RetType.IsPrimitive) continue;
if (!Match.Any(item => property.PropertySig.RetType.TypeName.StartsWith(item))) continue;
IncrementCount(property.PropertySig.RetType.FullName, counts);
}
}
private static void CountReferencesInMethod(MethodDef method, Dictionary<string, int> counts)
{
if (!method.HasBody) return;
foreach (var instr in method.Body.Instructions)
{
if (instr.Operand is FieldDef fieldDef && Match.Any(item => fieldDef.FieldType.TypeName.StartsWith(item)))
{
IncrementCount(fieldDef.FieldType.FullName, counts);
}
if (instr.Operand is PropertyDef propDef && Match.Any(item => propDef.PropertySig.RetType.FullName.StartsWith(item)))
{
IncrementCount(propDef.PropertySig.RetType.FullName, counts);
}
if (instr.Operand is MethodDef methodDef && Match.Any(item => methodDef.DeclaringType.FullName.StartsWith(item)))
{
if (methodDef.ReturnType.IsValueType || methodDef.ReturnType.IsPrimitive || methodDef.ReturnType.IsCorLibType) continue;
IncrementCount(methodDef.ReturnType.FullName, counts);
}
}
}
private static void IncrementCount(string typeName, Dictionary<string, int> counts)
{
counts[typeName] = counts.GetValueOrDefault(typeName, 0) + 1;
}
}

View File

@ -38,6 +38,10 @@ public class ReMap : ICommand
_remapper.InitializeRemap(remaps, AssemblyPath, Path.GetDirectoryName(AssemblyPath));
// Wait for log termination
Logger.Terminate();
while(Logger.IsRunning()) {}
return default;
}
}

View File

@ -30,12 +30,29 @@ partial class ReCodeItForm
{
components = new System.ComponentModel.Container();
RemapperTabPage = new TabPage();
label1 = new Label();
ResetSearchButton = new Button();
ActiveProjectMappingsCheckbox = new CheckBox();
LoadedMappingFilePath = new TextBox();
RMSearchBox = new TextBox();
RemapTreeView = new TreeView();
groupBox1 = new GroupBox();
label11 = new Label();
IsStructComboBox = new ComboBox();
label10 = new Label();
HasGenericParamsComboBox = new ComboBox();
label8 = new Label();
HasAttributeComboBox = new ComboBox();
label9 = new Label();
IsEnumComboBox = new ComboBox();
label2322 = new Label();
IsInterfaceComboBox = new ComboBox();
label7 = new Label();
IsSealedComboBox = new ComboBox();
label6 = new Label();
IsAbstractComboBox = new ComboBox();
label5 = new Label();
IsPublicComboBox = new ComboBox();
ConstuctorCountUpDown = new NumericUpDown();
ConstructorCountEnabled = new CheckBox();
Inclusions = new TabControl();
@ -77,27 +94,20 @@ partial class ReCodeItForm
NestedTypesIncludeBox = new ListBox();
NewTypeName = new TextBox();
PropertyCountEnabled = new CheckBox();
IsInterfaceUpDown = new DomainUpDown();
RemapperUseForceRename = new CheckBox();
NestedTypeCountEnabled = new CheckBox();
PropertyCountUpDown = new NumericUpDown();
FieldCountUpDown = new NumericUpDown();
IsPublicUpDown = new DomainUpDown();
FieldCountEnabled = new CheckBox();
NestedTypeParentName = new TextBox();
MethodCountUpDown = new NumericUpDown();
IsAbstractUpDown = new DomainUpDown();
BaseClassIncludeTextFIeld = new TextBox();
OriginalTypeName = new TextBox();
HasGenericParametersUpDown = new DomainUpDown();
IsEnumUpDown = new DomainUpDown();
NestedTypeCountUpDown = new NumericUpDown();
IsDerivedUpDown = new DomainUpDown();
IsNestedUpDown = new DomainUpDown();
HasAttributeUpDown = new DomainUpDown();
BaseClassExcludeTextField = new TextBox();
MethodCountEnabled = new CheckBox();
IsSealedUpDown = new DomainUpDown();
RemapperOutputDirectoryPath = new TextBox();
TargetAssemblyPath = new TextBox();
OutputDirectoryButton = new Button();
@ -168,7 +178,6 @@ partial class ReCodeItForm
SilentModeCheckbox = new CheckBox();
DebugLoggingCheckbox = new CheckBox();
toolTip1 = new ToolTip(components);
label1 = new Label();
RemapperTabPage.SuspendLayout();
groupBox1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)ConstuctorCountUpDown).BeginInit();
@ -222,6 +231,15 @@ partial class ReCodeItForm
RemapperTabPage.TabIndex = 1;
RemapperTabPage.Text = "Remapper";
//
// label1
//
label1.AutoSize = true;
label1.Location = new Point(777, 47);
label1.Name = "label1";
label1.Size = new Size(235, 25);
label1.TabIndex = 41;
label1.Text = "Double click to edit a remap";
//
// ResetSearchButton
//
ResetSearchButton.Location = new Point(1155, 14);
@ -276,32 +294,41 @@ partial class ReCodeItForm
//
// groupBox1
//
groupBox1.Controls.Add(label11);
groupBox1.Controls.Add(IsStructComboBox);
groupBox1.Controls.Add(label10);
groupBox1.Controls.Add(HasGenericParamsComboBox);
groupBox1.Controls.Add(label8);
groupBox1.Controls.Add(HasAttributeComboBox);
groupBox1.Controls.Add(label9);
groupBox1.Controls.Add(IsEnumComboBox);
groupBox1.Controls.Add(label2322);
groupBox1.Controls.Add(IsInterfaceComboBox);
groupBox1.Controls.Add(label7);
groupBox1.Controls.Add(IsSealedComboBox);
groupBox1.Controls.Add(label6);
groupBox1.Controls.Add(IsAbstractComboBox);
groupBox1.Controls.Add(label5);
groupBox1.Controls.Add(IsPublicComboBox);
groupBox1.Controls.Add(ConstuctorCountUpDown);
groupBox1.Controls.Add(ConstructorCountEnabled);
groupBox1.Controls.Add(Inclusions);
groupBox1.Controls.Add(NewTypeName);
groupBox1.Controls.Add(PropertyCountEnabled);
groupBox1.Controls.Add(IsInterfaceUpDown);
groupBox1.Controls.Add(RemapperUseForceRename);
groupBox1.Controls.Add(NestedTypeCountEnabled);
groupBox1.Controls.Add(PropertyCountUpDown);
groupBox1.Controls.Add(FieldCountUpDown);
groupBox1.Controls.Add(IsPublicUpDown);
groupBox1.Controls.Add(FieldCountEnabled);
groupBox1.Controls.Add(NestedTypeParentName);
groupBox1.Controls.Add(MethodCountUpDown);
groupBox1.Controls.Add(IsAbstractUpDown);
groupBox1.Controls.Add(BaseClassIncludeTextFIeld);
groupBox1.Controls.Add(OriginalTypeName);
groupBox1.Controls.Add(HasGenericParametersUpDown);
groupBox1.Controls.Add(IsEnumUpDown);
groupBox1.Controls.Add(NestedTypeCountUpDown);
groupBox1.Controls.Add(IsDerivedUpDown);
groupBox1.Controls.Add(IsNestedUpDown);
groupBox1.Controls.Add(HasAttributeUpDown);
groupBox1.Controls.Add(BaseClassExcludeTextField);
groupBox1.Controls.Add(MethodCountEnabled);
groupBox1.Controls.Add(IsSealedUpDown);
groupBox1.Location = new Point(6, 6);
groupBox1.Name = "groupBox1";
groupBox1.Size = new Size(769, 904);
@ -309,6 +336,158 @@ partial class ReCodeItForm
groupBox1.TabStop = false;
groupBox1.Text = "Remap Editor";
//
// label11
//
label11.AutoSize = true;
label11.Location = new Point(224, 264);
label11.Name = "label11";
label11.Size = new Size(75, 25);
label11.TabIndex = 53;
label11.Text = "Is Struct";
//
// IsStructComboBox
//
IsStructComboBox.BackColor = SystemColors.ScrollBar;
IsStructComboBox.FormattingEnabled = true;
IsStructComboBox.Location = new Point(10, 258);
IsStructComboBox.Name = "IsStructComboBox";
IsStructComboBox.Size = new Size(208, 33);
IsStructComboBox.TabIndex = 52;
toolTip1.SetToolTip(IsStructComboBox, "Is the type an enum?");
//
// label10
//
label10.AutoSize = true;
label10.Location = new Point(224, 380);
label10.Name = "label10";
label10.Size = new Size(197, 25);
label10.TabIndex = 51;
label10.Text = "Has Generic Parameters";
//
// HasGenericParamsComboBox
//
HasGenericParamsComboBox.BackColor = SystemColors.ScrollBar;
HasGenericParamsComboBox.FormattingEnabled = true;
HasGenericParamsComboBox.Location = new Point(10, 374);
HasGenericParamsComboBox.Name = "HasGenericParamsComboBox";
HasGenericParamsComboBox.Size = new Size(208, 33);
HasGenericParamsComboBox.TabIndex = 50;
toolTip1.SetToolTip(HasGenericParamsComboBox, "Does the type have generic parameters?");
//
// label8
//
label8.AutoSize = true;
label8.Location = new Point(224, 343);
label8.Name = "label8";
label8.Size = new Size(117, 25);
label8.TabIndex = 49;
label8.Text = "Has Attribute";
//
// HasAttributeComboBox
//
HasAttributeComboBox.BackColor = SystemColors.ScrollBar;
HasAttributeComboBox.FormattingEnabled = true;
HasAttributeComboBox.Location = new Point(10, 335);
HasAttributeComboBox.Name = "HasAttributeComboBox";
HasAttributeComboBox.Size = new Size(208, 33);
HasAttributeComboBox.TabIndex = 48;
toolTip1.SetToolTip(HasAttributeComboBox, "does the type have an attribute?");
//
// label9
//
label9.AutoSize = true;
label9.Location = new Point(224, 303);
label9.Name = "label9";
label9.Size = new Size(75, 25);
label9.TabIndex = 47;
label9.Text = "Is Enum";
//
// IsEnumComboBox
//
IsEnumComboBox.BackColor = SystemColors.ScrollBar;
IsEnumComboBox.FormattingEnabled = true;
IsEnumComboBox.Location = new Point(10, 297);
IsEnumComboBox.Name = "IsEnumComboBox";
IsEnumComboBox.Size = new Size(208, 33);
IsEnumComboBox.TabIndex = 46;
toolTip1.SetToolTip(IsEnumComboBox, "Is the type an enum?");
//
// label2322
//
label2322.AutoSize = true;
label2322.Location = new Point(224, 225);
label2322.Name = "label2322";
label2322.Size = new Size(98, 25);
label2322.TabIndex = 45;
label2322.Text = "Is Interface";
//
// IsInterfaceComboBox
//
IsInterfaceComboBox.BackColor = SystemColors.ScrollBar;
IsInterfaceComboBox.FormattingEnabled = true;
IsInterfaceComboBox.Location = new Point(10, 219);
IsInterfaceComboBox.Name = "IsInterfaceComboBox";
IsInterfaceComboBox.Size = new Size(208, 33);
IsInterfaceComboBox.TabIndex = 44;
toolTip1.SetToolTip(IsInterfaceComboBox, "Is the type an interface?");
//
// label7
//
label7.AutoSize = true;
label7.Location = new Point(224, 186);
label7.Name = "label7";
label7.Size = new Size(82, 25);
label7.TabIndex = 43;
label7.Text = "Is Sealed";
//
// IsSealedComboBox
//
IsSealedComboBox.BackColor = SystemColors.ScrollBar;
IsSealedComboBox.FormattingEnabled = true;
IsSealedComboBox.Location = new Point(10, 180);
IsSealedComboBox.Name = "IsSealedComboBox";
IsSealedComboBox.Size = new Size(208, 33);
IsSealedComboBox.TabIndex = 42;
toolTip1.SetToolTip(IsSealedComboBox, "Is the type sealed?");
//
// label6
//
label6.AutoSize = true;
label6.Location = new Point(224, 148);
label6.Name = "label6";
label6.Size = new Size(96, 25);
label6.TabIndex = 41;
label6.Text = "Is Abstract";
//
// IsAbstractComboBox
//
IsAbstractComboBox.BackColor = SystemColors.ScrollBar;
IsAbstractComboBox.FormattingEnabled = true;
IsAbstractComboBox.Location = new Point(10, 142);
IsAbstractComboBox.Name = "IsAbstractComboBox";
IsAbstractComboBox.Size = new Size(208, 33);
IsAbstractComboBox.TabIndex = 40;
toolTip1.SetToolTip(IsAbstractComboBox, "Is the type abstract? ");
//
// label5
//
label5.AutoSize = true;
label5.Location = new Point(224, 110);
label5.Name = "label5";
label5.Size = new Size(77, 25);
label5.TabIndex = 39;
label5.Text = "Is Public";
//
// IsPublicComboBox
//
IsPublicComboBox.BackColor = SystemColors.ScrollBar;
IsPublicComboBox.FormattingEnabled = true;
IsPublicComboBox.Location = new Point(10, 104);
IsPublicComboBox.Name = "IsPublicComboBox";
IsPublicComboBox.Size = new Size(208, 33);
IsPublicComboBox.TabIndex = 38;
toolTip1.SetToolTip(IsPublicComboBox, "Is the type public? This is required.");
//
// ConstuctorCountUpDown
//
ConstuctorCountUpDown.BackColor = SystemColors.ScrollBar;
@ -757,17 +936,6 @@ partial class ReCodeItForm
PropertyCountEnabled.Text = "Property Count";
PropertyCountEnabled.UseVisualStyleBackColor = true;
//
// IsInterfaceUpDown
//
IsInterfaceUpDown.BackColor = SystemColors.ScrollBar;
IsInterfaceUpDown.Location = new Point(10, 215);
IsInterfaceUpDown.Name = "IsInterfaceUpDown";
IsInterfaceUpDown.Size = new Size(208, 31);
IsInterfaceUpDown.Sorted = true;
IsInterfaceUpDown.TabIndex = 15;
IsInterfaceUpDown.Text = "IsInterface";
toolTip1.SetToolTip(IsInterfaceUpDown, "Is the type an interface?");
//
// RemapperUseForceRename
//
RemapperUseForceRename.AutoSize = true;
@ -807,17 +975,6 @@ partial class ReCodeItForm
FieldCountUpDown.TabIndex = 3;
toolTip1.SetToolTip(FieldCountUpDown, "How many fields are there?");
//
// IsPublicUpDown
//
IsPublicUpDown.BackColor = SystemColors.ScrollBar;
IsPublicUpDown.Location = new Point(10, 104);
IsPublicUpDown.Name = "IsPublicUpDown";
IsPublicUpDown.Size = new Size(208, 31);
IsPublicUpDown.Sorted = true;
IsPublicUpDown.TabIndex = 0;
IsPublicUpDown.Text = "IsPublic";
toolTip1.SetToolTip(IsPublicUpDown, "Is the type public? Note: Only public counts as public all other access modifiers fall under false.");
//
// FieldCountEnabled
//
FieldCountEnabled.AutoSize = true;
@ -831,7 +988,7 @@ partial class ReCodeItForm
// NestedTypeParentName
//
NestedTypeParentName.BackColor = SystemColors.ScrollBar;
NestedTypeParentName.Location = new Point(224, 363);
NestedTypeParentName.Location = new Point(221, 421);
NestedTypeParentName.Name = "NestedTypeParentName";
NestedTypeParentName.PlaceholderText = "Nested Type Parent Name";
NestedTypeParentName.Size = new Size(208, 31);
@ -847,21 +1004,10 @@ partial class ReCodeItForm
MethodCountUpDown.TabIndex = 6;
toolTip1.SetToolTip(MethodCountUpDown, "How many methods are there?");
//
// IsAbstractUpDown
//
IsAbstractUpDown.BackColor = SystemColors.ScrollBar;
IsAbstractUpDown.Location = new Point(10, 141);
IsAbstractUpDown.Name = "IsAbstractUpDown";
IsAbstractUpDown.Size = new Size(208, 31);
IsAbstractUpDown.Sorted = true;
IsAbstractUpDown.TabIndex = 1;
IsAbstractUpDown.Text = "IsAbstract";
toolTip1.SetToolTip(IsAbstractUpDown, "Is the class an abstract class?");
//
// BaseClassIncludeTextFIeld
//
BaseClassIncludeTextFIeld.BackColor = SystemColors.ScrollBar;
BaseClassIncludeTextFIeld.Location = new Point(224, 399);
BaseClassIncludeTextFIeld.Location = new Point(221, 457);
BaseClassIncludeTextFIeld.Name = "BaseClassIncludeTextFIeld";
BaseClassIncludeTextFIeld.PlaceholderText = "Include Base Class";
BaseClassIncludeTextFIeld.Size = new Size(208, 31);
@ -878,28 +1024,6 @@ partial class ReCodeItForm
OriginalTypeName.TabIndex = 1;
toolTip1.SetToolTip(OriginalTypeName, "The original name of the type, you can leave this blank if not using force rename.");
//
// HasGenericParametersUpDown
//
HasGenericParametersUpDown.BackColor = SystemColors.ScrollBar;
HasGenericParametersUpDown.Location = new Point(10, 326);
HasGenericParametersUpDown.Name = "HasGenericParametersUpDown";
HasGenericParametersUpDown.Size = new Size(208, 31);
HasGenericParametersUpDown.Sorted = true;
HasGenericParametersUpDown.TabIndex = 7;
HasGenericParametersUpDown.Text = "HasGenericParameters";
toolTip1.SetToolTip(HasGenericParametersUpDown, "Does the type have generic parameters? class Foo<T>");
//
// IsEnumUpDown
//
IsEnumUpDown.BackColor = SystemColors.ScrollBar;
IsEnumUpDown.Location = new Point(10, 252);
IsEnumUpDown.Name = "IsEnumUpDown";
IsEnumUpDown.Size = new Size(208, 31);
IsEnumUpDown.Sorted = true;
IsEnumUpDown.TabIndex = 2;
IsEnumUpDown.Text = "IsEnum";
toolTip1.SetToolTip(IsEnumUpDown, "Is the type an enum?");
//
// NestedTypeCountUpDown
//
NestedTypeCountUpDown.BackColor = SystemColors.ScrollBar;
@ -912,7 +1036,7 @@ partial class ReCodeItForm
// IsDerivedUpDown
//
IsDerivedUpDown.BackColor = SystemColors.ScrollBar;
IsDerivedUpDown.Location = new Point(10, 400);
IsDerivedUpDown.Location = new Point(7, 458);
IsDerivedUpDown.Name = "IsDerivedUpDown";
IsDerivedUpDown.Size = new Size(208, 31);
IsDerivedUpDown.Sorted = true;
@ -923,7 +1047,7 @@ partial class ReCodeItForm
// IsNestedUpDown
//
IsNestedUpDown.BackColor = SystemColors.ScrollBar;
IsNestedUpDown.Location = new Point(10, 363);
IsNestedUpDown.Location = new Point(7, 421);
IsNestedUpDown.Name = "IsNestedUpDown";
IsNestedUpDown.Size = new Size(208, 31);
IsNestedUpDown.Sorted = true;
@ -931,21 +1055,10 @@ partial class ReCodeItForm
IsNestedUpDown.Text = "IsNested";
toolTip1.SetToolTip(IsNestedUpDown, "Is the type nested within another type?");
//
// HasAttributeUpDown
//
HasAttributeUpDown.BackColor = SystemColors.ScrollBar;
HasAttributeUpDown.Location = new Point(10, 289);
HasAttributeUpDown.Name = "HasAttributeUpDown";
HasAttributeUpDown.Size = new Size(208, 31);
HasAttributeUpDown.Sorted = true;
HasAttributeUpDown.TabIndex = 5;
HasAttributeUpDown.Text = "HasAttribute";
toolTip1.SetToolTip(HasAttributeUpDown, "Does the type have an attribute?");
//
// BaseClassExcludeTextField
//
BaseClassExcludeTextField.BackColor = SystemColors.ScrollBar;
BaseClassExcludeTextField.Location = new Point(438, 400);
BaseClassExcludeTextField.Location = new Point(435, 458);
BaseClassExcludeTextField.Name = "BaseClassExcludeTextField";
BaseClassExcludeTextField.PlaceholderText = "Exclude Base Class";
BaseClassExcludeTextField.Size = new Size(208, 31);
@ -962,17 +1075,6 @@ partial class ReCodeItForm
MethodCountEnabled.Text = "Method Count";
MethodCountEnabled.UseVisualStyleBackColor = true;
//
// IsSealedUpDown
//
IsSealedUpDown.BackColor = SystemColors.ScrollBar;
IsSealedUpDown.Location = new Point(10, 179);
IsSealedUpDown.Name = "IsSealedUpDown";
IsSealedUpDown.Size = new Size(208, 31);
IsSealedUpDown.Sorted = true;
IsSealedUpDown.TabIndex = 4;
IsSealedUpDown.Text = "IsSealed";
toolTip1.SetToolTip(IsSealedUpDown, "Is the type sealed? Note that unsealing and publicization does not happen until after the remap so they can be used as parameters");
//
// RemapperOutputDirectoryPath
//
RemapperOutputDirectoryPath.BackColor = SystemColors.ScrollBar;
@ -1760,15 +1862,6 @@ partial class ReCodeItForm
DebugLoggingCheckbox.UseVisualStyleBackColor = true;
DebugLoggingCheckbox.CheckedChanged += DebugLoggingCheckbox_CheckedChanged;
//
// label1
//
label1.AutoSize = true;
label1.Location = new Point(777, 47);
label1.Name = "label1";
label1.Size = new Size(235, 25);
label1.TabIndex = 41;
label1.Text = "Double click to edit a remap";
//
// ReCodeItForm
//
AutoScaleDimensions = new SizeF(10F, 25F);
@ -1778,7 +1871,7 @@ partial class ReCodeItForm
Controls.Add(TabControlMain);
FormBorderStyle = FormBorderStyle.FixedSingle;
Name = "ReCodeItForm";
Text = "ReCodeIt V0.1.0";
Text = "ReCodeIt V0.2.0";
RemapperTabPage.ResumeLayout(false);
RemapperTabPage.PerformLayout();
groupBox1.ResumeLayout(false);
@ -1867,18 +1960,11 @@ partial class ReCodeItForm
private Button SaveRemapButton;
private ListView RemapListView;
private TabControl TabControlMain;
private DomainUpDown IsPublicUpDown;
private DomainUpDown HasGenericParametersUpDown;
private DomainUpDown IsDerivedUpDown;
private DomainUpDown HasAttributeUpDown;
private DomainUpDown IsSealedUpDown;
private DomainUpDown IsNestedUpDown;
private DomainUpDown IsEnumUpDown;
private DomainUpDown IsAbstractUpDown;
private CheckBox FieldCountEnabled;
private CheckBox PropertyCountEnabled;
private CheckBox NestedTypeCountEnabled;
private DomainUpDown IsInterfaceUpDown;
private TreeView RemapTreeView;
private Button RunRemapButton;
private Button LoadMappingFileButton;
@ -1964,4 +2050,20 @@ partial class ReCodeItForm
private TextBox RMSearchBox;
private Button ResetSearchButton;
private Label label1;
private ComboBox IsPublicComboBox;
private Label label7;
private ComboBox IsSealedComboBox;
private Label label6;
private ComboBox IsAbstractComboBox;
private Label label5;
private Label label8;
private ComboBox HasAttributeComboBox;
private Label label9;
private ComboBox IsEnumComboBox;
private Label label2322;
private ComboBox IsInterfaceComboBox;
private Label label10;
private ComboBox HasGenericParamsComboBox;
private Label label11;
private ComboBox IsStructComboBox;
}

View File

@ -2,7 +2,6 @@
using ReCodeIt.AutoMapper;
using ReCodeIt.CrossCompiler;
using ReCodeIt.Enums;
using ReCodeIt.Models;
using ReCodeIt.ReMapper;
using ReCodeIt.Utils;
@ -269,26 +268,51 @@ public partial class ReCodeItForm : Form
return;
}
ResetSearchButton_Click(this, e);
var newRemap = new RemapModel
{
Succeeded = false,
FailureReason = EFailureReason.None,
NoMatchReasons = [],
NewTypeName = NewTypeName.Text,
OriginalTypeName = OriginalTypeName.Text == string.Empty ? null : OriginalTypeName.Text,
UseForceRename = RemapperUseForceRename.Checked,
SearchParams = new SearchParams
{
IsPublic = IsPublicUpDown.GetEnabled(),
IsAbstract = IsAbstractUpDown.GetEnabled(),
IsInterface = IsInterfaceUpDown.GetEnabled(),
IsEnum = IsEnumUpDown.GetEnabled(),
IsNested = IsNestedUpDown.GetEnabled(),
IsSealed = IsSealedUpDown.GetEnabled(),
HasAttribute = HasAttributeUpDown.GetEnabled(),
IsDerived = IsDerivedUpDown.GetEnabled(),
HasGenericParameters = HasGenericParametersUpDown.GetEnabled(),
IsPublic = bool.Parse(IsPublicComboBox.GetSelectedItem<string>().AsSpan()),
ParentName = NestedTypeParentName.Text == string.Empty
IsAbstract = IsAbstractComboBox.SelectedItem as string != "Disabled"
? bool.Parse(IsAbstractComboBox.GetSelectedItem<string>().AsSpan())
: null,
IsSealed = IsSealedComboBox.SelectedItem as string != "Disabled"
? bool.Parse(IsSealedComboBox.GetSelectedItem<string>().AsSpan())
: null,
IsInterface = IsInterfaceComboBox.SelectedItem as string != "Disabled"
? bool.Parse(IsInterfaceComboBox.GetSelectedItem<string>().AsSpan())
: null,
IsStruct = IsStructComboBox.SelectedItem as string != "Disabled"
? bool.Parse(IsStructComboBox.GetSelectedItem<string>().AsSpan())
: null,
IsEnum = IsEnumComboBox.SelectedItem as string != "Disabled"
? bool.Parse(IsEnumComboBox.GetSelectedItem<string>().AsSpan())
: null,
HasAttribute = HasAttributeComboBox.SelectedItem as string != "Disabled"
? bool.Parse(HasAttributeComboBox.GetSelectedItem<string>().AsSpan())
: null,
HasGenericParameters = HasGenericParamsComboBox.SelectedItem as string != "Disabled"
? bool.Parse(HasGenericParamsComboBox.GetSelectedItem<string>().AsSpan())
: null,
IsNested = IsNestedUpDown.GetEnabled(),
IsDerived = IsDerivedUpDown.GetEnabled(),
NTParentName = NestedTypeParentName.Text == string.Empty
? null
: NestedTypeParentName.Text,
@ -436,9 +460,9 @@ public partial class ReCodeItForm : Form
}
Remapper.InitializeRemap(
DataProvider.Remaps,
DataProvider.LoadMappingFile(AppSettings.Remapper.MappingPath),
AppSettings.Remapper.AssemblyPath,
Path.GetDirectoryName(AppSettings.Remapper.OutputPath));
AppSettings.Remapper.OutputPath);
ReloadRemapTreeView(DataProvider.Remaps);
}
@ -512,6 +536,8 @@ public partial class ReCodeItForm : Form
private void MethodIncludeAddButton_Click(object sender, EventArgs e)
{
if (IncludeMethodTextBox.Text == string.Empty) return;
if (!MethodIncludeBox.Items.Contains(IncludeMethodTextBox.Text))
{
MethodIncludeBox.Items.Add(IncludeMethodTextBox.Text);
@ -529,6 +555,8 @@ public partial class ReCodeItForm : Form
private void MethodExcludeAddButton_Click(object sender, EventArgs e)
{
if (ExcludeMethodTextBox.Text == string.Empty) return;
if (!MethodExcludeBox.Items.Contains(ExcludeMethodTextBox.Text))
{
MethodExcludeBox.Items.Add(ExcludeMethodTextBox.Text);
@ -546,6 +574,8 @@ public partial class ReCodeItForm : Form
private void FIeldIncludeAddButton_Click(object sender, EventArgs e)
{
if (FieldsIncludeTextInput.Text == string.Empty) return;
if (!FieldIncludeBox.Items.Contains(FieldsIncludeTextInput.Text))
{
FieldIncludeBox.Items.Add(FieldsIncludeTextInput.Text);
@ -563,6 +593,8 @@ public partial class ReCodeItForm : Form
private void FieldExcludeAddButton_Click(object sender, EventArgs e)
{
if (FieldsExcludeTextInput.Text == string.Empty) return;
if (!FieldExcludeBox.Items.Contains(FieldsExcludeTextInput.Text))
{
FieldExcludeBox.Items.Add(FieldsExcludeTextInput.Text);
@ -580,6 +612,8 @@ public partial class ReCodeItForm : Form
private void PropertiesIncludeAddButton_Click(object sender, EventArgs e)
{
if (PropertiesIncludeTextField.Text == string.Empty) return;
if (!PropertiesIncludeBox.Items.Contains(PropertiesIncludeTextField.Text))
{
PropertiesIncludeBox.Items.Add(PropertiesIncludeTextField.Text);
@ -597,6 +631,8 @@ public partial class ReCodeItForm : Form
private void PropertiesExcludeAddButton_Click(object sender, EventArgs e)
{
if (PropertiesExcludeTextField.Text == string.Empty) return;
if (!PropertiesExcludeBox.Items.Contains(PropertiesExcludeTextField.Text))
{
PropertiesExcludeBox.Items.Add(PropertiesExcludeTextField.Text);
@ -614,6 +650,8 @@ public partial class ReCodeItForm : Form
private void NestedTypesAddButton_Click(object sender, EventArgs e)
{
if (NestedTypesIncludeTextField.Text == string.Empty) return;
if (!NestedTypesIncludeBox.Items.Contains(NestedTypesIncludeTextField.Text))
{
NestedTypesIncludeBox.Items.Add(NestedTypesIncludeTextField.Text);
@ -631,6 +669,8 @@ public partial class ReCodeItForm : Form
private void NestedTypesExlcudeAddButton_Click(object sender, EventArgs e)
{
if (NestedTypesExcludeTextField.Text == string.Empty) return;
if (!NestedTypesExcludeBox.Items.Contains(NestedTypesExcludeTextField.Text))
{
NestedTypesExcludeBox.Items.Add(NestedTypesExcludeTextField.Text);
@ -648,6 +688,8 @@ public partial class ReCodeItForm : Form
private void AutoMapperExcludeAddButton_Click(object sender, EventArgs e)
{
if (AutoMapperTypesToIgnoreTextField.Text == string.Empty) return;
if (!AutoMapperTypesExcludeBox.Items.Contains(AutoMapperTypesToIgnoreTextField.Text))
{
DataProvider.Settings.AutoMapper.TypesToIgnore.Add(AutoMapperTypesToIgnoreTextField.Text);
@ -1070,12 +1112,6 @@ public partial class ReCodeItForm : Form
AppSettings.CrossCompiler.AutoLoadLastActiveProject = CCAutoLoadLastProj.Checked;
}
// Use the projects remap list on the remap tab
private void ActiveProjectMappingsCheckbox_CheckedChanged(object sender, EventArgs e)
{
// TODO
}
private void CCImportMappings_Click(object sender, EventArgs e)
{
if (CrossCompiler.ActiveProject == null)
@ -1236,29 +1272,80 @@ public partial class ReCodeItForm : Form
BaseClassIncludeTextFIeld.Text = remap.SearchParams.MatchBaseClass;
BaseClassExcludeTextField.Text = remap.SearchParams.IgnoreBaseClass;
NestedTypeParentName.Text = remap.SearchParams.ParentName;
NestedTypeParentName.Text = remap.SearchParams.NTParentName;
ConstructorCountEnabled.Checked = remap.SearchParams.ConstructorParameterCount != null ? remap.SearchParams.ConstructorParameterCount > 0 : false;
MethodCountEnabled.Checked = remap.SearchParams.MethodCount != null ? remap.SearchParams.MethodCount >= 0 : false;
FieldCountEnabled.Checked = remap.SearchParams.FieldCount != null ? remap.SearchParams.FieldCount >= 0 : false;
PropertyCountEnabled.Checked = remap.SearchParams.PropertyCount != null ? remap.SearchParams.PropertyCount >= 0 : false;
NestedTypeCountEnabled.Checked = remap.SearchParams.NestedTypeCount != null ? remap.SearchParams.NestedTypeCount >= 0 : false;
ConstructorCountEnabled.Checked = remap.SearchParams.ConstructorParameterCount is not null
? remap.SearchParams.ConstructorParameterCount > 0
: false;
ConstuctorCountUpDown.Value = (decimal)((remap.SearchParams.ConstructorParameterCount != null ? remap.SearchParams.ConstructorParameterCount : 0));
MethodCountUpDown.Value = (decimal)(remap.SearchParams.MethodCount != null ? remap.SearchParams.MethodCount : 0);
FieldCountUpDown.Value = (decimal)(remap.SearchParams.FieldCount != null ? remap.SearchParams.FieldCount : 0);
PropertyCountUpDown.Value = (decimal)(remap.SearchParams.PropertyCount != null ? remap.SearchParams.PropertyCount : 0);
NestedTypeCountUpDown.Value = (decimal)(remap.SearchParams.NestedTypeCount != null ? remap.SearchParams.NestedTypeCount : 0);
MethodCountEnabled.Checked = remap.SearchParams.MethodCount is not null
? remap.SearchParams.MethodCount >= 0
: false;
IsPublicUpDown.BuildStringList("IsPublic", remap.SearchParams.IsPublic);
IsAbstractUpDown.BuildStringList("IsAbstract", remap.SearchParams.IsAbstract);
IsInterfaceUpDown.BuildStringList("IsInterface", remap.SearchParams.IsInterface);
IsEnumUpDown.BuildStringList("IsEnum", remap.SearchParams.IsEnum);
IsNestedUpDown.BuildStringList("IsNested", remap.SearchParams.IsNested);
IsSealedUpDown.BuildStringList("IsSealed", remap.SearchParams.IsSealed);
HasAttributeUpDown.BuildStringList("HasAttribute", remap.SearchParams.HasAttribute);
IsDerivedUpDown.BuildStringList("IsDerived", remap.SearchParams.IsDerived);
HasGenericParametersUpDown.BuildStringList("HasGenericParams", remap.SearchParams.HasGenericParameters);
FieldCountEnabled.Checked = remap.SearchParams.FieldCount is not null
? remap.SearchParams.FieldCount >= 0
: false;
PropertyCountEnabled.Checked = remap.SearchParams.PropertyCount is not null
? remap.SearchParams.PropertyCount >= 0
: false;
NestedTypeCountEnabled.Checked = remap.SearchParams.NestedTypeCount is not null
? remap.SearchParams.NestedTypeCount >= 0
: false;
ConstuctorCountUpDown.Value = (decimal)((remap.SearchParams.ConstructorParameterCount != null
? remap.SearchParams.ConstructorParameterCount
: 0));
MethodCountUpDown.Value = (decimal)(remap.SearchParams.MethodCount != null
? remap.SearchParams.MethodCount
: 0);
FieldCountUpDown.Value = (decimal)(remap.SearchParams.FieldCount != null
? remap.SearchParams.FieldCount
: 0);
PropertyCountUpDown.Value = (decimal)(remap.SearchParams.PropertyCount != null
? remap.SearchParams.PropertyCount
: 0);
NestedTypeCountUpDown.Value = (decimal)(remap.SearchParams.NestedTypeCount != null
? remap.SearchParams.NestedTypeCount
: 0);
IsPublicComboBox.SelectedItem = remap.SearchParams.IsPublic.ToString();
IsAbstractComboBox.SelectedItem = remap.SearchParams.IsAbstract is not null
? remap.SearchParams.IsAbstract.ToString()
: "Disabled";
IsSealedComboBox.SelectedItem = remap.SearchParams.IsSealed is not null
? remap.SearchParams.IsSealed.ToString()
: "Disabled";
IsInterfaceComboBox.SelectedItem = remap.SearchParams.IsInterface is not null
? remap.SearchParams.IsInterface.ToString()
: "Disabled";
IsStructComboBox.SelectedItem = remap.SearchParams.IsStruct is not null
? remap.SearchParams.IsStruct.ToString()
: "Disabled";
IsEnumComboBox.SelectedItem = remap.SearchParams.IsEnum is not null
? remap.SearchParams.IsEnum.ToString()
: "Disabled";
HasAttributeComboBox.SelectedItem = remap.SearchParams.HasAttribute is not null
? remap.SearchParams.HasAttribute.ToString()
: "Disabled";
HasGenericParamsComboBox.SelectedItem = remap.SearchParams.HasGenericParameters is not null
? remap.SearchParams.HasGenericParameters.ToString()
: "Disabled";
IsNestedUpDown.BuildStringList("IsNested", false, remap.SearchParams.IsNested);
IsDerivedUpDown.BuildStringList("IsDerived", false, remap.SearchParams.IsDerived);
foreach (var method in remap.SearchParams.IncludeMethods)
{
@ -1304,15 +1391,32 @@ public partial class ReCodeItForm : Form
private void PopulateDomainUpDowns()
{
// Clear them all first just incase
IsPublicUpDown.BuildStringList("IsPublic");
IsAbstractUpDown.BuildStringList("IsAbstract");
IsInterfaceUpDown.BuildStringList("IsInterface");
IsEnumUpDown.BuildStringList("IsEnum");
IsNestedUpDown.BuildStringList("IsNested");
IsSealedUpDown.BuildStringList("IsSealed");
HasAttributeUpDown.BuildStringList("HasAttribute");
IsDerivedUpDown.BuildStringList("IsDerived");
HasGenericParametersUpDown.BuildStringList("HasGenericParams");
IsPublicComboBox.AddItemsToComboBox(["True", "False"]);
IsPublicComboBox.SelectedItem = "True";
IsAbstractComboBox.AddItemsToComboBox(["Disabled", "True", "False"]);
IsAbstractComboBox.SelectedItem = "Disabled";
IsSealedComboBox.AddItemsToComboBox(["Disabled", "True", "False"]);
IsSealedComboBox.SelectedItem = "Disabled";
IsInterfaceComboBox.AddItemsToComboBox(["Disabled", "True", "False"]);
IsInterfaceComboBox.SelectedItem = "Disabled";
IsStructComboBox.AddItemsToComboBox(["Disabled", "True", "False"]);
IsStructComboBox.SelectedItem = "Disabled";
IsEnumComboBox.AddItemsToComboBox(["Disabled", "True", "False"]);
IsEnumComboBox.SelectedItem = "Disabled";
HasAttributeComboBox.AddItemsToComboBox(["Disabled", "True", "False"]);
HasAttributeComboBox.SelectedItem = "Disabled";
HasGenericParamsComboBox.AddItemsToComboBox(["Disabled", "True", "False"]);
HasGenericParamsComboBox.SelectedItem = "Disabled";
IsNestedUpDown.BuildStringList("IsNested", false);
IsDerivedUpDown.BuildStringList("IsDerived", false);
}
/// <summary>

View File

@ -120,4 +120,7 @@
<metadata name="toolTip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="toolTip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
</root>

View File

@ -1,4 +1,5 @@
using ReCodeIt.Models;
using ReCodeIt.Utils;
namespace ReCodeIt.GUI;
@ -38,10 +39,14 @@ internal static class GUIHelpers
/// </summary>
/// <param name="domainUpDown"></param>
/// <param name="name"></param>
public static void BuildStringList(this DomainUpDown domainUpDown, string name, bool? update = null)
public static void BuildStringList(this DomainUpDown domainUpDown, string name, bool required, bool? update = null)
{
domainUpDown.Items.Clear();
domainUpDown.Text = name + " (Disabled)";
domainUpDown.Text = required
? name + @" (Required)"
: name + @" (Disabled)";
domainUpDown.ReadOnly = true;
var list = new List<string>
@ -51,14 +56,44 @@ internal static class GUIHelpers
"False",
};
if (required)
{
list.RemoveAt(0);
}
if (update != null)
{
domainUpDown.Text = update.ToString();
if (update.ToString() == "True")
{
Logger.Log("Updating!");
domainUpDown.SelectedItem = "True";
}
else
{
domainUpDown.SelectedItem = "False";
}
}
domainUpDown.Items.AddRange(list);
}
public static void AddItemsToComboBox(this ComboBox cb, List<string> items)
{
cb.Items.Clear();
foreach (var item in items)
{
cb.Items.Add(item);
}
}
public static T? GetSelectedItem<T>(this ComboBox cb)
{
return (T)cb.SelectedItem;
}
/// <summary>
/// Generates a tree node to display on the GUI
/// </summary>
@ -66,9 +101,10 @@ internal static class GUIHelpers
/// <returns></returns>
public static TreeNode GenerateTreeNode(RemapModel model, ReCodeItForm gui)
{
var isPublic = model.SearchParams.IsPublic == null ? null : model.SearchParams.IsPublic;
var isPublic = model.SearchParams.IsPublic;
var isAbstract = model.SearchParams.IsAbstract == null ? null : model.SearchParams.IsAbstract;
var isInterface = model.SearchParams.IsInterface == null ? null : model.SearchParams.IsInterface;
var isStruct = model.SearchParams.IsStruct == null ? null : model.SearchParams.IsStruct;
var isEnum = model.SearchParams.IsEnum == null ? null : model.SearchParams.IsEnum;
var isNested = model.SearchParams.IsNested == null ? null : model.SearchParams.IsNested;
var isSealed = model.SearchParams.IsSealed == null ? null : model.SearchParams.IsSealed;
@ -87,10 +123,7 @@ internal static class GUIHelpers
remapTreeItem.Nodes.Add(new TreeNode($"Force Rename: {model.UseForceRename}"));
}
if (isPublic is not null)
{
remapTreeItem.Nodes.Add(new TreeNode($"IsPublic: {isPublic}"));
}
if (isAbstract is not null)
{
@ -102,14 +135,19 @@ internal static class GUIHelpers
remapTreeItem.Nodes.Add(new TreeNode($"IsInterface: {isInterface}"));
}
if (isStruct is not null)
{
remapTreeItem.Nodes.Add(new TreeNode($"IsStruct: {isStruct}"));
}
if (isEnum is not null)
{
remapTreeItem.Nodes.Add(new TreeNode($"isEnum: {isEnum}"));
remapTreeItem.Nodes.Add(new TreeNode($"IsEnum: {isEnum}"));
}
if (isNested is not null)
{
remapTreeItem.Nodes.Add(new TreeNode($"IsNested: {isEnum}"));
remapTreeItem.Nodes.Add(new TreeNode($"IsNested: {isNested}"));
}
if (isSealed is not null)

View File

@ -1,4 +1,4 @@
using Mono.Cecil;
using dnlib.DotNet;
namespace ReCodeIt.AutoMapper;
@ -10,18 +10,18 @@ namespace ReCodeIt.AutoMapper;
/// <param name="isInterface"></param>
/// <param name="isStruct"></param>
public sealed class MappingPair(
TypeDefinition type,
TypeDef type,
string name,
bool isInterface,
bool isStruct,
bool isPublic)
{
public TypeDefinition OriginalTypeDefinition { get; private set; } = type;
public TypeDef OriginalTypeDefinition { get; private set; } = type;
/// <summary>
/// The type reference we want to change
/// </summary>
public TypeDefinition NewTypeRef { get; set; }
public TypeDef NewTypeRef { get; set; }
/// <summary>
/// Is this field an interface?

View File

@ -1,19 +1,18 @@
using Mono.Cecil;
using Mono.Collections.Generic;
using dnlib.DotNet;
using ReCodeIt.Models;
using ReCodeIt.ReMapper;
using ReCodeIt.Utils;
using ReCodeIt.Utils;
namespace ReCodeIt.AutoMapper;
public class ReCodeItAutoMapper
{
private ModuleDefMD Module { get; set; }
private List<MappingPair> MappingPairs { get; set; } = [];
private List<string> CompilerGeneratedClasses = [];
private List<TypeDefinition> AllTypes { get; set; } = [];
private List<TypeDef> AllTypes { get; set; } = [];
private List<string> AlreadyChangedNames { get; set; } = [];
@ -39,16 +38,16 @@ public class ReCodeItAutoMapper
AllTypes = [];
AlreadyChangedNames = [];
DataProvider.LoadAssemblyDefinition(Settings.AssemblyPath);
Module = DataProvider.LoadModule(Settings.AssemblyPath);
Error = false;
FailureCount = 0;
TotalFieldRenameCount = 0;
TotalPropertyRenameCount = 0;
FindCompilerGeneratedObjects(DataProvider.ModuleDefinition.Types);
var types = Module.GetTypes();
var types = DataProvider.ModuleDefinition.Types;
FindCompilerGeneratedObjects(types);
GetAllTypes(types);
@ -79,7 +78,7 @@ public class ReCodeItAutoMapper
WriteChanges();
}
private void GetAllTypes(Collection<TypeDefinition> types)
private void GetAllTypes(IEnumerable<TypeDef> types)
{
AllTypes.AddRange(types);
@ -96,7 +95,7 @@ public class ReCodeItAutoMapper
/// Finds any compiler generated code so we can ignore it, its mostly LINQ garbage
/// </summary>
/// <param name="types"></param>
private void FindCompilerGeneratedObjects(Collection<TypeDefinition> types)
private void FindCompilerGeneratedObjects(IEnumerable<TypeDef> types)
{
foreach (var typeDefinition in types)
{
@ -120,7 +119,7 @@ public class ReCodeItAutoMapper
#region METHODS
private List<MappingPair> GatherFromMethods(TypeDefinition type)
private List<MappingPair> GatherFromMethods(TypeDef type)
{
var methodsWithTypes = new List<MappingPair>();
@ -132,7 +131,7 @@ public class ReCodeItAutoMapper
var methods = type.Methods
// We only want methods with parameters
.Where(m => m.HasParameters)
.Where(m => m.HasParams())
// Only want parameter names of a certain length
.Where(m => m.Parameters.Any(p => p.Name.Length > Settings.MinLengthToMatch));
@ -140,31 +139,26 @@ public class ReCodeItAutoMapper
// Now go over over all filterd methods manually, because fuck this with linq
foreach (var method in methods)
{
var parmNames = method.Parameters.Select(p => p.Name);
var parmTypes = method.Parameters.Select(p => p.ParameterType.Name);
// Now over all parameters in the method
foreach (var parm in method.Parameters)
{
// We dont want blacklisted items
if (Settings.MethodParamaterBlackList.Contains(parm.ParameterType.Name.TrimAfterSpecialChar())
|| Settings.TypesToIgnore.Contains(parm.ParameterType.Name.TrimAfterSpecialChar()))
if (Settings.MethodParamaterBlackList.Contains(parm.Name)
|| Settings.TypesToIgnore.Contains(parm.Name))
{
continue;
}
if (parm.ParameterType.Resolve() == null) { continue; }
//Logger.Log($"Method Data Found");
//Logger.Log($"Parameter count: {method.Parameters.Count}");
//Logger.Log($"Paremeter Names: {string.Join(", ", parmNames)}");
//Logger.Log($"Paremeter Types: {string.Join(", ", parmTypes)}\n");
var mapPair = new MappingPair(
parm.ParameterType.Resolve(),
parm.Type.TryGetTypeDef(),
parm.Name,
parm.ParameterType.Resolve().IsInterface,
parm.ParameterType.Name.Contains("Struct"),
parm.Type.TryGetTypeDef().IsInterface,
parm.Type.TryGetTypeDef().Name.Contains("Struct"),
true);
mapPair.AutoMappingResult = AutoMappingResult.Match_From_Method;
@ -185,7 +179,7 @@ public class ReCodeItAutoMapper
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
private List<MappingPair> FilterFieldNames(TypeDefinition type)
private List<MappingPair> FilterFieldNames(TypeDef type)
{
var fieldsWithTypes = new List<MappingPair>();
@ -197,7 +191,7 @@ public class ReCodeItAutoMapper
var fields = type.Fields
// we dont want names shorter than 4
.Where(f => f.FieldType.Name.Length > 3)
.Where(f => f.Name.Length > 3)
// Skip value types
.Where(f => !f.FieldType.IsValueType)
@ -206,14 +200,14 @@ public class ReCodeItAutoMapper
.Where(p => !p.FieldType.IsArray)
// We dont want fields in the system type ignore list
.Where(f => !Settings.TypesToIgnore.Contains(f.FieldType.Name.TrimAfterSpecialChar()));
.Where(f => !Settings.TypesToIgnore.Contains(f.Name.TrimAfterSpecialChar()));
// Include fields from the current type
foreach (var field in fields)
{
//Logger.Log($"Collecting Field: OriginalTypeRef: {field.FieldType.Name.TrimAfterSpecialChar()} Field Name: {field.Name}");
var typeDef = field.FieldType.Resolve();
var typeDef = field.FieldType.TryGetTypeDef();
// Dont rename things we cant resolve
if (typeDef is null) { continue; }
@ -221,8 +215,8 @@ public class ReCodeItAutoMapper
var pair = new MappingPair(
typeDef,
field.Name,
field.FieldType.Name.Contains("Interface"),
field.FieldType.Name.Contains("Struct"),
typeDef.Name.Contains("Interface"),
typeDef.Name.Contains("Struct"),
field.IsPublic);
pair.AutoMappingResult = AutoMappingResult.Match_From_Field;
@ -238,7 +232,7 @@ public class ReCodeItAutoMapper
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
private IEnumerable<MappingPair> FilterPropertyNames(TypeDefinition type)
private IEnumerable<MappingPair> FilterPropertyNames(TypeDef type)
{
var propertiesWithTypes = new List<MappingPair>();
@ -250,23 +244,23 @@ public class ReCodeItAutoMapper
var properties = type.Properties
// we dont want names shorter than 4
.Where(p => p.PropertyType.Name.Length > 3)
.Where(p => p.Name.Length > 3)
// Skip value types
.Where(p => !p.PropertyType.IsValueType)
.Where(p => !p.PropertySig.RetType.GetIsValueType())
// TODO: Renaming arrays is strange, come back to this later
.Where(p => !p.PropertyType.IsArray)
.Where(p => !p.PropertySig.RetType.IsArray)
// We dont want fields in the global ignore list
.Where(p => !Settings.TypesToIgnore.Contains(p.PropertyType.Name.TrimAfterSpecialChar()));
.Where(p => !Settings.TypesToIgnore.Contains(p.Name.TrimAfterSpecialChar()));
// Include fields from the current type
foreach (var property in properties)
{
//Logger.Log($"Collecting Property: OriginalTypeRef: {property.PropertyType.Name.TrimAfterSpecialChar()} Field Name: {property.Name}");
var typeDef = property.PropertyType.Resolve();
var typeDef = property.PropertySig.RetType.TryGetTypeDef();
// Dont rename things we cant resolve
if (typeDef is null) { continue; }
@ -274,8 +268,8 @@ public class ReCodeItAutoMapper
var mapPair = new MappingPair(
typeDef,
property.Name,
property.PropertyType.Name.Contains("Interface"),
property.PropertyType.Name.Contains("Struct"),
typeDef.Name.Contains("Interface"),
typeDef.Name.Contains("Struct"),
true);
mapPair.AutoMappingResult = AutoMappingResult.Match_From_Property;
@ -430,7 +424,7 @@ public class ReCodeItAutoMapper
private void StartRenameProcess()
{
// Gather up any matches we have
foreach (var type in DataProvider.ModuleDefinition.Types.ToArray())
foreach (var type in Module.GetTypes().ToArray())
{
foreach (var pair in MappingPairs.ToArray())
{
@ -450,15 +444,12 @@ public class ReCodeItAutoMapper
var fieldCount = RenameHelper.RenameAllFields(
pair.OriginalTypeDefinition.Name,
pair.Name,
DataProvider.ModuleDefinition.Types);
Module.GetTypes());
var propCount = RenameHelper.RenameAllProperties(
pair.OriginalTypeDefinition.Name,
pair.Name,
DataProvider.ModuleDefinition.Types);
TotalFieldRenameCount += fieldCount;
TotalPropertyRenameCount += propCount;
Module.GetTypes());
Logger.Log($"Renamed: {fieldCount} fields", ConsoleColor.Green);
Logger.Log($"Renamed: {propCount} properties", ConsoleColor.Green);
@ -508,7 +499,7 @@ public class ReCodeItAutoMapper
/// </summary>
/// <param name="pair"></param>
/// <param name="type"></param>
private void GatherMatchedTypeRefs(MappingPair pair, TypeDefinition type)
private void GatherMatchedTypeRefs(MappingPair pair, TypeDef type)
{
// Handle nested types recursively
foreach (var nestedType in type.NestedTypes.ToArray())
@ -524,14 +515,14 @@ public class ReCodeItAutoMapper
private void WriteChanges()
{
var path = DataProvider.WriteAssemblyDefinition(Settings.OutputPath);
Module.Write(Settings.OutputPath);
var fieldCountMatchResult = MappingPairs.Where(x => x.AutoMappingResult == AutoMappingResult.Match_From_Property).Count();
var propertyCountMatchResult = MappingPairs.Where(x => x.AutoMappingResult == AutoMappingResult.Match_From_Property).Count();
var methodCountMatchResult = MappingPairs.Where(x => x.AutoMappingResult == AutoMappingResult.Match_From_Method).Count();
Logger.Log($"-------------------------------RESULT-----------------------------------", ConsoleColor.Green);
Logger.Log($"Complete: Assembly written to `{path}`", ConsoleColor.Green);
Logger.Log($"Complete: Assembly written to `{Settings.OutputPath}`", ConsoleColor.Green);
Logger.Log($"Found {MappingPairs.Count()} automatic remaps", ConsoleColor.Green);
Logger.Log($"Found {fieldCountMatchResult} automatic remaps from fields", ConsoleColor.Green);
Logger.Log($"Found {propertyCountMatchResult} automatic remaps from properties", ConsoleColor.Green);

View File

@ -1,19 +1,14 @@
namespace ReCodeIt.Enums;
public enum EFailureReason
public enum ENoMatchReason
{
None,
IsAbstract,
IsEnum,
IsNested,
IsSealed,
IsDerived,
IsInterface,
IsPublic,
HasGenericParameters,
HasAttribute,
IsAttribute,
Constructor,
ConstructorParameterCount,
MethodsInclude,
MethodsExclude,
MethodsCount,

View File

@ -1,5 +1,6 @@
using ReCodeIt.Enums;
using dnlib.DotNet;
using Newtonsoft.Json;
using ReCodeIt.Enums;
namespace ReCodeIt.Models;
@ -12,7 +13,19 @@ public class RemapModel
public bool Succeeded { get; set; } = false;
[JsonIgnore]
public EFailureReason FailureReason { get; set; }
public List<ENoMatchReason> NoMatchReasons { get; set; } = [];
/// <summary>
/// This is a list of type candidates that made it through the filter
/// </summary>
[JsonIgnore]
public HashSet<TypeDef> TypeCandidates { get; set; } = [];
/// <summary>
/// This is the final chosen type we will use to remap
/// </summary>
[JsonIgnore]
public TypeDef TypePrimeCandidate { get; set; }
public string NewTypeName { get; set; } = string.Empty;
@ -30,9 +43,14 @@ public class SearchParams
{
#region BOOL_PARAMS
public bool? IsPublic { get; set; } = null;
/// <summary>
/// Default to true, most types are public
/// </summary>
public bool IsPublic { get; set; } = true;
public bool? IsAbstract { get; set; } = null;
public bool? IsInterface { get; set; } = null;
public bool? IsStruct { get; set; } = null;
public bool? IsEnum { get; set; } = null;
public bool? IsNested { get; set; } = null;
public bool? IsSealed { get; set; } = null;
@ -44,8 +62,19 @@ public class SearchParams
#region STR_PARAMS
public string? ParentName { get; set; } = null;
/// <summary>
/// Name of the nested types parent
/// </summary>
public string? NTParentName { get; set; } = null;
/// <summary>
/// Name of the derived classes declaring type
/// </summary>
public string? MatchBaseClass { get; set; } = null;
/// <summary>
/// Name of the derived classes declaring type we want to ignore
/// </summary>
public string? IgnoreBaseClass { get; set; } = null;
#endregion STR_PARAMS

View File

@ -1,18 +0,0 @@
using ReCodeIt.Enums;
using Mono.Cecil;
namespace ReCodeIt.Models;
public class ScoringModel
{
public string ProposedNewName { get; set; }
public int Score { get; set; } = 0;
public TypeDefinition Definition { get; set; }
public RemapModel ReMap { get; internal set; }
public EFailureReason FailureReason { get; set; } = EFailureReason.None;
public ScoringModel()
{
}
}

View File

@ -9,14 +9,13 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="dnlib" Version="4.4.0" />
<PackageReference Include="Microsoft.Build.Locator" Version="1.7.8" />
<PackageReference Include="Microsoft.CodeAnalysis" Version="4.10.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.10.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.10.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="4.10.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
<PackageReference Include="Mono.Cecil" Version="0.11.5" />
<PackageReference Include="morelinq" Version="4.2.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>

View File

@ -1,5 +1,5 @@
using Mono.Cecil;
using Mono.Cecil.Cil;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using ReCodeIt.Utils;
using System.Diagnostics;
@ -13,17 +13,18 @@ public static class Deobfuscator
string token;
using (var assemblyDefinition = AssemblyDefinition.ReadAssembly(assemblyPath))
{
var potentialStringDelegates = new List<MethodDefinition>();
ModuleContext modCtx = ModuleDef.CreateModuleContext();
ModuleDefMD module = ModuleDefMD.Load(assemblyPath, modCtx);
foreach (var type in assemblyDefinition.MainModule.Types)
var potentialStringDelegates = new List<MethodDef>();
foreach (var type in module.GetTypes())
{
foreach (var method in type.Methods)
{
if (method.ReturnType.FullName != "System.String"
|| method.Parameters.Count != 1
|| method.Parameters[0].ParameterType.FullName != "System.Int32"
|| method.Parameters[0].Type.FullName != "System.Int32"
|| method.Body == null
|| !method.IsStatic)
{
@ -32,7 +33,7 @@ public static class Deobfuscator
if (!method.Body.Instructions.Any(x =>
x.OpCode.Code == Code.Callvirt &&
((MethodReference)x.Operand).FullName == "System.Object System.AppDomain::GetData(System.String)"))
((MethodDef)x.Operand).FullName == "System.Object System.AppDomain::GetData(System.String)"))
{
continue;
}
@ -46,12 +47,12 @@ public static class Deobfuscator
Logger.Log($"Expected to find 1 potential string delegate method; found {potentialStringDelegates.Count}. Candidates: {string.Join("\r\n", potentialStringDelegates.Select(x => x.FullName))}");
}
var deobfRid = potentialStringDelegates[0].MetadataToken;
token = $"0x{((uint)deobfRid.TokenType | deobfRid.RID):x4}";
var methodDef = potentialStringDelegates[0];
MDToken deobfRid = methodDef.MDToken;
// Construct the token string (similar to Mono.Cecil's format)
token = $"0x{(deobfRid.Raw | deobfRid.Rid):x4}";
Console.WriteLine($"Deobfuscation token: {token}");
}
var process = Process.Start(executablePath,
$"--un-name \"!^<>[a-z0-9]$&!^<>[a-z0-9]__.*$&![A-Z][A-Z]\\$<>.*$&^[a-zA-Z_<{{$][a-zA-Z_0-9<>{{}}$.`-]*$\" \"{assemblyPath}\" --strtyp delegate --strtok \"{token}\"");
@ -61,16 +62,13 @@ public static class Deobfuscator
// Fixes "ResolutionScope is null" by rewriting the assembly
var cleanedDllPath = Path.Combine(Path.GetDirectoryName(assemblyPath), Path.GetFileNameWithoutExtension(assemblyPath) + "-cleaned.dll");
var resolver = new DefaultAssemblyResolver();
resolver.AddSearchDirectory(Path.GetDirectoryName(assemblyPath));
ModuleDefMD assemblyRewrite = null;
using (var memoryStream = new MemoryStream(File.ReadAllBytes(cleanedDllPath)))
using (var assemblyDefinition = AssemblyDefinition.ReadAssembly(memoryStream, new ReaderParameters()
{
AssemblyResolver = resolver
}))
{
assemblyDefinition.Write(cleanedDllPath);
}
assemblyRewrite = ModuleDefMD.Load(memoryStream, modCtx);
}
assemblyRewrite.Write(cleanedDllPath);
}
}

View File

@ -1,66 +1,15 @@
using Mono.Cecil;
using Mono.Cecil.Rocks;
using ReCodeIt.Utils;
using dnlib.DotNet;
using System.Runtime.CompilerServices;
namespace ReCodeIt.ReMapper;
public static class Publicizer
{
public static void Publicize()
{
Logger.Log("Starting publicization...", ConsoleColor.Green);
foreach (var type in DataProvider.ModuleDefinition.Types)
{
if (type.IsNotPublic) { type.IsPublic = true; }
// We only want to do methods and properties
if (type.HasMethods)
{
foreach (var method in type.Methods)
{
method.IsPublic = true;
}
}
if (type.HasProperties)
{
foreach (var property in type.Properties)
{
if (property.SetMethod != null)
{
property.SetMethod.IsPublic = true;
}
if (property.GetMethod != null)
{
property.GetMethod.IsPublic = true;
}
}
}
}
}
public static void Unseal()
{
Logger.Log("Starting unseal...", ConsoleColor.Green);
foreach (var type in DataProvider.ModuleDefinition.Types)
{
if (type.IsSealed) { type.IsSealed = false; }
}
}
}
internal static class SPTPublicizer
{
private static ModuleDefinition MainModule;
private static ModuleDefMD MainModule;
public static void PublicizeClasses(ModuleDefinition definition)
public static void PublicizeClasses(ModuleDefMD definition)
{
var types = definition.GetAllTypes();
var types = definition.GetTypes();
foreach (var type in types)
{
@ -70,7 +19,7 @@ internal static class SPTPublicizer
}
}
private static void PublicizeType(TypeDefinition type)
private static void PublicizeType(TypeDef type)
{
// if (type.CustomAttributes.Any(a => a.AttributeType.Name ==
// nameof(CompilerGeneratedAttribute))) { return; }
@ -109,11 +58,11 @@ internal static class SPTPublicizer
// Workaround to not publicize some nested types that cannot be patched easily and cause
// issues Specifically, we want to find any type that implements the "IHealthController"
// interface and make sure none of it's nested types that implement "IEffect" are changed
if (GetFlattenedInterfacesRecursive(type).Any(i => i.InterfaceType.Name == "IHealthController"))
if (GetFlattenedInterfacesRecursive(type).Any(i => i.Interface.Name == "IHealthController"))
{
// Specifically, any type that implements the IHealthController interface needs to not
// publicize any nested types that implement the IEffect interface
nestedTypesToPublicize = type.NestedTypes.Where(t => t.IsAbstract || t.Interfaces.All(i => i.InterfaceType.Name != "IEffect")).ToArray();
nestedTypesToPublicize = type.NestedTypes.Where(t => t.IsAbstract || t.Interfaces.All(i => i.Interface.Name != "IEffect")).ToArray();
}
foreach (var nestedType in nestedTypesToPublicize)
@ -122,15 +71,7 @@ internal static class SPTPublicizer
}
}
// Don't publicize methods that implement interfaces not belonging to the current assembly
// Unused - sometimes some ambiguous reference errors appear due to this, but the pros outweigh
// the cons at the moment
private static bool CanPublicizeMethod(MethodDefinition method)
{
return !method.HasOverrides && method.GetBaseMethod().Equals(method) && !method.IsVirtual;
}
private static void PublicizeMethod(MethodDefinition method)
private static void PublicizeMethod(MethodDef method)
{
if (method.IsCompilerControlled /*|| method.CustomAttributes.Any(a => a.AttributeType.Name == nameof(CompilerGeneratedAttribute))*/)
{
@ -151,7 +92,7 @@ internal static class SPTPublicizer
// Unused for now - publicizing fields is tricky, as it often creates MonoBehaviour loading
// errors and prevents scenes from loading, most notably breaking the initial game loader scene
// and causing the game to CTD right after starting
private static void PublicizeField(FieldDefinition field)
private static void PublicizeField(FieldDef field)
{
if (field.CustomAttributes.Any(a => a.AttributeType.Name == nameof(CompilerGeneratedAttribute))
// || field.HasCustomAttributes
@ -167,9 +108,9 @@ internal static class SPTPublicizer
field.Attributes |= FieldAttributes.Public;
}
private static List<InterfaceImplementation> GetFlattenedInterfacesRecursive(TypeDefinition type)
private static List<InterfaceImpl> GetFlattenedInterfacesRecursive(TypeDef type)
{
var interfaces = new List<InterfaceImplementation>();
var interfaces = new List<InterfaceImpl>();
if (type is null) return interfaces;
@ -180,7 +121,7 @@ internal static class SPTPublicizer
if (type.BaseType != null && !type.BaseType.Name.Contains("Object"))
{
var baseTypeDefinition = MainModule?.ImportReference(type.BaseType)?.Resolve();
var baseTypeDefinition = MainModule?.Find(type.BaseType);
var baseTypeInterfaces = GetFlattenedInterfacesRecursive(baseTypeDefinition);
if (baseTypeInterfaces.Any())

View File

@ -1,10 +1,10 @@
using Mono.Cecil;
using Mono.Cecil.Rocks;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using ReCodeIt.CrossCompiler;
using ReCodeIt.Enums;
using ReCodeIt.Models;
using ReCodeIt.ReMapper.Search;
using ReCodeIt.Utils;
using ReCodeItLib.Remapper.Search;
using System.Diagnostics;
namespace ReCodeIt.ReMapper;
@ -19,6 +19,8 @@ public class ReCodeItRemapper
public ReCodeItRemapper()
{ }
private ModuleDefMD Module { get; set; }
private readonly ReCodeItCrossCompiler _compiler;
public static bool IsRunning { get; private set; } = false;
@ -37,6 +39,8 @@ public class ReCodeItRemapper
private string AssemblyPath { get; set; }
private List<RemapModel> _remaps = [];
/// <summary>
/// Start the remapping process
/// </summary>
@ -46,7 +50,9 @@ public class ReCodeItRemapper
string outPath,
bool crossMapMode = false)
{
DataProvider.LoadAssemblyDefinition(assemblyPath);
_remaps = [];
_remaps = remapModels;
Module = DataProvider.LoadModule(assemblyPath);
AssemblyPath = assemblyPath;
CrossMapMode = crossMapMode;
@ -54,32 +60,43 @@ public class ReCodeItRemapper
OutPath = outPath;
IsRunning = true;
DisplayBasicModuleInformation();
Stopwatch.Start();
var types = Module.GetTypes();
var tasks = new List<Task>(remapModels.Count);
foreach (var remap in remapModels)
{
Logger.Log($"Finding best match for {remap.NewTypeName}...", ConsoleColor.Gray);
ScoreMapping(remap);
tasks.Add(
Task.Factory.StartNew(() =>
{
Logger.Log($"\nFinding best match for {remap.NewTypeName}...", ConsoleColor.Gray);
ScoreMapping(remap, types);
})
);
}
Task.WaitAll(tasks.ToArray());
ChooseBestMatches();
var renameTasks = new List<Task>(remapModels.Count);
foreach (var remap in remapModels)
{
renameTasks.Add(
Task.Factory.StartNew(() =>
{
RenameHelper.RenameAll(types, remap);
})
);
}
Task.WaitAll(renameTasks.ToArray());
// Don't publicize and unseal until after the remapping, so we can use those as search parameters
if (Settings.MappingSettings.Publicize)
{
//Publicizer.Publicize();
Logger.Log("Publicizing classes...", ConsoleColor.Yellow);
Logger.Log("Publicizing classes...", ConsoleColor.Green);
SPTPublicizer.PublicizeClasses(DataProvider.ModuleDefinition);
}
if (Settings.MappingSettings.Unseal)
{
//Publicizer.Unseal();
SPTPublicizer.PublicizeClasses(Module);
}
// We are done, write the assembly
@ -92,134 +109,54 @@ public class ReCodeItRemapper
}
/// <summary>
/// Display information about the module we are remapping
/// </summary>
private void DisplayBasicModuleInformation()
{
Logger.Log("-----------------------------------------------", ConsoleColor.Yellow);
Logger.Log($"Starting remap...", ConsoleColor.Yellow);
Logger.Log($"Module contains {DataProvider.ModuleDefinition.Types.Count} Types", ConsoleColor.Yellow);
Logger.Log($"Publicize: {Settings.MappingSettings.Publicize}", ConsoleColor.Yellow);
Logger.Log($"Unseal: {Settings.MappingSettings.Unseal}", ConsoleColor.Yellow);
Logger.Log("-----------------------------------------------", ConsoleColor.Yellow);
}
/// <summary>
/// Loop over all types in the assembly and score them
/// First we filter our type collection based on simple search parameters (true/false/null)
/// where null is a third disabled state. Then we score the types based on the search parameters
/// </summary>
/// <param name="mapping">Mapping to score</param>
private void ScoreMapping(RemapModel mapping)
private void ScoreMapping(RemapModel mapping, IEnumerable<TypeDef> types)
{
foreach (var type in DataProvider.ModuleDefinition.Types)
{
FindMatch(type, mapping);
}
}
/// <summary>
/// Find a match result
/// </summary>
/// <param name="type">OriginalTypeRef to score</param>
/// <param name="remap">Remap to check against</param>
/// <param name="parentTypeName"></param>
/// <returns>EMatchResult</returns>
private void FindMatch(TypeDefinition type, RemapModel remap)
{
// Handle Direct Remaps by strict naming first bypasses everything else
if (remap.UseForceRename)
{
HandleByDirectName(type, remap);
return;
}
var tokens = DataProvider.Settings.AutoMapper.TokensToMatch;
bool ignore = tokens
.Where(token => !tokens
.Any(token => type.Name.StartsWith(token))).Any();
if (ignore && remap.SearchParams.IsNested is null)
if (mapping.SearchParams.IsNested is false or null)
{
return;
types = types.Where(type => tokens.Any(token => type.Name.StartsWith(token)));
}
foreach (var nestedType in type.NestedTypes)
types = GenericTypeFilters.FilterPublic(types, mapping.SearchParams);
if (!types.Any())
{
FindMatch(nestedType, remap);
Logger.Log($"All types filtered out after public filter for: {mapping.NewTypeName}", ConsoleColor.Red);
}
var score = new ScoringModel
{
ProposedNewName = remap.NewTypeName,
ReMap = remap,
Definition = type,
};
types = GenericTypeFilters.FilterAbstract(types, mapping.SearchParams);
types = GenericTypeFilters.FilterSealed(types, mapping.SearchParams);
types = GenericTypeFilters.FilterInterface(types, mapping.SearchParams);
types = GenericTypeFilters.FilterStruct(types, mapping.SearchParams);
types = GenericTypeFilters.FilterEnum(types, mapping.SearchParams);
types = GenericTypeFilters.FilterAttributes(types, mapping.SearchParams);
types = GenericTypeFilters.FilterDerived(types, mapping.SearchParams);
types = GenericTypeFilters.FilterByGenericParameters(types, mapping.SearchParams);
var matches = new List<EMatchResult>
{
type.MatchConstructors(remap.SearchParams, score),
type.MatchMethods(remap.SearchParams, score),
type.MatchFields(remap.SearchParams, score),
type.MatchProperties(remap.SearchParams, score),
type.MatchNestedTypes(remap.SearchParams, score),
type.MatchIsPublic(remap.SearchParams, score) ,
type.MatchIsInterface(remap.SearchParams, score),
type.MatchIsAbstract(remap.SearchParams, score),
type.MatchIsSealed(remap.SearchParams, score) ,
type.MatchIsEnum(remap.SearchParams, score) ,
type.MatchIsNested(remap.SearchParams, score),
type.MatchIsDerived(remap.SearchParams, score) ,
type.MatchHasGenericParameters(remap.SearchParams, score),
type.MatchHasAttribute(remap.SearchParams, score),
};
types = MethodTypeFilters.FilterByInclude(types, mapping.SearchParams);
types = MethodTypeFilters.FilterByExclude(types, mapping.SearchParams);
types = MethodTypeFilters.FilterByCount(types, mapping.SearchParams);
var NoMatch = matches.Where(x => x.Equals(EMatchResult.NoMatch)).FirstOrDefault();
types = FieldTypeFilters.FilterByInclude(types, mapping.SearchParams);
types = FieldTypeFilters.FilterByExclude(types, mapping.SearchParams);
types = FieldTypeFilters.FilterByCount(types, mapping.SearchParams);
if (NoMatch == EMatchResult.NoMatch)
{
remap.FailureReason = score.FailureReason;
return;
}
types = PropertyTypeFilters.FilterByInclude(types, mapping.SearchParams);
types = PropertyTypeFilters.FilterByExclude(types, mapping.SearchParams);
types = PropertyTypeFilters.FilterByCount(types, mapping.SearchParams);
var match = matches
.Where(x => x.Equals(EMatchResult.Match))
.Where(x => !x.Equals(EMatchResult.Disabled))
.Any();
types = CtorTypeFilters.FilterByParameterCount(types, mapping.SearchParams);
if (match)
{
// Set the original type name to be used later
score.ReMap.OriginalTypeName = type.FullName;
remap.OriginalTypeName = type.FullName;
remap.Succeeded = true;
remap.FailureReason = EFailureReason.None;
score.AddScoreToResult();
}
}
types = NestedTypeFilters.FilterByInclude(types, mapping.SearchParams);
types = NestedTypeFilters.FilterByExclude(types, mapping.SearchParams);
types = NestedTypeFilters.FilterByCount(types, mapping.SearchParams);
private void HandleByDirectName(TypeDefinition type, RemapModel remap)
{
if (type.Name != remap.OriginalTypeName) { return; }
var oldName = type.Name;
remap.OriginalTypeName = type.Name;
remap.FailureReason = EFailureReason.None;
remap.Succeeded = true;
if (CrossMapMode)
{
// Store the original types for caching
_compiler.ActiveProject.ChangedTypes.Add(remap.NewTypeName, type.Name);
}
type.Name = remap.NewTypeName;
Logger.Log("-----------------------------------------------", ConsoleColor.Green);
Logger.Log($"Renamed {oldName} to {type.Name} directly", ConsoleColor.Green);
RenameHelper.RenameAllDirect(remap, type);
Logger.Log("-----------------------------------------------", ConsoleColor.Green);
mapping.TypeCandidates.UnionWith(types);
}
/// <summary>
@ -227,76 +164,34 @@ public class ReCodeItRemapper
/// </summary>
private void ChooseBestMatches()
{
foreach (var score in DataProvider.ScoringModels)
foreach (var remap in _remaps)
{
ChooseBestMatch(score.Value);
ChooseBestMatch(remap);
}
var failures = 0;
var changes = 0;
foreach (var remap in DataProvider.Remaps)
{
if (remap.Succeeded is false)
{
Logger.Log("-----------------------------------------------", ConsoleColor.Red);
Logger.Log($"Renaming {remap.NewTypeName} failed with reason {remap.FailureReason}", ConsoleColor.Red);
Logger.Log("-----------------------------------------------", ConsoleColor.Red);
failures++;
continue;
}
changes++;
}
Logger.Log("-----------------------------------------------", ConsoleColor.Yellow);
Logger.Log($"Result: Remapped {changes} Types. Failed to remap {failures} Types", ConsoleColor.Yellow);
Logger.Log("-----------------------------------------------", ConsoleColor.Yellow);
}
/// <summary>
/// Choose best match from a collection of scores, then start the renaming process
/// </summary>
/// <param name="scores">Scores to rate</param>
private void ChooseBestMatch(HashSet<ScoringModel> scores)
private void ChooseBestMatch(RemapModel remap)
{
if (scores.Count == 0) { return; }
if (remap.TypeCandidates.Count == 0) { return; }
var filteredScores = scores
.Where(score => score.Score > 0)
.OrderByDescending(score => score.Score)
.Take(5);
var winner = remap.TypeCandidates.FirstOrDefault();
remap.TypePrimeCandidate = winner;
remap.OriginalTypeName = winner.Name.String;
var highestScore = filteredScores.FirstOrDefault();
if (winner is null) { return; }
if (highestScore is null) { return; }
remap.Succeeded = true;
Logger.Log("-----------------------------------------------", ConsoleColor.Green);
Logger.Log($"Renaming {highestScore.Definition.FullName} to {highestScore.ProposedNewName}", ConsoleColor.Green);
Logger.Log($"Scored: {highestScore.Score} points", ConsoleColor.Green);
if (filteredScores.Count() > 1 && filteredScores.Skip(1).Any(score => score.Score == highestScore.Score))
{
Logger.Log($"Warning! There were {filteredScores.Count()} possible matches. Considering adding more search parameters, Only showing first 5.", ConsoleColor.Yellow);
foreach (var score in filteredScores.Skip(1).Take(5))
{
Logger.Log($"{score.Definition.Name} - Score [{score.Score}]", ConsoleColor.Yellow);
}
}
highestScore.ReMap.OriginalTypeName = highestScore.Definition.Name;
remap.OriginalTypeName = winner.Name.String;
if (CrossMapMode)
{// Store the original types for caching
_compiler.ActiveProject.ChangedTypes.Add(highestScore.ProposedNewName, highestScore.Definition.Name);
//_compiler.ActiveProject.ChangedTypes.Add(highestScore.ProposedNewName, highestScore.Definition.Name);
}
// Rename type and all associated type members
RenameHelper.RenameAll(highestScore);
Logger.Log("-----------------------------------------------", ConsoleColor.Green);
}
/// <summary>
@ -304,28 +199,35 @@ public class ReCodeItRemapper
/// </summary>
private void WriteAssembly()
{
var moduleName = DataProvider.AssemblyDefinition.MainModule.Name;
var moduleName = Module.Name;
moduleName = moduleName.Replace(".dll", "-Remapped.dll");
OutPath = Path.Combine(OutPath, moduleName);
var path = DataProvider.WriteAssemblyDefinition(OutPath);
try
{
Module.Write(OutPath);
}
catch (Exception e)
{
Logger.Log(e);
throw;
}
Logger.Log("Creating Hollow...", ConsoleColor.Yellow);
Hollow();
var hollowedDir = Path.GetDirectoryName(OutPath);
var hollowedPath = Path.Combine(hollowedDir, "Hollowed.dll");
DataProvider.WriteAssemblyDefinition(hollowedPath);
Module.Write(hollowedPath);
Logger.Log("-----------------------------------------------", ConsoleColor.Green);
Logger.Log($"Complete: Assembly written to `{path}`", ConsoleColor.Green);
Logger.Log($"Complete: Hollowed written to `{hollowedPath}`", ConsoleColor.Green);
Logger.Log("Original type names updated on mapping file.", ConsoleColor.Green);
Logger.Log($"Remap took {Stopwatch.Elapsed.TotalSeconds:F1} seconds", ConsoleColor.Green);
Logger.Log("-----------------------------------------------", ConsoleColor.Green);
DisplayEndBanner(hollowedPath);
if (DataProvider.Settings.Remapper.MappingPath != string.Empty)
{
DataProvider.UpdateMapping(DataProvider.Settings.Remapper.MappingPath, _remaps);
}
DataProvider.ScoringModels = [];
Stopwatch.Reset();
IsRunning = false;
@ -337,14 +239,75 @@ public class ReCodeItRemapper
/// </summary>
private void Hollow()
{
foreach (var type in DataProvider.ModuleDefinition.GetAllTypes())
foreach (var type in Module.GetTypes())
{
foreach (var method in type.Methods.Where(m => m.HasBody))
{
var ilProcessor = method.Body.GetILProcessor();
if (!method.HasBody) continue;
// Remove existing instructions
ilProcessor.Clear();
method.Body = new CilBody();
method.Body.Instructions.Add(OpCodes.Ret.ToInstruction());
}
}
}
private void DisplayEndBanner(string hollowedPath)
{
var failures = 0;
var changes = 0;
foreach (var remap in _remaps)
{
if (remap.Succeeded is false)
{
Logger.Log("-----------------------------------------------", ConsoleColor.Red);
Logger.Log($"Renaming {remap.NewTypeName} failed with reason(s)", ConsoleColor.Red);
foreach (var reason in remap.NoMatchReasons)
{
Logger.Log($"Reason: {reason}", ConsoleColor.Red);
}
Logger.Log("-----------------------------------------------", ConsoleColor.Red);
failures++;
continue;
}
changes++;
}
Logger.Log("-----------------------------------------------", ConsoleColor.Green);
Logger.Log("-----------------------------------------------", ConsoleColor.Green);
foreach (var remap in _remaps)
{
if (remap.Succeeded is false) { continue; }
var original = remap.OriginalTypeName;
var proposed = remap.NewTypeName;
Logger.Log($"Renamed {original} to {proposed}", ConsoleColor.Green);
DisplayAlternativeMatches(remap);
}
Logger.Log("-----------------------------------------------", ConsoleColor.Green);
Logger.Log("-----------------------------------------------", ConsoleColor.Green);
Logger.Log($"Result renamed {changes} Types. Failed to rename {failures} Types", ConsoleColor.Green);
Logger.Log($"Assembly written to `{OutPath}`", ConsoleColor.Green);
Logger.Log($"Hollowed written to `{hollowedPath}`", ConsoleColor.Green);
Logger.Log($"Remap took {Stopwatch.Elapsed.TotalSeconds:F1} seconds", ConsoleColor.Green);
}
private void DisplayAlternativeMatches(RemapModel remap)
{
if (remap.TypeCandidates.Count() > 1)
{
Logger.Log($"Warning! There were {remap.TypeCandidates.Count()} possible matches for {remap.NewTypeName}. Consider adding more search parameters, Only showing the first 5.", ConsoleColor.Yellow);
foreach (var type in remap.TypeCandidates.Skip(1).Take(5))
{
Logger.Log($"{type.Name}", ConsoleColor.Yellow);
}
}
}

View File

@ -1,5 +1,4 @@
using Mono.Cecil;
using Mono.Cecil.Rocks;
using dnlib.DotNet;
using ReCodeIt.Models;
using ReCodeIt.Utils;
@ -12,42 +11,45 @@ internal static class RenameHelper
/// <summary>
/// Only used by the manual remapper, should probably be removed
/// </summary>
/// <param name="score"></param>
public static void RenameAll(ScoringModel score, bool direct = false)
/// <param name="module"></param>
/// <param name="remap"></param>
/// <param name="direct"></param>
public static void RenameAll(IEnumerable<TypeDef> types, RemapModel remap, bool direct = false)
{
var types = DataProvider.ModuleDefinition.GetAllTypes();
// Rename all fields and properties first
if (DataProvider.Settings.Remapper.MappingSettings.RenameFields)
{
RenameAllFields(score.Definition.Name, score.ReMap.NewTypeName, types);
RenameAllFields(
remap.TypePrimeCandidate.Name.String,
remap.NewTypeName,
types);
}
if (DataProvider.Settings.Remapper.MappingSettings.RenameProperties)
{
RenameAllProperties(score.Definition.Name, score.ReMap.NewTypeName, types);
RenameAllProperties(
remap.TypePrimeCandidate.Name.String,
remap.NewTypeName,
types);
}
if (!direct)
{
RenameType(types, score);
RenameType(types, remap);
}
Logger.Log($"{score.Definition.Name} Renamed.", ConsoleColor.Green);
Logger.Log($"{remap.TypePrimeCandidate.Name.String} Renamed.", ConsoleColor.Green);
}
/// <summary>
/// Only used by the manual remapper, should probably be removed
/// </summary>
/// <param name="score"></param>
public static void RenameAllDirect(RemapModel remap, TypeDefinition type)
/// <param name="module"></param>
/// <param name="remap"></param>
/// <param name="type"></param>
public static void RenameAllDirect(IEnumerable<TypeDef> types, RemapModel remap, TypeDef type)
{
var directRename = new ScoringModel
{
Definition = type,
ReMap = remap
};
RenameAll(directRename, true);
RenameAll(types, remap, true);
}
/// <summary>
@ -57,10 +59,11 @@ internal static class RenameHelper
/// <param name="newTypeName"></param>
/// <param name="typesToCheck"></param>
/// <returns></returns>
public static int RenameAllFields(
public static IEnumerable<TypeDef> RenameAllFields(
string oldTypeName,
string newTypeName,
IEnumerable<TypeDefinition> typesToCheck,
IEnumerable<TypeDef> typesToCheck,
int overAllCount = 0)
{
foreach (var type in typesToCheck)
@ -73,29 +76,89 @@ internal static class RenameHelper
int fieldCount = 0;
foreach (var field in fields)
{
if (field.FieldType.Name == oldTypeName)
if (field.FieldType.TypeName == oldTypeName)
{
var newFieldName = GetNewFieldName(newTypeName, field.IsPrivate, fieldCount);
var newFieldName = GetNewFieldName(newTypeName, fieldCount);
// Dont need to do extra work
if (field.Name == newFieldName) { continue; }
Logger.Log($"Renaming original field type name: `{field.FieldType.Name}` with name `{field.Name}` to `{newFieldName}`", ConsoleColor.Green);
Logger.Log($"Renaming field on type {type.Name} named `{field.Name}` with type `{field.FieldType.TypeName}` to `{newFieldName}`", ConsoleColor.Green);
var oldName = field.Name.ToString();
field.Name = newFieldName;
UpdateTypeFieldMemberRefs(type, field, oldName);
UpdateAllTypeFieldMemberRefs(typesToCheck, field, oldName);
fieldCount++;
overAllCount++;
}
}
}
if (type.HasNestedTypes)
return typesToCheck;
}
private static void UpdateAllTypeFieldMemberRefs(IEnumerable<TypeDef> typesToCheck, FieldDef newDef, string oldName)
{
RenameAllFields(oldTypeName, newTypeName, type.NestedTypes, overAllCount);
foreach (var type in typesToCheck)
{
UpdateTypeFieldMemberRefs(type, newDef, oldName);
}
}
return overAllCount;
private static void UpdateTypeFieldMemberRefs(TypeDef type, FieldDef newDef, string oldName)
{
foreach (var method in type.Methods)
{
if (!method.HasBody) continue;
foreach (var instr in method.Body.Instructions)
{
if (instr.Operand is MemberRef memRef && memRef.Name == oldName)
{
//if (!memRef.Name.IsFieldOrPropNameInList(TokensToMatch)) continue;
Logger.Log($"Renaming MemRef in method {method.DeclaringType.Name}::{method.Name} from `{memRef.Name}` to `{newDef.Name}`", ConsoleColor.Yellow);
memRef.Name = newDef.Name;
}
}
}
}
private static void RenameAllFieldRefsInMethods(IEnumerable<TypeDef> typesToCheck, FieldDef newDef, string oldName)
{
foreach (var type in typesToCheck)
{
foreach (var method in type.Methods)
{
if (!method.HasBody) continue;
ChangeFieldNamesInMethods(method, newDef, oldName);
}
}
}
/// <summary>
/// Rename all field and member refs in a method
/// </summary>
/// <param name="method"></param>
/// <param name="newDef"></param>
/// <param name="oldName"></param>
private static void ChangeFieldNamesInMethods(MethodDef method, FieldDef newDef, string oldName)
{
foreach (var instr in method.Body.Instructions)
{
if (instr.Operand is FieldDef fieldDef && fieldDef.Name == oldName)
{
if (!fieldDef.Name.IsFieldOrPropNameInList(TokensToMatch)) continue;
Logger.Log($"Renaming fieldDef in method {method.Name} from `{fieldDef.Name}` to `{newDef.Name}`", ConsoleColor.Yellow);
fieldDef.Name = newDef.Name;
}
}
}
/// <summary>
@ -108,7 +171,7 @@ internal static class RenameHelper
public static int RenameAllProperties(
string oldTypeName,
string newTypeName,
IEnumerable<TypeDefinition> typesToCheck,
IEnumerable<TypeDef> typesToCheck,
int overAllCount = 0)
{
foreach (var type in typesToCheck)
@ -121,35 +184,30 @@ internal static class RenameHelper
int propertyCount = 0;
foreach (var property in properties)
{
if (property.PropertyType.Name == oldTypeName)
if (property.PropertySig.RetType.TypeName == oldTypeName)
{
var newPropertyName = GetNewPropertyName(newTypeName, propertyCount);
// Dont need to do extra work
if (property.Name == newPropertyName) { continue; }
Logger.Log($"Renaming original property type name: `{property.PropertyType.Name}` with name `{property.Name}` to `{newPropertyName}`", ConsoleColor.Green);
property.Name = newPropertyName;
Logger.Log($"Renaming property on type {type.Name} named `{property.Name}` with type `{property.PropertySig.RetType.TypeName}` to `{newPropertyName}`", ConsoleColor.Green);
property.Name = new UTF8String(newPropertyName);
propertyCount++;
overAllCount++;
}
}
if (type.HasNestedTypes)
{
RenameAllProperties(oldTypeName, newTypeName, type.NestedTypes, overAllCount);
}
}
return overAllCount;
}
public static string GetNewFieldName(string NewName, bool isPrivate, int fieldCount = 0)
public static string GetNewFieldName(string NewName, int fieldCount = 0)
{
var discard = isPrivate ? "_" : "";
string newFieldCount = fieldCount > 0 ? $"_{fieldCount}" : string.Empty;
return $"{discard}{char.ToLower(NewName[0])}{NewName[1..]}{newFieldCount}";
return $"{char.ToLower(NewName[0])}{NewName[1..]}{newFieldCount}";
}
public static string GetNewPropertyName(string newName, int propertyCount = 0)
@ -157,26 +215,26 @@ internal static class RenameHelper
return propertyCount > 0 ? $"{newName}_{propertyCount}" : newName;
}
private static void RenameType(IEnumerable<TypeDefinition> typesToCheck, ScoringModel score)
private static void RenameType(IEnumerable<TypeDef> typesToCheck, RemapModel remap)
{
foreach (var type in typesToCheck)
{
if (type.HasNestedTypes)
{
RenameType(type.NestedTypes, score);
RenameType(type.NestedTypes, remap);
}
if (score.Definition.Name is null) { continue; }
if (remap.TypePrimeCandidate.Name is null) { continue; }
if (score.ReMap.SearchParams.IsNested is true &&
type.IsNested && type.Name == score.Definition.Name)
if (remap.SearchParams.IsNested is true &&
type.IsNested && type.Name == remap.TypePrimeCandidate.Name)
{
type.Name = score.ProposedNewName;
type.Name = remap.NewTypeName;
}
if (type.FullName == score.Definition.Name)
if (type.FullName == remap.TypePrimeCandidate.Name)
{
type.Name = score.ProposedNewName;
type.Name = remap.NewTypeName;
}
}
}

View File

@ -1,28 +0,0 @@
using ReCodeIt.Enums;
using ReCodeIt.Models;
using Mono.Cecil;
using Mono.Cecil.Rocks;
namespace ReCodeIt.ReMapper.Search;
internal static class Constructors
{
/// <summary>
/// Search for types with a constructor of a given length
/// </summary>
/// <param name="parms"></param>
/// <param name="score"></param>
/// <returns>Match if constructor parameters matches</returns>
public static EMatchResult GetTypeByParameterCount(TypeDefinition type, SearchParams parms, ScoringModel score)
{
if (parms.ConstructorParameterCount is null) return EMatchResult.Disabled;
var match = type.GetConstructors()
.Where(c => c.Parameters.Count == parms.ConstructorParameterCount)
.Any();
return match
? EMatchResult.Match
: EMatchResult.NoMatch;
}
}

View File

@ -0,0 +1,30 @@
using dnlib.DotNet;
using ReCodeIt.Models;
namespace ReCodeIt.ReMapper.Search;
internal static class CtorTypeFilters
{
/// <summary>
/// Search for types with a constructor of a given length
/// </summary>
/// <param name="parms"></param>
/// <param name="score"></param>
/// <returns>Filtered list</returns>
public static IEnumerable<TypeDef> FilterByParameterCount(IEnumerable<TypeDef> types, SearchParams parms)
{
if (parms.ConstructorParameterCount is null) return types;
return types.Where(type =>
{
var constructors = type.FindConstructors();
return constructors != null && constructors.Any(ctor =>
{
// Ensure Parameters isn't null before checking Count
var parameters = ctor.Parameters;
// This +1 offset is needed for some reason, needs investigation
return parameters != null && parameters.Count == parms.ConstructorParameterCount + 1;
});
});
}
}

View File

@ -0,0 +1,78 @@
using dnlib.DotNet;
using ReCodeIt.Models;
using ReCodeIt.Utils;
namespace ReCodeItLib.Remapper.Search;
internal static class FieldTypeFilters
{
/// <summary>
/// Filters based on field name
/// </summary>
/// <param name="types"></param>
/// <param name="parms"></param>
/// <returns>Filtered list</returns>
public static IEnumerable<TypeDef> FilterByInclude(IEnumerable<TypeDef> types, SearchParams parms)
{
if (parms.IncludeFields.Count == 0) return types;
List<TypeDef> filteredTypes = [];
foreach (var type in types)
{
if (parms.IncludeFields
.All(includeName => type.Fields
.Any(field => field.Name.String == includeName)))
{
filteredTypes.Add(type);
}
}
return filteredTypes.Any() ? filteredTypes : types;
}
/// <summary>
/// Filters based on field name
/// </summary>
/// <param name="types"></param>
/// <param name="parms"></param>
/// <returns>Filtered list</returns>
public static IEnumerable<TypeDef> FilterByExclude(IEnumerable<TypeDef> types, SearchParams parms)
{
if (parms.ExcludeFields.Count == 0) return types;
List<TypeDef> filteredTypes = [];
foreach (var type in types)
{
var match = type.Fields
.Where(field => parms.ExcludeFields.Contains(field.Name.String));
if (!match.Any())
{
filteredTypes.Add(type);
}
}
return filteredTypes.Any() ? filteredTypes : types;
}
/// <summary>
/// Filters based on method count
/// </summary>
/// <param name="types"></param>
/// <param name="parms"></param>
/// <returns>Filtered list</returns>
public static IEnumerable<TypeDef> FilterByCount(IEnumerable<TypeDef> types, SearchParams parms)
{
if (parms.FieldCount is null) return types;
if (parms.FieldCount >= 0)
{
Logger.Log("Matching field count", ConsoleColor.Yellow);
types = types.Where(t => t.Fields.Count == parms.FieldCount);
}
return types;
}
}

View File

@ -1,79 +0,0 @@
using Mono.Cecil;
using MoreLinq;
using ReCodeIt.Enums;
using ReCodeIt.Models;
namespace ReCodeIt.ReMapper.Search;
internal static class Fields
{
/// <summary>
/// Returns a match on any type with the provided fields
/// </summary>
/// <param name="type"></param>
/// <param name="parms"></param>
/// <param name="score"></param>
/// <returns></returns>
public static EMatchResult Include(TypeDefinition type, SearchParams parms, ScoringModel score)
{
if (parms.IncludeFields is null || parms.IncludeFields.Count == 0) return EMatchResult.Disabled;
var matches = type.Fields
.Where(field => parms.IncludeFields.Contains(field.Name))
.Count();
score.Score += matches > 0 ? matches : -matches;
score.FailureReason = matches > 0 ? EFailureReason.None : EFailureReason.FieldsInclude;
return matches > 0
? EMatchResult.Match
: EMatchResult.NoMatch;
}
/// <summary>
/// Returns a match on any type without the provided fields
/// </summary>
/// <param name="type"></param>
/// <param name="parms"></param>
/// <param name="score"></param>
/// <returns></returns>
public static EMatchResult Exclude(TypeDefinition type, SearchParams parms, ScoringModel score)
{
if (parms.ExcludeFields is null || parms.ExcludeFields.Count == 0) return EMatchResult.Disabled;
var matches = type.Fields
.Where(field => parms.ExcludeFields.Contains(field.Name))
.Count();
score.Score += matches > 0 ? -matches : 1;
score.FailureReason = matches > 0 ? EFailureReason.FieldsExclude : EFailureReason.None;
return matches > 0
? EMatchResult.NoMatch
: EMatchResult.Match;
}
/// <summary>
/// Returns a match on any type with a matching number of fields
/// </summary>
/// <param name="type"></param>
/// <param name="parms"></param>
/// <param name="score"></param>
/// <returns></returns>
public static EMatchResult Count(TypeDefinition type, SearchParams parms, ScoringModel score)
{
if (parms.FieldCount is null) return EMatchResult.Disabled;
var match = type.Fields.Exactly((int)parms.FieldCount);
score.Score += match ? (int)parms.FieldCount : -(int)parms.FieldCount;
score.FailureReason = match ? EFailureReason.None : EFailureReason.FieldsCount;
return match
? EMatchResult.Match
: EMatchResult.NoMatch;
}
}

View File

@ -0,0 +1,256 @@
using dnlib.DotNet;
using ReCodeIt.Models;
using ReCodeIt.Utils;
namespace ReCodeItLib.Remapper.Search;
internal static class GenericTypeFilters
{
/// <summary>
/// Filters based on public, or nested public or private if the nested flag is set. This is a
/// required property
/// </summary>
/// <param name="types"></param>
/// <param name="parms"></param>
/// <returns>Filtered list</returns>
public static IEnumerable<TypeDef> FilterPublic(IEnumerable<TypeDef> types, SearchParams parms)
{
// REQUIRED PROPERTY
if (parms.IsPublic)
{
if (parms.IsNested is true)
{
Logger.Log("IsNested Public", ConsoleColor.Yellow);
types = types.Where(t => t.IsNestedPublic);
types = FilterNestedByName(types, parms);
}
else
{
Logger.Log("IsPublic is true", ConsoleColor.Yellow);
types = types.Where(t => t.IsPublic);
}
}
else
{
if (parms.IsNested is true)
{
Logger.Log("IsNested Private or family", ConsoleColor.Yellow);
types = types.Where(t => t.IsNestedPrivate
|| t.IsNestedFamily
|| t.IsNestedFamilyAndAssembly
|| t.IsNestedAssembly);
types = FilterNestedByName(types, parms);
}
else
{
Logger.Log("IsPublic is false", ConsoleColor.Yellow);
types = types.Where(t => t.IsNotPublic);
}
}
return types;
}
private static IEnumerable<TypeDef> FilterNestedByName(IEnumerable<TypeDef> types, SearchParams parms)
{
if (parms.NTParentName is not null)
{
Logger.Log($"NT Parent: {parms.NTParentName}", ConsoleColor.Yellow);
types = types.Where(t => t.DeclaringType.Name.String == parms.NTParentName);
}
return types;
}
/// <summary>
/// Filters based on IsAbstract
/// </summary>
/// <param name="types"></param>
/// <param name="parms"></param>
/// <returns>Filtered list</returns>
public static IEnumerable<TypeDef> FilterAbstract(IEnumerable<TypeDef> types, SearchParams parms)
{
// Filter based on abstract or not
if (parms.IsAbstract is true)
{
Logger.Log("IsAbstract is true", ConsoleColor.Yellow);
types = types.Where(t => t.IsAbstract && !t.IsInterface);
}
else if (parms.IsAbstract is false)
{
Logger.Log("IsAbstract is false", ConsoleColor.Yellow);
types = types.Where(t => !t.IsAbstract);
}
return types;
}
/// <summary>
/// Filters based on IsAbstract
/// </summary>
/// <param name="types"></param>
/// <param name="parms"></param>
/// <returns>Filtered list</returns>
public static IEnumerable<TypeDef> FilterSealed(IEnumerable<TypeDef> types, SearchParams parms)
{
// Filter based on abstract or not
if (parms.IsSealed is true)
{
Logger.Log("IsSealed is true", ConsoleColor.Yellow);
types = types.Where(t => t.IsSealed);
}
else if (parms.IsSealed is false)
{
Logger.Log("IsSealed is false", ConsoleColor.Yellow);
types = types.Where(t => !t.IsSealed);
}
return types;
}
/// <summary>
/// Filters based on IsInterface
/// </summary>
/// <param name="types"></param>
/// <param name="parms"></param>
/// <returns>Filtered list</returns>
public static IEnumerable<TypeDef> FilterInterface(IEnumerable<TypeDef> types, SearchParams parms)
{
// Filter based on interface or not
if (parms.IsInterface is true)
{
Logger.Log("IsInterface is true", ConsoleColor.Yellow);
types = types.Where(t => t.IsInterface);
}
else if (parms.IsInterface is false)
{
Logger.Log("IsInterface is false", ConsoleColor.Yellow);
types = types.Where(t => !t.IsInterface);
}
return types;
}
/// <summary>
/// Filters based on IsStruct
/// </summary>
/// <param name="types"></param>
/// <param name="parms"></param>
/// <returns>Filtered list</returns>
public static IEnumerable<TypeDef> FilterStruct(IEnumerable<TypeDef> types, SearchParams parms)
{
if (parms.IsStruct is true)
{
Logger.Log("IsStruct is true", ConsoleColor.Yellow);
types = types.Where(t => t.IsValueType && !t.IsEnum);
}
else if (parms.IsStruct is false)
{
Logger.Log("IsStruct is false", ConsoleColor.Yellow);
types = types.Where(t => !t.IsValueType);
}
return types;
}
/// <summary>
/// Filters based on IsEnum
/// </summary>
/// <param name="types"></param>
/// <param name="parms"></param>
/// <returns>Filtered list</returns>
public static IEnumerable<TypeDef> FilterEnum(IEnumerable<TypeDef> types, SearchParams parms)
{
// Filter based on enum or not
if (parms.IsEnum is true)
{
Logger.Log("IsEnum is true", ConsoleColor.Yellow);
types = types.Where(t => t.IsEnum);
}
else if (parms.IsEnum is false)
{
Logger.Log("IsEnum is false", ConsoleColor.Yellow);
types = types.Where(t => !t.IsEnum);
}
return types;
}
/// <summary>
/// Filters based on HasAttribute
/// </summary>
/// <param name="types"></param>
/// <param name="parms"></param>
/// <returns>Filtered list</returns>
public static IEnumerable<TypeDef> FilterAttributes(IEnumerable<TypeDef> types, SearchParams parms)
{
// Filter based on HasAttribute or not
if (parms.HasAttribute is true)
{
Logger.Log("HasAttribute is true", ConsoleColor.Yellow);
types = types.Where(t => t.HasCustomAttributes);
}
else if (parms.HasAttribute is false)
{
Logger.Log("HasAttribute is false", ConsoleColor.Yellow);
types = types.Where(t => !t.HasCustomAttributes);
}
return types;
}
/// <summary>
/// Filters based on HasAttribute
/// </summary>
/// <param name="types"></param>
/// <param name="parms"></param>
/// <returns>Filtered list</returns>
public static IEnumerable<TypeDef> FilterDerived(IEnumerable<TypeDef> types, SearchParams parms)
{
// Filter based on IsDerived or not
if (parms.IsDerived is true)
{
Logger.Log("IsDerived is true", ConsoleColor.Yellow);
types = types.Where(t => t.GetBaseType()?.Name?.String != "Object");
if (parms.MatchBaseClass is not null and not "")
{
Logger.Log($"Matching base class: {parms.MatchBaseClass}", ConsoleColor.Yellow);
types = types.Where(t => t.GetBaseType()?.Name?.String == parms.MatchBaseClass);
}
if (parms.IgnoreBaseClass is not null and not "")
{
Logger.Log($"Ignoring base class: {parms.MatchBaseClass}", ConsoleColor.Yellow);
types = types.Where(t => t.GetBaseType()?.Name?.String != parms.IgnoreBaseClass);
}
}
else if (parms.IsDerived is false)
{
Logger.Log("IsDerived is false", ConsoleColor.Yellow);
types = types.Where(t => t.GetBaseType()?.Name?.String is "Object");
}
return types;
}
/// <summary>
/// Filters based on method count
/// </summary>
/// <param name="types"></param>
/// <param name="parms"></param>
/// <returns>Filtered list</returns>
public static IEnumerable<TypeDef> FilterByGenericParameters(IEnumerable<TypeDef> types, SearchParams parms)
{
if (parms.HasGenericParameters is null) return types;
Logger.Log("Matching generic parameters", ConsoleColor.Yellow);
types = types.Where(t => t.HasGenericParameters == parms.HasGenericParameters);
return types;
}
}

View File

@ -0,0 +1,96 @@
using dnlib.DotNet;
using ReCodeIt.Models;
using ReCodeIt.Utils;
namespace ReCodeItLib.Remapper.Search;
internal static class MethodTypeFilters
{
/// <summary>
/// Filters based on method includes
/// </summary>
/// <param name="types"></param>
/// <param name="parms"></param>
/// <returns>Filtered list</returns>
public static IEnumerable<TypeDef> FilterByInclude(IEnumerable<TypeDef> types, SearchParams parms)
{
if (parms.IncludeMethods.Count == 0) return types;
List<TypeDef> filteredTypes = [];
foreach (var type in types)
{
if (parms.IncludeMethods
.All(includeName => type.Methods
.Any(method => method.Name.String == includeName)))
{
filteredTypes.Add(type);
}
}
return filteredTypes.Any() ? filteredTypes : types;
}
/// <summary>
/// Filters based on method excludes
/// </summary>
/// <param name="types"></param>
/// <param name="parms"></param>
/// <returns>Filtered list</returns>
public static IEnumerable<TypeDef> FilterByExclude(IEnumerable<TypeDef> types, SearchParams parms)
{
if (parms.ExcludeMethods.Count == 0) return types;
List<TypeDef> filteredTypes = [];
foreach (var type in types)
{
var match = type.Methods
.Where(method => parms.ExcludeMethods.Contains(method.Name.String));
if (!match.Any())
{
filteredTypes.Add(type);
}
}
return filteredTypes.Any() ? filteredTypes : types;
}
/// <summary>
/// Filters based on method count
/// </summary>
/// <param name="types"></param>
/// <param name="parms"></param>
/// <returns>Filtered list</returns>
public static IEnumerable<TypeDef> FilterByCount(IEnumerable<TypeDef> types, SearchParams parms)
{
if (parms.MethodCount is null) return types;
if (parms.MethodCount >= 0)
{
Logger.Log("Matching method count", ConsoleColor.Yellow);
types = types.Where(t => GetMethodCountExcludingConstructors(t) == parms.MethodCount);
}
return types;
}
/// <summary>
/// We don't want the constructors included in the count
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
private static int GetMethodCountExcludingConstructors(TypeDef type)
{
int count = 0;
foreach (var method in type.Methods)
{
if (!method.IsConstructor && !method.IsSpecialName)
{
count++;
}
}
return count;
}
}

View File

@ -1,80 +0,0 @@
using Mono.Cecil;
using Mono.Cecil.Rocks;
using ReCodeIt.Enums;
using ReCodeIt.Models;
namespace ReCodeIt.ReMapper.Search;
internal static class Methods
{
/// <summary>
/// returns a match on all types with the specified methods
/// </summary>
/// <param name="type"></param>
/// <param name="parms"></param>
/// <param name="score"></param>
/// <returns>Match if type contains any supplied methods</returns>
public static EMatchResult Include(TypeDefinition type, SearchParams parms, ScoringModel score)
{
if (parms.IncludeMethods is null || parms.IncludeMethods.Count == 0) return EMatchResult.Disabled;
var matches = type.Methods
.Where(method => parms.IncludeMethods.Any(include => method.Name.Contains(include)))
.Count();
score.Score += matches > 0 ? matches : -matches;
score.FailureReason = matches > 0 ? EFailureReason.None : EFailureReason.MethodsInclude;
return matches > 0
? EMatchResult.Match
: EMatchResult.NoMatch;
}
/// <summary>
/// Returns a match on all types without methods
/// </summary>
/// <param name="type"></param>
/// <param name="parms"></param>
/// <param name="score"></param>
/// <returns>Match if type has no methods</returns>
public static EMatchResult Exclude(TypeDefinition type, SearchParams parms, ScoringModel score)
{
if (parms.ExcludeMethods is null || parms.ExcludeMethods.Count == 0) return EMatchResult.Disabled;
var matches = type.Methods
.Where(method => parms.ExcludeMethods.Contains(method.Name))
.Count();
score.Score += matches > 0 ? -matches : 1;
score.FailureReason = matches > 0 ? EFailureReason.MethodsExclude : EFailureReason.None;
return matches > 0
? EMatchResult.NoMatch
: EMatchResult.Match;
}
/// <summary>
/// Returns a match if the type has the provided number of methods
/// </summary>
/// <param name="type"></param>
/// <param name="parms"></param>
/// <param name="score"></param>
/// <returns></returns>
public static EMatchResult Count(TypeDefinition type, SearchParams parms, ScoringModel score)
{
if (parms.MethodCount is null) return EMatchResult.Disabled;
var numMethods = type.Methods.Count - type.GetConstructors().Count();
bool match = numMethods == parms.MethodCount;
score.Score += match ? (int)parms.MethodCount : -(int)parms.MethodCount;
score.FailureReason = match ? EFailureReason.None : EFailureReason.MethodsCount;
return match
? EMatchResult.Match
: EMatchResult.NoMatch;
}
}

View File

@ -0,0 +1,76 @@
using dnlib.DotNet;
using ReCodeIt.Models;
namespace ReCodeIt.ReMapper.Search;
internal static class NestedTypeFilters
{
/// <summary>
/// Filters based on nested type includes
/// </summary>
/// <param name="types"></param>
/// <param name="parms"></param>
/// <returns>Filtered list</returns>
public static IEnumerable<TypeDef> FilterByInclude(IEnumerable<TypeDef> types, SearchParams parms)
{
if (parms.IncludeNestedTypes.Count == 0) return types;
List<TypeDef> filteredTypes = [];
foreach (var type in types)
{
if (parms.IncludeNestedTypes
.All(includeName => type.NestedTypes
.Any(nestedType => nestedType.Name.String == includeName)))
{
filteredTypes.Add(type);
}
}
return filteredTypes.Any() ? filteredTypes : types;
}
/// <summary>
/// Filters based on nested type excludes
/// </summary>
/// <param name="types"></param>
/// <param name="parms"></param>
/// <returns>Filtered list</returns>
public static IEnumerable<TypeDef> FilterByExclude(IEnumerable<TypeDef> types, SearchParams parms)
{
if (parms.ExcludeNestedTypes.Count == 0) return types;
List<TypeDef> filteredTypes = [];
foreach (var type in types)
{
var match = type.Fields
.Where(field => parms.ExcludeNestedTypes.Contains(field.Name.String));
if (!match.Any())
{
filteredTypes.Add(type);
}
}
return filteredTypes.Any() ? filteredTypes : types;
}
/// <summary>
/// Filters based on nested type count
/// </summary>
/// <param name="types"></param>
/// <param name="parms"></param>
/// <returns>Filtered list</returns>
public static IEnumerable<TypeDef> FilterByCount(IEnumerable<TypeDef> types, SearchParams parms)
{
if (parms.NestedTypeCount is null) return types;
if (parms.NestedTypeCount >= 0)
{
types = types.Where(t => t.NestedTypes.Count == parms.NestedTypeCount);
}
return types;
}
}

View File

@ -1,58 +0,0 @@
using Mono.Cecil;
using MoreLinq;
using ReCodeIt.Enums;
using ReCodeIt.Models;
namespace ReCodeIt.ReMapper.Search;
internal class NestedTypes
{
public static EMatchResult Include(TypeDefinition type, SearchParams parms, ScoringModel score)
{
if (parms.IncludeNestedTypes is null || parms.IncludeNestedTypes.Count == 0) return EMatchResult.Disabled;
var matches = type.NestedTypes
.Where(nt => parms.IncludeNestedTypes.Contains(nt.Name))
.Count();
score.Score += matches > 0 ? matches : -matches;
score.FailureReason = matches > 0 ? EFailureReason.None : EFailureReason.NestedTypeInclude;
return matches > 0
? EMatchResult.Match
: EMatchResult.NoMatch;
}
public static EMatchResult Exclude(TypeDefinition type, SearchParams parms, ScoringModel score)
{
if (parms.ExcludeNestedTypes is null || parms.ExcludeNestedTypes.Count == 0) return EMatchResult.Disabled;
var matches = type.NestedTypes
.Where(nt => parms.ExcludeNestedTypes.Contains(nt.Name))
.Count();
score.Score += matches > 0 ? -matches : 1;
score.FailureReason = matches > 0 ? EFailureReason.NestedTypeExclude : EFailureReason.None;
return matches > 0
? EMatchResult.NoMatch
: EMatchResult.Match;
}
public static EMatchResult Count(TypeDefinition type, SearchParams parms, ScoringModel score)
{
if (parms.NestedTypeCount is null) return EMatchResult.Disabled;
var match = type.NestedTypes.Exactly((int)parms.NestedTypeCount);
score.Score += match ? type.NestedTypes.Count : -type.NestedTypes.Count - 1;
score.FailureReason = match ? EFailureReason.None : EFailureReason.NestedTypeCount;
return match
? EMatchResult.Match
: EMatchResult.NoMatch;
}
}

View File

@ -1,57 +0,0 @@
using Mono.Cecil;
using MoreLinq;
using ReCodeIt.Enums;
using ReCodeIt.Models;
namespace ReCodeIt.ReMapper.Search
{
internal class Properties
{
public static EMatchResult Include(TypeDefinition type, SearchParams parms, ScoringModel score)
{
if (parms.IncludeProperties is null || parms.IncludeProperties.Count == 0) return EMatchResult.Disabled;
var matches = type.Properties
.Where(property => parms.IncludeProperties.Contains(property.Name))
.Count();
score.Score += matches > 0 ? matches : -matches;
score.FailureReason = matches > 0 ? EFailureReason.None : EFailureReason.PropertiesInclude;
return matches > 0
? EMatchResult.Match
: EMatchResult.NoMatch;
}
public static EMatchResult Exclude(TypeDefinition type, SearchParams parms, ScoringModel score)
{
if (parms.ExcludeProperties is null || parms.ExcludeProperties.Count == 0) return EMatchResult.Disabled;
var matches = type.Properties
.Where(property => parms.ExcludeProperties.Contains(property.Name))
.Count();
score.Score += matches > 0 ? -matches : 1;
score.FailureReason = matches > 0 ? EFailureReason.PropertiesExclude : EFailureReason.None;
return matches > 0
? EMatchResult.NoMatch
: EMatchResult.Match;
}
public static EMatchResult Count(TypeDefinition type, SearchParams parms, ScoringModel score)
{
if (parms.PropertyCount is null) return EMatchResult.Disabled;
var match = type.Properties.Exactly((int)parms.PropertyCount);
score.Score += match ? (int)parms.PropertyCount : -(int)parms.PropertyCount;
return match
? EMatchResult.Match
: EMatchResult.NoMatch;
}
}
}

View File

@ -0,0 +1,78 @@
using dnlib.DotNet;
using ReCodeIt.Models;
using ReCodeIt.Utils;
namespace ReCodeItLib.Remapper.Search;
internal static class PropertyTypeFilters
{
/// <summary>
/// Filters based on property includes
/// </summary>
/// <param name="types"></param>
/// <param name="parms"></param>
/// <returns>Filtered list</returns>
public static IEnumerable<TypeDef> FilterByInclude(IEnumerable<TypeDef> types, SearchParams parms)
{
if (parms.IncludeProperties.Count == 0) return types;
List<TypeDef> filteredTypes = [];
foreach (var type in types)
{
if (parms.IncludeProperties
.All(includeName => type.Properties
.Any(prop => prop.Name.String == includeName)))
{
filteredTypes.Add(type);
}
}
return filteredTypes.Any() ? filteredTypes : types;
}
/// <summary>
/// Filters based on property excludes
/// </summary>
/// <param name="types"></param>
/// <param name="parms"></param>
/// <returns>Filtered list</returns>
public static IEnumerable<TypeDef> FilterByExclude(IEnumerable<TypeDef> types, SearchParams parms)
{
if (parms.ExcludeProperties.Count == 0) return types;
List<TypeDef> filteredTypes = [];
foreach (var type in types)
{
var match = type.Properties
.Where(prop => parms.ExcludeProperties.Contains(prop.Name.String));
if (!match.Any())
{
filteredTypes.Add(type);
}
}
return filteredTypes.Any() ? filteredTypes : types;
}
/// <summary>
/// Filters based on property count
/// </summary>
/// <param name="types"></param>
/// <param name="parms"></param>
/// <returns>Filtered list</returns>
public static IEnumerable<TypeDef> FilterByCount(IEnumerable<TypeDef> types, SearchParams parms)
{
if (parms.PropertyCount is null) return types;
if (parms.PropertyCount >= 0)
{
Logger.Log("Matching property count", ConsoleColor.Yellow);
types = types.Where(t => t.Properties.Count == parms.PropertyCount);
}
return types;
}
}

View File

@ -1,266 +0,0 @@
using Mono.Cecil;
using ReCodeIt.Enums;
using ReCodeIt.Models;
using ReCodeIt.Utils;
namespace ReCodeIt.ReMapper.Search;
internal static class TypeDefExtensions
{
public static EMatchResult MatchIsAbstract(this TypeDefinition type, SearchParams parms, ScoringModel score)
{
if (parms.IsAbstract is null)
{
return EMatchResult.Disabled;
}
// Interfaces cannot be abstract
if (type.IsInterface)
{
score.FailureReason = EFailureReason.IsAbstract;
return EMatchResult.NoMatch;
}
if (type.IsAbstract == parms.IsAbstract)
{
score.Score++;
return EMatchResult.Match;
}
score.FailureReason = EFailureReason.IsAbstract;
return EMatchResult.NoMatch;
}
public static EMatchResult MatchIsEnum(this TypeDefinition type, SearchParams parms, ScoringModel score)
{
if (parms.IsEnum is null)
{
return EMatchResult.Disabled;
}
if (type.IsEnum == parms.IsEnum)
{
score.Score++;
return EMatchResult.Match;
}
score.FailureReason = EFailureReason.IsEnum;
return EMatchResult.NoMatch;
}
public static EMatchResult MatchIsNested(this TypeDefinition type, SearchParams parms, ScoringModel score)
{
if (parms.IsNested is null)
{
return EMatchResult.Disabled;
}
if (parms.ParentName is not null)
{
if (type.Name == parms.ParentName)
{
score.Score++;
return EMatchResult.Match;
}
}
if (type.IsNested == parms.IsNested)
{
score.Score++;
return EMatchResult.Match;
}
score.FailureReason = EFailureReason.IsNested;
return EMatchResult.NoMatch;
}
public static EMatchResult MatchIsSealed(this TypeDefinition type, SearchParams parms, ScoringModel score)
{
if (parms.IsSealed is null)
{
return EMatchResult.Disabled;
}
if (type.IsSealed == parms.IsSealed)
{
score.Score++;
return EMatchResult.Match;
}
score.FailureReason = EFailureReason.IsSealed;
return EMatchResult.NoMatch;
}
public static EMatchResult MatchIsDerived(this TypeDefinition type, SearchParams parms, ScoringModel score)
{
if (parms.IsDerived is null)
{
return EMatchResult.Disabled;
}
if (type.BaseType is not null && (bool)parms.IsDerived is true)
{
if (type.BaseType.Name.Contains("Object")) { return EMatchResult.NoMatch; }
score.Score++;
return EMatchResult.Match;
}
if (type.BaseType?.Name == parms.MatchBaseClass)
{
return EMatchResult.Match;
}
if (type.BaseType?.Name == parms.IgnoreBaseClass)
{
score.FailureReason = EFailureReason.IsDerived;
return EMatchResult.NoMatch;
}
score.FailureReason = EFailureReason.IsDerived;
return EMatchResult.NoMatch;
}
public static EMatchResult MatchIsInterface(this TypeDefinition type, SearchParams parms, ScoringModel score)
{
if (parms.IsInterface is null)
{
return EMatchResult.Disabled;
}
if (type.IsInterface == parms.IsInterface)
{
score.Score++;
return EMatchResult.Match;
}
score.FailureReason = EFailureReason.IsInterface;
return EMatchResult.NoMatch;
}
public static EMatchResult MatchHasGenericParameters(this TypeDefinition type, SearchParams parms, ScoringModel score)
{
if (parms.HasGenericParameters is null)
{
return EMatchResult.Disabled;
}
if (type.HasGenericParameters == parms.HasGenericParameters)
{
score.Score++;
return EMatchResult.Match;
}
score.FailureReason = EFailureReason.HasGenericParameters;
return EMatchResult.NoMatch;
}
public static EMatchResult MatchIsPublic(this TypeDefinition type, SearchParams parms, ScoringModel score)
{
if (parms.IsPublic == null)
{
return EMatchResult.Disabled;
}
if ((bool)!parms.IsPublic && type.IsNotPublic)
{
score.Score++;
return EMatchResult.Match;
}
if ((bool)parms.IsPublic && type.IsPublic)
{
score.Score++;
return EMatchResult.Match;
}
score.FailureReason = EFailureReason.IsPublic;
return EMatchResult.NoMatch;
}
public static EMatchResult MatchHasAttribute(this TypeDefinition type, SearchParams parms, ScoringModel score)
{
if (parms.HasAttribute is null)
{
return EMatchResult.Disabled;
}
if (type.HasCustomAttributes == parms.HasAttribute)
{
score.Score++;
return EMatchResult.Match;
}
score.FailureReason = EFailureReason.HasAttribute;
return EMatchResult.NoMatch;
}
public static EMatchResult MatchConstructors(this TypeDefinition type, SearchParams parms, ScoringModel score)
{
var matches = new List<EMatchResult> { };
if (parms.ConstructorParameterCount is not null)
{
matches.Add(Constructors.GetTypeByParameterCount(type, parms, score));
}
return matches.GetMatch();
}
/// <summary>
/// Handle running all method matching routines
/// </summary>
/// <returns>Match if any search criteria met</returns>
public static EMatchResult MatchMethods(this TypeDefinition type, SearchParams parms, ScoringModel score)
{
var matches = new List<EMatchResult>
{
Methods.Include(type, parms, score),
Methods.Exclude(type, parms, score),
Methods.Count(type, parms, score)
};
// return match if any condition matched
return matches.GetMatch();
}
public static EMatchResult MatchFields(this TypeDefinition type, SearchParams parms, ScoringModel score)
{
var matches = new List<EMatchResult>
{
Fields.Include(type, parms, score),
Fields.Exclude(type, parms, score),
Fields.Count(type, parms, score)
};
// return match if any condition matched
return matches.GetMatch();
}
public static EMatchResult MatchProperties(this TypeDefinition type, SearchParams parms, ScoringModel score)
{
var matches = new List<EMatchResult>
{
Properties.Include(type, parms, score),
Properties.Exclude(type, parms, score),
Properties.Count(type, parms, score)
};
// return match if any condition matched
return matches.GetMatch();
}
public static EMatchResult MatchNestedTypes(this TypeDefinition type, SearchParams parms, ScoringModel score)
{
var matches = new List<EMatchResult>
{
NestedTypes.Include(type, parms, score),
NestedTypes.Exclude(type, parms, score),
NestedTypes.Count(type, parms, score)
};
// return match if any condition matched
return matches.GetMatch();
}
}

View File

@ -1,4 +1,4 @@
using Mono.Cecil;
using dnlib.DotNet;
using Newtonsoft.Json;
using ReCodeIt.Models;
using ReCodeItLib.Utils;
@ -26,14 +26,8 @@ public static class DataProvider
public static List<RemapModel> Remaps { get; set; } = [];
public static Dictionary<string, HashSet<ScoringModel>> ScoringModels { get; set; } = [];
public static Settings Settings { get; private set; }
public static AssemblyDefinition AssemblyDefinition { get; private set; }
public static ModuleDefinition ModuleDefinition { get; private set; }
public static void LoadAppSettings()
{
if (IsCli)
@ -97,26 +91,11 @@ public static class DataProvider
var jsonText = File.ReadAllText(path);
ScoringModels = [];
var remaps = JsonConvert.DeserializeObject<List<RemapModel>>(jsonText);
if (remaps == null) { return []; }
var properties = typeof(SearchParams).GetProperties();
foreach (var remap in Remaps)
{
foreach (var property in properties)
{
if (property.PropertyType == typeof(List<string>) && property.GetValue(remap.SearchParams) is null)
{
property.SetValue(remap.SearchParams, new List<string>());
}
}
}
Logger.Log($"Mapping file loaded from '{path}' containing {Remaps.Count} remaps");
Logger.Log($"Mapping file loaded from '{path}' containing {remaps.Count} remaps");
return remaps;
}
@ -137,7 +116,7 @@ public static class DataProvider
Logger.Log($"Mapping File Saved To {path}");
}
public static void UpdateMapping(string path)
public static void UpdateMapping(string path, List<RemapModel> remaps)
{
if (!File.Exists(path))
{
@ -150,62 +129,26 @@ public static class DataProvider
Formatting = Formatting.Indented
};
var properties = typeof(SearchParams).GetProperties();
foreach (var remap in Remaps)
{
foreach (var property in properties)
{
if (property.PropertyType == typeof(List<string>))
{
var val = property.GetValue(remap.SearchParams);
if (val is List<string> list && list.Count > 0) { continue; }
property.SetValue(remap.SearchParams, null);
}
}
}
var jsonText = JsonConvert.SerializeObject(Remaps, settings);
File.WriteAllText(path, jsonText);
Logger.Log($"Mapping file saved to {path}");
Logger.Log($"Mapping file updated with new type names and saved to {path}", ConsoleColor.Yellow);
}
public static void LoadAssemblyDefinition(string path)
public static ModuleDefMD LoadModule(string path)
{
AssemblyDefinition = null;
ModuleDefinition = null;
var mcOptions = new ModuleCreationOptions(ModuleDef.CreateModuleContext());
ModuleDefMD module = ModuleDefMD.Load(path, mcOptions);
DefaultAssemblyResolver resolver = new();
module.Context = mcOptions.Context;
Console.WriteLine(path);
resolver.AddSearchDirectory(Path.GetDirectoryName(path)); // Replace with the correct path : (6/14) I have no idea what I met by that
ReaderParameters parameters = new() { AssemblyResolver = resolver };
var assemblyDefinition = AssemblyDefinition.ReadAssembly(
path,
parameters);
if (assemblyDefinition is null)
if (module is null)
{
throw new NullReferenceException("AssemblyDefinition was null...");
throw new NullReferenceException("Module is null...");
}
var fileName = Path.GetFileName(path);
AssemblyDefinition = assemblyDefinition;
ModuleDefinition = assemblyDefinition.MainModule;
}
public static string WriteAssemblyDefinition(string path)
{
AssemblyDefinition.Write(path);
return path;
return module;
}
private static Settings CreateFakeSettings()

View File

@ -1,5 +1,4 @@
using ReCodeIt.Enums;
using MoreLinq.Extensions;
namespace ReCodeIt.Utils;

View File

@ -1,62 +0,0 @@
using ReCodeIt.Models;
namespace ReCodeIt.Utils;
internal static class ExtentionMethods
{
public static void AddScoreToResult(this ScoringModel model)
{
try
{
if (DataProvider.ScoringModels.TryGetValue(model.ProposedNewName, out HashSet<ScoringModel> modelHashset))
{
foreach (var outVal in modelHashset)
{
if (outVal.Definition.Name == model.Definition.Name)
{
return;
}
}
modelHashset.Add(model);
return;
}
var newHash = new HashSet<ScoringModel>
{
model
};
DataProvider.ScoringModels.Add(model.ProposedNewName, newHash);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
public static int CalculateMaxScore(this SearchParams parms)
{
var propInfos = typeof(SearchParams).GetProperties();
int maxScore = 0;
foreach (var propInfo in propInfos)
{
object value = propInfo.GetValue(parms);
if (value == null) continue;
if (value is List<string> list)
{
maxScore += list.Count;
}
else
{
maxScore++;
}
}
return maxScore;
}
}

View File

@ -1,9 +1,20 @@
using ReCodeItLib.Utils;
using System.Collections.Concurrent;
using ReCodeItLib.Utils;
namespace ReCodeIt.Utils;
public static class Logger
{
// This queue will hold the messages to then place them on the wait list
private static readonly ConcurrentQueue<LogMessage> _messages = new();
private static bool Running = true;
private static bool IsTerminated;
// This dictionary acts as a waitlist, we are going to wait _defaultWaitTimeMs before logging all the messages
// coming from certain thread into the console, this way we can make sure they are grouped in relevance
private static readonly Dictionary<int, HeldMessages> _heldMessages = new();
// This is the timeout we will wait before logging a whole group of messages coming from a single thread
private static readonly TimeSpan _defaultWaitTimeMs = TimeSpan.FromMilliseconds(500);
static Logger()
{
if (File.Exists(_logPath))
@ -11,9 +22,70 @@ public static class Logger
File.Delete(_logPath);
File.Create(_logPath).Close();
}
Task.Factory.StartNew(LogThread, TaskCreationOptions.LongRunning);
}
private static string _logPath => RegistryHelper.GetRegistryValue<string>("LogPath");
private static void LogThread()
{
while (Running || _heldMessages.Count > 0)
{
Thread.Sleep(TimeSpan.FromMilliseconds(100));
// Check the message queue and add them to the waitlist
CheckAndHoldMessages();
// Check the waitlist messages and see if any are ready to be logged
LogHeldMessages();
}
IsTerminated = true;
}
private static void LogHeldMessages()
{
var currentLogExecution = DateTime.Now;
foreach (var heldMessagesKP in _heldMessages)
{
var heldMessages = heldMessagesKP.Value;
if (currentLogExecution - heldMessages.FirstInsertion > _defaultWaitTimeMs)
{
while (heldMessages.Messages.TryDequeue(out var messageToLog))
LogInternal(messageToLog);
_heldMessages.Remove(heldMessagesKP.Key);
}
}
}
private static void CheckAndHoldMessages()
{
var currentLogExecution = DateTime.Now;
while (_messages.TryDequeue(out var messageToHold))
{
if (!_heldMessages.TryGetValue(messageToHold.ThreadId, out var heldMessages))
{
heldMessages = new HeldMessages
{
FirstInsertion = currentLogExecution,
ThreadID = messageToHold.ThreadId
};
_heldMessages.Add(heldMessages.ThreadID, heldMessages);
}
heldMessages.Messages.Enqueue(messageToHold);
}
}
public static void Terminate()
{
Running = false;
}
public static bool IsRunning()
{
return !IsTerminated;
}
private const string _defaultFileName = "ReCodeIt.log";
private static string _logPath => RegistryHelper.GetRegistryValue<string>("LogPath") ?? $"{AppDomain.CurrentDomain.BaseDirectory}{_defaultFileName}";
public static void ClearLog()
{
@ -26,32 +98,23 @@ public static class Logger
public static void Log(object message, ConsoleColor color = ConsoleColor.Gray, bool silent = false)
{
if (!silent)
{
Console.ForegroundColor = color;
Console.WriteLine(message);
_messages.Enqueue(new LogMessage {Message = message, Color = color, Silent = silent, ThreadId = Thread.CurrentThread.ManagedThreadId});
}
WriteToDisk(message);
}
public static void LogDebug(object message, ConsoleColor color = ConsoleColor.Gray, bool silent = false)
private static void LogInternal(LogMessage message)
{
if (DataProvider.Settings.AppSettings.Debug)
if (!message.Silent)
{
Console.ForegroundColor = color;
Console.WriteLine(message);
Console.ForegroundColor = message.Color;
Console.WriteLine(message.Message);
Console.ResetColor();
WriteToDisk(message);
}
WriteToDisk(message);
WriteToDisk(message.Message);
}
private static void WriteToDisk(object message)
{
if (DataProvider.IsCli) { return; }
try
{
using (StreamWriter sw = File.AppendText(_logPath))
@ -66,4 +129,18 @@ public static class Logger
Console.WriteLine($"Error logging: {ex.Message}");
}
}
private class LogMessage
{
public object Message { get; init; }
public ConsoleColor Color { get; init; }
public bool Silent { get; init; }
public int ThreadId { get; init; }
}
private class HeldMessages
{
public int ThreadID { get; init; }
public DateTime FirstInsertion { get; init; }
public Queue<LogMessage> Messages { get; } = new(10);
}
}

View File

@ -26,7 +26,6 @@ public static class RegistryHelper
public static T? GetRegistryValue<T>(string key)
{
var regKey = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\ReCodeIt");
return (T)regKey.GetValue(key);
return (T)regKey?.GetValue(key);
}
}

View File

@ -1,9 +1,45 @@
using System.Text;
using dnlib.DotNet;
using System.Text;
namespace ReCodeIt.Utils;
public static class SysTypeExtentions
{
/// <summary>
/// Returns a string trimmed after any non letter character
/// </summary>
/// <param name="str"></param>
/// <returns>Trimmed string if special character found, or the original string</returns>
public static string TrimAfterSpecialChar(this UTF8String str)
{
var sb = new StringBuilder();
var trimChars = new char[] { '`', '[', ']' };
foreach (char c in str.ToString())
{
if (trimChars.Contains(c))
{
}
if (char.IsLetter(c) || char.IsDigit(c))
{
sb.Append(c);
}
else
{
return sb.ToString();
}
}
if (sb.Length > 0)
{
return sb.ToString();
}
return str;
}
/// <summary>
/// Returns a string trimmed after any non letter character
/// </summary>
@ -39,6 +75,24 @@ public static class SysTypeExtentions
return str;
}
/// <summary>
/// Does the property or field name exist in a given list, this applies prefixes and handles capitalization.
/// </summary>
/// <param name="str"></param>
/// <param name="list"></param>
/// <returns>True if it in the list</returns>
public static bool IsFieldOrPropNameInList(this UTF8String str, List<string> list)
{
if (str.Trim().StartsWith("_"))
{
str = str.Replace("_", "");
}
var result = list.Any(item => str.StartsWith(item, StringComparison.CurrentCultureIgnoreCase));
return result;
}
/// <summary>
/// Does the property or field name exist in a given list, this applies prefixes and handles capitalization.
/// </summary>
@ -47,7 +101,7 @@ public static class SysTypeExtentions
/// <returns>True if it in the list</returns>
public static bool IsFieldOrPropNameInList(this string str, List<string> list)
{
if (str.Trim().ElementAt(0) == '_')
if (str.Trim().StartsWith("_"))
{
str = str.Replace("_", "");
}

View File

@ -1,33 +1,33 @@
{
"AppSettings": {
"Debug": false, // Enables extra debug logging, slows down the program by alot
"SilentMode": true // The tool will stop and prompt you to continue on every remapping if disable
"Debug": false,
"SilentMode": true
},
"Remapper": {
"AssemblyPath": "", // Path to the assembly we want to remap
"OutputPath": "", // Path including the filename and extension we want to write the changes to
"MappingPath": "", // Path to the mapping file
"UseProjectMappings": true, // Use the active cross compiler projects mappings
"AssemblyPath": "G:\\development\\ReCodeIt\\RecodeItGUI\\bin\\Debug\\net8.0-windows\\Data\\Managed\\Assembly-CSharp-cleaned.dll",
"OutputPath": "G:\\development\\ReCodeIt\\RecodeItGUI\\bin\\Debug\\net8.0-windows\\Data",
"MappingPath": "G:\\development\\ReCodeIt\\RecodeItGUI\\bin\\Debug\\net8.0-windows\\Data\\Mappings.jsonc",
"UseProjectMappings": false,
"MappingSettings": {
"RenameFields": true, // Names of fields of the matched type will be renamed to the type name with approproiate convention
"RenameProperties": true, // Names of properties of the matched type will be renamed to the type name with approproiate convention
"Publicize": true, // Publicize all types, methods, and properties : NOTE: Not run until after the remap has completed
"Unseal": true // Unseal all types : NOTE: Not run until after the remap has completed
"RenameFields": true,
"RenameProperties": true,
"Publicize": true,
"Unseal": true
}
},
"AutoMapper": {
"AssemblyPath": "", // Path to the assembly we want to remap
"OutputPath": "", // Path including the filename and extension we want to write the changes to
"RequiredMatches": 5, // Minimum number of times a member must have this name in the assembly before considering it for remapping
"MinLengthToMatch": 7, // Minimum length of the field/property name in code before it will be considered for a rename
"SearchMethods": true, // Will attempt to map types from method meta data and parameters
"AssemblyPath": "",
"OutputPath": "",
"RequiredMatches": 5,
"MinLengthToMatch": 7,
"SearchMethods": true,
"MappingSettings": {
"RenameFields": true, // Names of fields of the matched type will be renamed to the type name with approproiate convention
"RenameProperties": true, // Names of properties of the matched type will be renamed to the type name with approproiate convention
"Publicize": true, // Publicize all types, methods, and properties : NOTE: Not run until after the remap has completed
"Unseal": true // Unseal all types : NOTE: Not run until after the remap has completed
"RenameFields": true,
"RenameProperties": true,
"Publicize": true,
"Unseal": true
},
"TypesToIgnore": [ // Any member name you want to ignore while iterating through the assembly
"TypesToIgnore": [
"Boolean",
"List",
"Dictionary",
@ -46,14 +46,14 @@
"Double",
"IEnumerator"
],
"TokensToMatch": [ // The auto mapper will look for these tokens in class names and prioritize those
"TokensToMatch": [
"Class",
"GClass",
"GStruct",
"Interface",
"GInterface"
],
"PropertyFieldBlackList": [ // Property or fields names to ignore in the automap, these are case sanitized so case does not matter
"PropertyFieldBlackList": [
"Columns",
"mColumns",
"Template",
@ -64,11 +64,10 @@
"Command",
"_template"
],
"MethodParamaterBlackList": [ // method parameter names to ignore in the automap, these are case sanitized so case does not matter
]
"MethodParamaterBlackList": []
},
"CrossCompiler": {
"AutoLoadLastActiveProject": true, // Autoload last active project
"LastLoadedProject": "" // Last loaded project path
"LastLoadedProject": "",
"AutoLoadLastActiveProject": true
}
}