Decompiled source of FurryPaintings v1.0.0

FurryPaintings.dll

Decompiled 9 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Net;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using CustomPaintings.Configuration;
using FurryPaintings;
using GameNetcodeStuff;
using HarmonyLib;
using LethalLib;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("FurryPaintings")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("FurryPaintings")]
[assembly: AssemblyCopyright("Copyright ©  2024")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("ed6ca998-521e-4059-bbc4-b670e25343f0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace CustomPaintings.Configuration
{
	[Serializable]
	public class Config : SyncedInstance<Config>
	{
		public string directory;

		public string customUrls;

		public bool defaultPaintings;

		public bool forceDownload;

		public int maxTextures;

		public Config(ConfigFile cfg)
		{
			InitInstance(this);
			directory = cfg.Bind<string>("General", "Directory", "plugins/FurryPaintings", "Directory in which the mod will search for the paintings (using BepInEx as root, use / as separator)").Value;
			customUrls = cfg.Bind<string>("General", "Custom Urls", "", "Custom urls of the images to download them as default (separate them with commas, for example: https://i.imgur.com/ePiClDl.png,https://i.imgur.com/yZCdjxh.png)").Value;
			defaultPaintings = cfg.Bind<bool>("General", "Default Paintings", true, "Enable it to use the default paintings of famous works").Value;
			forceDownload = cfg.Bind<bool>("General", "Force Download", false, "Enable it to download the url images in every launch (if it is false, the mod will download the textures only when creates the directory)").Value;
			maxTextures = cfg.Bind<int>("General", "Max Textures", 5, "Number of textures per game to prevent duplicated ones (try to avoid high numbers)").Value;
		}

		public static void RequestSync()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			if (!SyncedInstance<Config>.IsClient)
			{
				return;
			}
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(SyncedInstance<Config>.IntSize, (Allocator)2, -1);
			try
			{
				SyncedInstance<Config>.MessageManager.SendNamedMessage("FurryPaintings_OnRequestConfigSync", 0uL, val, (NetworkDelivery)3);
			}
			finally
			{
				((FastBufferWriter)(ref val)).Dispose();
			}
		}

		public static void OnRequestSync(ulong clientId, FastBufferReader _)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			if (!SyncedInstance<Config>.IsHost)
			{
				return;
			}
			Plugin.logger.LogInfo((object)$"Config sync request received from client: {clientId}");
			byte[] array = SyncedInstance<Config>.SerializeToBytes(SyncedInstance<Config>.Instance);
			int num = array.Length;
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(num + SyncedInstance<Config>.IntSize, (Allocator)2, -1);
			try
			{
				((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref num, default(ForPrimitives));
				((FastBufferWriter)(ref val)).WriteBytesSafe(array, 0, array.Length);
				SyncedInstance<Config>.MessageManager.SendNamedMessage("FurryPaintings_OnReceiveConfigSync", clientId, val, (NetworkDelivery)3);
			}
			catch (Exception arg)
			{
				Plugin.logger.LogInfo((object)$"Error occurred syncing config with client: {clientId}\n{arg}");
			}
			finally
			{
				((IDisposable)(FastBufferWriter)(ref val)).Dispose();
			}
		}

		public static void OnReceiveSync(ulong _, FastBufferReader reader)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			if (!((FastBufferReader)(ref reader)).TryBeginRead(SyncedInstance<Config>.IntSize))
			{
				Plugin.logger.LogError((object)"Config sync error: Could not begin reading buffer.");
				return;
			}
			int num = default(int);
			((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives));
			if (!((FastBufferReader)(ref reader)).TryBeginRead(num))
			{
				Plugin.logger.LogError((object)"Config sync error: Host could not sync.");
				return;
			}
			byte[] data = new byte[num];
			((FastBufferReader)(ref reader)).ReadBytesSafe(ref data, num, 0);
			SyncedInstance<Config>.SyncInstance(data);
			Plugin.logger.LogInfo((object)"Successfully synced config with host.");
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")]
		public static void InitializeLocalPlayer()
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			if (SyncedInstance<Config>.IsHost)
			{
				SyncedInstance<Config>.MessageManager.RegisterNamedMessageHandler("FurryPaintings_OnRequestConfigSync", new HandleNamedMessageDelegate(OnRequestSync));
				SyncedInstance<Config>.Synced = true;
			}
			else
			{
				SyncedInstance<Config>.Synced = false;
				SyncedInstance<Config>.MessageManager.RegisterNamedMessageHandler("FurryPaintings_OnReceiveConfigSync", new HandleNamedMessageDelegate(OnReceiveSync));
				RequestSync();
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(GameNetworkManager), "StartDisconnect")]
		public static void PlayerLeave()
		{
			SyncedInstance<Config>.RevertSync();
		}
	}
}
namespace FurryPaintings
{
	[BepInPlugin("Hasan.FurryPaintings", "FurryPaintings", "1.0.0")]
	public class CustomPaintings : BaseUnityPlugin
	{
		private const string modGUID = "Hasan.FurryPaintings";

