using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using System.Text.Json; using BepInEx; using BepInEx.Configuration; using BepInEx.Core.Logging.Interpolation; using BepInEx.Logging; using BepInEx.Unity.IL2CPP; using BigWalkLocalizationAPI.Api; using HarmonyLib; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("BigWalkLocalizationAPI")] [assembly: AssemblyDescription("Big Walk Localization API for Big Walk by Ice Box Studio")] [assembly: AssemblyProduct("BigWalkLocalizationAPI")] [assembly: ComVisible(false)] [assembly: Guid("e335fa34-e0fc-41e6-9c93-88cf9ff63f57")] [assembly: AssemblyFileVersion("1.1.0.0")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyVersion("1.1.0.0")] namespace BigWalkLocalizationAPI { [BepInPlugin("IceBoxStudio.BigWalk.LocalizationAPI", "BigWalkLocalizationAPI", "1.1.0")] public sealed class BigWalkLocalizationAPI : BasePlugin { internal static ManualLogSource Logger { get; private set; } public override void Load() { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Expected O, but got Unknown //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown Logger = ((BasePlugin)this).Log; bool flag = default(bool); try { new Harmony("IceBoxStudio.BigWalk.LocalizationAPI").PatchAll(Assembly.GetExecutingAssembly()); ManualLogSource logger = Logger; BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(14, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendFormatted("BigWalkLocalizationAPI"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted("1.1.0"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" initialized."); } logger.LogInfo(val); } catch (Exception ex) { ManualLogSource logger2 = Logger; BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(43, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Failed to initialize the localization API: "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted(ex); } logger2.LogError(val2); } } } public static class PluginInfo { public const string PLUGIN_GUID = "IceBoxStudio.BigWalk.LocalizationAPI"; public const string PLUGIN_NAME = "BigWalkLocalizationAPI"; public const string PLUGIN_VERSION = "1.1.0"; } } namespace BigWalkLocalizationAPI.Patches { [HarmonyPatch(typeof(LocalizationManager), "SetLanguage", new Type[] { typeof(LocalizationLanguage) })] public static class LocalizationManagerSetLanguagePatch { [HarmonyPostfix] public static void Postfix() { LocalizationApi.NotifyLanguageChanged(); } } } namespace BigWalkLocalizationAPI.Api { internal sealed class ConfigSectionTag { private readonly ModLocalizer _localizer; private readonly string _key; public string Section { get; } public int? Order { get; } internal ConfigSectionTag(ModLocalizer localizer, string section, string key, int order) { _localizer = localizer; _key = key; Section = section; Order = order; } internal bool TryGetDisplayName(out string displayName) { displayName = _localizer.GetLocalizedText(_key); return !string.Equals(displayName, _key, StringComparison.Ordinal); } } internal sealed class ConfigEntryTag { private readonly ModLocalizer _localizer; private readonly string _key; public int? Order { get; } public double? SliderStep { get; } internal ConfigEntryTag(ModLocalizer localizer, string key, int order, double? sliderStep) { _localizer = localizer; _key = key; Order = order; SliderStep = sliderStep; } internal bool TryGetText(string propertyName, out string text) { string text2 = (string.Equals(propertyName, "DisplayName", StringComparison.Ordinal) ? ".name" : ".description"); string text3 = _key + text2; text = _localizer.GetLocalizedText(text3); return !string.Equals(text, text3, StringComparison.Ordinal); } internal bool TryGetDisplayValue(object value, out string displayValue) { displayValue = null; string text = NormalizeValue(value); if (text.Length == 0) { return false; } string text2 = _key + "." + text; string localizedText = _localizer.GetLocalizedText(text2); if (string.Equals(localizedText, text2, StringComparison.Ordinal)) { return false; } displayValue = localizedText; return true; } private static string NormalizeValue(object value) { string text = Convert.ToString(value, CultureInfo.InvariantCulture); if (string.IsNullOrWhiteSpace(text)) { return string.Empty; } StringBuilder stringBuilder = new StringBuilder(text.Length + 4); for (int i = 0; i < text.Length; i++) { char c = text[i]; if (!char.IsLetterOrDigit(c)) { if (stringBuilder.Length > 0 && stringBuilder[stringBuilder.Length - 1] != '_') { stringBuilder.Append('_'); } continue; } if (char.IsUpper(c) && i > 0 && char.IsLower(text[i - 1]) && stringBuilder.Length > 0 && stringBuilder[stringBuilder.Length - 1] != '_') { stringBuilder.Append('_'); } stringBuilder.Append(char.ToLowerInvariant(c)); } return stringBuilder.ToString().Trim('_'); } } public static class LocalizationApi { public const string DefaultLanguage = "English"; private const string LanguageSaveKey = "setting_language"; private static readonly Dictionary Localizers = new Dictionary(StringComparer.OrdinalIgnoreCase); private static bool _languageApplied; public static string CurrentLanguage { get { TryGetCurrentGameLanguage(out var language); return language; } } public static event Action LanguageChanged; public static ModLocalizer For(string pluginGuid) { if (string.IsNullOrWhiteSpace(pluginGuid)) { throw new ArgumentException("Plugin GUID cannot be empty.", "pluginGuid"); } if (!Localizers.TryGetValue(pluginGuid, out var value)) { value = new ModLocalizer(pluginGuid); Localizers.Add(pluginGuid, value); } return value; } public static bool TryGetCurrentGameLanguage(out string language) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) try { if (!_languageApplied && TryGetSavedLanguage(out language)) { return true; } LocalizationManager instance = LocalizationManager.instance; language = ((instance == null) ? "English" : ((object)instance.currentLanguage/*cast due to .constrained prefix*/).ToString()); if (string.IsNullOrWhiteSpace(language)) { language = "English"; } return instance != null; } catch { language = "English"; return false; } } public static string GetConfigDescription(ConfigEntryBase entry) { if (entry != null) { ConfigDescription description = entry.Description; object[] array = ((description != null) ? description.Tags : null) ?? Array.Empty(); for (int i = 0; i < array.Length; i++) { if (array[i] is ConfigEntryTag configEntryTag && configEntryTag.TryGetText("Description", out var text)) { return text; } } } if (entry == null) { return null; } ConfigDescription description2 = entry.Description; if (description2 == null) { return null; } return description2.Description; } public static string GetConfigDisplayName(ConfigEntryBase entry) { if (entry != null) { ConfigDescription description = entry.Description; object[] array = ((description != null) ? description.Tags : null) ?? Array.Empty(); for (int i = 0; i < array.Length; i++) { if (array[i] is ConfigEntryTag configEntryTag && configEntryTag.TryGetText("DisplayName", out var text)) { return text; } } } if (entry == null) { return null; } ConfigDefinition definition = entry.Definition; if (definition == null) { return null; } return definition.Key; } public static string GetConfigSection(string section, ConfigFile config) { if (section == null || config == null) { return section; } foreach (ConfigEntryBase value in config.Values) { if (!string.Equals(value.Definition.Section, section, StringComparison.Ordinal)) { continue; } ConfigDescription description = value.Description; object[] array = ((description != null) ? description.Tags : null) ?? Array.Empty(); for (int i = 0; i < array.Length; i++) { if (array[i] is ConfigSectionTag configSectionTag && string.Equals(configSectionTag.Section, section, StringComparison.Ordinal) && configSectionTag.TryGetDisplayName(out var displayName)) { return displayName; } } } return section; } public static bool TryGetConfigDisplayValue(ConfigEntryBase entry, object value, out string displayValue) { displayValue = null; if (entry == null || value == null) { return false; } ConfigDescription description = entry.Description; object[] array = ((description != null) ? description.Tags : null) ?? Array.Empty(); for (int i = 0; i < array.Length; i++) { if (array[i] is ConfigEntryTag configEntryTag && configEntryTag.TryGetDisplayValue(value, out displayValue)) { return true; } } return false; } internal static void NotifyLanguageChanged() { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown _languageApplied = true; Action languageChanged = LocalizationApi.LanguageChanged; if (languageChanged == null) { return; } string currentLanguage = CurrentLanguage; Delegate[] invocationList = languageChanged.GetInvocationList(); bool flag = default(bool); foreach (Delegate obj in invocationList) { try { ((Action)obj)(currentLanguage); } catch (Exception ex) { ManualLogSource logger = BigWalkLocalizationAPI.Logger; if (logger != null) { BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(33, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Language change callback failed: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(ex); } logger.LogError(val); } } } } private static bool TryGetSavedLanguage(out string language) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) language = null; if (!PlayerPrefs.HasKey("setting_language")) { return false; } int num = PlayerPrefs.GetInt("setting_language"); if (num < 1 || num > 15) { return false; } language = ((object)(LocalizationLanguage)num/*cast due to .constrained prefix*/).ToString(); return !string.IsNullOrWhiteSpace(language); } } public sealed class ModLocalizer { private readonly Dictionary> _localizations = new Dictionary>(StringComparer.OrdinalIgnoreCase); public string PluginGuid { get; } internal ModLocalizer(string pluginGuid) { PluginGuid = pluginGuid; } public void RegisterJson(string jsonPath) { if (string.IsNullOrWhiteSpace(jsonPath)) { throw new ArgumentException("Localization file path cannot be empty.", "jsonPath"); } if (!File.Exists(jsonPath)) { throw new FileNotFoundException("Localization file not found.", jsonPath); } Dictionary> dictionary = new Dictionary>(StringComparer.OrdinalIgnoreCase); using (JsonDocument jsonDocument = JsonDocument.Parse(File.ReadAllText(jsonPath))) { if (jsonDocument.RootElement.ValueKind != JsonValueKind.Object) { throw new InvalidDataException("Localization file root must be a JSON object."); } foreach (JsonProperty item in jsonDocument.RootElement.EnumerateObject()) { if (item.Value.ValueKind != JsonValueKind.Object) { continue; } Dictionary dictionary2 = new Dictionary(StringComparer.OrdinalIgnoreCase); foreach (JsonProperty item2 in item.Value.EnumerateObject()) { if (item2.Value.ValueKind == JsonValueKind.String) { dictionary2[item2.Name] = item2.Value.GetString() ?? string.Empty; } } if (dictionary2.Count > 0) { dictionary[item.Name] = dictionary2; } } } if (!dictionary.ContainsKey("English")) { throw new InvalidDataException("Localization file must contain a English section."); } _localizations.Clear(); foreach (KeyValuePair> item3 in dictionary) { _localizations.Add(item3.Key, item3.Value); } } public string GetLocalizedText(string key, params object[] args) { if (string.IsNullOrEmpty(key)) { return string.Empty; } string currentLanguage = LocalizationApi.CurrentLanguage; if (TryGetText(currentLanguage, key, out var text)) { return Format(text, args); } if (!string.Equals(currentLanguage, "English", StringComparison.OrdinalIgnoreCase) && TryGetText("English", key, out var text2)) { return Format(text2, args); } return key; } public ConfigDescription Config(string key, int entryOrder, string section, string sectionKey, int sectionOrder, AcceptableValueBase acceptableValues = null, double? sliderStep = null) { //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Expected O, but got Unknown if (string.IsNullOrWhiteSpace(key)) { throw new ArgumentException("Localization key cannot be empty.", "key"); } if (string.IsNullOrWhiteSpace(section)) { throw new ArgumentException("Config section cannot be empty.", "section"); } if (string.IsNullOrWhiteSpace(sectionKey)) { throw new ArgumentException("Section localization key cannot be empty.", "sectionKey"); } string text = key + ".description"; string text2 = GetLocalizedText(text); if (string.Equals(text2, text, StringComparison.Ordinal)) { text2 = string.Empty; } return new ConfigDescription(text2, acceptableValues, new object[2] { new ConfigSectionTag(this, section, sectionKey, sectionOrder), new ConfigEntryTag(this, key, entryOrder, sliderStep) }); } private bool TryGetText(string language, string key, out string text) { text = null; if (_localizations.TryGetValue(language, out var value)) { return value.TryGetValue(key, out text); } return false; } private static string Format(string text, object[] args) { if (args == null || args.Length == 0) { return text; } try { return string.Format(text, args); } catch (FormatException) { return text; } } } }