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);
}
}
}
}