		private const string modName = "FurryPaintings";

		private const string modVersion = "1.0.0";

		private readonly Harmony harmony = new Harmony("Hasan.FurryPaintings");

		internal static CustomPaintings instance;

		internal static ManualLogSource mls;

		public static readonly List<string> paintingFiles = new List<string>();

		public static Random random;

		private string separator = "/";

		public string[] urls = new string[0];

		public static Config cfg { get; internal set; }

		private void Awake()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			if ((Object)instance == (Object)null)
			{
				instance = this;
			}
			mls = Logger.CreateLogSource("Hasan.FurryPaintings");
			cfg = new Config(((BaseUnityPlugin)this).Config);
			if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
			{
				separator = "\\";
			}
			if (cfg.defaultPaintings)
			{
				urls = new string[7] { "https://i.imgur.com/lmLk6MY.png", "https://i.imgur.com/dhq1JD9.png", "https://i.imgur.com/tYHnVcM.png", "https://i.imgur.com/RaIfyE6.png", "https://i.imgur.com/cExQlja.png", "https://i.imgur.com/vIKQb2f.png", "https://i.imgur.com/NG13GHS.png" };
			}
			if (!cfg.customUrls.Equals(""))
			{
				urls = CollectionExtensions.AddRangeToArray<string>(urls, cfg.customUrls.Split(new char[1] { ',' }));
			}
			string[] array = new string[1] { Paths.BepInExRootPath };
			string[] paths = CollectionExtensions.AddRangeToArray<string>(array, cfg.directory.Split(new char[1] { '/' }));
			string text = Path.Combine(paths);
			if (!Directory.Exists(text))
			{
				Directory.CreateDirectory(text);
				mls.LogInfo((object)("Created directory at " + text));
				if (!cfg.forceDownload)
				{
					DownloadTextures(text);
				}
			}
			else if (!cfg.defaultPaintings)
			{
				DeleteDefaultTextures(text);
			}
			if (cfg.forceDownload)
			{
				DownloadTextures(text);
			}
			string[] files = Directory.GetFiles(text);
			if (files.Length == 0)
			{
				mls.LogWarning((object)"No paintings found");
			}
			else
			{
				paintingFiles.AddRange(files);
				harmony.PatchAll(typeof(CustomPaintings));
			}
			mls.LogInfo((object)"------- FurryPaintings loaded -------");
		}

		[HarmonyPatch(typeof(GrabbableObject), "Start")]
		[HarmonyPostfix]
		private static void PaintingPatch(GrabbableObject __instance)
		{
			if (__instance.itemProperties.itemName == "Painting")
			{
				random = new Random((int)((NetworkBehaviour)__instance).NetworkObjectId);
				UpdateTextures(paintingFiles, __instance);
			}
		}

