using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.Localization; using UnityEngine.Localization.Settings; using UnityEngine.Localization.Tables; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Kalamies")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.1.0.0")] [assembly: AssemblyInformationalVersion("0.1.0")] [assembly: AssemblyProduct("StrongerBeer")] [assembly: AssemblyTitle("StrongerBeer")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.1.0.0")] [module: UnverifiableCode] [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 StrongerBeer { [BepInPlugin("kalamies.StrongerBeer", "StrongerBeer", "0.1.0")] public class Plugin : BaseUnityPlugin { public const string Guid = "kalamies.StrongerBeer"; public const string Name = "StrongerBeer"; public const string Version = "0.1.0"; internal static ManualLogSource Log; private void Awake() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; try { new Harmony("kalamies.StrongerBeer").PatchAll(); } catch (Exception arg) { Log.LogError((object)$"Could not patch; bait models may look wrong. {arg}"); } ((MonoBehaviour)this).StartCoroutine(Run()); } private IEnumerator Run() { while ((Object)(object)LocalizationSettings.SelectedLocale == (Object)null || GameInfo.AllCreatureCount == 0) { yield return null; } try { Text.Apply(); } catch (Exception arg) { Log.LogError((object)$"Text pass failed, game untouched: {arg}"); } try { Models.Apply(); } catch (Exception arg2) { Log.LogError((object)$"Model pass failed, game untouched: {arg2}"); } LocalizationSettings.SelectedLocaleChanged += delegate { ((MonoBehaviour)this).StartCoroutine(Reapply()); }; SceneManager.sceneLoaded += delegate { try { Models.ApplyToScene(); } catch (Exception ex) { Log.LogWarning((object)("Scene pass failed: " + ex.Message)); } }; } private IEnumerator Reapply() { yield return (object)new WaitForSeconds(1f); try { Text.Apply(); } catch (Exception ex) { Log.LogWarning((object)("Re-apply failed: " + ex.Message)); } } } internal static class Text { private static readonly (string Pattern, string Replacement)[] Rules = new(string, string)[14] { ("empty beer cans", "empty Koskenkorva bottles"), ("empty beer can", "empty Koskenkorva bottle"), ("Empty Beer Can", "Empty Koskenkorva Bottle"), ("beer can", "Koskenkorva bottle"), ("\\bBeer\\b", "Koskenkorva"), ("\\bbeer\\b", "Koskenkorva"), ("Leere Bierdose", "Leere Koskenkorva-Flasche"), ("leeren bierdose", "leeren Koskenkorva-Flasche"), ("\\bBierdose\\b", "Koskenkorva-Flasche"), ("\\bBier\\b", "Koskenkorva"), ("Lattina di birra vuota", "Bottiglia di Koskenkorva vuota"), ("lattina di birra", "bottiglia di Koskenkorva"), ("\\bBirra\\b", "Koskenkorva"), ("\\bbirra\\b", "Koskenkorva") }; internal static void Apply() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) foreach (StringTable item in ((LocalizedDatabase)(object)LocalizationSettings.StringDatabase).GetAllTables((Locale)null).WaitForCompletion()) { if ((Object)(object)item == (Object)null) { continue; } foreach (StringTableEntry value in ((DetailedLocalizationTable)(object)item).Values) { if (value == null) { continue; } string localizedValue = ((TableEntry)value).LocalizedValue; if (!string.IsNullOrEmpty(localizedValue)) { string text = Rules.Aggregate(localizedValue, (string input, (string Pattern, string Replacement) rule) => Regex.Replace(input, rule.Pattern, rule.Replacement)); if (!(text == localizedValue)) { value.Value = text; } } } } } } internal static class Models { private const string BundleFile = "koskenkorva.bundle"; private static readonly string[] OriginalMeshes = new string[1] { "beercan" }; private static Mesh _source; private static Material _material; private static Mesh _bottle; private static readonly Dictionary Borrowed = new Dictionary(); private static Item Beer { get { if (!GameInfo._nameToSpawnable.TryGetValue("beer", out var value)) { return null; } return value; } } internal static void Apply() { var (val, val2) = LoadModel(); if (!Object.op_Implicit((Object)(object)val)) { Plugin.Log.LogWarning((object)"No bottle model available; text changed, models left alone."); return; } CheckShader(val2); _source = val; _material = (Object.op_Implicit((Object)(object)val2) ? val2 : CloneMaterialFrom(Beer)); Item beer = Beer; if (!Build(Reference(beer))) { return; } if (Object.op_Implicit((Object)(object)beer)) { MeshFilter[] componentsInChildren = ((Component)beer).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { Swap(componentsInChildren[i]); } if (IsOriginal(beer._mesh)) { beer._mesh = _bottle; } } else { Plugin.Log.LogWarning((object)"Could not find the beer item."); } foreach (BaitInfo allBait in GameInfo.AllBaits) { if (Object.op_Implicit((Object)(object)allBait) && ((Object)allBait).name.IndexOf("beercan", StringComparison.OrdinalIgnoreCase) >= 0) { if (IsOriginal(allBait._mesh)) { allBait._mesh = _bottle; } if (IsOriginal(allBait._meshForNpc)) { allBait._meshForNpc = _bottle; } } } ApplyToScene(); } internal static void ApplyToScene() { if (!Object.op_Implicit((Object)(object)_bottle)) { return; } MeshFilter[] array = Resources.FindObjectsOfTypeAll(); foreach (MeshFilter val in array) { if (Object.op_Implicit((Object)(object)val)) { Swap(val); } } } internal static void Materialise(MeshFilter filter) { try { MeshRenderer val = default(MeshRenderer); if (!Object.op_Implicit((Object)(object)filter) || !((Component)filter).TryGetComponent(ref val)) { return; } Material value; if (Object.op_Implicit((Object)(object)_bottle) && Object.op_Implicit((Object)(object)_material) && (Object)(object)filter.sharedMesh == (Object)(object)_bottle) { if (!Borrowed.ContainsKey(val)) { Borrowed[val] = ((Renderer)val).sharedMaterial; } ((Renderer)val).sharedMaterial = _material; } else if (Borrowed.TryGetValue(val, out value)) { ((Renderer)val).sharedMaterial = value; Borrowed.Remove(val); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not set the bottle material: " + ex.Message)); } } private static void Swap(MeshFilter filter) { if (Object.op_Implicit((Object)(object)_bottle) && IsOriginal(filter.sharedMesh)) { filter.sharedMesh = _bottle; MeshRenderer val = default(MeshRenderer); if (Object.op_Implicit((Object)(object)_material) && ((Component)filter).TryGetComponent(ref val)) { ((Renderer)val).sharedMaterial = _material; } } } private static Mesh Reference(Item beer) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)beer)) { if (IsOriginal(beer._mesh)) { return beer._mesh; } MeshFilter[] componentsInChildren = ((Component)beer).GetComponentsInChildren(true); foreach (MeshFilter val in componentsInChildren) { if (IsOriginal(val.sharedMesh)) { return val.sharedMesh; } } } Mesh val2 = null; Mesh[] array = Resources.FindObjectsOfTypeAll(); foreach (Mesh val3 in array) { if (!IsOriginal(val3)) { continue; } if (Object.op_Implicit((Object)(object)val2)) { Bounds bounds = val3.bounds; float num = Longest(((Bounds)(ref bounds)).size); bounds = val2.bounds; if (!(num > Longest(((Bounds)(ref bounds)).size))) { continue; } } val2 = val3; } return val2; } private static bool Build(Mesh reference) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)_source) || !Object.op_Implicit((Object)(object)reference)) { Plugin.Log.LogWarning((object)"Nothing to size the bottle against; models left alone."); return false; } Bounds bounds = reference.bounds; float num = Longest(((Bounds)(ref bounds)).size); bounds = _source.bounds; float num2 = Longest(((Bounds)(ref bounds)).size); if (num <= 0f || num2 <= 0f) { return false; } float num3 = num / num2; Mesh val = Object.Instantiate(_source); ((Object)val).name = "KoskenkorvaBottle"; if (!_source.isReadable) { Plugin.Log.LogWarning((object)("'" + ((Object)_source).name + "' is not readable, so it cannot be resized here. It is " + Size(_source) + " against the can's " + Size(reference) + " - either scale the model to match via the importer's Scale Factor, or tick Read/Write Enabled to let this resize it.")); _bottle = _source; return true; } Vector3[] vertices = val.vertices; for (int i = 0; i < vertices.Length; i++) { ref Vector3 reference2 = ref vertices[i]; reference2 *= num3; } val.vertices = vertices; val.RecalculateBounds(); _bottle = val; return true; } private static string Size(Mesh mesh) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) Bounds bounds = mesh.bounds; Vector3 size = ((Bounds)(ref bounds)).size; return $"{size.x:0.####} x {size.y:0.####} x {size.z:0.####} units (longest {Longest(size):0.####})"; } private static bool IsOriginal(Mesh mesh) { if (Object.op_Implicit((Object)(object)mesh)) { return OriginalMeshes.Any((string n) => ((Object)mesh).name.IndexOf(n, StringComparison.OrdinalIgnoreCase) >= 0); } return false; } private static bool Approximately(Vector3 v, Vector3 to) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) if (Mathf.Approximately(v.x, to.x) && Mathf.Approximately(v.y, to.y)) { return Mathf.Approximately(v.z, to.z); } return false; } private static float Longest(Vector3 size) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) return Mathf.Max(size.x, Mathf.Max(size.y, size.z)); } private static (Mesh, Material) LoadModel() { //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) string text = Path.Combine(Path.GetDirectoryName(typeof(Plugin).Assembly.Location) ?? ".", "koskenkorva.bundle"); if (!File.Exists(text)) { Plugin.Log.LogWarning((object)"koskenkorva.bundle is missing from the plugin folder."); return (null, null); } try { AssetBundle val = AssetBundle.LoadFromFile(text); if (!Object.op_Implicit((Object)(object)val)) { Plugin.Log.LogWarning((object)"koskenkorva.bundle could not be opened."); return (null, null); } GameObject[] array = val.LoadAllAssets(); foreach (GameObject val2 in array) { MeshFilter val3 = (Object.op_Implicit((Object)(object)val2) ? val2.GetComponentInChildren(true) : null); if (Object.op_Implicit((Object)(object)val3) && Object.op_Implicit((Object)(object)val3.sharedMesh)) { Vector3 localScale = val2.transform.localScale; Vector3 localScale2 = ((Component)val3).transform.localScale; if (!Approximately(localScale, Vector3.one) || !Approximately(localScale2, Vector3.one)) { Plugin.Log.LogWarning((object)($"The bundled prefab is scaled ({localScale.x:0.###},{localScale.y:0.###},{localScale.z:0.###}) " + $"with the mesh at ({localScale2.x:0.###},{localScale2.y:0.###},{localScale2.z:0.###}). That scale " + "is ignored - set the size on the model importer's Scale Factor instead.")); } Renderer component = ((Component)val3).GetComponent(); return (val3.sharedMesh, Object.op_Implicit((Object)(object)component) ? component.sharedMaterial : null); } } Mesh val4 = ((IEnumerable)val.LoadAllAssets()).FirstOrDefault((Func)((Mesh m) => Object.op_Implicit((Object)(object)m))); Material item = ((IEnumerable)val.LoadAllAssets()).FirstOrDefault((Func)((Material m) => Object.op_Implicit((Object)(object)m))); if (!Object.op_Implicit((Object)(object)val4)) { Plugin.Log.LogWarning((object)"koskenkorva.bundle holds no mesh."); } return (val4, item); } catch (Exception ex) { Plugin.Log.LogWarning((object)("koskenkorva.bundle failed to load: " + ex.Message)); return (null, null); } } private static void CheckShader(Material material) { if (Object.op_Implicit((Object)(object)material) && (!Object.op_Implicit((Object)(object)material.shader) || ((Object)material.shader).name == "Hidden/InternalErrorShader")) { Plugin.Log.LogError((object)"The bundle's shader did not load, so the bottle will be magenta. Usual causes: the bundle was built by an editor other than 6000.4.4f1, the shader was not a dependency of the tagged prefab, or its name collides with one already in the game."); } } private static Material CloneMaterialFrom(Item item) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown Renderer val = (Object.op_Implicit((Object)(object)item) ? ((Component)item).GetComponentInChildren(true) : null); if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.sharedMaterial)) { return null; } return new Material(val.sharedMaterial) { name = "KoskenkorvaBottle" }; } } [HarmonyPatch(typeof(Bait), "SetBaitInfo")] internal static class SetBaitInfo_Patch { private static void Postfix(Bait __instance) { Models.Materialise(__instance._meshFilter); } } [HarmonyPatch(typeof(BaitSlot), "SetBait")] internal static class SetBait_Patch { private static void Postfix(BaitSlot __instance) { Models.Materialise(((InventorySlot)__instance)._filter); } } [HarmonyPatch(typeof(QuestInteractable), "SetQuest")] internal static class SetQuest_Patch { private static void Postfix(QuestInteractable __instance) { Models.Materialise(__instance._meshToUpdate); } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }