Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of OdinHorse HU v1.0.1
BepInEx/plugins/SeHun-OdinHorseAdapter/SeHun.OdinHorseAdapter.dll
Decompiled 4 days agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using BepInEx; using BepInEx.Bootstrap; using HarmonyLib; using Microsoft.CodeAnalysis; using SeHun.Core; using SeHunTranslationLoader; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("SeHun.OdinHorseAdapter")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.1.0.0")] [assembly: AssemblyInformationalVersion("0.1.0")] [assembly: AssemblyProduct("SeHun.OdinHorseAdapter")] [assembly: AssemblyTitle("SeHun.OdinHorseAdapter")] [assembly: AssemblyVersion("0.1.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace SeHun.OdinHorseAdapter { [BepInPlugin("sehun.odinhorse.adapter", "SeHun OdinHorse Adapter TEST", "0.1.0")] [BepInDependency("sehun.translationloader", "0.6.0")] [BepInDependency("Raelaziel.OdinHorse", "1.9.1")] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "sehun.odinhorse.adapter"; private Adapter adapter; private void Awake() { try { Assembly assembly = ((object)Chainloader.PluginInfos["Raelaziel.OdinHorse"].Instance).GetType().Assembly; adapter = new Adapter(assembly); SeHunPlugin.Adapters.Register((ITranslationAdapter)(object)adapter); ((BaseUnityPlugin)this).Logger.LogInfo((object)"OdinHorseAdapter 0.1.0 REGISTERED; waiting for Loader dispatch (valheim.odinhorse)."); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("OdinHorseAdapter DISABLED: " + ex)); } } private void OnDestroy() { adapter?.Stop(); } } public sealed class Adapter : ITranslationAdapter { private readonly Assembly odin; private Harmony harmony; private static Bridge bridge; private static Action<string> warning; private static bool faulted; public string Id => "valheim.odinhorse"; public Adapter(Assembly odin) { this.odin = odin; } public void Load(Package package, Action<string> info, Action<string> warn) { //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Expected O, but got Unknown //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Expected O, but got Unknown if (harmony != null) { throw new InvalidOperationException("Only one OdinHorse package is supported."); } if (package.SchemaVersion != 1 || package.Game != "valheim" || package.Id != "OdinHorse" || package.Adapter != Id || package.Language != "Hungarian") { throw new InvalidDataException("Expected OdinHorse / valheim.odinhorse / Hungarian schema 1 package."); } RequireHash(odin.Location, "4618EA520BC1B51407E09F46D34D8F6E03F8D1B67291BB3BE90AE27A9179664A"); RequireHash(typeof(SeHunPlugin).Assembly.Location, "586771DECBAD1CA1A4E1282483A05CDEDBA1DF7A0E4FD48FFAF4B944654AA9C9"); RequireHash(typeof(ITranslationAdapter).Assembly.Location, "C483573FA7751A2FE6FAEB795F21ACF5B7A4E39B9C53A344DD38968157E545DA"); Dictionary<string, string> dictionary = Packages.ReadTranslations(package.FilePath); Type type = odin.GetType("LocalizationManager.Localizer", throwOnError: true); MethodInfo method = type.GetMethod("UpdatePlaceholderText", BindingFlags.Static | BindingFlags.NonPublic, null, new Type[2] { typeof(Localization), typeof(string) }, null); if (method == null || method.ReturnType != typeof(void)) { throw new MissingMethodException("OdinHorse UpdatePlaceholderText(Localization,string) not found."); } ConditionalWeakTable<Localization, string> conditionalWeakTable = type.GetField("localizationLanguage", BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null) as ConditionalWeakTable<Localization, string>; List<WeakReference<Localization>> list = type.GetField("localizationObjects", BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null) as List<WeakReference<Localization>>; if (conditionalWeakTable == null || list == null) { throw new InvalidOperationException("OdinHorse localization tracking unavailable."); } Bridge bridge = new Bridge(dictionary, conditionalWeakTable); Harmony val = new Harmony("sehun.odinhorse.adapter"); try { warning = warn; faulted = false; Adapter.bridge = bridge; val.Patch((MethodBase)method, (HarmonyMethod)null, new HarmonyMethod(typeof(Adapter), "AfterOriginalWord", (Type[])null) { priority = 0 }, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); int num = 0; WeakReference<Localization>[] array = list.ToArray(); for (int i = 0; i < array.Length; i++) { if (array[i].TryGetTarget(out var target)) { num += bridge.RestoreAll(target); } } harmony = val; info("OdinHorseAdapter 0.1.0 ACTIVE via Loader; keys=" + dictionary.Count + "; catch-up writes=" + num + "; only tracked Hungarian instances; English cache untouched."); } catch { val.UnpatchSelf(); Adapter.bridge = null; throw; } } private static void AfterOriginalWord(Localization __0, string __1) { if (bridge == null || faulted) { return; } try { bridge.Restore(__0, __1); } catch (Exception ex) { faulted = true; warning?.Invoke("OdinHorseAdapter DISABLED for this session after error: " + ex); } } public void Stop() { Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } harmony = null; bridge = null; } public static void RequireHash(string path, string expected) { using FileStream inputStream = File.OpenRead(path); using SHA256 sHA = SHA256.Create(); if (BitConverter.ToString(sHA.ComputeHash(inputStream)).Replace("-", "") != expected) { throw new InvalidOperationException("Unsupported DLL hash: " + Path.GetFileName(path)); } } } public sealed class Bridge { private readonly Dictionary<string, string> translations; private readonly ConditionalWeakTable<Localization, string> languages; private readonly FieldInfo words = typeof(Localization).GetField("m_translations", BindingFlags.Instance | BindingFlags.NonPublic); private readonly MethodInfo addWord = typeof(Localization).GetMethod("AddWord", BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[2] { typeof(string), typeof(string) }, null); public Bridge(Dictionary<string, string> translations, ConditionalWeakTable<Localization, string> languages) { if (words == null || words.FieldType != typeof(Dictionary<string, string>) || addWord == null) { throw new MissingMemberException("Valheim Localization contract changed."); } if (translations == null || translations.Count == 0 || languages == null) { throw new InvalidDataException("Missing translations/language tracking."); } foreach (KeyValuePair<string, string> translation in translations) { if (string.IsNullOrWhiteSpace(translation.Key) || translation.Key.StartsWith("$") || translation.Value == null) { throw new InvalidDataException("Invalid translation key/value."); } } this.translations = new Dictionary<string, string>(translations, StringComparer.Ordinal); this.languages = languages; } public bool Restore(Localization target, string key) { if (target == null || key == null || !languages.TryGetValue(target, out var value) || value != "Hungarian" || !translations.TryGetValue(key, out var value2)) { return false; } if (!(words.GetValue(target) is Dictionary<string, string> dictionary) || !dictionary.TryGetValue(key, out var value3) || value3 == value2) { return false; } addWord.Invoke(target, new object[2] { key, value2 }); return true; } public int RestoreAll(Localization target) { int num = 0; foreach (string key in translations.Keys) { if (Restore(target, key)) { num++; } } return num; } } }