Decompiled source of StrongerBeer v0.1.0

StrongerBeer.dll

Decompiled 2 hours ago
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<StringTable, StringTableEntry>)(object)LocalizationSettings.StringDatabase).GetAllTables((Locale)null).WaitForCompletion())
			{
				if ((Object)(object)item == (Object)null)
				{
					continue;
				}
				foreach (StringTableEntry value in ((DetailedLocalizationTable<StringTableEntry>)(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<MeshRenderer, Material> Borrowed = new Dictionary<MeshRenderer, Material>();

		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<MeshFilter>(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<MeshFilter>();
			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<MeshRenderer>(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<MeshRenderer>(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<MeshFilter>(true);
				foreach (MeshFilter val in componentsInChildren)
				{
					if (IsOriginal(val.sharedMesh))
					{
						return val.sharedMesh;
					}
				}
			}
			Mesh val2 = null;
			Mesh[] array = Resources.FindObjectsOfTypeAll<Mesh>();
			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<Mesh>(_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<GameObject>();
				foreach (GameObject val2 in array)
				{
					MeshFilter val3 = (Object.op_Implicit((Object)(object)val2) ? val2.GetComponentInChildren<MeshFilter>(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<Renderer>();
						return (val3.sharedMesh, Object.op_Implicit((Object)(object)component) ? component.sharedMaterial : null);
					}
				}
				Mesh val4 = ((IEnumerable<Mesh>)val.LoadAllAssets<Mesh>()).FirstOrDefault((Func<Mesh, bool>)((Mesh m) => Object.op_Implicit((Object)(object)m)));
				Material item = ((IEnumerable<Material>)val.LoadAllAssets<Material>()).FirstOrDefault((Func<Material, bool>)((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<Renderer>(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)
		{
		}
	}
}