Decompiled source of GWYFCustomPaintings v0.4.0

plugins/GWYFCustomPaintings.dll

Decompiled 6 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("GWYFCustomPaintings")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.4.0.0")]
[assembly: AssemblyInformationalVersion("0.4.0")]
[assembly: AssemblyProduct("GWYFCustomPaintings")]
[assembly: AssemblyTitle("GWYFCustomPaintings")]
[assembly: AssemblyVersion("0.4.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 GWYFCustomPaintings
{
	internal readonly struct PaintingSlot
	{
		public readonly string Id;

		public readonly int X;

		public readonly int Y;

		public readonly int W;

		public readonly int H;

		public PaintingSlot(string id, int x, int y, int w, int h)
		{
			Id = id;
			X = x;
			Y = y;
			W = w;
			H = h;
		}
	}
	internal static class PaintingSlots
	{
		public sealed class Atlas
		{
			public string MaterialName;

			public int RefSize;

			public PaintingSlot[] Slots;
		}

		public static readonly List<Atlas> All = new List<Atlas>
		{
			new Atlas
			{
				MaterialName = "Paintings",
				RefSize = 1024,
				Slots = new PaintingSlot[10]
				{
					new PaintingSlot("casino_01", 12, 9, 300, 270),
					new PaintingSlot("casino_02", 4, 294, 315, 221),
					new PaintingSlot("casino_03", 332, 0, 249, 571),
					new PaintingSlot("casino_04", 596, 191, 272, 385),
					new PaintingSlot("casino_05", 886, 16, 122, 183),
					new PaintingSlot("casino_06", 904, 205, 94, 140),
					new PaintingSlot("casino_07", 915, 355, 85, 117),
					new PaintingSlot("casino_08", 0, 538, 250, 210),
					new PaintingSlot("casino_09", 0, 749, 251, 210),
					new PaintingSlot("casino_10", 252, 734, 257, 232)
				}
			},
			new Atlas
			{
				MaterialName = "Paintings_Win",
				RefSize = 2048,
				Slots = new PaintingSlot[12]
				{
					new PaintingSlot("win_01", 800, 0, 185, 175),
					new PaintingSlot("win_02", 527, 229, 450, 208),
					new PaintingSlot("win_03", 544, 441, 441, 248),
					new PaintingSlot("win_04", 275, 231, 230, 414),
					new PaintingSlot("win_05", 25, 519, 226, 230),
					new PaintingSlot("win_06", 437, 723, 408, 298),
					new PaintingSlot("win_07", 27, 769, 382, 300),
					new PaintingSlot("win_08", 908, 795, 218, 187),
					new PaintingSlot("win_09", 35, 1089, 714, 252),
					new PaintingSlot("win_10", 776, 1088, 144, 189),
					new PaintingSlot("win_11", 1419, 1115, 629, 322),
					new PaintingSlot("win_12", 9, 1379, 428, 642)
				}
			}
		};
	}
	[BepInPlugin("lmc.gwyf.custompaintings", "GWYF Custom Paintings", "0.4.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "lmc.gwyf.custompaintings";

		public const string Name = "GWYF Custom Paintings";

		public const string Version = "0.4.0";

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> CropToFill;

		internal static ConfigEntry<Key> ReloadKey;

		internal static ConfigEntry<int> AtlasScale;

		internal static ConfigEntry<string> SquareTextures;

		private static readonly string[] Extensions = new string[3] { ".png", ".jpg", ".jpeg" };

		private string _imagesDir;

		private string _texturesDir;

		private readonly Dictionary<string, Texture> _originals = new Dictionary<string, Texture>();

		private readonly Dictionary<string, Texture2D> _patched = new Dictionary<string, Texture2D>();

		private readonly Dictionary<string, Texture2D> _swaps = new Dictionary<string, Texture2D>();

		private readonly Dictionary<(Material mat, string prop), Texture> _swapped = new Dictionary<(Material, string), Texture>();

		private readonly Dictionary<MeshFilter, Mesh> _reshaped = new Dictionary<MeshFilter, Mesh>();

		private readonly Dictionary<Mesh, Mesh> _squareCache = new Dictionary<Mesh, Mesh>();

		private void Awake()
		{
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			CropToFill = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "CropToFill", true, "true: la imagen llena el cuadro recortando lo que sobra. false: se estira para caber exacta.");
			ReloadKey = ((BaseUnityPlugin)this).Config.Bind<Key>("General", "ReloadKey", (Key)99, "Tecla para recargar las imágenes de la carpeta Cuadros sin reiniciar el juego.");
			SquareTextures = ((BaseUnityPlugin)this).Config.Bind<string>("Texturas", "SquareTextures", "T_JeffBooth_Image", "Texturas (separadas por coma) cuyos objetos se cambian por una placa cuadrada cuando tienen imagen propia, para que la imagen se vea completa en vez de con la silueta original.");
			AtlasScale = ((BaseUnityPlugin)this).Config.Bind<int>("General", "AtlasScale", 2, new ConfigDescription("Multiplica la resolución del atlas cuando hay imágenes propias (más nitidez, más memoria).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 4), Array.Empty<object>()));
			_imagesDir = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), "Cuadros");
			Directory.CreateDirectory(_imagesDir);
			_texturesDir = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), "Texturas");
			Directory.CreateDirectory(_texturesDir);
			SceneManager.sceneLoaded += delegate
			{
				ApplyAll(rebuild: false);
			};
			Log.LogInfo((object)("GWYF Custom Paintings 0.4.0 cargado. Imágenes en: " + _imagesDir + " y " + _texturesDir));
		}

		private void Update()
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			Keyboard current = Keyboard.current;
			if (current != null && ((ButtonControl)current[ReloadKey.Value]).wasPressedThisFrame)
			{
				Log.LogInfo((object)"Recargando cuadros...");
				ApplyAll(rebuild: true);
			}
		}

		private void ApplyAll(bool rebuild)
		{
			if (rebuild)
			{
				foreach (Texture2D value2 in _patched.Values)
				{
					if ((Object)(object)value2 != (Object)null)
					{
						Object.Destroy((Object)(object)value2);
					}
				}
				_patched.Clear();
				foreach (KeyValuePair<(Material, string), Texture> item in _swapped)
				{
					if ((Object)(object)item.Key.Item1 != (Object)null)
					{
						item.Key.Item1.SetTexture(item.Key.Item2, item.Value);
					}
				}
				_swapped.Clear();
				foreach (Texture2D value3 in _swaps.Values)
				{
					if ((Object)(object)value3 != (Object)null)
					{
						Object.Destroy((Object)(object)value3);
					}
				}
				_swaps.Clear();
				foreach (KeyValuePair<MeshFilter, Mesh> item2 in _reshaped)
				{
					if ((Object)(object)item2.Key != (Object)null)
					{
						item2.Key.sharedMesh = item2.Value;
					}
				}
				_reshaped.Clear();
			}
			Material[] array = Resources.FindObjectsOfTypeAll<Material>();
			foreach (Material val in array)
			{
				SwapTextures(val);
				PaintingSlots.Atlas atlas = FindAtlas(((Object)val).name);
				if (atlas == null)
				{
					continue;
				}
				if (!_patched.TryGetValue(atlas.MaterialName, out var value))
				{
					Texture original = GetOriginal(atlas.MaterialName, val);
					if ((Object)(object)original == (Object)null)
					{
						continue;
					}
					value = BuildAtlas(atlas, original);
					_patched[atlas.MaterialName] = value;
				}
				Texture val2 = (Texture)(((Object)(object)value != (Object)null) ? ((object)value) : ((object)_originals[atlas.MaterialName]));
				if ((Object)(object)val.mainTexture != (Object)(object)val2)
				{
					SetTexture(val, val2);
				}
			}
			ReshapeMeshes();
		}

		private void ReshapeMeshes()
		{
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			HashSet<string> hashSet = new HashSet<string>();
			string[] array = SquareTextures.Value.Split(',');
			foreach (string text in array)
			{
				if (text.Trim().Length > 0)
				{
					hashSet.Add(text.Trim());
				}
			}
			HashSet<Material> hashSet2 = new HashSet<Material>();
			foreach (KeyValuePair<(Material, string), Texture> item in _swapped)
			{
				if ((Object)(object)item.Value != (Object)null && hashSet.Contains(((Object)item.Value).name))
				{
					hashSet2.Add(item.Key.Item1);
				}
			}
			if (hashSet2.Count == 0)
			{
				return;
			}
			int num = 0;
			MeshFilter[] array2 = Resources.FindObjectsOfTypeAll<MeshFilter>();
			foreach (MeshFilter val in array2)
			{
				Scene scene = ((Component)val).gameObject.scene;
				if (!((Scene)(ref scene)).IsValid() || (Object)(object)val.sharedMesh == (Object)null || _reshaped.ContainsKey(val))
				{
					continue;
				}
				MeshRenderer component = ((Component)val).GetComponent<MeshRenderer>();
				if ((Object)(object)component == (Object)null)
				{
					continue;
				}
				bool flag = false;
				Material[] sharedMaterials = ((Renderer)component).sharedMaterials;
				foreach (Material val2 in sharedMaterials)
				{
					if ((Object)(object)val2 != (Object)null && hashSet2.Contains(val2))
					{
						flag = true;
						break;
					}
				}
				if (flag)
				{
					if (!_squareCache.TryGetValue(val.sharedMesh, out var value))
					{
						value = (_squareCache[val.sharedMesh] = BuildSquare(val.sharedMesh));
					}
					_reshaped[val] = val.sharedMesh;
					val.sharedMesh = value;
					num++;
				}
			}
			if (num > 0)
			{
				Log.LogInfo((object)$"{num} objeto(s) cambiados a placa cuadrada");
			}
		}

		private static Mesh BuildSquare(Mesh original)
		{
			//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_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: 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_0091: Expected O, but got Unknown
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: 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_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: 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_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: 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_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			Bounds bounds = original.bounds;
			float num = Mathf.Min(((Bounds)(ref bounds)).size.x, ((Bounds)(ref bounds)).size.y) / 2f;
			float z = ((Bounds)(ref bounds)).min.z;
			float z2 = ((Bounds)(ref bounds)).max.z;
			float x = ((Bounds)(ref bounds)).center.x;
			float y = ((Bounds)(ref bounds)).center.y;
			float num2 = x - num;
			float num3 = x + num;
			float num4 = y - num;
			float num5 = y + num;
			Mesh val = new Mesh
			{
				name = ((Object)original).name + "_Square"
			};
			val.vertices = (Vector3[])(object)new Vector3[8]
			{
				new Vector3(num2, num4, z),
				new Vector3(num3, num4, z),
				new Vector3(num3, num5, z),
				new Vector3(num2, num5, z),
				new Vector3(num2, num4, z2),
				new Vector3(num3, num4, z2),
				new Vector3(num3, num5, z2),
				new Vector3(num2, num5, z2)
			};
			val.uv = (Vector2[])(object)new Vector2[8]
			{
				new Vector2(0f, 0f),
				new Vector2(1f, 0f),
				new Vector2(1f, 1f),
				new Vector2(0f, 1f),
				new Vector2(1f, 0f),
				new Vector2(0f, 0f),
				new Vector2(0f, 1f),
				new Vector2(1f, 1f)
			};
			val.triangles = new int[12]
			{
				0, 2, 1, 0, 3, 2, 4, 5, 6, 4,
				6, 7
			};
			val.RecalculateNormals();
			val.RecalculateTangents();
			val.RecalculateBounds();
			return val;
		}

		private void SwapTextures(Material mat)
		{
			string[] texturePropertyNames = mat.GetTexturePropertyNames();
			foreach (string text in texturePropertyNames)
			{
				Texture texture = mat.GetTexture(text);
				if ((Object)(object)texture == (Object)null || _swapped.ContainsKey((mat, text)))
				{
					continue;
				}
				if (!_swaps.TryGetValue(((Object)texture).name, out var value))
				{
					value = LoadImage(_texturesDir, ((Object)texture).name, mipmaps: true);
					if ((Object)(object)value != (Object)null)
					{
						((Object)value).name = ((Object)texture).name + "_Custom";
						Log.LogInfo((object)("Textura " + ((Object)texture).name + " reemplazada"));
					}
					_swaps[((Object)texture).name] = value;
				}
				if (!((Object)(object)value == (Object)null))
				{
					_swapped[(mat, text)] = texture;
					mat.SetTexture(text, (Texture)(object)value);
				}
			}
		}

		private static PaintingSlots.Atlas FindAtlas(string materialName)
		{
			string text = materialName.Replace(" (Instance)", "");
			foreach (PaintingSlots.Atlas item in PaintingSlots.All)
			{
				if (item.MaterialName == text)
				{
					return item;
				}
			}
			return null;
		}

		private Texture GetOriginal(string key, Material mat)
		{
			if (_originals.TryGetValue(key, out var value))
			{
				return value;
			}
			value = mat.mainTexture;
			if ((Object)(object)value == (Object)null)
			{
				return null;
			}
			_originals[key] = value;
			return value;
		}

		private static void SetTexture(Material mat, Texture tex)
		{
			mat.mainTexture = tex;
			if (mat.HasProperty("_MainTex"))
			{
				mat.SetTexture("_MainTex", tex);
			}
			if (mat.HasProperty("_BaseMap"))
			{
				mat.SetTexture("_BaseMap", tex);
			}
		}

		private Texture2D BuildAtlas(PaintingSlots.Atlas atlas, Texture original)
		{
			List<(PaintingSlot, Texture2D)> list = new List<(PaintingSlot, Texture2D)>();
			PaintingSlot[] slots = atlas.Slots;
			for (int i = 0; i < slots.Length; i++)
			{
				PaintingSlot item = slots[i];
				Texture2D val = LoadImage(_imagesDir, item.Id, mipmaps: false);
				if ((Object)(object)val != (Object)null)
				{
					list.Add((item, val));
				}
			}
			if (list.Count == 0)
			{
				return null;
			}
			int num = Mathf.Max(original.width, atlas.RefSize * AtlasScale.Value);
			Texture2D val2 = ReadableCopy(original, num, num);
			float num2 = (float)((Texture)val2).width / (float)atlas.RefSize;
			foreach (var item4 in list)
			{
				PaintingSlot item2 = item4.Item1;
				Texture2D item3 = item4.Item2;
				int num3 = Mathf.RoundToInt((float)item2.W * num2);
				int num4 = Mathf.RoundToInt((float)item2.H * num2);
				int num5 = Mathf.RoundToInt((float)item2.X * num2);
				int num6 = ((Texture)val2).height - Mathf.RoundToInt((float)item2.Y * num2) - num4;
				val2.SetPixels(num5, num6, num3, num4, Resample(item3, num3, num4, CropToFill.Value));
				Object.Destroy((Object)(object)item3);
				Log.LogInfo((object)("  " + item2.Id + " reemplazado"));
			}
			val2.Apply(true);
			((Object)val2).name = ((Object)original).name + "_Custom";
			Log.LogInfo((object)$"{atlas.MaterialName}: {list.Count} cuadro(s) personalizados");
			return val2;
		}

		private Texture2D LoadImage(string dir, string id, bool mipmaps)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			string[] extensions = Extensions;
			foreach (string text in extensions)
			{
				string text2 = Path.Combine(dir, id + text);
				if (!File.Exists(text2))
				{
					continue;
				}
				Texture2D val = new Texture2D(2, 2, (TextureFormat)4, mipmaps);
				try
				{
					if (ImageConversion.LoadImage(val, File.ReadAllBytes(text2), mipmaps))
					{
						return val;
					}
					Log.LogWarning((object)("No se pudo leer " + text2));
				}
				catch (Exception ex)
				{
					Log.LogWarning((object)("Error leyendo " + text2 + ": " + ex.Message));
				}
				Object.Destroy((Object)(object)val);
			}
			return null;
		}

		private static Texture2D ReadableCopy(Texture src, int width, int height)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			RenderTexture temporary = RenderTexture.GetTemporary(width, height, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)2);
			RenderTexture active = RenderTexture.active;
			Graphics.Blit(src, temporary);
			RenderTexture.active = temporary;
			Texture2D val = new Texture2D(width, height, (TextureFormat)4, true);
			val.ReadPixels(new Rect(0f, 0f, (float)width, (float)height), 0, 0);
			RenderTexture.active = active;
			RenderTexture.ReleaseTemporary(temporary);
			return val;
		}

		private static Color[] Resample(Texture2D img, int w, int h, bool crop)
		{
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			float num = 0f;
			float num2 = 0f;
			float num3 = 1f;
			float num4 = 1f;
			if (crop)
			{
				float num5 = (float)((Texture)img).width / (float)((Texture)img).height;
				float num6 = (float)w / (float)h;
				if (num5 > num6)
				{
					num3 = num6 / num5;
					num = (1f - num3) / 2f;
				}
				else
				{
					num4 = num5 / num6;
					num2 = (1f - num4) / 2f;
				}
			}
			Color[] array = (Color[])(object)new Color[w * h];
			for (int i = 0; i < h; i++)
			{
				float num7 = num2 + ((float)i + 0.5f) / (float)h * num4;
				for (int j = 0; j < w; j++)
				{
					array[i * w + j] = img.GetPixelBilinear(num + ((float)j + 0.5f) / (float)w * num3, num7);
				}
			}
			return array;
		}
	}
}