internal LdstrFile MergeInternal(LdstrFile main, LdstrFile addition) { var result = new LdstrFile { LdstrEntries = new Dictionary <string, LdstrEntry>() }; foreach (var e in main.LdstrEntries) { result.LdstrEntries.Add(e.Key, e.Value.Clone() as LdstrEntry); } foreach (var pair in addition.LdstrEntries) { if (result.LdstrEntries.ContainsKey(pair.Key)) { result.LdstrEntries[pair.Key] = Merge(main.LdstrEntries[pair.Key], pair.Value); } else { result.LdstrEntries.Add(pair.Key, pair.Value); } } return(result); }
protected override void ImportInternal(LdstrFile file, IMod mod, CultureInfo culture) { entries = new Dictionary <MethodBase, LdstrEntry>(); var module = mod.Code.ManifestModule; var entryDict = file.LdstrEntries; foreach (var entryPair in entryDict) { Utils.SafeWrap(() => { if (!HaveTranslation(entryPair.Value)) { return; } Utils.LogDebug($"Finding method: [{entryPair.Key}]"); var method = module.FindMethod(entryPair.Key); if (method == null) { Utils.LogDebug($"Cannot find."); return; } entries.Add(method, entryPair.Value); var transpiler = typeof(HarmonyLdstrImporter).GetMethod("Transpile", BindingFlags.NonPublic | BindingFlags.Static); harmony.Patch(method, null, null, new HarmonyMethod(transpiler)); Utils.LogDebug($"Patched: {entryPair.Key}"); }); } }
protected override void ImportInternal(LdstrFile file, IMod mod, CultureInfo culture) { entries = new Dictionary <MethodBase, LdstrEntry>(); var module = mod.Code.ManifestModule; var entryDict = file.LdstrEntries; foreach (var entryPair in entryDict) { Utils.SafeWrap(() => { if (!HaveTranslation(entryPair.Value)) { return; } Utils.LogDebug($"Finding method: [{entryPair.Key}]"); var method = Utils.FindMethodByID(module, entryPair.Key); if (method == null) { Utils.LogDebug($"Cannot find."); return; } entries.Add(method, entryPair.Value); harmony.Patch(method, transpiler: new HarmonyMethod(NoroHelper.MethodInfo(() => Transpile(null, null)))); Utils.LogDebug($"Patched: {entryPair.Key}"); }); } }
public IFile Merge(IFile main, IFile addition) { if (main == null || main.GetType() != addition.GetType() || main.GetType() != typeof(LdstrFile)) { return(null); } var mainFile = main as LdstrFile; var additionFile = addition as LdstrFile; var result = new LdstrFile(); result.LdstrEntries = new Dictionary <string, LdstrEntry>(); foreach (var pair in additionFile.LdstrEntries) { if (mainFile.LdstrEntries.ContainsKey(pair.Key)) { result.LdstrEntries.Add(pair.Key, Merge(mainFile.LdstrEntries[pair.Key], pair.Value)); } else { result.LdstrEntries.Add(pair.Key, pair.Value); } } return(result); }
public void Export(IPackage package, IExportConfig config) { if (package?.Mod == null) { return; } var modFile = package.Mod.File; var asmManager = "Terraria.ModLoader.Core.AssemblyManager".Type(); var assemblyName = (string)asmManager.Invoke("GetModAssemblyFileName", modFile, true); var loadedMod = asmManager.ValueOf("loadedMods").Invoke("get_Item", package.Mod.Name); var reref = (byte[])asmManager.GetNestedType("LoadedMod", NoroHelper.Any).Method("EncapsulateReferences") .Invoke(loadedMod, new object[] { modFile.GetBytes(assemblyName), null }); var asm = AssemblyDefinition.ReadAssembly(new MemoryStream(reref)); var file = new LdstrFile { LdstrEntries = new Dictionary <string, LdstrEntry>() }; foreach (var type in asm.MainModule.GetTypes()) { if (type.Namespace == null) { continue; } foreach (var method in type.Methods) { if (method.DeclaringType?.Namespace == null || method.IsAbstract) { continue; } try { LogDebug($"Exporting method: [{method.GetID()}]"); var entry = GetEntryFromMethod(method); if (entry != null && !file.LdstrEntries.ContainsKey(method.GetID())) { file.LdstrEntries.Add(method.GetID(), entry); } } catch (Exception e) { Localizer.Log.Error(e.ToString()); } } } package.AddFile(file); }
protected override void ImportInternal(LdstrFile file, IMod mod, CultureInfo culture) { Terraria.ModLoader.ContentInstance.Register(Utils.GetModByName(mod.Name)); var module = mod.Code.ManifestModule; var entryDict = file.LdstrEntries; foreach (var entryPair in entryDict) { var method = Utils.FindMethodByID(module, entryPair.Key); if (method == null) { continue; } var e = entryPair.Value; if (!HaveTranslation(e)) { continue; } var modification = new ILContext.Manipulator(il => { foreach (var instruction in il.Instrs) { var ins = e.Instructions.FirstOrDefault(i => instruction.MatchLdstr(i.Origin)); if (ins == null || string.IsNullOrEmpty(ins.Translation)) { continue; } instruction.Operand = ins.Translation; foreach (var label in il.Labels) { if (label.Target.MatchLdstr(ins.Origin)) { label.Target = instruction; } } } }); if (!modifications.ContainsKey(method)) { HookEndpointManager.Modify(method, modification); modifications.Add(method, modification); } } }
public void Export(IPackage package, IExportConfig config) { if (package?.Mod == null) { return; } var asm = package.Mod.Code; var file = new LdstrFile { LdstrEntries = new Dictionary <string, LdstrEntry>() }; foreach (var type in asm.ManifestModule.GetTypes()) { /* The return value of GetTypes() and other methods will include types they derived from. * So we should check the namespace to ensure it belongs to the assembly, but there still are * some issues. */ if (type.Namespace == null || !type.Namespace.StartsWith(package.Mod.Name)) { continue; } foreach (var method in type.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static)) { if (method.DeclaringType?.Namespace == null || !method.DeclaringType.Namespace.StartsWith( package.Mod.Name) || method.IsAbstract) { continue; } try { var entry = GetEntryFromMethod(method); if (entry != null && !file.LdstrEntries.ContainsKey(method.GetID())) { file.LdstrEntries.Add(method.GetID(), entry); } } catch (Exception e) { Localizer.Log.Error(e.ToString()); } } } package.AddFile(file); }
public void Export(IPackage package, IExportConfig config) { if (package?.Mod == null) { return; } var asm = package.Mod.Code; var file = new LdstrFile { LdstrEntries = new Dictionary <string, LdstrEntry>() }; foreach (var type in asm.ManifestModule.GetTypes()) { if (type.Namespace == null) { continue; } var methodBases = new List <MethodBase>(); methodBases.AddRange(type.GetMethods(All | BindingFlags.DeclaredOnly)); methodBases.AddRange(type.GetConstructors(All | BindingFlags.DeclaredOnly)); foreach (var method in methodBases) { if (method.DeclaringType?.Namespace == null || method.IsAbstract) { continue; } try { Utils.LogDebug($"Exporting method: [{method.GetID()}]"); var entry = GetEntryFromMethod(method); if (entry != null && !file.LdstrEntries.ContainsKey(method.GetID())) { file.LdstrEntries.Add(method.GetID(), entry); } } catch (Exception e) { Localizer.Log.Error(e.ToString()); } } } package.AddFile(file); }
protected override void ImportInternal(LdstrFile file, IMod mod, CultureInfo culture) { Importing = true; try { ImportingFile = file; ImportingMod = mod; if ((mod as LoadedModWrapper).wrapped.TryGetTarget(out var loadedMod)) { loadedMod.Invoke("set_NeedsReload", true); loadedMod.Invoke("LoadAssemblies"); } } finally { Importing = false; } }
public void UpdateInternal(LdstrFile oldFile, LdstrFile newFile, IUpdateLogger logger) { var oldEntries = oldFile.LdstrEntries; var newEntries = newFile.LdstrEntries; foreach (var newEntryKey in newEntries.Keys) { if (oldEntries.Keys.Contains(newEntryKey)) { var o = oldEntries[newEntryKey]; var n = newEntries[newEntryKey]; foreach (var newIns in n.Instructions) { if (o.Instructions.Exists(oi => oi.Origin == newIns.Origin)) { continue; } o.Instructions.Add(newIns); logger.Change($"New instruction of {newEntryKey}: [{newIns}]"); } } else { logger.Add($"[{newEntryKey}]"); var entry = newEntries[newEntryKey]; oldEntries.Add(newEntryKey, entry); } } var removed = oldEntries.Keys.Where(k => !newEntries.ContainsKey(k)); foreach (var r in removed) { logger.Remove($"[{r}]"); } }
protected abstract void ImportInternal(LdstrFile file, IMod mod, CultureInfo culture);
public void MergeFile_Correct() { var service = new HarmonyLdstrFileImport(); var main = new LdstrFile() { LdstrEntries = new Dictionary <string, LdstrEntry>() { { "Key1", new LdstrEntry() { Instructions = new List <BaseEntry>() { new BaseEntry() { Origin = "Origin1", Translation = "Translation1" }, new BaseEntry() { Origin = "Origin2", Translation = "Translation2" }, } } }, { "Key2", new LdstrEntry() { Instructions = new List <BaseEntry>() { new BaseEntry() { Origin = "Origin3", Translation = "Translation3" }, new BaseEntry() { Origin = "Origin4", Translation = "Translation4" }, } } }, } }; var addition = new LdstrFile() { LdstrEntries = new Dictionary <string, LdstrEntry>() { { "Key1", new LdstrEntry() { Instructions = new List <BaseEntry>() { new BaseEntry() { Origin = "Origin1", Translation = "AnotherTranslation1" }, new BaseEntry() { Origin = "AnotherOrigin1", Translation = "Translation1" }, new BaseEntry() { Origin = "Origin5", Translation = "Translation5" }, } } }, { "Key3", new LdstrEntry() { Instructions = new List <BaseEntry>() { new BaseEntry() { Origin = "Origin6", Translation = "Translation6" } } } }, } }; var result = service.Merge(main, addition); result.LdstrEntries.Count.Should().Be(3); result.LdstrEntries["Key1"].Instructions.Should().ContainSingle(i => i.Origin == "Origin1" && i.Translation == "Translation1"); result.LdstrEntries["Key1"].Instructions.Should().ContainSingle(i => i.Origin == "AnotherOrigin1" && i.Translation == "Translation1"); result.LdstrEntries["Key1"].Instructions.Should().ContainSingle(i => i.Origin == "Origin5" && i.Translation == "Translation5"); result.LdstrEntries["Key3"].Instructions.Count.Should().Be(1); result.LdstrEntries["Key3"].Instructions[0].Origin.Should().Be("Origin6"); result.LdstrEntries["Key3"].Instructions[0].Translation.Should().Be("Translation6"); }
public void Update_Correct() { var service = new LdstrFileUpdater(); var logger = new UpdateLogger(); var oldFile = new LdstrFile() { LdstrEntries = new Dictionary <string, LdstrEntry>() { { "Key1", new LdstrEntry() { Instructions = new List <BaseEntry>() { new BaseEntry() { Origin = "Origin1", Translation = "Translation1" }, new BaseEntry() { Origin = "Origin2", Translation = "Translation2" }, } } }, { "Key2", new LdstrEntry() { Instructions = new List <BaseEntry>() { new BaseEntry() { Origin = "Origin3", Translation = "Translation3" }, new BaseEntry() { Origin = "Origin4", Translation = "Translation4" }, } } }, } }; var newFile = new LdstrFile() { LdstrEntries = new Dictionary <string, LdstrEntry>() { { "Key1", new LdstrEntry() { Instructions = new List <BaseEntry>() { new BaseEntry() { Origin = "Origin1", Translation = "" }, new BaseEntry() { Origin = "AnotherOrigin1", Translation = "" }, new BaseEntry() { Origin = "Origin5", Translation = "" }, } } }, { "Key3", new LdstrEntry() { Instructions = new List <BaseEntry>() { new BaseEntry() { Origin = "Origin6", Translation = "" } } } }, } }; service.Update(oldFile, newFile, logger); logger.Added.Count.Should().Be(1); logger.Changed.Count.Should().Be(2); logger.Added.Count.Should().Be(1); oldFile.LdstrEntries.Count.Should().Be(3); oldFile.LdstrEntries["Key1"].Instructions.Count.Should().Be(4); oldFile.LdstrEntries["Key1"].Instructions.Should().ContainSingle(i => i.Origin == "Origin1" && i.Translation == "Translation1"); oldFile.LdstrEntries["Key1"].Instructions.Should().ContainSingle(i => i.Origin == "Origin2" && i.Translation == "Translation2"); oldFile.LdstrEntries["Key1"].Instructions.Should().ContainSingle(i => i.Origin == "AnotherOrigin1" && i.Translation == ""); oldFile.LdstrEntries["Key1"].Instructions.Should().ContainSingle(i => i.Origin == "Origin5" && i.Translation == ""); oldFile.LdstrEntries["Key2"].Instructions.Count.Should().Be(2); oldFile.LdstrEntries["Key2"].Instructions.Should().ContainSingle(i => i.Origin == "Origin3" && i.Translation == "Translation3"); oldFile.LdstrEntries["Key2"].Instructions.Should().ContainSingle(i => i.Origin == "Origin4" && i.Translation == "Translation4"); oldFile.LdstrEntries["Key3"].Instructions.Count.Should().Be(1); oldFile.LdstrEntries["Key3"].Instructions.Should().ContainSingle(i => i.Origin == "Origin6" && i.Translation == ""); }