Decompiled source of Real TCG Overhaul v5.1.0

BepinEx/plugins/ArtExpander/ArtExpander.dll

Decompiled 2 days ago
using System;
using System.Collections;
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.Security;
using System.Security.Permissions;
using System.Text;
using ArtExpander.Core;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ArtExpander")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("3.4.3.0")]
[assembly: AssemblyInformationalVersion("3.4.3+aba323460dec283ee9f7013a940bdc9ffa76d247")]
[assembly: AssemblyProduct("Art Expander")]
[assembly: AssemblyTitle("ArtExpander")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("3.4.3.0")]
[module: UnverifiableCode]
[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 ArtExpander
{
	[BepInPlugin("ArtExpander", "Art Expander", "3.4.3")]
	[BepInProcess("Card Shop Simulator.exe")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		internal static AnimationCache animated_ghost_cache;

		internal static ManualLogSource Logger;

		private readonly Harmony harmony = new Harmony("ArtExpander");

		internal static string PluginPath;

		internal static ArtCache art_cache = new ArtCache();

		internal static ConfigEntry<bool> EnableAnimations;

		private void Awake()
		{
			Logger = ((BaseUnityPlugin)this).Logger;
			EnableAnimations = ((BaseUnityPlugin)this).Config.Bind<bool>("Animation Settings", "Enable Animations", true, "Enable or disable all card animations");
			PluginPath = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
			Logger.LogDebug((object)("Art Expander starting! Plugin path: " + PluginPath));
			string basePath = Path.Combine(PluginPath, "cardart");
			if (EnableAnimations.Value)
			{
				animated_ghost_cache = new AnimationCache((MonoBehaviour)(object)this);
				string rootPath = Path.Combine(PluginPath, "animated");
				animated_ghost_cache.Initialize(rootPath);
			}
			else
			{
				Logger.LogInfo((object)"Animations disabled in config - skipping animation loading");
			}
			art_cache.Initialize(basePath);
			harmony.PatchAll();
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "ArtExpander";

		public const string PLUGIN_NAME = "Art Expander";

		public const string PLUGIN_VERSION = "3.4.3";
	}
}
namespace ArtExpander.Patches
{
	[HarmonyPatch(typeof(CardUI))]
	[HarmonyPatch("SetCardUI")]
	[HarmonyPatch(new Type[] { typeof(CardData) })]
	public class CardUISetCardPatch
	{
		internal static class CardDataTracker
		{
			private static CardData currentCardData;

			public static void SetCurrentCard(CardData data)
			{
				currentCardData = data;
			}

			public static void ClearCurrentCard()
			{
				currentCardData = null;
			}

			public static (ECardBorderType borderType, bool isDestiny, bool isFoil) GetCurrentCardInfo()
			{
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				if (currentCardData != null)
				{
					return (currentCardData.borderType, currentCardData.isDestiny, currentCardData.isFoil);
				}
				return ((ECardBorderType)0, false, false);
			}
		}

		private static void Prefix(CardData cardData)
		{
			CardDataTracker.SetCurrentCard(cardData);
		}

		private static void Postfix()
		{
			CardDataTracker.ClearCurrentCard();
		}
	}
	[HarmonyPatch(typeof(CardUI))]
	public class GhostCardPatch
	{
		private static readonly string LOG_PREFIX = "[GhostCardPatch] ";

		private static void LogError(string message, Exception ex = null)
		{
			Plugin.Logger.LogError((object)(LOG_PREFIX + message + ((ex != null) ? $"\nException: {ex}" : "")));
		}

		private static void LogWarning(string message)
		{
			Plugin.Logger.LogWarning((object)(LOG_PREFIX + message));
		}

		private static void LogInfo(string message)
		{
			Plugin.Logger.LogInfo((object)(LOG_PREFIX + message));
		}

		[HarmonyPatch("SetGhostCardUI")]
		[HarmonyPostfix]
		private static void Postfix(CardUI __instance, MonsterData data, bool isBlackGhost)
		{
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.EnableAnimations.Value)
			{
				return;
			}
			try
			{
				CardUI ghostCard = default(CardUI);
				ref CardUI reference = ref ghostCard;
				object? value = AccessTools.Field(typeof(CardUI), "m_GhostCard").GetValue(__instance);
				reference = (CardUI)((value is CardUI) ? value : null);
				if (!((Object)(object)ghostCard != (Object)null))
				{
					return;
				}
				GhostCardAnimatedRenderer[] components = ((Component)ghostCard).GetComponents<GhostCardAnimatedRenderer>();
				GhostCardAnimatedRenderer[] array = components;
				foreach (GhostCardAnimatedRenderer ghostCardAnimatedRenderer in array)
				{
					ghostCardAnimatedRenderer.StopAnimation();
					Object.Destroy((Object)(object)ghostCardAnimatedRenderer);
				}
				CardData cardData = __instance.GetCardData();
				Image mainImage = null;
				Image maskImage = null;
				Image glowImage = null;
				ref Image reference2 = ref mainImage;
				object? value2 = AccessTools.Field(typeof(CardUI), "m_MonsterImage").GetValue(ghostCard);
				reference2 = (Image)((value2 is Image) ? value2 : null);
				ref Image reference3 = ref maskImage;
				object? value3 = AccessTools.Field(typeof(CardUI), "m_MonsterMaskImage").GetValue(ghostCard);
				reference3 = (Image)((value3 is Image) ? value3 : null);
				ref Image reference4 = ref glowImage;
				object? value4 = AccessTools.Field(typeof(CardUI), "m_MonsterGlowMask").GetValue(ghostCard);
				reference4 = (Image)((value4 is Image) ? value4 : null);
				bool flag = false;
				try
				{
					flag = Plugin.animated_ghost_cache.RequestAnimationForCard(data.MonsterType, cardData.borderType, (ECardExpansionType)2, isBlackGhost, cardData.isFoil, delegate(Sprite[] frames)
					{
						try
						{
							if (frames == null || frames.Length == 0)
							{
								LogError("Received null or empty frames array");
							}
							else if ((Object)(object)ghostCard == (Object)null || (Object)(object)((Component)ghostCard).gameObject == (Object)null)
							{
								LogWarning("Ghost card was destroyed before animation could be applied");
							}
							else
							{
								GhostCardAnimatedRenderer ghostCardAnimatedRenderer2 = ((Component)ghostCard).gameObject.AddComponent<GhostCardAnimatedRenderer>();
								ghostCardAnimatedRenderer2.Initialize(mainImage, maskImage, glowImage, frames);
							}
						}
						catch (Exception ex3)
						{
							LogError("Error in animation callback", ex3);
						}
					});
				}
				catch (Exception ex)
				{
					LogError("Error requesting animation", ex);
				}
			}
			catch (Exception ex2)
			{
				LogError("Unhandled error in SetGhostCardUI postfix", ex2);
			}
		}
	}
	[HarmonyPatch(typeof(MonsterData))]
	[HarmonyPatch("GetIcon")]
	[HarmonyPatch(new Type[] { typeof(ECardExpansionType) })]
	public class GetIconPatch
	{
		public static bool Prefix(MonsterData __instance, ECardExpansionType cardExpansionType, ref Sprite __result)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//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_0026: Unknown result type (might be due to invalid IL or missing references)
			(ECardBorderType borderType, bool isDestiny, bool isFoil) currentCardInfo = CardUISetCardPatch.CardDataTracker.GetCurrentCardInfo();
			ECardBorderType item = currentCardInfo.borderType;
			bool item2 = currentCardInfo.isDestiny;
			bool item3 = currentCardInfo.isFoil;
			string text = Plugin.art_cache.ResolveArtPath(__instance.MonsterType, item, cardExpansionType, item2, item3);
			if (!string.IsNullOrEmpty(text))
			{
				Sprite val = Plugin.art_cache.LoadSprite(text);
				if ((Object)(object)val != (Object)null)
				{
					__result = val;
					return false;
				}
			}
			return true;
		}
	}
}
namespace ArtExpander.Core
{
	public class AnimationCache
	{
		private readonly Dictionary<(EMonsterType monsterType, ECardBorderType BorderType, ECardExpansionType ExpansionType, bool IsFoil), List<string>> _animationFilePaths = new Dictionary<(EMonsterType, ECardBorderType, ECardExpansionType, bool), List<string>>();

