Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of FurryPaintings v1.0.0
FurryPaintings.dll
Decompiled 2 years agousing 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); } } } }