Decompiled source of Painting Texture Replacer v1.0.0

PaintingReplacer.dll

Decompiled a day 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.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[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("PaintingReplacer")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("PaintingReplacer")]
[assembly: AssemblyTitle("PaintingReplacer")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 PaintingReplacer
{
	[BepInPlugin("RKMods.PaintingReplacer", "Painting Texture Replacer", "1.0.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "RKMods.PaintingReplacer";

		public const string PluginName = "Painting Texture Replacer";

		public const string PluginVersion = "1.0.0";

		private static readonly Random TextureRandom = new Random();

		private Harmony? _harmony;

		internal static ManualLogSource ModLogger { get; private set; } = null;

		internal static IReadOnlyList<PaintingTexture> PaintingTextures { get; private set; } = Array.Empty<PaintingTexture>();

		private void Awake()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			ModLogger = ((BaseUnityPlugin)this).Logger;
			LoadPaintingTextures();
			_harmony = new Harmony("RKMods.PaintingReplacer");
			_harmony.PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Painting Texture Replacer 1.0.0 successfully loaded.");
		}

		private void LoadPaintingTextures()
		{
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Expected O, but got Unknown
			string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
			if (string.IsNullOrEmpty(directoryName))
			{
				((BaseUnityPlugin)this).Logger.LogError((object)"Could not determine the PaintingReplacer plugin directory; painting PNG files cannot be loaded.");
				return;
			}
			string[] files = Directory.GetFiles(directoryName, "painting*.png", SearchOption.TopDirectoryOnly);
			Array.Sort(files, (IComparer<string>?)StringComparer.OrdinalIgnoreCase);
			if (files.Length == 0)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("No painting PNG files were found next to PaintingReplacer.dll in: " + directoryName));
				((BaseUnityPlugin)this).Logger.LogError((object)"Add one or more files named painting.png, painting1.png, painting2.png, and so on.");
				return;
			}
			List<PaintingTexture> list = new List<PaintingTexture>();
			string[] array = files;
			foreach (string text in array)
			{
				try
				{
					byte[] imageData = File.ReadAllBytes(text);
					Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
					if (!val.LoadImage(imageData))
					{
						Object.Destroy((Object)(object)val);
						((BaseUnityPlugin)this).Logger.LogError((object)("Painting image could not be decoded and was skipped: " + text));
						continue;
					}
					string fileName = Path.GetFileName(text);
					((Object)val).name = "PaintingReplacer_" + Path.GetFileNameWithoutExtension(fileName);
					list.Add(new PaintingTexture(fileName, val));
					((BaseUnityPlugin)this).Logger.LogInfo((object)("Painting image successfully loaded: " + fileName));
				}
				catch (Exception arg)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)$"Failed to load painting image '{text}': {arg}");
				}
			}
			PaintingTextures = list;
			if (list.Count > 0)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"Successfully loaded {list.Count} painting image(s).");
			}
		}

		internal static PaintingTexture? GetRandomPaintingTexture()
		{
			if (PaintingTextures.Count == 0)
			{
				return null;
			}
			return PaintingTextures[TextureRandom.Next(PaintingTextures.Count)];
		}
	}
	internal sealed class PaintingTexture
	{
		internal string FileName { get; }

		internal Texture2D Texture { get; }

		internal PaintingTexture(string fileName, Texture2D texture)
		{
			FileName = fileName;
			Texture = texture;
		}
	}
	internal static class Texture2DLoadImageCompatibility
	{
		internal static bool LoadImage(this Texture2D texture, byte[] imageData)
		{
			MethodInfo? obj = Type.GetType("UnityEngine.ImageConversion, UnityEngine.ImageConversionModule", throwOnError: false)?.GetMethod("LoadImage", BindingFlags.Static | BindingFlags.Public, null, new Type[3]
			{
				typeof(Texture2D),
				typeof(byte[]),
				typeof(bool)
			}, null);
			if (obj == null)
			{
				throw new MissingMethodException("UnityEngine.ImageConversion.LoadImage(Texture2D, byte[], bool) was not found.");
			}
			object obj2 = obj.Invoke(null, new object[3] { texture, imageData, false });
			bool flag = default(bool);
			int num;
			if (obj2 is bool)
			{
				flag = (bool)obj2;
				num = 1;
			}
			else
			{
				num = 0;
			}
			return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
		}
	}
}
namespace PaintingReplacer.Patches
{
	[HarmonyPatch(typeof(GrabbableObject), "SetScrapValue")]
	internal static class PaintingPatch
	{
		private const int AtlasSize = 512;