		private readonly Dictionary<string, Sprite[]> _loadedAnimations = new Dictionary<string, Sprite[]>();

		private AssetBundle _animationsBundle;

		private AssetBundleLoader _bundleLoader;

		private readonly MonoBehaviour _coroutineRunner;

		public void LogCacheContents()
		{
			if (_animationFilePaths == null || _animationFilePaths.Count == 0)
			{
				Plugin.Logger.LogInfo((object)"Animation cache is empty.");
				return;
			}
			Plugin.Logger.LogInfo((object)$"Animation Cache Contents ({_animationFilePaths.Count} total animations):");
			Plugin.Logger.LogInfo((object)"----------------------------------------");
			Plugin.Logger.LogInfo((object)$"Currently loaded animations in memory: {_loadedAnimations.Count}");
			foreach (string key in _loadedAnimations.Keys)
			{
				Plugin.Logger.LogInfo((object)$"Loaded animation directory: {key} ({_loadedAnimations[key].Length} frames)");
			}
		}

		public AnimationCache(MonoBehaviour coroutineRunner)
		{
			_coroutineRunner = coroutineRunner;
		}

		public void Initialize(string rootPath)
		{
			try
			{
				_bundleLoader = new AssetBundleLoader(rootPath, ".assets");
				if (_bundleLoader.IsUsingBundle)
				{
					ScanAnimationPaths(_bundleLoader.GetAllAssetNames());
				}
				else if (!Directory.Exists(rootPath))
				{
					Plugin.Logger.LogWarning((object)" plugins/artexpander/animated not found. pluginsartexpander/animated.assets not found. If not using animations, ignore this warning.");
				}
				else
				{
					ScanAnimationPaths(Directory.GetFiles(rootPath, "*.png", SearchOption.AllDirectories));
				}
			}
			catch (Exception ex) when (!(ex is ArgumentNullException) && !(ex is DirectoryNotFoundException))
			{
				Plugin.Logger.LogError((object)("Error during AnimationCache initialization: " + ex.Message));
				_bundleLoader?.Dispose();
			}
		}

