Decompiled source of IntegratedKoreanPatch v1.7.1

IntegratedKoreanPatch/IntegratedKoreanPatch.dll

Decompiled 6 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using HarmonyLib;
using UnityEngine;

[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace IntegratedKoreanPatch;

[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInPlugin("rexmods.integratedkoreanpatch", "통합한글패치", "1.7.1")]
public sealed class Plugin : BaseUnityPlugin
{
	private sealed class BoundText
	{
		public object Target;

		public FieldInfo Field;

		public string Original;

		public string Token;
	}

	private const string Guid = "rexmods.integratedkoreanpatch";

	private static Plugin self;

	private Harmony harmony;

	private Action<Localization, string, string> addWord;

	private FieldInfo cacheField;

	private FieldInfo singletonField;

	private MethodInfo evictCache;

	private bool pending;

	private readonly Dictionary<string, string> cuisine = new Dictionary<string, string>(StringComparer.Ordinal);

	private int lastCuisineCount = -1;

	private readonly Dictionary<string, string> monstrum = new Dictionary<string, string>(StringComparer.Ordinal);

	private int lastMonstrumCount = -1;

	private bool warfareActive;

	private bool southsilActive;

	private string mainLanguage;

	private int lastWarfareCount = -1;

	private int lastSouthsilCount = -1;

	private bool bindingWarning;

	private readonly Dictionary<string, string> warfare = new Dictionary<string, string>(StringComparer.Ordinal);

	private readonly Dictionary<string, string[]> southsil = new Dictionary<string, string[]>(StringComparer.Ordinal);

	private readonly Dictionary<string, string> southsilWords = new Dictionary<string, string>(StringComparer.Ordinal);

	private readonly Dictionary<string, string> southsilEnglish = new Dictionary<string, string>(StringComparer.Ordinal);

	private readonly Dictionary<string, string[]> effects = new Dictionary<string, string[]>(StringComparer.Ordinal);

	private readonly Dictionary<string, string> setNames = new Dictionary<string, string>(StringComparer.Ordinal);

	private readonly HashSet<SharedData> ownedItems = new HashSet<SharedData>();

	private readonly List<BoundText> boundTexts = new List<BoundText>();

	private void Awake()
	{
		//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ea: Expected O, but got Unknown
		self = this;
		MethodInfo method = typeof(Localization).GetMethod("AddWord", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[2]
		{
			typeof(string),
			typeof(string)
		}, null);
		if (method == null || method.ReturnType != typeof(void))
		{
			throw new MissingMethodException("Localization.AddWord(string,string)");
		}
		addWord = (Action<Localization, string, string>)Delegate.CreateDelegate(typeof(Action<Localization, string, string>), method);
		cacheField = typeof(Localization).GetField("m_cache", BindingFlags.Instance | BindingFlags.NonPublic);
		if (cacheField == null)
		{
			throw new MissingFieldException("Localization.m_cache");
		}
		singletonField = typeof(Localization).GetField("m_instance", BindingFlags.Static | BindingFlags.NonPublic);
		if (singletonField == null)
		{
			throw new MissingFieldException("Localization.m_instance");
		}
		evictCache = cacheField.FieldType.GetMethod("EvictAll", Type.EmptyTypes);
		if (evictCache == null)
		{
			throw new MissingMethodException("Localization cache EvictAll");
		}
		string path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Data");
		LoadData(Path.Combine(path, "Monstrum.tsv"), 2, monstrum, null);
		LoadData(Path.Combine(path, "Warfare.tsv"), 2, warfare, null);
		LoadData(Path.Combine(path, "ValheimCuisine.tsv"), 2, cuisine, null);
		LoadData(Path.Combine(path, "SouthsilArmor.tsv"), 5, null, southsil);
		LoadData(Path.Combine(path, "SouthsilEffects.tsv"), 5, null, effects);
		LoadData(Path.Combine(path, "SouthsilSets.tsv"), 2, setNames, null);
		harmony = new Harmony("rexmods.integratedkoreanpatch");
		Install(typeof(Localization), "SetupLanguage", new Type[1] { typeof(string) }, "LanguageReady");
		Install(typeof(ObjectDB), "Awake", Type.EmptyTypes, "DatabaseReady");
		Install(typeof(ObjectDB), "CopyOtherDB", new Type[1] { typeof(ObjectDB) }, "DatabaseReady");
		Install(typeof(ZNetScene), "Awake", Type.EmptyTypes, "DatabaseReady");
		Install(typeof(ItemData), "GetTooltip", new Type[6]
		{
			typeof(ItemData),
			typeof(int),
			typeof(bool),
			typeof(float),
			typeof(int),
			typeof(bool)
		}, "ItemTooltipReady");
		((BaseUnityPlugin)this).Logger.LogInfo((object)"통합한글패치 1.7.1: Warfare / SouthsilArmor / ValheimCuisine / Monstrum 번역.");
	}

	private void LoadData(string path, int columns, Dictionary<string, string> words, Dictionary<string, string[]> records)
	{
		try
		{
			Dictionary<string, string[]> dictionary = ParseData(File.ReadAllLines(ResolveTranslationPath(path), Encoding.ASCII), columns);
			foreach (KeyValuePair<string, string[]> item in dictionary)
			{
				words?.Add(item.Key, item.Value[1]);
				records?.Add(item.Key, item.Value);
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)(Path.GetFileName(path) + " 번역 읽기 실패: " + ex.Message));
		}
	}

	internal static string ResolveTranslationPath(string expectedPath)
	{
		if (File.Exists(expectedPath))
		{
			return expectedPath;
		}
		string directoryName = Path.GetDirectoryName(Path.GetDirectoryName(expectedPath));
		string text = Path.Combine(directoryName, Path.GetFileName(expectedPath));
		if (File.Exists(text))
		{
			return text;
		}
		throw new FileNotFoundException("Translation file not found in Data or plugin directory: " + Path.GetFileName(expectedPath), expectedPath);
	}

	internal static Dictionary<string, string[]> ParseData(string[] lines, int columns)
	{
		Dictionary<string, string[]> dictionary = new Dictionary<string, string[]>(StringComparer.Ordinal);
		foreach (string text in lines)
		{
			if (!string.IsNullOrWhiteSpace(text))
			{
				string[] array = text.Split(new char[1] { '\t' }, StringSplitOptions.None);
				if (array.Length != columns)
				{
					throw new InvalidDataException("잘못된 번역 열 개수");
				}
				for (int j = 0; j < array.Length; j++)
				{
					array[j] = Encoding.UTF8.GetString(Convert.FromBase64String(array[j]));
				}
				if (string.IsNullOrEmpty(array[0]) || dictionary.ContainsKey(array[0]))
				{
					throw new InvalidDataException("비어 있거나 중복된 번역 키: " + array[0]);
				}
				dictionary.Add(array[0], array);
			}
		}
		return dictionary;
	}

	private void Install(Type type, string name, Type[] parameters, string handler)
	{
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Expected O, but got Unknown
		MethodInfo method = type.GetMethod(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, parameters, null);
		if (method == null)
		{
			throw new MissingMethodException(type.FullName, name);
		}
		HarmonyMethod val = new HarmonyMethod(typeof(Plugin).GetMethod(handler, BindingFlags.Static | BindingFlags.NonPublic));
		val.priority = 0;
		val.after = new string[1] { "shudnal.MyLittleUI" };
		harmony.Patch((MethodBase)method, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
	}

	private IEnumerator Start()
	{
		yield return null;
		Refresh();
	}

	private static void LanguageReady(Localization __instance, string __0)
	{
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Expected O, but got Unknown
		if (!((Object)self == (Object)null))
		{
			self.Apply(__instance, __0);
			if (object.ReferenceEquals(__instance, self.singletonField.GetValue(null)))
			{
				self.mainLanguage = __0;
				self.QueueRefresh();
			}
		}
	}

	private static void DatabaseReady()
	{
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Expected O, but got Unknown
		if ((Object)self != (Object)null)
		{
			self.QueueRefresh();
		}
	}

	private void QueueRefresh()
	{
		if (!pending && ((Behaviour)this).isActiveAndEnabled)
		{
			pending = true;
			((MonoBehaviour)this).StartCoroutine(RefreshNextFrame());
		}
	}

	private IEnumerator RefreshNextFrame()
	{
		yield return null;
		pending = false;
		Refresh();
	}

	private void Refresh()
	{
		Localization instance = Localization.instance;
		if (instance != null)
		{
			Apply(instance, mainLanguage ?? instance.GetSelectedLanguage());
		}
	}

	private static bool IsLoaded(string guid)
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Expected O, but got Unknown
		if (Chainloader.PluginInfos.TryGetValue(guid, out var value) && value != null)
		{
			return (Object)value.Instance != (Object)null;
		}
		return false;
	}

	internal static bool ShouldApplyMonstrum(bool loaded, string language)
	{
		if (loaded)
		{
			return string.Equals(language, "Korean", StringComparison.Ordinal);
		}
		return false;
	}

	private void Apply(Localization localization, string language)
	{
		if (localization == null)
		{
			return;
		}
		bool flag = string.Equals(language, "Korean", StringComparison.Ordinal);
		warfareActive = IsLoaded("Therzie.Warfare");
		southsilActive = IsLoaded("southsil.SouthsilArmor");
		bool flag2 = IsLoaded("Therzie.Monstrum");
		if (ShouldApplyMonstrum(flag2, language))
		{
			foreach (KeyValuePair<string, string> item in monstrum)
			{
				addWord(localization, item.Key, item.Value);
			}
			if (lastMonstrumCount != monstrum.Count)
			{
				lastMonstrumCount = monstrum.Count;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Monstrum 한글 번역 적용: " + monstrum.Count + "개"));
			}
		}
		bool flag3 = IsLoaded("XutzBR.ValheimCuisine");
		if (flag3 && flag)
		{
			foreach (KeyValuePair<string, string> item2 in cuisine)
			{
				addWord(localization, item2.Key, item2.Value);
			}
			if (lastCuisineCount != cuisine.Count)
			{
				lastCuisineCount = cuisine.Count;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("ValheimCuisine 한글 보완 적용: " + cuisine.Count + "개"));
			}
		}
		if (warfareActive && flag)
		{
			foreach (KeyValuePair<string, string> item3 in warfare)
			{
				addWord(localization, item3.Key, item3.Value);
			}
			if (lastWarfareCount != warfare.Count)
			{
				lastWarfareCount = warfare.Count;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Warfare 한글 번역 적용: " + warfare.Count + "개"));
			}
		}
		if (southsilActive)
		{
			BindSouthsilKeys();
			foreach (KeyValuePair<string, string> item4 in flag ? southsilWords : southsilEnglish)
			{
				addWord(localization, item4.Key, localization.Localize(item4.Value));
			}
			if (lastSouthsilCount != southsilWords.Count)
			{
				lastSouthsilCount = southsilWords.Count;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("SouthsilArmor 번역 키 등록: " + southsilWords.Count + "개 (장비 " + southsil.Count + "종, 효과 " + effects.Count + "종, 세트명 " + setNames.Count + "개)"));
			}
		}
		if (warfareActive || southsilActive || (flag3 && flag) || (flag2 && flag))
		{
			evictCache.Invoke(cacheField.GetValue(localization), null);
		}
	}

	private void BindSouthsilKeys()
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Expected O, but got Unknown
		//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d2: Expected O, but got Unknown
		//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00df: Expected O, but got Unknown
		//IL_0108: Unknown result type (might be due to invalid IL or missing references)
		//IL_0113: Expected O, but got Unknown
		try
		{
			if (!Chainloader.PluginInfos.TryGetValue("southsil.SouthsilArmor", out var value) || (Object)value.Instance == (Object)null)
			{
				return;
			}
			Type type = ((object)value.Instance).GetType().Assembly.GetType("ItemManager.Item", throwOnError: true);
			BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
			FieldInfo field = type.GetField("registeredItems", BindingFlags.Static | BindingFlags.NonPublic);
			FieldInfo field2 = type.GetField("Prefab", bindingAttr);
			if (field == null || field2 == null)
			{
				throw new MissingFieldException("Southsil ItemManager binding");
			}
			if (!(field.GetValue(null) is IEnumerable enumerable))
			{
				return;
			}
			foreach (object item in enumerable)
			{
				object value2 = field2.GetValue(item);
				GameObject val = (GameObject)((value2 is GameObject) ? value2 : null);
				if (!((Object)val == (Object)null) && southsil.TryGetValue(((Object)val).name, out var value3))
				{
					ItemDrop component = val.GetComponent<ItemDrop>();
					if (!((Object)component == (Object)null) && component.m_itemData != null && component.m_itemData.m_shared != null)
					{
						SharedData shared = component.m_itemData.m_shared;
						ownedItems.Add(shared);
						BindText(shared, "m_name", "rex_ikp_item_" + ((Object)val).name + "_name", value3[1], value3[2]);
						BindText(shared, "m_description", "rex_ikp_item_" + ((Object)val).name + "_desc", value3[3], value3[4]);
						BindEffect(shared.m_setStatusEffect);
						BindEffect(shared.m_equipStatusEffect);
					}
				}
			}
		}
		catch (Exception ex)
		{
			if (!bindingWarning)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Southsil 번역 연결 실패: " + ex.Message));
			}
			bindingWarning = true;
		}
	}

	private void BindText(object target, string fieldName, string key, string english, string korean)
	{
		if (target == null)
		{
			return;
		}
		FieldInfo field = target.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		if (field == null || field.FieldType != typeof(string))
		{
			throw new MissingFieldException(fieldName);
		}
		string text = "$" + key;
		southsilWords[key] = korean;
		southsilEnglish[key] = english;
		foreach (BoundText boundText in boundTexts)
		{
			if (object.ReferenceEquals(boundText.Target, target) && boundText.Field.Name == fieldName)
			{
				field.SetValue(target, text);
				return;
			}
		}
		boundTexts.Add(new BoundText
		{
			Target = target,
			Field = field,
			Original = (field.GetValue(target) as string),
			Token = text
		});
		field.SetValue(target, text);
	}

	private void BindEffect(StatusEffect effect)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Expected O, but got Unknown
		if (!((Object)effect == (Object)null) && effects.TryGetValue(((Object)effect).name, out var value))
		{
			string text = "rex_ikp_effect_" + ((Object)effect).name.Replace(" ", "_");
			BindText(effect, "m_name", text + "_name", value[1], value[2]);
			BindText(effect, "m_tooltip", text + "_desc", value[3], value[4]);
		}
	}

	private static void ItemTooltipReady(ItemData __0, ref string __result)
	{
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Expected O, but got Unknown
		if (!((Object)self == (Object)null) && __0 != null && __0.m_shared != null && !string.IsNullOrEmpty(__result) && self.ownedItems.Contains(__0.m_shared) && string.Equals(self.mainLanguage ?? Localization.instance.GetSelectedLanguage(), "Korean", StringComparison.Ordinal))
		{
			string setName = __0.m_shared.m_setName;
			if (!string.IsNullOrEmpty(setName) && self.setNames.TryGetValue(setName, out var value))
			{
				__result = __result.Replace(setName, value);
			}
		}
	}

	internal void RestoreTextBindings()
	{
		foreach (BoundText boundText in boundTexts)
		{
			if (string.Equals(boundText.Field.GetValue(boundText.Target) as string, boundText.Token, StringComparison.Ordinal))
			{
				boundText.Field.SetValue(boundText.Target, boundText.Original);
			}
		}
	}

	private void OnDestroy()
	{
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_002e: Expected O, but got Unknown
		//IL_002e: Expected O, but got Unknown
		if (harmony != null)
		{
			harmony.UnpatchSelf();
		}
		RestoreTextBindings();
		if ((Object)self == (Object)this)
		{
			self = null;
		}
	}
}