		private static readonly Rect PaintingArea = new Rect(264f, 20f, 243f, 324f);

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

		[HarmonyPostfix]
		private static void SetScrapValuePostfix(GrabbableObject __instance)
		{
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Expected O, but got Unknown
			if ((Object)(object)__instance == (Object)null || (Object)(object)__instance.itemProperties == (Object)null || __instance.itemProperties.itemName != "Painting")
			{
				return;
			}
			PaintingTexture randomPaintingTexture = Plugin.GetRandomPaintingTexture();
			if (randomPaintingTexture == null)
			{
				return;
			}
			Material[] materialVariants = __instance.itemProperties.materialVariants;
			if (materialVariants == null || materialVariants.Length == 0)
			{
				Plugin.ModLogger.LogWarning((object)"Painting found, but its expected materialVariants do not exist.");
				return;
			}
			if (materialVariants.Length < 2)
			{
				Plugin.ModLogger.LogWarning((object)$"Painting has {materialVariants.Length} materialVariant(s); 2 were expected.");
			}
			if ((Object)(object)__instance.mainObjectRenderer == (Object)null)
			{
				Plugin.ModLogger.LogWarning((object)"Painting found, but its mainObjectRenderer is missing.");
				return;
			}
			Material sharedMaterial = ((Renderer)__instance.mainObjectRenderer).sharedMaterial;
			if ((Object)(object)sharedMaterial == (Object)null)
			{
				Plugin.ModLogger.LogWarning((object)"Painting found, but its selected vanilla material is missing.");
			}
			else if (!((Object)sharedMaterial).name.StartsWith("PaintingReplacer_Instance"))
			{
				Texture2D orCreateAtlas = GetOrCreateAtlas(sharedMaterial, randomPaintingTexture);
				if (!((Object)(object)orCreateAtlas == (Object)null))
				{
					Material val = new Material(sharedMaterial)
					{
						name = "PaintingReplacer_Instance_" + ((Object)sharedMaterial).name
					};
					val.mainTexture = (Texture)(object)orCreateAtlas;
					((Renderer)__instance.mainObjectRenderer).sharedMaterial = val;
					Plugin.ModLogger.LogInfo((object)("Painting found and random texture applied: " + randomPaintingTexture.FileName));
				}
			}
		}

		private static Texture2D? GetOrCreateAtlas(Material material, PaintingTexture selectedPainting)
		{
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Expected O, but got Unknown
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			string key = $"{((Object)material).GetInstanceID()}:{((Object)selectedPainting.Texture).GetInstanceID()}";
			if (AtlasCache.TryGetValue(key, out Texture2D value))
			{
				return value;
			}
			Texture mainTexture = material.mainTexture;
			if ((Object)(object)mainTexture == (Object)null)
			{
				Plugin.ModLogger.LogWarning((object)("Painting material '" + ((Object)material).name + "' has no mainTexture to use as an atlas base."));
				return null;
			}
			if (mainTexture.width != 512 || mainTexture.height != 512)
			{
				Plugin.ModLogger.LogWarning((object)($"Painting material '{((Object)material).name}' uses a {mainTexture.width}x{mainTexture.height} texture; " + $"the expected vanilla atlas size is {512}x{512}."));
				return null;
			}
			RenderTexture temporary = RenderTexture.GetTemporary(512, 512, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)0);
			RenderTexture active = RenderTexture.active;
			try
			{
				Graphics.Blit(mainTexture, temporary);
				RenderTexture.active = temporary;
				GL.PushMatrix();
				try
				{
					GL.LoadPixelMatrix(0f, 512f, 512f, 0f);
					Graphics.DrawTexture(PaintingArea, (Texture)(object)selectedPainting.Texture);
				}
				finally
				{
					GL.PopMatrix();
				}
				Texture2D val = new Texture2D(512, 512, (TextureFormat)4, false);
				val.ReadPixels(new Rect(0f, 0f, 512f, 512f), 0, 0, false);
				val.Apply(false, false);
				((Object)val).name = "PaintingReplacer_Atlas_" + ((Object)material).name + "_" + selectedPainting.FileName;
				AtlasCache.Add(key, val);
				return val;
			}
			finally
			{
				RenderTexture.active = active;
				RenderTexture.ReleaseTemporary(temporary);
			}
		}
	}
}