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 PaintingTextures { get; private set; } = Array.Empty(); 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?)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 list = new List(); 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 AtlasCache = new Dictionary(); [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); } } } }