Decompiled source of CustomPaintings v1.0.7

CustomPaintings.dll

Decompiled 3 days ago
using System;
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.Threading.Tasks;
using BepInEx;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
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("CustomPaintings")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("CustomPaintings")]
[assembly: AssemblyTitle("CustomPaintings")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 CustomPaintings
{
	[BepInPlugin("UnderratedJunk.CustomPaintings", "CustomPaintings", "1.0.7")]
	public class CustomPaintings : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(LoadingUI), "LevelAnimationComplete")]
		public class PaintingSwapPatch
		{
			private static void Postfix()
			{
				Task.Run(async delegate
				{
					int waited = 0;
					int interval = 50;
					while (!receivedSeed.HasValue && waited < maxWaitTimeMs)
					{
						await Task.Delay(interval);
						waited += interval;
					}
					if (receivedSeed.HasValue)
					{
						logger.LogInfo($"[Postfix] Client using received seed: {receivedSeed.Value}");
						CustomPaintingsSwap.ReceivedSeed = receivedSeed.Value;
						receivedSeed = null;
					}
					else
					{
						logger.LogWarning("[Postfix] Client did not receive seed in time. Proceeding without it.");
					}
					swapper.ReplacePaintings();
				});
			}

			private static void Prefix()
			{
				if (swapper.GetModState() == CustomPaintingsSwap.ModState.Client)
				{
					PhotonNetwork.AddCallbackTarget((object)sync);
				}
				if (swapper.GetModState() == CustomPaintingsSwap.ModState.Host)
				{
					CustomPaintingsSwap.HostSeed = Random.Range(0, int.MaxValue);
					logger.LogInfo($"Generated Hostseed: {CustomPaintingsSwap.HostSeed}");
					PhotonNetwork.AddCallbackTarget((object)sync);
					sync.SendSeed(CustomPaintingsSwap.HostSeed);
				}
			}
		}

		[HarmonyPatch(typeof(NetworkConnect), "TryJoiningRoom")]
		public class JoinLobbyPatch
		{
			private static void Prefix()
			{
				if (swapper.GetModState() != 0)
				{
					swapper.SetState(CustomPaintingsSwap.ModState.Client);
				}
			}
		}

		[HarmonyPatch(typeof(SteamManager), "HostLobby")]
		public class HostLobbyPatch
		{
			private static bool Prefix()
			{
				swapper.SetState(CustomPaintingsSwap.ModState.Host);
				return true;
			}
		}

		[HarmonyPatch(typeof(SteamManager), "LeaveLobby")]
		public class LeaveLobbyPatch
		{
			private static void Postfix()
			{
				PhotonNetwork.RemoveCallbackTarget((object)sync);
				swapper.SetState(CustomPaintingsSwap.ModState.SinglePlayer);
			}
		}

		private static Logger logger;

		private static CustomPaintingsLoader loader;

		private static CustomPaintingsSwap swapper;

		private static CustomPaintingsSync sync;

		public static int? receivedSeed = null;

		public static readonly int maxWaitTimeMs = 1000;

		private readonly Harmony harmony = new Harmony("UnderratedJunk.CustomPaintings");

		private void Awake()
		{
			logger = new Logger("CustomPaintings");
			logger.LogInfo("CustomPaintings mod initialized.");
			loader = new CustomPaintingsLoader(logger);
			loader.LoadImagesFromAllPlugins();
			swapper = new CustomPaintingsSwap(logger, loader);
			sync = new CustomPaintingsSync(logger);
			harmony.PatchAll();
		}
	}
	public class CustomPaintingsLoader
	{
		private const string IMAGE_FOLDER_NAME = "CustomPaintings";

		private readonly Logger logger;

		public List<Material> LoadedMaterials { get; } = new List<Material>();


		public CustomPaintingsLoader(Logger logger)
		{
			this.logger = logger;
		}

		public void LoadImagesFromAllPlugins()
		{
			string text = Path.Combine(Paths.PluginPath);
			if (!Directory.Exists(text))
			{
				logger.LogWarning("Plugins directory not found: " + text);
				return;
			}
			string[] directories = Directory.GetDirectories(text, "CustomPaintings", SearchOption.AllDirectories);
			if (directories.Length == 0)
			{
				logger.LogWarning("No 'CustomPaintings' folders found in plugins.");
				return;
			}
			string[] array = directories;
			foreach (string text2 in array)
			{
				logger.LogInfo("Loading images from: " + text2);
				LoadImagesFromDirectory(text2);
			}
		}

		private void LoadImagesFromDirectory(string directoryPath)
		{
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Expected O, but got Unknown
			if (!Directory.Exists(directoryPath))
			{
				logger.LogWarning("Directory does not exist: " + directoryPath);
				return;
			}
			string[] validExtensions = new string[4] { ".png", ".jpg", ".jpeg", ".bmp" };
			string[] array = (from file in Directory.EnumerateFiles(directoryPath, "*.*", SearchOption.AllDirectories)
				where validExtensions.Contains(Path.GetExtension(file).ToLower())
				select file).ToArray();
			if (array.Length == 0)
			{
				logger.LogWarning("No images found in " + directoryPath);
				return;
			}
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i];
				Texture2D val = LoadTextureFromFile(text);
				if ((Object)(object)val != (Object)null)
				{
					Material item = new Material(Shader.Find("Standard"))
					{
						mainTexture = (Texture)(object)val
					};
					LoadedMaterials.Add(item);
					logger.LogInfo($"Loaded image #{i + 1}: {Path.GetFileName(text)}");
				}
				else
				{
					logger.LogWarning($"Failed to load image #{i + 1}: {text}");
				}
			}
			logger.LogInfo($"Total images loaded: {LoadedMaterials.Count}");
		}

		private Texture2D LoadTextureFromFile(string filePath)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Expected O, but got Unknown
			byte[] array = File.ReadAllBytes(filePath);
			Texture2D val = new Texture2D(2, 2);
			if (ImageConversion.LoadImage(val, array))
			{
				val.Apply();
				return val;
			}
			return null;
		}
	}
	public class CustomPaintingsSwap
	{
		public enum ModState
		{
			Host,
			Client,
			SinglePlayer
		}

		private readonly Logger logger;

		private readonly CustomPaintingsLoader loader;

		private static int randomSeed = 0;

		public static int HostSeed = 0;

		public static int ReceivedSeed = 0;

		public static int Seed = 0;

		private int paintingsChangedCount;

		private static ModState currentState = ModState.SinglePlayer;

		public ModState GetModState()
		{
			return currentState;
		}

		public CustomPaintingsSwap(Logger logger, CustomPaintingsLoader loader)
		{
			this.logger = logger;
			this.loader = loader;
			logger.LogInfo($"Initial ModState: {currentState}");
			if (randomSeed == 0)
			{
				randomSeed = Random.Range(0, int.MaxValue);
				logger.LogInfo($"Generated initial random seed: {randomSeed}");
			}
		}

		public void ReplacePaintings()
		{
			//IL_0035: 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_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			if (currentState == ModState.SinglePlayer)
			{
				Seed = randomSeed;
			}
			if (currentState == ModState.Host)
			{
				Seed = HostSeed;
			}
			if (currentState == ModState.Client)
			{
				Seed = ReceivedSeed;
			}
			Scene activeScene = SceneManager.GetActiveScene();
			logger.LogInfo($"Applying seed {Seed} for painting swaps in scene: {((Scene)(ref activeScene)).name}");
			logger.LogInfo("Replacing all materials containing 'painting' with custom images...");
			paintingsChangedCount = 0;
			int num = 0;
			Scene activeScene2 = SceneManager.GetActiveScene();
			GameObject[] rootGameObjects = ((Scene)(ref activeScene2)).GetRootGameObjects();
			for (int i = 0; i < rootGameObjects.Length; i++)
			{
				MeshRenderer[] componentsInChildren = rootGameObjects[i].GetComponentsInChildren<MeshRenderer>();
				foreach (MeshRenderer val in componentsInChildren)
				{
					Material[] sharedMaterials = ((Renderer)val).sharedMaterials;
					for (int k = 0; k < sharedMaterials.Length; k++)
					{
						num++;
						if ((Object)(object)sharedMaterials[k] != (Object)null && ((Object)sharedMaterials[k]).name.ToLower().Contains("painting") && !((Object)sharedMaterials[k]).name.Contains("Painting Frame Vertical Gold") && !((Object)sharedMaterials[k]).name.Contains("Painting Frame Horizontal Gold") && loader.LoadedMaterials.Count > 0)
						{
							int index = Mathf.Abs((Seed + paintingsChangedCount) % loader.LoadedMaterials.Count);
							sharedMaterials[k] = loader.LoadedMaterials[index];
							paintingsChangedCount++;
						}
					}
					((Renderer)val).sharedMaterials = sharedMaterials;
				}
			}
			logger.LogInfo($"Total materials checked: {num}");
			logger.LogInfo($"Total paintings changed in this scene: {paintingsChangedCount}");
			logger.LogInfo($"RandomSeed = {randomSeed}");
			logger.LogInfo($"HostSeed = {HostSeed}");
			logger.LogInfo($"ReceivedSeed = {ReceivedSeed}");
		}

		public void SetState(ModState newState)
		{
			currentState = newState;
			logger.LogInfo($"Mod state set to: {currentState}");
		}
	}
	public class CustomPaintingsSync : MonoBehaviourPunCallbacks, IOnEventCallback
	{
		private readonly Logger logger;

		public const byte SeedEventCode = 1;

		public CustomPaintingsSync(Logger logger)
		{
			this.logger = logger;
		}

		public void SendSeed(int seed)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: 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_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			object[] array = new object[1] { seed };
			logger.LogInfo("sharing seed with other clients");
			RaiseEventOptions val = new RaiseEventOptions
			{
				Receivers = (ReceiverGroup)1,
				CachingOption = (EventCaching)4
			};
			PhotonNetwork.RaiseEvent((byte)1, (object)array, val, SendOptions.SendReliable);
		}

		public void OnEvent(EventData photonEvent)
		{
			if (photonEvent.Code == 1)
			{
				int num = (int)((object[])photonEvent.CustomData)[0];
				logger.LogInfo($"Received seed: {num}");
				CustomPaintingsSwap.ReceivedSeed = num;
			}
		}
	}
	public class Logger
	{
		private readonly string logFilePath;

		private readonly ManualLogSource logSource;

		public Logger(string modName)
		{
			string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			logFilePath = Path.Combine(directoryName, modName + "_log.txt");
			if (File.Exists(logFilePath))
			{
				File.Delete(logFilePath);
			}
			logSource = Logger.CreateLogSource(modName);
		}

		public void LogInfo(string message)
		{
			WriteLog("INFO", message);
			logSource.LogInfo((object)message);
		}

		public void LogWarning(string message)
		{
			WriteLog("WARNING", message);
			logSource.LogWarning((object)message);
		}

		public void LogError(string message)
		{
			WriteLog("ERROR", message);
			logSource.LogError((object)message);
		}

		private void WriteLog(string level, string message)
		{
			string text = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} [{level}] {message}";
			File.AppendAllText(logFilePath, text + Environment.NewLine);
		}

		public void LogMaterial(Material material)
		{
			if ((Object)(object)material != (Object)null && ((Object)material).name.ToLower().Contains("painting"))
			{
				LogInfo("Material containing 'painting': " + ((Object)material).name);
			}
		}

		public void ClearLog()
		{
			if (File.Exists(logFilePath))
			{
				File.Delete(logFilePath);
			}
		}
	}
}