		private void ScanAnimationPaths(IEnumerable<string> paths)
		{
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			_animationFilePaths.Clear();
			IEnumerable<string> source = paths.Where((string path) => path.EndsWith(".png", StringComparison.OrdinalIgnoreCase));
			IEnumerable<IGrouping<string, string>> enumerable = source.GroupBy(Path.GetDirectoryName);
			foreach (IGrouping<string, string> item in enumerable)
			{
				string filename = item.Key.Replace("_white", "").Replace("_black", "");
				if (!FileNameToMonsterTypeResolver.TryResolveMonsterType(filename, out var monsterType))
				{
					Plugin.Logger.LogWarning((object)("Could not resolve monster type for directory: " + item.Key));
					continue;
				}
				string filepath = item.First();
				CardAssetResolver.CardFolderResolutionResult cardFolderResolutionResult = CardAssetResolver.CardInfoFromPath(filepath);
				(EMonsterType, ECardBorderType, ECardExpansionType, bool) key = (monsterType, cardFolderResolutionResult.BorderType, cardFolderResolutionResult.ExpansionType, cardFolderResolutionResult.IsFoil);
				List<string> value = item.OrderBy(delegate(string p)
				{
					string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(p);
					int result;
					return int.TryParse(fileNameWithoutExtension, out result) ? result : int.MaxValue;
				}).ToList();
				_animationFilePaths[key] = value;
			}
			Plugin.Logger.LogInfo((object)$"Scanning complete. Found {_animationFilePaths.Count} animation sets");
		}

		public bool RequestAnimationForCard(EMonsterType monsterType, ECardBorderType borderType, ECardExpansionType expansionType, bool isBlackGhost, bool isFoil, Action<Sprite[]> onFramesReady)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			List<string> list = CardAssetResolver.ResolvePathFromCardInfo(_animationFilePaths, monsterType, borderType, expansionType, isBlackGhost, isFoil);
			if (list == null || !list.Any())
			{
				return false;
			}
			string directoryName = Path.GetDirectoryName(list[0]);
			if (_loadedAnimations.TryGetValue(directoryName, out var value))
			{
				onFramesReady(value);
				return true;
			}
			_coroutineRunner.StartCoroutine(LoadFramesCoroutine(list, directoryName, onFramesReady));
			return true;
		}

		private IEnumerator LoadFramesCoroutine(List<string> framePaths, string directoryPath, Action<Sprite[]> onFramesReady)
		{
			if (!framePaths.Any())
			{
				yield break;
			}
			List<Sprite> loadedFrames = new List<Sprite>();
			foreach (string path in framePaths)
			{
				Sprite sprite;
				try
				{
					sprite = _bundleLoader.LoadSprite(path);
				}
				catch (Exception ex)
				{
					Plugin.Logger.LogError((object)("Failed to load frame from " + path + ": " + ex.Message));
					continue;
				}
				if ((Object)(object)sprite != (Object)null)
				{
					loadedFrames.Add(sprite);
				}
				yield return null;
			}
			if (loadedFrames.Count > 0)
			{
				Sprite[] frames = loadedFrames.ToArray();
				_loadedAnimations[directoryPath] = frames;
				onFramesReady(frames);
			}
		}