		private static void UpdateTextures(IReadOnlyList<string> files, GrabbableObject __instance)
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Expected O, but got Unknown
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Expected O, but got Unknown
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Expected O, but got Unknown
			if (files.Count == 0)
			{
				return;
			}
			if (cfg.maxTextures > files.Count)
			{
				cfg.maxTextures = files.Count;
			}
			Material[] array = (Material[])(object)new Material[cfg.maxTextures];
			List<int> list = new List<int>();
			list.Clear();
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = new Material(__instance.itemProperties.materialVariants[0]);
				int num;
				do
				{
					num = random.Next(files.Count);
				}
				while (list.Contains(num));
				list.Add(num);
				Texture2D val = new Texture2D(2, 2);
				ImageConversion.LoadImage(val, File.ReadAllBytes(files[num]));
				array[i].mainTexture = (Texture)val;
			}
			__instance.itemProperties.materialVariants = array;
		}

		private void DownloadTextures(string directory)
		{
			int num = 1;
			string[] array = urls;
			string[] array2 = array;
			foreach (string requestUriString in array2)
			{
				HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(requestUriString);
				HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
				if (httpWebResponse.StatusCode == HttpStatusCode.OK)
				{
					Image val = Image.FromStream(httpWebResponse.GetResponseStream());
					if (cfg.defaultPaintings)
					{
						if (num < 9)
						{
							val.Save(directory + separator + "default" + num + ".png", ImageFormat.Png);
						}
						else
						{
							val.Save(directory + separator + "custom" + (num - 8) + ".png", ImageFormat.Png);
						}
					}
					else
					{
						val.Save(directory + separator + "custom" + num + ".png", ImageFormat.Png);
					}
				}
				else if (cfg.defaultPaintings)
				{
					if (num < 9)
					{
						mls.LogWarning((object)("Error downloading default image " + num));
					}
					else
					{
						mls.LogWarning((object)("Error downloading custom image " + (num - 8)));
					}
				}
				else
				{
					mls.LogWarning((object)("Error downloading custom image " + num));
				}
				num++;
			}
		}

		private void DeleteDefaultTextures(string directory)
		{
			if (File.Exists(directory + separator + "default1.png"))
			{
				for (int i = 1; i < 9; i++)
				{
					File.Delete(directory + separator + "default" + i + ".png");
				}
			}
		}
	}
	[Serializable]
	public class SyncedInstance<T>
	{
		[NonSerialized]
		protected static int IntSize = 4;

		internal static CustomMessagingManager MessageManager => NetworkManager.Singleton.CustomMessagingManager;

		internal static bool IsClient => NetworkManager.Singleton.IsClient;

		internal static bool IsHost => NetworkManager.Singleton.IsHost;

		public static T Default { get; private set; }

		public static T Instance { get; private set; }

		public static bool Synced { get; internal set; }

		protected void InitInstance(T instance)
		{
			Default = instance;
			Instance = instance;
			IntSize = 4;
		}

		internal static void SyncInstance(byte[] data)
		{
			Instance = DeserializeFromBytes(data);
			Synced = true;
		}

		internal static void RevertSync()
		{
			Instance = Default;
			Synced = false;
		}

		public static byte[] SerializeToBytes(T val)
		{
			BinaryFormatter binaryFormatter = new BinaryFormatter();
			MemoryStream memoryStream = new MemoryStream();
			try
			{
				binaryFormatter.Serialize(memoryStream, val);
				return memoryStream.ToArray();
			}
			catch (Exception arg)
			{
				Plugin.logger.LogError((object)$"Error serializing instance: {arg}");
				return null;
			}
		}

		public static T DeserializeFromBytes(byte[] data)
		{
			BinaryFormatter binaryFormatter = new BinaryFormatter();
			MemoryStream serializationStream = new MemoryStream(data);
			try
			{
				return (T)binaryFormatter.Deserialize(serializationStream);
			}
			catch (Exception arg)
			{
				Plugin.logger.LogError((object)$"Error deserializing instance: {arg}");
				return default(T);
			}
		}
	}
}