2024-06-12 00:07:44 -04:00
|
|
|
|
using AssemblyRemapper.Enums;
|
|
|
|
|
using AssemblyRemapper.Models;
|
2024-06-13 04:56:08 -04:00
|
|
|
|
using AssemblyRemapper.Remapper.Search;
|
2024-06-11 19:18:48 -04:00
|
|
|
|
using AssemblyRemapper.Utils;
|
|
|
|
|
using Mono.Cecil;
|
2024-06-13 17:05:34 -04:00
|
|
|
|
using System.Diagnostics;
|
2024-06-11 19:18:48 -04:00
|
|
|
|
|
2024-06-13 04:56:08 -04:00
|
|
|
|
namespace AssemblyRemapper.Remapper;
|
2024-06-11 19:18:48 -04:00
|
|
|
|
|
2024-06-13 18:15:52 -04:00
|
|
|
|
public class Remapper
|
2024-06-11 19:18:48 -04:00
|
|
|
|
{
|
2024-06-13 17:05:34 -04:00
|
|
|
|
private static Stopwatch Stopwatch = new();
|
|
|
|
|
|
2024-06-13 01:53:43 -04:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Start the remapping process
|
|
|
|
|
/// </summary>
|
2024-06-11 19:18:48 -04:00
|
|
|
|
public void InitializeRemap()
|
|
|
|
|
{
|
|
|
|
|
DisplayBasicModuleInformation();
|
|
|
|
|
|
2024-06-13 17:05:34 -04:00
|
|
|
|
Stopwatch.Start();
|
|
|
|
|
|
2024-06-12 00:05:59 -04:00
|
|
|
|
foreach (var remap in DataProvider.Remaps)
|
2024-06-11 19:18:48 -04:00
|
|
|
|
{
|
2024-06-12 18:59:08 -04:00
|
|
|
|
Logger.Log($"Finding best match for {remap.NewTypeName}...", ConsoleColor.Gray);
|
2024-06-11 19:18:48 -04:00
|
|
|
|
|
|
|
|
|
HandleMapping(remap);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ChooseBestMatches();
|
|
|
|
|
|
2024-06-13 17:55:06 -04:00
|
|
|
|
if (DataProvider.Settings.AppSettings.MatchMode) { return; }
|
2024-06-11 19:18:48 -04:00
|
|
|
|
|
|
|
|
|
// Dont publicize and unseal until after the remapping so we can use those as search parameters
|
2024-06-13 17:55:06 -04:00
|
|
|
|
if (!DataProvider.Settings.RemapperSettings.Publicize)
|
|
|
|
|
{
|
|
|
|
|
Publicizer.Publicize();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!DataProvider.Settings.RemapperSettings.Unseal)
|
|
|
|
|
{
|
|
|
|
|
Publicizer.Unseal();
|
|
|
|
|
}
|
2024-06-11 19:18:48 -04:00
|
|
|
|
|
|
|
|
|
// We are done, write the assembly
|
|
|
|
|
WriteAssembly();
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-13 01:53:43 -04:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Display information about the module we are remapping
|
|
|
|
|
/// </summary>
|
2024-06-12 14:38:43 -04:00
|
|
|
|
private void DisplayBasicModuleInformation()
|
|
|
|
|
{
|
|
|
|
|
Logger.Log("-----------------------------------------------", ConsoleColor.Yellow);
|
|
|
|
|
Logger.Log($"Starting remap...", ConsoleColor.Yellow);
|
|
|
|
|
Logger.Log($"Module contains {DataProvider.ModuleDefinition.Types.Count} Types", ConsoleColor.Yellow);
|
2024-06-13 17:55:06 -04:00
|
|
|
|
Logger.Log($"Publicize: {DataProvider.Settings.RemapperSettings.Publicize}", ConsoleColor.Yellow);
|
|
|
|
|
Logger.Log($"Unseal: {DataProvider.Settings.RemapperSettings.Unseal}", ConsoleColor.Yellow);
|
2024-06-12 14:38:43 -04:00
|
|
|
|
Logger.Log("-----------------------------------------------", ConsoleColor.Yellow);
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-13 01:53:43 -04:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Loop over all types in the assembly and score them
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="mapping">Mapping to score</param>
|
2024-06-12 00:05:59 -04:00
|
|
|
|
private void HandleMapping(RemapModel mapping)
|
2024-06-11 19:18:48 -04:00
|
|
|
|
{
|
|
|
|
|
foreach (var type in DataProvider.ModuleDefinition.Types)
|
|
|
|
|
{
|
2024-06-13 17:31:38 -04:00
|
|
|
|
var _ = FindMatch(type, mapping);
|
2024-06-11 19:18:48 -04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-13 01:53:43 -04:00
|
|
|
|
/// <summary>
|
2024-06-13 17:31:38 -04:00
|
|
|
|
/// Find a match result
|
2024-06-13 01:53:43 -04:00
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="type">Type to score</param>
|
|
|
|
|
/// <param name="remap">Remap to check against</param>
|
|
|
|
|
/// <param name="parentTypeName"></param>
|
2024-06-13 17:31:38 -04:00
|
|
|
|
/// <returns>EMatchResult</returns>
|
|
|
|
|
private EMatchResult FindMatch(TypeDefinition type, RemapModel remap)
|
2024-06-11 19:18:48 -04:00
|
|
|
|
{
|
2024-06-11 23:07:59 -04:00
|
|
|
|
// Handle Direct Remaps by strict naming first bypasses everything else
|
|
|
|
|
if (remap.UseForceRename)
|
|
|
|
|
{
|
|
|
|
|
HandleByDirectName(type, remap);
|
2024-06-13 17:05:34 -04:00
|
|
|
|
return EMatchResult.HandleDirect;
|
2024-06-11 23:07:59 -04:00
|
|
|
|
}
|
|
|
|
|
|
2024-06-11 19:18:48 -04:00
|
|
|
|
foreach (var nestedType in type.NestedTypes)
|
|
|
|
|
{
|
2024-06-13 17:37:14 -04:00
|
|
|
|
FindMatch(nestedType, remap);
|
2024-06-11 19:18:48 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var score = new ScoringModel
|
|
|
|
|
{
|
|
|
|
|
ProposedNewName = remap.NewTypeName,
|
2024-06-13 01:46:51 -04:00
|
|
|
|
ReMap = remap,
|
2024-06-12 00:05:59 -04:00
|
|
|
|
Definition = type,
|
2024-06-11 19:18:48 -04:00
|
|
|
|
};
|
|
|
|
|
|
2024-06-13 17:05:34 -04:00
|
|
|
|
var matches = new HashSet<EMatchResult>
|
|
|
|
|
{
|
|
|
|
|
type.MatchIsAbstract(remap.SearchParams, score),
|
|
|
|
|
type.MatchIsEnum(remap.SearchParams, score) ,
|
|
|
|
|
type.MatchIsNested(remap.SearchParams, score),
|
|
|
|
|
type.MatchIsSealed(remap.SearchParams, score) ,
|
|
|
|
|
type.MatchIsDerived(remap.SearchParams, score) ,
|
|
|
|
|
type.MatchIsInterface(remap.SearchParams, score),
|
|
|
|
|
type.MatchHasGenericParameters(remap.SearchParams, score),
|
|
|
|
|
type.MatchIsPublic(remap.SearchParams, score) ,
|
|
|
|
|
type.MatchHasAttribute(remap.SearchParams, score),
|
|
|
|
|
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)
|
|
|
|
|
};
|
2024-06-13 04:56:08 -04:00
|
|
|
|
|
2024-06-13 17:05:34 -04:00
|
|
|
|
var NoMatch = matches.Where(x => x.Equals(EMatchResult.NoMatch)).FirstOrDefault();
|
2024-06-11 19:18:48 -04:00
|
|
|
|
|
2024-06-13 17:05:34 -04:00
|
|
|
|
if (NoMatch == EMatchResult.NoMatch)
|
2024-06-11 19:18:48 -04:00
|
|
|
|
{
|
2024-06-13 17:05:34 -04:00
|
|
|
|
return NoMatch;
|
2024-06-11 19:18:48 -04:00
|
|
|
|
}
|
|
|
|
|
|
2024-06-13 17:05:34 -04:00
|
|
|
|
var match = matches.Where(x => x.Equals(EMatchResult.Match)).Any();
|
2024-06-11 19:18:48 -04:00
|
|
|
|
|
2024-06-13 17:05:34 -04:00
|
|
|
|
if (match)
|
2024-06-11 19:18:48 -04:00
|
|
|
|
{
|
2024-06-13 17:05:34 -04:00
|
|
|
|
// Set the original type name to be used later
|
|
|
|
|
score.ReMap.OriginalTypeName = type.Name;
|
|
|
|
|
remap.OriginalTypeName = type.Name;
|
|
|
|
|
remap.Succeeded = true;
|
|
|
|
|
remap.FailureReason = EFailureReason.None;
|
|
|
|
|
score.AddScoreToResult();
|
|
|
|
|
return EMatchResult.Match;
|
2024-06-11 19:18:48 -04:00
|
|
|
|
}
|
2024-06-11 23:07:59 -04:00
|
|
|
|
|
2024-06-13 17:05:34 -04:00
|
|
|
|
return EMatchResult.Disabled;
|
2024-06-11 19:18:48 -04:00
|
|
|
|
}
|
|
|
|
|
|
2024-06-12 00:05:59 -04:00
|
|
|
|
private void HandleByDirectName(TypeDefinition type, RemapModel remap)
|
2024-06-11 23:07:59 -04:00
|
|
|
|
{
|
2024-06-12 00:05:59 -04:00
|
|
|
|
if (type.Name != remap.OriginalTypeName) { return; }
|
2024-06-11 23:07:59 -04:00
|
|
|
|
|
|
|
|
|
var oldName = type.Name;
|
2024-06-12 20:16:12 -04:00
|
|
|
|
remap.OriginalTypeName = type.Name;
|
2024-06-13 01:46:51 -04:00
|
|
|
|
remap.FailureReason = EFailureReason.None;
|
|
|
|
|
remap.Succeeded = true;
|
2024-06-12 22:31:41 -04:00
|
|
|
|
type.Name = remap.NewTypeName;
|
2024-06-12 20:16:12 -04:00
|
|
|
|
|
2024-06-12 14:38:43 -04:00
|
|
|
|
Logger.Log("-----------------------------------------------", ConsoleColor.Green);
|
2024-06-11 23:07:59 -04:00
|
|
|
|
Logger.Log($"Renamed {oldName} to {type.Name} directly", ConsoleColor.Green);
|
2024-06-12 14:38:43 -04:00
|
|
|
|
|
2024-06-12 20:17:23 -04:00
|
|
|
|
Renamer.RenameAllDirect(remap, type);
|
2024-06-12 14:38:43 -04:00
|
|
|
|
|
|
|
|
|
Logger.Log("-----------------------------------------------", ConsoleColor.Green);
|
2024-06-11 23:07:59 -04:00
|
|
|
|
}
|
|
|
|
|
|
2024-06-13 01:53:43 -04:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Choose the best possible match from all remaps
|
|
|
|
|
/// </summary>
|
2024-06-11 19:18:48 -04:00
|
|
|
|
private void ChooseBestMatches()
|
|
|
|
|
{
|
2024-06-11 23:07:59 -04:00
|
|
|
|
foreach (var score in DataProvider.ScoringModels)
|
2024-06-11 19:18:48 -04:00
|
|
|
|
{
|
2024-06-13 01:53:43 -04:00
|
|
|
|
ChooseBestMatch(score.Value);
|
2024-06-11 19:18:48 -04:00
|
|
|
|
}
|
2024-06-13 01:46:51 -04:00
|
|
|
|
|
|
|
|
|
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++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
changes++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Logger.Log("-----------------------------------------------", ConsoleColor.Yellow);
|
|
|
|
|
Logger.Log($"Result: Remapped {changes} Types. Failed to remap {failures} Types", ConsoleColor.Yellow);
|
|
|
|
|
Logger.Log("-----------------------------------------------", ConsoleColor.Yellow);
|
2024-06-11 19:18:48 -04:00
|
|
|
|
}
|
|
|
|
|
|
2024-06-13 01:53:43 -04:00
|
|
|
|
/// <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)
|
2024-06-11 19:18:48 -04:00
|
|
|
|
{
|
2024-06-13 01:46:51 -04:00
|
|
|
|
if (scores.Count == 0) { return; }
|
2024-06-11 19:18:48 -04:00
|
|
|
|
|
2024-06-13 08:18:16 -04:00
|
|
|
|
var filteredScores = scores
|
|
|
|
|
.OrderByDescending(score => score.Score)
|
2024-06-13 17:55:06 -04:00
|
|
|
|
.Take(DataProvider.Settings.RemapperSettings.MaxMatchCount);
|
2024-06-13 08:18:16 -04:00
|
|
|
|
|
|
|
|
|
var highestScore = filteredScores.FirstOrDefault();
|
2024-06-11 19:18:48 -04:00
|
|
|
|
|
2024-06-11 23:07:59 -04:00
|
|
|
|
if (highestScore is null) { return; }
|
2024-06-11 19:18:48 -04:00
|
|
|
|
|
2024-06-11 23:07:59 -04:00
|
|
|
|
Logger.Log("-----------------------------------------------", ConsoleColor.Green);
|
2024-06-12 00:05:59 -04:00
|
|
|
|
Logger.Log($"Renaming {highestScore.Definition.Name} to {highestScore.ProposedNewName}", ConsoleColor.Green);
|
2024-06-13 01:46:51 -04:00
|
|
|
|
Logger.Log($"Max possible score: {highestScore.ReMap.SearchParams.CalculateMaxScore()}", ConsoleColor.Green);
|
2024-06-12 15:47:11 -04:00
|
|
|
|
Logger.Log($"Scored: {highestScore.Score} points", ConsoleColor.Green);
|
|
|
|
|
|
|
|
|
|
if (scores.Count > 1)
|
|
|
|
|
{
|
2024-06-13 08:18:16 -04:00
|
|
|
|
Logger.Log($"Warning! There were {filteredScores.Count()} possible matches. Considering adding more search parameters", ConsoleColor.Yellow);
|
2024-06-12 15:47:11 -04:00
|
|
|
|
|
2024-06-13 08:18:16 -04:00
|
|
|
|
foreach (var score in filteredScores.Skip(1))
|
2024-06-12 15:47:11 -04:00
|
|
|
|
{
|
|
|
|
|
Logger.Log($"{score.Definition.Name} - Score [{score.Score}]", ConsoleColor.Yellow);
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-06-12 00:05:59 -04:00
|
|
|
|
|
2024-06-13 17:55:06 -04:00
|
|
|
|
if (DataProvider.Settings.AppSettings.MatchMode) { return; }
|
|
|
|
|
|
2024-06-13 01:46:51 -04:00
|
|
|
|
highestScore.ReMap.OriginalTypeName = highestScore.Definition.Name;
|
2024-06-12 20:40:10 -04:00
|
|
|
|
|
2024-06-12 14:38:43 -04:00
|
|
|
|
// Rename type and all associated type members
|
2024-06-12 20:17:23 -04:00
|
|
|
|
Renamer.RenameAll(highestScore);
|
2024-06-11 19:18:48 -04:00
|
|
|
|
|
2024-06-11 23:07:59 -04:00
|
|
|
|
Logger.Log("-----------------------------------------------", ConsoleColor.Green);
|
2024-06-11 19:18:48 -04:00
|
|
|
|
}
|
|
|
|
|
|
2024-06-13 01:53:43 -04:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Write the assembly back to disk and update the mapping file on disk
|
|
|
|
|
/// </summary>
|
2024-06-11 19:18:48 -04:00
|
|
|
|
private void WriteAssembly()
|
|
|
|
|
{
|
2024-06-13 17:55:06 -04:00
|
|
|
|
var filename = Path.GetFileNameWithoutExtension(DataProvider.Settings.RemapperSettings.AssemblyPath);
|
2024-06-11 19:18:48 -04:00
|
|
|
|
var strippedPath = Path.GetDirectoryName(filename);
|
|
|
|
|
|
|
|
|
|
filename = $"{filename}-Remapped.dll";
|
|
|
|
|
|
|
|
|
|
var remappedPath = Path.Combine(strippedPath, filename);
|
|
|
|
|
|
|
|
|
|
DataProvider.AssemblyDefinition.Write(remappedPath);
|
2024-06-12 20:40:10 -04:00
|
|
|
|
DataProvider.UpdateMapping();
|
2024-06-11 19:18:48 -04:00
|
|
|
|
|
2024-06-11 23:07:59 -04:00
|
|
|
|
Logger.Log("-----------------------------------------------", ConsoleColor.Green);
|
|
|
|
|
Logger.Log($"Complete: Assembly written to `{remappedPath}`", ConsoleColor.Green);
|
2024-06-12 20:40:10 -04:00
|
|
|
|
Logger.Log("Original type names updated on mapping file.", ConsoleColor.Green);
|
2024-06-13 17:05:34 -04:00
|
|
|
|
Logger.Log($"Remap took {Stopwatch.Elapsed.TotalSeconds:F0} seconds", ConsoleColor.Green);
|
2024-06-11 23:07:59 -04:00
|
|
|
|
Logger.Log("-----------------------------------------------", ConsoleColor.Green);
|
2024-06-13 17:05:34 -04:00
|
|
|
|
|
|
|
|
|
Stopwatch.Stop();
|
2024-06-11 19:18:48 -04:00
|
|
|
|
}
|
|
|
|
|
}
|