Decompiled source of texturePackLoader v1.0.1

texturepack_loader.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("texturepack_loader")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("My first plugin")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("texturepack_loader")]
[assembly: AssemblyTitle("texturepack_loader")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[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 texturepack_loader
{
	internal class Patches
	{
		[HarmonyPatch(typeof(SpriteRenderer), "set_sprite")]
		private class SpriteRendererSetSpritePatch
		{
			private static void Postfix(SpriteRenderer __instance, Sprite value)
			{
				if (!((Object)(object)__instance == (Object)null) && !((Object)(object)value == (Object)null) && !((Object)(object)value.texture == (Object)null))
				{
					Plugin.instance.RegisterSprite(((Object)value).name, value.texture, ui: false);
				}
			}
		}
	}
	[BepInPlugin("com.erwer.texturepack_loader", "texturepack_loader", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		private class ProcessableSprite
		{
			public string Name;

			public Texture2D Tex;

			public bool NeedsToChange;

			public bool uiSpace;

			public ProcessableSprite(string name, Texture2D tex, bool needsToChange, bool uispace)
			{
				Name = name;
				Tex = tex;
				NeedsToChange = needsToChange;
				uiSpace = uispace;
			}
		}

		public static class TextureMenu
		{
			public static Rect windowRect = new Rect(10f, 125f, 400f, 250f);
		}

		public const string PLUGIN_GUID = "com.erwer.texturepack_loader";

		public const string PLUGIN_NAME = "texturepack_loader";

		public const string PLUGIN_VERSION = "1.0.0";

		public static ManualLogSource logger;

		public string PluginDirectory;

		private ConfigEntry<int> discoveryInterval;

		private ConfigEntry<bool> verbose;

		private ConfigEntry<bool> vanillaBasing;

		public static Plugin instance;

		private List<TexturePack> TexturePacks = new List<TexturePack>();

		private Dictionary<Texture2D, ProcessableSprite> FullProcessed = new Dictionary<Texture2D, ProcessableSprite>();

		private static uint frame;

		private bool hasHiddenBefore;

		private bool showTextureLoader = true;

		private string notificationMessage = "";

		private Vector2 scrollPosition;

		private void Awake()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			PluginDirectory = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
			instance = this;
			new Harmony("com.erwer.texturepack_loader").PatchAll(typeof(Patches));
			discoveryInterval = ((BaseUnityPlugin)this).Config.Bind<int>("Texture Pack Loader", "DiscoveryInterval", 4, "Higher values are better for preformance but cause visual artifacting the first frame a texture is loaded.");
			verbose = ((BaseUnityPlugin)this).Config.Bind<bool>("Texture Pack Loader Dev", "Verbose", false, "Enables \"additional\" logging. Useful for me developing this mod or for you creating your own texture pack.");
			vanillaBasing = ((BaseUnityPlugin)this).Config.Bind<bool>("Texture Pack Loader", "Vanilla Base", true, "Loads vanilla textures as a base before applying the active texture pack, allowing packs to include only the textures they change. Disabling this may cause missing textures or unexpected results. Disable this option when developing a texture pack.");
			CharacterSelectHandler_online.clientSideMods_you_can_increment_this_to_enable_matchmaking_for_your_mods__please_dont_use_it_to_cheat_thats_really_cringe_especially_if_its_desyncing_others___you_didnt_even_win_on_your_opponents_screen___I_cannot_imagine_a_sadder_existence++;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Plugin com.erwer.texturepack_loader is loaded!");
			logger = ((BaseUnityPlugin)this).Logger;
			if (!Directory.Exists(activeTexturePath()))
			{
				Directory.CreateDirectory(activeTexturePath());
			}
			if (!Directory.Exists(texturePacksPath()))
			{
				Directory.CreateDirectory(texturePacksPath());
			}
			if (!Directory.Exists(unpackPath()))
			{
				Directory.CreateDirectory(unpackPath());
			}
			string text = Path.Combine(PluginDirectory, "vanilla.zip");
			if (File.Exists(text))
			{
				File.Move(text, Path.Combine(texturePacksPath(), "vanilla.zip"));
			}
			RefreshTexturePacks();
		}

		private void Update()
		{
			if (((ButtonControl)Keyboard.current[(Key)21]).wasPressedThisFrame)
			{
				showTextureLoader = !showTextureLoader;
				hasHiddenBefore = true;
			}
			frame++;
			if (frame % discoveryInterval.Value == 0L)
			{
				SpriteRenderer[] array = Object.FindObjectsOfType<SpriteRenderer>();
				foreach (SpriteRenderer val in array)
				{
					if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null) && !((Object)(object)val.sprite == (Object)null) && Object.op_Implicit((Object)(object)val.sprite.texture))
					{
						Texture2D texture = val.sprite.texture;
						RegisterSprite(((Object)val.sprite).name, texture, ui: false);
					}
				}
				Image[] array2 = Object.FindObjectsOfType<Image>();
				foreach (Image val2 in array2)
				{
					if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2.sprite == (Object)null) && !((Object)(object)val2.sprite.texture == (Object)null))
					{
						Texture2D texture2 = val2.sprite.texture;
						RegisterSprite(((Object)val2.sprite).name, texture2, ui: true);
					}
				}
			}
			ApplyChangesToSprites();
		}

		public void RegisterSprite(string name, Texture2D tex, bool ui)
		{
			if (!FullProcessed.ContainsKey(tex))
			{
				FullProcessed.Add(tex, new ProcessableSprite(name, tex, needsToChange: true, ui));
			}
		}

		private void ApplyChangesToSprites()
		{
			foreach (ProcessableSprite value in FullProcessed.Values)
			{
				if (value.NeedsToChange)
				{
					value.NeedsToChange = false;
					processImage(value.Tex, value.Name, value.uiSpace);
				}
			}
		}

		private void processImage(Texture2D tex, string spriteName, bool uiSpace = false)
		{
			if ((Object)(object)tex == (Object)null)
			{
				return;
			}
			string text = Translator.Translate(spriteName, uiSpace);
			string text2 = Path.Combine(activeTexturePath(), text + ".png");
			if (File.Exists(text2))
			{
				byte[] array = File.ReadAllBytes(text2);
				ImageConversion.LoadImage(tex, array);
				if (verbose.Value)
				{
					((BaseUnityPlugin)this).Logger.LogMessage((object)("[Verbose] [Name: " + spriteName + "] replaced with -> [Path: " + text2 + "]"));
				}
			}
			else if (verbose.Value)
			{
				((BaseUnityPlugin)this).Logger.LogMessage((object)("[Verbose] [Name: " + spriteName + "] [Path: " + text2 + "] was not found, so this texture has been skipped."));
			}
		}

		public string GetFirstLineLimited(string filePath, int x)
		{
			if (!File.Exists(filePath))
			{
				return string.Empty;
			}
			using StreamReader streamReader = new StreamReader(filePath);
			string text = streamReader.ReadLine();
			if (string.IsNullOrEmpty(text))
			{
				return string.Empty;
			}
			return (text.Length <= x) ? text : text.Substring(0, x);
		}

		private void RefreshTexturePacks()
		{
			TexturePacks.Clear();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"@Checking textures");
			if (!Directory.Exists(texturePacksPath()))
			{
				return;
			}
			string[] directories = Directory.GetDirectories(texturePacksPath());
			foreach (string text in directories)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)text);
				string text2 = Path.Combine(text, "version");
				if (File.Exists(text2))
				{
					if (int.TryParse(GetFirstLineLimited(text2, 250), out var result))
					{
						TexturePacks.Add(new TexturePack(Path.GetFileName(text), text, zipped: false, result));
					}
					else
					{
						((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to parse version as a number. Pack [" + text + "] rejected."));
					}
				}
				else
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)("No version file. Pack [" + text + "] rejected."));
				}
			}
			directories = Directory.GetFiles(texturePacksPath());
			foreach (string text3 in directories)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("@" + text3));
				if (!Path.GetExtension(text3).Equals(".zip", StringComparison.OrdinalIgnoreCase))
				{
					continue;
				}
				try
				{
					string s = "";
					int num = 0;
					using (ZipArchive zipArchive = ZipFile.Open(text3, ZipArchiveMode.Read))
					{
						foreach (ZipArchiveEntry entry in zipArchive.Entries)
						{
							if (!(entry.Name == "version"))
							{
								continue;
							}
							if (entry.Length > 256)
							{
								((BaseUnityPlugin)this).Logger.LogError((object)(text3 + " was rejected. Entry length > 256"));
								return;
							}
							using Stream stream = entry.Open();
							using StreamReader streamReader = new StreamReader(stream, Encoding.UTF8);
							s = streamReader.ReadToEnd().Trim();
						}
					}
					if (int.TryParse(s, out var result2))
					{
						num = result2;
						TexturePacks.Add(new TexturePack(Path.GetFileNameWithoutExtension(text3), text3, zipped: true, num));
					}
					else
					{
						((BaseUnityPlugin)this).Logger.LogError((object)("Failed to parse version. " + text3 + " was rejected."));
						notificationMessage += "\nFailed to parse version number. Check log for details.";
					}
				}
				catch (Exception arg)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)$"Failed to parse. {text3} was rejected. {arg}");
					notificationMessage += "\nFailed to parse. Check log for details.";
				}
			}
		}

		private void ApplyPack(TexturePack pack, bool NoDelete = false)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Preparing Textures Folder for pack: " + pack.Name));
			if (!NoDelete)
			{
				ClearFolder(activeTexturePath());
				foreach (ProcessableSprite value in FullProcessed.Values)
				{
					value.NeedsToChange = true;
				}
			}
			if (vanillaBasing.Value && pack.Name != "vanilla")
			{
				TexturePack pack2 = TexturePacks.FirstOrDefault((TexturePack texturePack) => texturePack.Name.Equals("vanilla", StringComparison.OrdinalIgnoreCase));
				if (!Utility.IsNullOrWhiteSpace(pack2.Name))
				{
					ApplyPack(pack2, NoDelete: true);
				}
				else
				{
					notificationMessage = "Couldn't find 'vanilla' texture pack. Hotswapping textures with a vanilla pack may cause overlap.";
				}
			}
			string text = pack.Path;
			if (pack.Zipped)
			{
				string text2 = Path.Combine(unpackPath(), pack.Name);
				int num = -1;
				string text3 = Path.Combine(text2, "version");
				if (File.Exists(text3))
				{
					if (!int.TryParse(GetFirstLineLimited(text3, 250), out var result))
					{
						((BaseUnityPlugin)this).Logger.LogError((object)("Failed to parse version number for " + pack.Name + " | This pack was rejected."));
						notificationMessage += "\nFailed to parse version number. Check log for details.";
						return;
					}
					num = result;
				}
				if (verbose.Value)
				{
					if (num >= pack.Version)
					{
						((BaseUnityPlugin)this).Logger.LogMessage((object)$"[Verbose] The zip for {pack.Name}v{pack.Version} is not a higher version than {num} so it will not be extracted.");
					}
					else
					{
						((BaseUnityPlugin)this).Logger.LogMessage((object)$"[Verbose] The zip for {pack.Name}v{pack.Version} is a higher version than {num} so it will replace the cache.");
					}
				}
				if (Directory.Exists(text2) && num >= pack.Version)
				{
					text = text2;
				}
				else
				{
					try
					{
						ClearFolder(text2);
						SafeZip.Code num2 = SafeZip.Extract(pack.Path, text2);
						text = text2;
						if (num2 == SafeZip.Code.TOO_LARGE)
						{
							notificationMessage += "The pack's size exceeded an expected value.";
							text = null;
						}
						if (num2 == SafeZip.Code.PARTIAL)
						{
							notificationMessage += "This pack has failed to load fully.";
							text = null;
						}
						if (num2 == SafeZip.Code.SLIP)
						{
							text = null;
						}
					}
					catch (Exception ex)
					{
						notificationMessage += ex.Message;
					}
				}
			}
			if (text == null)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)"Failed to load a texturepack.");
				return;
			}
			string[] files = Directory.GetFiles(text, "*.*", SearchOption.AllDirectories);
			for (int num3 = 0; num3 < files.Length; num3++)
			{
				string? fileNameWithoutExtension = Path.GetFileNameWithoutExtension(files[num3]);
				string extension = Path.GetExtension(files[num3]);
				string text4 = Translator.Translate(fileNameWithoutExtension, isUI: false);
				File.Copy(files[num3], Path.Combine(activeTexturePath(), text4 + extension), overwrite: true);
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"Loaded texture pack {pack.Name} ({files.Length}/{files.Length})");
		}

		private void ClearFolder(string folderName)
		{
			DirectoryInfo directoryInfo = new DirectoryInfo(folderName);
			if (directoryInfo.Exists)
			{
				FileInfo[] files = directoryInfo.GetFiles();
				for (int i = 0; i < files.Length; i++)
				{
					files[i].Delete();
				}
				DirectoryInfo[] directories = directoryInfo.GetDirectories();
				foreach (DirectoryInfo directoryInfo2 in directories)
				{
					ClearFolder(directoryInfo2.FullName);
					directoryInfo2.Delete();
				}
			}
		}

		private void OnGUI()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			if (showTextureLoader)
			{
				TextureMenu.windowRect = GUI.Window(42069, TextureMenu.windowRect, new WindowFunction(TexturepackWin), "Texturepack Loader");
			}
			if (!Utility.IsNullOrWhiteSpace(notificationMessage))
			{
				Rect val = default(Rect);
				((Rect)(ref val))..ctor(10f, 10f, (float)(15 * notificationMessage.Length), 100f);
				GUI.Box(val, notificationMessage);
				if (GUI.Button(new Rect(((Rect)(ref val)).x + ((Rect)(ref val)).width - 25f, ((Rect)(ref val)).y + 5f, 20f, 20f), "X"))
				{
					notificationMessage = "";
				}
			}
		}

		private void TexturepackWin(int windowID)
		{
			//IL_0002: 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)
			scrollPosition = GUILayout.BeginScrollView(scrollPosition, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(376f),
				GUILayout.Height(180f)
			});
			for (int i = 0; i < TexturePacks.Count; i++)
			{
				TexturePack pack = TexturePacks[i];
				if (GUILayout.Button(pack.Name, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(22f) }))
				{
					ApplyPack(pack);
				}
			}
			GUILayout.EndScrollView();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("REFRESH", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(22f) }))
			{
				RefreshTexturePacks();
			}
			if (GUILayout.Button("Open Pack Folder", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(22f) }) && Directory.Exists(texturePacksPath()))
			{
				Process.Start(new ProcessStartInfo
				{
					FileName = texturePacksPath(),
					UseShellExecute = true,
					Verb = "open"
				});
			}
			GUILayout.EndHorizontal();
			if (!hasHiddenBefore)
			{
				GUILayout.Label("[G] Toggles Visibility", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(22f) });
			}
			GUI.DragWindow();
		}

		public static string textureloaderPath()
		{
			return instance.PluginDirectory;
		}

		public static string unpackPath()
		{
			return Path.Combine(textureloaderPath(), "unpacks");
		}

		public static string activeTexturePath()
		{
			return Path.Combine(textureloaderPath(), "activeTextures");
		}

		public static string texturePacksPath()
		{
			return Path.Combine(textureloaderPath(), "texturePacks");
		}
	}
	internal struct TexturePack
	{
		public string Name { get; set; }

		public string Path { get; set; }

		public bool Zipped { get; set; }

		public int Version { get; set; }

		public TexturePack(string name, string path, bool zipped, int version)
		{
			Name = name;
			Path = path;
			Zipped = zipped;
			Version = version;
		}
	}
	internal class SafeZip
	{
		internal enum Code
		{
			PARTIAL,
			SLIP,
			SUCCESS,
			TOO_LARGE
		}

		internal static Code Extract(string zipPath, string toDirectory)
		{
			long num = 0L;
			bool flag = false;
			string text = Path.GetFullPath(toDirectory);
			string text2 = text;
			char directorySeparatorChar = Path.DirectorySeparatorChar;
			if (!text2.EndsWith(directorySeparatorChar.ToString()))
			{
				string text3 = text;
				directorySeparatorChar = Path.DirectorySeparatorChar;
				text = text3 + directorySeparatorChar;
			}
			using (ZipArchive zipArchive = ZipFile.OpenRead(zipPath))
			{
				foreach (ZipArchiveEntry entry in zipArchive.Entries)
				{
					num += entry.Length;
					if (num > 524288000)
					{
						Plugin.logger.LogError((object)("[Rejected] Size of zip file during extraction exceeded 500MB. " + zipPath + " I: " + entry.FullName + "."));
						return Code.TOO_LARGE;
					}
					string fullPath = Path.GetFullPath(Path.Combine(text, entry.FullName));
					if (!fullPath.StartsWith(text))
					{
						Plugin.logger.LogWarning((object)("[Rejected] Potential path traversal attack in " + zipPath + " I: " + entry.FullName + "."));
						return Code.SLIP;
					}
					if (string.IsNullOrEmpty(entry.Name))
					{
						Directory.CreateDirectory(fullPath);
						continue;
					}
					Directory.CreateDirectory(Path.GetDirectoryName(fullPath));
					try
					{
						entry.ExtractToFile(fullPath, overwrite: false);
					}
					catch (Exception ex)
					{
						Plugin.logger.LogError((object)ex);
						flag = true;
					}
				}
			}
			if (!flag)
			{
				return Code.SUCCESS;
			}
			return Code.PARTIAL;
		}
	}
	internal static class Translator
	{
		internal static readonly Dictionary<string, string> TextureMappings = new Dictionary<string, string>
		{
			{ "Mine", "FlammableObject3" },
			{ "SpikeAttack", "SpikeSpriteLongRounded" },
			{ "MagnetGun", "Timeline 1_0010" },
			{ "duplicatorTransform", "Timeline 1_0014" },
			{ "MachoThrow3", "Throw" }
		};

		internal static string Translate(string key, bool isUI)
		{
			if (key.Contains("_"))
			{
				int num = key.LastIndexOf("_");
				string text = key.Substring(0, num);
				if (int.TryParse(key.Substring(num + 1), out var _))
				{
					key = text;
				}
			}
			if (TextureMappings.TryGetValue(key, out var value))
			{
				return value;
			}
			if (isUI && key.Equals("circle"))
			{
				return "UIcircle";
			}
			return key;
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "texturepack_loader";

		public const string PLUGIN_NAME = "texturepack_loader";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}