		public void Dispose()
		{
			if ((Object)(object)_animationsBundle != (Object)null)
			{
				_animationsBundle.Unload(true);
				_animationsBundle = null;
			}
			ClearCache();
		}

		public void ClearCache()
		{
			foreach (Sprite[] value in _loadedAnimations.Values)
			{
				Sprite[] array = value;
				foreach (Sprite val in array)
				{
					if ((Object)(object)val != (Object)null)
					{
						Object.Destroy((Object)(object)val);
					}
				}
			}
			_loadedAnimations.Clear();
		}
	}
	public class ArtCache : IDisposable
	{
		private Dictionary<string, Sprite> _imageCache = new Dictionary<string, Sprite>();

		private readonly Dictionary<(EMonsterType, ECardBorderType, ECardExpansionType, bool), string> _resolvedPathCache = new Dictionary<(EMonsterType, ECardBorderType, ECardExpansionType, bool), string>();

		private string _baseArtPath;

		private AssetBundleLoader _bundleLoader;

		public string ResolveArtPath(EMonsterType monsterType, ECardBorderType borderType, ECardExpansionType expansionType, bool isBlackGhost, bool isFoil = false)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			return CardAssetResolver.ResolvePathFromCardInfo(_resolvedPathCache, monsterType, borderType, expansionType, isBlackGhost, isFoil);
		}

		public void LogCacheContents()
		{
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Expected I4, but got Unknown
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			Plugin.Logger.LogInfo((object)"=== Art Cache Contents ===");
			IOrderedEnumerable<IGrouping<ECardExpansionType, KeyValuePair<(EMonsterType, ECardBorderType, ECardExpansionType, bool), string>>> orderedEnumerable = from kvp in _resolvedPathCache
				group kvp by kvp.Key.Item3 into g
				orderby g.Key
				select g;
			foreach (IGrouping<ECardExpansionType, KeyValuePair<(EMonsterType, ECardBorderType, ECardExpansionType, bool), string>> item in orderedEnumerable)
			{
				Plugin.Logger.LogInfo((object)$"\nExpansion: {item.Key}");
				IOrderedEnumerable<IGrouping<ECardBorderType, KeyValuePair<(EMonsterType, ECardBorderType, ECardExpansionType, bool), string>>> orderedEnumerable2 = from kvp in item
					group kvp by kvp.Key.Item2 into g
					orderby g.Key
					select g;
				foreach (IGrouping<ECardBorderType, KeyValuePair<(EMonsterType, ECardBorderType, ECardExpansionType, bool), string>> item2 in orderedEnumerable2)
				{
					ECardBorderType key = item2.Key;
					if (1 == 0)
					{
					}
					string text;
					switch (key - -3)
					{
					case 2:
						text = "None";
						break;
					case 1:
						text = "GhostWhite";
						break;
					case 0:
						text = "GhostBlack";
						break;
					default:
					{
						ECardBorderType key2 = item2.Key;
						text = ((object)(ECardBorderType)(ref key2)).ToString();
						break;
					}
					}
					if (1 == 0)
					{
					}
					string text2 = text;
					Plugin.Logger.LogInfo((object)("\n  Border: " + text2));
					foreach (KeyValuePair<(EMonsterType, ECardBorderType, ECardExpansionType, bool), string> item3 in item2.OrderBy((KeyValuePair<(EMonsterType, ECardBorderType, ECardExpansionType, bool), string> kvp) => kvp.Key.Item1))
					{
						string arg = item3.Value.Replace(_baseArtPath, "").TrimStart('\\', '/');
						string arg2 = (item3.Key.Item4 ? "Foil" : "Normal");
						Plugin.Logger.LogInfo((object)$"    {item3.Key.Item1} ({arg2}): {arg}");
					}
				}
			}
			Plugin.Logger.LogInfo((object)"\n=== End Art Cache Contents ===");
		}

		public void Initialize(string basePath)
		{
			_baseArtPath = basePath;
			try
			{
				_bundleLoader = new AssetBundleLoader(basePath, ".assets");
				if (_bundleLoader.IsUsingBundle)
				{
					Plugin.Logger.LogInfo((object)("Loaded cardart.assets at " + basePath + ".assets"));
					ScanArtPaths(_bundleLoader.GetAllAssetNames());
					return;
				}
				if (!Directory.Exists(basePath))
				{
					Plugin.Logger.LogError((object)("cardart directory does not exist at " + basePath + ". failed to initialize ArtCache."));
					return;
				}
				List<string> list = new List<string>();
				string[] directories = Directory.GetDirectories(_baseArtPath);
				string[] array = directories;
				foreach (string text in array)
				{
					List<string> list2 = new List<string> { text };
					list2.AddRange(Directory.GetDirectories(text, "*", SearchOption.AllDirectories));
					foreach (string item in list2)
					{
						if (item.Contains("animated", StringComparison.OrdinalIgnoreCase))
						{
							Plugin.Logger.LogWarning((object)("Skipping animated folder: " + item));
						}
						else
						{
							list.AddRange(Directory.GetFiles(item, "*.png").Concat(Directory.GetFiles(item, "*.PNG")).Distinct<string>(StringComparer.OrdinalIgnoreCase));
						}
					}
				}
				ScanArtPaths(list);
			}
			catch (Exception ex) when (!(ex is ArgumentNullException) && !(ex is DirectoryNotFoundException))
			{
				Plugin.Logger.LogError((object)("Error during ArtCache initialization: " + ex.Message));
				_bundleLoader?.Dispose();
			}
		}

		private void ScanArtPaths(IEnumerable<string> paths)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			_resolvedPathCache.Clear();
			IEnumerable<string> enumerable = paths.Where((string path) => path.EndsWith(".png", StringComparison.OrdinalIgnoreCase) && !path.Contains("animated", StringComparison.OrdinalIgnoreCase));
			foreach (string item in enumerable)
			{
				try
				{
					CardAssetResolver.CardFolderResolutionResult cardFolderResolutionResult = CardAssetResolver.CardInfoFromPath(item);
					if (FileNameToMonsterTypeResolver.TryResolveMonsterType(Path.GetFileNameWithoutExtension(item), out var monsterType))
					{
						(EMonsterType, ECardBorderType, ECardExpansionType, bool) key = (monsterType, cardFolderResolutionResult.BorderType, cardFolderResolutionResult.ExpansionType, cardFolderResolutionResult.IsFoil);
						if (!_resolvedPathCache.ContainsKey(key))
						{
							_resolvedPathCache[key] = item;
						}
					}
					else
					{
						Plugin.Logger.LogWarning((object)("Failed to parse Monster Name " + item));
					}
				}
				catch (Exception ex)
				{
					Plugin.Logger.LogWarning((object)("Failed to process file " + item + ": " + ex.Message));
				}
			}
			Plugin.Logger.LogInfo((object)$"Scanning complete. Found {_resolvedPathCache.Count} art assets");
		}

		public Sprite LoadSprite(string path)
		{
			if (string.IsNullOrEmpty(path))
			{
				return null;
			}
			if (_imageCache.TryGetValue(path, out var value))
			{
				return value;
			}
			try
			{
				Sprite val = _bundleLoader.LoadSprite(path);
				if ((Object)(object)val != (Object)null)
				{
					_imageCache[path] = val;
				}
				return val;
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Failed to load image from " + path + ": " + ex.Message));
				return null;
			}
		}

		public void ClearImageCache()
		{
			foreach (Sprite value in _imageCache.Values)
			{
				if ((Object)(object)value != (Object)null)
				{
					Object.Destroy((Object)(object)value);
				}
			}
			_imageCache.Clear();
		}

		public void Dispose()
		{
			ClearImageCache();
			_bundleLoader?.Dispose();
		}
	}
	public class AssetBundleLoader : IDisposable
	{
		private AssetBundle _bundle;

		private readonly string _bundlePath;

		private readonly string _rootPath;

		private bool _loadFromBundle;

		private string[] _allAssetNames;

		public bool IsUsingBundle => _loadFromBundle && (Object)(object)_bundle != (Object)null;

		private static (bool isValid, string compression) CheckAssetBundle(string filePath)
		{
			using (FileStream input = new FileStream(filePath, FileMode.Open, FileAccess.Read))
			{
				using BinaryReader binaryReader = new BinaryReader(input, Encoding.UTF8);
				long length = new FileInfo(filePath).Length;
				byte[] bytes = binaryReader.ReadBytes(8);
				string text = Encoding.ASCII.GetString(bytes).TrimEnd('\0');
				if (!text.StartsWith("UnityFS"))
				{
					return (false, "Unknown");
				}
				byte b = binaryReader.ReadByte();
				binaryReader.ReadBytes(3);
				string text2 = ReadNullTerminatedString(binaryReader);
				string text3 = ReadNullTerminatedString(binaryReader);
				byte[] value = binaryReader.ReadBytes(8);
				byte[] value2 = binaryReader.ReadBytes(4);
				byte[] value3 = binaryReader.ReadBytes(4);
				byte[] value4 = binaryReader.ReadBytes(4);
				long num = BitConverter.ToInt64(value, 0);
				uint num2 = BitConverter.ToUInt32(value2, 0);
				uint num3 = BitConverter.ToUInt32(value3, 0);
				uint num4 = BitConverter.ToUInt32(value4, 0);
				int num5 = (int)((num4 >> 16) & 3);
				if (1 == 0)
				{
				}
				string text4 = num5 switch
				{
					0 => "None", 
					1 => "LZMA", 
					2 => "LZ4", 
					3 => "LZ4HC", 
					_ => "Unknown", 
				};
				if (1 == 0)
				{
				}
				string item = text4;
				return (true, item);
			}
			static string ReadNullTerminatedString(BinaryReader reader)
			{
				List<byte> list = new List<byte>();
				byte item2;
				while ((item2 = reader.ReadByte()) != 0)
				{
					list.Add(item2);
				}
				return Encoding.UTF8.GetString(list.ToArray());
			}
		}

		public AssetBundleLoader(string rootPath, string bundleSuffix)
		{
			_rootPath = rootPath;
			_bundlePath = rootPath + bundleSuffix;
			_loadFromBundle = File.Exists(_bundlePath);
			if (_loadFromBundle)
			{
				try
				{
					bool flag = false;
					string text = "Unknown";
					(flag, text) = CheckAssetBundle(_bundlePath);
					if (!flag)
					{
						Plugin.Logger.LogError((object)("!!! AssetBundle not in a readable unity 2021.3.38f format. Please rebuild bundle. Filepath: " + _bundlePath));
						_loadFromBundle = false;
					}
					else
					{
						if (text != "None" && text != "LZ4")
						{
							Plugin.Logger.LogError((object)("!!! ASSETBUNDLE NOT IN LZ4 format. compression_type is " + text + " Please package in LZ4 or UNCOMPRESSED for better performance."));
						}
						_bundle = AssetBundle.LoadFromFile(_bundlePath);
						_allAssetNames = _bundle.GetAllAssetNames();
					}
					return;
				}
				catch (Exception ex)
				{
					Plugin.Logger.LogError((object)("Failed to check or load bundle " + _bundlePath + ": " + ex.Message));
					_loadFromBundle = false;
					return;
				}
			}
			Plugin.Logger.LogInfo((object)(".assets file not found at: " + _bundlePath + ". Ignore this if not using .assets"));
			_loadFromBundle = false;
		}

		public string[] GetAllAssetNames()
		{
			return _allAssetNames;
		}

		public Sprite LoadSprite(string path)
		{
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Expected O, but got Unknown
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(path))
			{
				Plugin.Logger.LogWarning((object)("Path is null or empty  " + path));
				return null;
			}
			try
			{
				if (_loadFromBundle)
				{
					Sprite val = _bundle.LoadAsset<Sprite>(path);
					if ((Object)(object)val == (Object)null)
					{
						Plugin.Logger.LogWarning((object)("Failed to load sprite from bundle path " + path));
					}
					return val;
				}
				string text = Path.Combine(_rootPath, path);
				if (!File.Exists(text))
				{
					Plugin.Logger.LogWarning((object)("File does not exist at path: " + text));
					return null;
				}
				byte[] array = File.ReadAllBytes(text);
				Texture2D val2 = new Texture2D(2, 2, (TextureFormat)4, true);
				ImageConversion.LoadImage(val2, array);
				return Sprite.Create(val2, new Rect(0f, 0f, (float)((Texture)val2).width, (float)((Texture)val2).height), new Vector2(0.5f, 0.5f));
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Error loading sprite from " + path + ": " + ex.Message));
				return null;
			}
		}

		public void Dispose()
		{
			if ((Object)(object)_bundle != (Object)null)
			{
				_bundle.Unload(true);
				_bundle = null;
			}
		}
	}
	public class CardAssetResolver
	{
		public class CardFolderResolutionResult
		{
			public ECardExpansionType ExpansionType = (ECardExpansionType)(-1);

			public ECardBorderType BorderType = (ECardBorderType)(-1);

			public bool IsFoil = false;
		}

		public const ECardBorderType NoneBorder = -1;

		public const ECardBorderType GhostWhiteBorder = -2;

		public const ECardBorderType GhostBlackBorder = -3;

		public static CardFolderResolutionResult CardInfoFromPath(string filepath)
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			CardFolderResolutionResult cardFolderResolutionResult = new CardFolderResolutionResult();
			string[] array = filepath.Split(new char[2] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries);
			string[] array2 = array;
			foreach (string text in array2)
			{
				if (!string.IsNullOrEmpty(text))
				{
					ECardExpansionType result;
					ECardBorderType borderType;
					if (text.Contains("foil", StringComparison.OrdinalIgnoreCase))
					{
						cardFolderResolutionResult.IsFoil = true;
					}
					else if (Enum.TryParse<ECardExpansionType>(text, ignoreCase: true, out result))
					{
						cardFolderResolutionResult.ExpansionType = result;
					}
					else if (TryParseBorderFolder(text, out borderType))
					{
						cardFolderResolutionResult.BorderType = borderType;
					}
				}
			}
			return cardFolderResolutionResult;
		}

		private static bool TryParseBorderFolder(string borderName, out ECardBorderType borderType)
		{
			if (borderName.Equals("GhostWhite", StringComparison.OrdinalIgnoreCase))
			{
				borderType = (ECardBorderType)(-2);
				return true;
			}
			if (borderName.Equals("GhostBlack", StringComparison.OrdinalIgnoreCase))
			{
				borderType = (ECardBorderType)(-3);
				return true;
			}
			if (borderName.EndsWith("_black", StringComparison.OrdinalIgnoreCase))
			{
				borderType = (ECardBorderType)(-3);
				return true;
			}
			if (borderName.EndsWith("_white", StringComparison.OrdinalIgnoreCase))
			{
				borderType = (ECardBorderType)(-2);
				return true;
			}
			return Enum.TryParse<ECardBorderType>(borderName, ignoreCase: true, out borderType);
		}

		public static T ResolvePathFromCardInfo<T>(Dictionary<(EMonsterType, ECardBorderType, ECardExpansionType, bool), T> cache, EMonsterType monsterType, ECardBorderType borderType, ECardExpansionType expansionType, bool isBlackGhost, bool isFoil) where T : class
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Invalid comparison between Unknown and I4
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: 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_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: 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_008a: Unknown result type (might be due to invalid IL or missing references)
			ECardBorderType bt2 = borderType;
			if ((int)expansionType == 2)
			{
				bt2 = (ECardBorderType)(isBlackGhost ? (-3) : (-2));
			}
			T val = TryLookup(monsterType, bt2, expansionType);
			if (val != null)
			{
				return val;
			}
			val = TryLookup(monsterType, (ECardBorderType)(-1), expansionType);
			if (val != null)
			{
				return val;
			}
			val = TryLookup(monsterType, bt2, (ECardExpansionType)(-1));
			if (val != null)
			{
				return val;
			}
			return TryLookup(monsterType, (ECardBorderType)(-1), (ECardExpansionType)(-1));
			T TryLookup(EMonsterType mt, ECardBorderType bt, ECardExpansionType et, bool tryFoilFallback = true)
			{
				//IL_0003: Unknown result type (might be due to invalid IL or missing references)
				//IL_0004: Unknown result type (might be due to invalid IL or missing references)
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				//IL_0039: 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_003b: Unknown result type (might be due to invalid IL or missing references)
				(EMonsterType, ECardBorderType, ECardExpansionType, bool) key = (mt, bt, et, isFoil);
				if (cache.TryGetValue(key, out var value))
				{
					return value;
				}
				if (tryFoilFallback && isFoil)
				{
					key = (mt, bt, et, false);
					if (cache.TryGetValue(key, out value))
					{
						return value;
					}
				}
				return null;
			}
		}
	}
	public static class FileNameToMonsterTypeResolver
	{
		public static bool TryResolveMonsterType(string filename, out EMonsterType monsterType)
		{
			monsterType = (EMonsterType)0;
			if (int.TryParse(filename, out var _))
			{
				return false;
			}
			filename = Path.GetFileNameWithoutExtension(filename);
			string[] array = new string[7] { "Tetramon_", "Destiny_", "Ghost_", "Megabot_", "FantasyRPG_", "CatJob_", "FoodieGO_" };
			string[] array2 = array;
			foreach (string oldValue in array2)
			{
				filename = filename.Replace(oldValue, "", StringComparison.OrdinalIgnoreCase);
			}
			switch (filename.ToLowerInvariant())
			{
			case "mummy":
				monsterType = (EMonsterType)38;
				return true;
			case "crystala":
				monsterType = (EMonsterType)85;
				return true;
			case "crystalb":
				monsterType = (EMonsterType)86;
				return true;
			case "crystalc":
				monsterType = (EMonsterType)87;
				return true;
			case "max":
				monsterType = (EMonsterType)1026;
				return true;
			default:
				return !string.IsNullOrWhiteSpace(filename) && Enum.TryParse<EMonsterType>(filename, ignoreCase: true, out monsterType);
			}
		}
	}
	public class GhostCardAnimatedRenderer : MonoBehaviour
	{
		private Image mainImage;

		private Image maskImage;

		private Image glowImage;

		private Sprite[] frames;

		private Coroutine animationCoroutine;

		private float frameDelay = 0.1f;

		private CardUI parentCardUI;

		private bool wasAnimating = false;

		private string componentId;

		private bool pendingStart = false;

		private void Awake()
		{
			componentId = Guid.NewGuid().ToString().Substring(0, 8);
		}

		private void LogAnimationState(string eventName)
		{
		}

		public void Initialize(Image mainImage, Image maskImage, Image glowImage, Sprite[] frames)
		{
			GhostCardAnimatedRenderer[] components = ((Component)this).GetComponents<GhostCardAnimatedRenderer>();
			if (components.Length > 1)
			{
				GhostCardAnimatedRenderer[] array = components;
				foreach (GhostCardAnimatedRenderer ghostCardAnimatedRenderer in array)
				{
					if ((Object)(object)ghostCardAnimatedRenderer != (Object)(object)this)
					{
						ghostCardAnimatedRenderer.StopAnimation();
						Object.Destroy((Object)(object)ghostCardAnimatedRenderer);
					}
				}
			}
			LogAnimationState("Initialize");
			this.mainImage = mainImage;
			this.maskImage = maskImage;
			this.glowImage = glowImage;
			this.frames = frames;
			pendingStart = false;
			parentCardUI = ((Component)this).GetComponentInParent<CardUI>();
			StopAnimation();
			if (((Component)this).gameObject.activeInHierarchy)
			{
				StartAnimation();
			}
			else
			{
				pendingStart = true;
			}
		}

		public void StartAnimation()
		{
			LogAnimationState("StartAnimation Called");
			if (!((Component)this).gameObject.activeInHierarchy)
			{
				pendingStart = true;
			}
			else if (frames != null && frames.Length != 0 && animationCoroutine == null)
			{
				pendingStart = false;
				animationCoroutine = ((MonoBehaviour)this).StartCoroutine(AnimateSprites());
				LogAnimationState("Animation Started");
			}
		}

		public void StopAnimation()
		{
			LogAnimationState("StopAnimation Called");
			if (animationCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(animationCoroutine);
				animationCoroutine = null;
				LogAnimationState("Animation Stopped");
			}
		}

		private IEnumerator AnimateSprites()
		{
			LogAnimationState("Animation Coroutine Started");
			int currentFrame = 0;
			while (true)
			{
				mainImage.sprite = frames[currentFrame];
				maskImage.sprite = frames[currentFrame];
				if ((Object)(object)glowImage != (Object)null)
				{
					glowImage.sprite = frames[currentFrame];
				}
				currentFrame = (currentFrame + 1) % frames.Length;
				yield return (object)new WaitForSeconds(frameDelay);
			}
		}

		private void OnDisable()
		{
			LogAnimationState("OnDisable");
			wasAnimating = animationCoroutine != null;
			StopAnimation();
		}

		private void OnEnable()
		{
			LogAnimationState("OnEnable");
			if (wasAnimating || pendingStart)
			{
				StartAnimation();
			}
		}

		private void OnDestroy()
		{
			LogAnimationState("OnDestroy");
			StopAnimation();
		}

		public void ResetAnimation()
		{
			LogAnimationState("ResetAnimation Called");
			StopAnimation();
			StartAnimation();
		}
	}
}