Decompiled source of Stitchwork v0.8.6

plugins/Stitchwork.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using GlobalEnums;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Stitchwork;
using Stitchwork.GUI;
using Stitchwork.GUI.Pillars;
using Stitchwork.Handlers;
using Stitchwork.Packs;
using Stitchwork.Util;
using Stitchwork.Watchers;
using TMProOld;
using TeamCherry.Cinematics;
using TeamCherry.Localization;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.Networking;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using UnityEngine.Scripting;
using UnityEngine.TextCore;
using UnityEngine.TextCore.LowLevel;
using UnityEngine.UI;
using UnityEngine.Video;
using UnityStandardAssets.ImageEffects;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Stitchwork")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.8.6.0")]
[assembly: AssemblyInformationalVersion("0.8.6+c28c073e0f977ca49375077628d1be4bda3c86ac")]
[assembly: AssemblyProduct("Stitchwork")]
[assembly: AssemblyTitle("Stitchwork")]
[assembly: AssemblyMetadata("GameLibsPin", "1.2.0-silksong1.0.30000")]
[assembly: AssemblyMetadata("DevTools", "false")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.8.6.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;
		}
	}
}
[HarmonyPatch]
public static class AnimationController
{
	private sealed class AnimEntry
	{
		public string Name;

		public int Seq;

		public tk2dSpriteAnimator Live;

		public bool Stale;

		public float LastSeenRealtime;

		public tk2dSpriteAnimationClip Clip;

		public tk2dSpriteCollectionData FrameColl;

		public int Frame;

		public int SpriteId;

		public string ClipName;

		public string CollName;

		public string SpriteName;

		public int FrameCount;

		public tk2dSpriteAnimation Library;

		public tk2dSpriteAnimationClip ViewClip;

		public int ViewFrame;

		public readonly List<string> RecentClips = new List<string>();
	}

	private sealed class ClipCoverage
	{
		public int Frames;

		public int Shared;

		public int SharedFromPack;

		public int PerClip;

		public readonly List<string> MissingShared = new List<string>();
	}

	private static bool Paused = false;

	private static bool FrameChangeRequested = false;

	private static bool Frozen = false;

	private static Vector3 FrozenPosition;

	private const string HeroName = "Hero_Hornet(Clone)";

	private const int MaxRecentClips = 5;

	private static readonly Dictionary<string, AnimEntry> _entries = new Dictionary<string, AnimEntry>();

	private static int _seqCounter = 0;

	private const int MaxEntries = 64;

	private static readonly Color ColStale = new Color(0.5f, 0.5f, 0.5f);

	private static bool _browseClips;

	private static Vector2 _objectScroll;

	private static Vector2 _clipScroll;

	private static string _clipSearch = "";

	private static tk2dSpriteCollectionData _lensColl;

	private static int _lensSpriteId = -1;

	private static string _lensSpriteName;

	private static Action _pendingUiAction;

	private static bool _previewPlaying;

	private static tk2dSpriteAnimationClip _previewClip;

	private static int _previewFrame;

	private static float _previewClock;

	private static float _previewFps = 12f;

	private const float PreviewFallbackFps = 12f;

	private static float _wsCountAt = -999f;

	private static int _wsListSize = -1;

	private static List<tk2dSpriteAnimationClip> _wsClips;

	private const float SuffixColW = 132f;

	private static GUIStyle _suffixStyle;

	private static readonly Dictionary<(int libId, string clip, string coll), ClipCoverage> _coverage = new Dictionary<(int, string, string), ClipCoverage>();

	private static int _coverageIndexVersion = -1;

	private static readonly FieldInfo _windyLibField = AccessTools.Field(typeof(HeroAnimationController), "windyAnimLib");

	private static readonly Type _heroConfigType = AccessTools.TypeByName("HeroControllerConfig");

	private static readonly FieldInfo _heroConfigOverrideLib = ((_heroConfigType != null) ? AccessTools.Field(_heroConfigType, "heroAnimOverrideLib") : null);

	private static readonly List<tk2dSpriteAnimation> _configOverrideLibs = new List<tk2dSpriteAnimation>();

	private static float _configLibsNextScan;

	private static readonly Dictionary<int, string> _libDominantColl = new Dictionary<int, string>();

	private static int _dominantCollVersion = -1;

	private const string KeybindHex = "#B78CFF";

	private static GUIStyle _transportStyle;

	private static GUIStyle _hintStyle;

	private static Texture2D _spritePreviewTex;

	private static int _spvCollId = 0;

	private static int _spvSpriteId = -1;

	private static int _spvFileVer = -1;

	private static readonly Dictionary<(int coll, int sprite), Texture2D> _thumbCache = new Dictionary<(int, int), Texture2D>();

	private static int _thumbFileVer = -1;

	private const int ThumbCacheCap = 96;

	private const int ThumbRenderSize = 96;

	private static Texture2D _previewWhite;

	private static string _reuseCacheKey = null;

	private static int _reuseFrameCount = 0;

	private static int _reuseClipCount = 0;

	private static readonly List<(tk2dSpriteAnimationClip Clip, List<int> Frames)> _reuseSources = new List<(tk2dSpriteAnimationClip, List<int>)>();

	private static string _anchorCacheKey = null;

	private static bool _anchorReplExists = false;

	private static string _anchorCurrent = null;

	private static string _anchorFilePath = null;

	private static string _anchorPackSource = null;

	public static string SelectedAnimator { get; private set; } = null;

	private static GUIStyle SuffixStyle
	{
		get
		{
			//IL_000e: 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_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			object obj = _suffixStyle;
			if (obj == null)
			{
				GUIStyle val = new GUIStyle(GUIHelper.LabelStyle)
				{
					wordWrap = false,
					clipping = (TextClipping)1
				};
				_suffixStyle = val;
				obj = (object)val;
			}
			return (GUIStyle)obj;
		}
	}

	private static GUIStyle TransportStyle
	{
		get
		{
			//IL_0026: 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_0032: 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_0045: Expected O, but got Unknown
			int num = GUIHelper.FontSize(12);
			if (_transportStyle == null || _transportStyle.fontSize != num)
			{
				_transportStyle = new GUIStyle(GUI.skin.button)
				{
					fontSize = num,
					richText = true,
					alignment = (TextAnchor)4
				};
			}
			return _transportStyle;
		}
	}

	private static GUIStyle HintStyle
	{
		get
		{
			//IL_0026: 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_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			int num = GUIHelper.FontSize(12);
			if (_hintStyle == null || _hintStyle.fontSize != num)
			{
				_hintStyle = new GUIStyle(GUI.skin.label)
				{
					fontSize = num,
					wordWrap = true
				};
			}
			return _hintStyle;
		}
	}

	internal static void SelectFromWorldPick(string name)
	{
		SelectedAnimator = name;
		_browseClips = true;
	}

	public static void RegisterAnimator(tk2dSpriteAnimator animator)
	{
		if (!((Object)(object)animator == (Object)null) && !((Object)(object)((Component)animator).gameObject == (Object)null))
		{
			string name = ((Object)((Component)animator).gameObject).name;
			if (!_entries.TryGetValue(name, out var value))
			{
				value = new AnimEntry
				{
					Name = name,
					Seq = _seqCounter++
				};
				_entries[name] = value;
			}
			value.Live = animator;
			value.Stale = false;
		}
	}

	public static void ClearAnimators()
	{
		_entries.Clear();
		SelectedAnimator = null;
		Paused = false;
		Frozen = false;
		_seqCounter = 0;
		_browseClips = false;
		_clipSearch = "";
		ClearLens();
		StopPreview();
		_coverage.Clear();
		ClearThumbCache();
	}

	public static void ApplyPatches(Harmony harmony)
	{
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Expected O, but got Unknown
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: Expected O, but got Unknown
		//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c5: Expected O, but got Unknown
		//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_010d: Expected O, but got Unknown
		//IL_0154: Unknown result type (might be due to invalid IL or missing references)
		//IL_0162: Expected O, but got Unknown
		//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b7: Expected O, but got Unknown
		//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ff: Expected O, but got Unknown
		//IL_0246: Unknown result type (might be due to invalid IL or missing references)
		//IL_0254: Expected O, but got Unknown
		//IL_029b: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a9: Expected O, but got Unknown
		//IL_02fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_030b: Expected O, but got Unknown
		harmony.Patch((MethodBase)AccessTools.Method(typeof(tk2dSpriteAnimator), "Play", (Type[])null, (Type[])null), new HarmonyMethod(typeof(AnimationController), "PlayPatch", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		harmony.Patch((MethodBase)AccessTools.Method(typeof(tk2dSpriteAnimator), "Play", new Type[1] { typeof(string) }, (Type[])null), new HarmonyMethod(typeof(AnimationController), "PlayWithNamePatch", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		harmony.Patch((MethodBase)AccessTools.Method(typeof(tk2dSpriteAnimator), "Play", new Type[1] { typeof(tk2dSpriteAnimationClip) }, (Type[])null), new HarmonyMethod(typeof(AnimationController), "PlayWithClipPatch", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		harmony.Patch((MethodBase)AccessTools.Method(typeof(tk2dSpriteAnimator), "PlayFromFrame", new Type[1] { typeof(int) }, (Type[])null), new HarmonyMethod(typeof(AnimationController), "PlayFromFramePatch", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		harmony.Patch((MethodBase)AccessTools.Method(typeof(tk2dSpriteAnimator), "PlayFromFrame", new Type[2]
		{
			typeof(string),
			typeof(int)
		}, (Type[])null), new HarmonyMethod(typeof(AnimationController), "PlayFromFrameWithNamePatch", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		harmony.Patch((MethodBase)AccessTools.Method(typeof(tk2dSpriteAnimator), "PlayFromFrame", new Type[2]
		{
			typeof(tk2dSpriteAnimationClip),
			typeof(int)
		}, (Type[])null), new HarmonyMethod(typeof(AnimationController), "PlayFromFrameWithClipPatch", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		harmony.Patch((MethodBase)AccessTools.Method(typeof(tk2dSpriteAnimator), "PlayFrom", new Type[1] { typeof(float) }, (Type[])null), new HarmonyMethod(typeof(AnimationController), "PlayFromPatch", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		harmony.Patch((MethodBase)AccessTools.Method(typeof(tk2dSpriteAnimator), "PlayFrom", new Type[2]
		{
			typeof(string),
			typeof(float)
		}, (Type[])null), new HarmonyMethod(typeof(AnimationController), "PlayFromWithNamePatch", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		harmony.Patch((MethodBase)AccessTools.Method(typeof(tk2dSpriteAnimator), "PlayFrom", new Type[2]
		{
			typeof(tk2dSpriteAnimationClip),
			typeof(float)
		}, (Type[])null), new HarmonyMethod(typeof(AnimationController), "PlayFromWithClipPatch", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		harmony.Patch((MethodBase)AccessTools.Method(typeof(tk2dSpriteAnimator), "Play", new Type[3]
		{
			typeof(tk2dSpriteAnimationClip),
			typeof(float),
			typeof(float)
		}, (Type[])null), new HarmonyMethod(typeof(AnimationController), "PlayOverrideFpsPatch", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
	}

	private static bool PlayPatchInternal(tk2dSpriteAnimator __instance)
	{
		long heapBefore = DevProfiler.SnapshotHeapBytes();
		try
		{
			if ((Object)(object)__instance != (Object)null)
			{
				RegisterAnimator(__instance);
				if (SelectedAnimator == ((Object)((Component)__instance).gameObject).name && Paused && !FrameChangeRequested)
				{
					return false;
				}
			}
			return true;
		}
		finally
		{
			DevProfiler.AddOpPositiveNetHeapDelta("Prefix.tk2dAnim.Play", heapBefore);
		}
	}

	public static bool PlayPatch(tk2dSpriteAnimator __instance)
	{
		return PlayPatchInternal(__instance);
	}

	public static bool PlayWithNamePatch(tk2dSpriteAnimator __instance, string name)
	{
		return PlayPatchInternal(__instance);
	}

	public static bool PlayWithClipPatch(tk2dSpriteAnimator __instance, tk2dSpriteAnimationClip clip)
	{
		return PlayPatchInternal(__instance);
	}

	public static bool PlayFromFramePatch(tk2dSpriteAnimator __instance, int frame)
	{
		return PlayPatchInternal(__instance);
	}

	public static bool PlayFromFrameWithNamePatch(tk2dSpriteAnimator __instance, string name, int frame)
	{
		return PlayPatchInternal(__instance);
	}

	public static bool PlayFromFrameWithClipPatch(tk2dSpriteAnimator __instance, tk2dSpriteAnimationClip clip, int frame)
	{
		return PlayPatchInternal(__instance);
	}

	public static bool PlayFromPatch(tk2dSpriteAnimator __instance, float clipStartTime)
	{
		return PlayPatchInternal(__instance);
	}

	public static bool PlayFromWithNamePatch(tk2dSpriteAnimator __instance, string name, float clipStartTime)
	{
		return PlayPatchInternal(__instance);
	}

	public static bool PlayFromWithClipPatch(tk2dSpriteAnimator __instance, tk2dSpriteAnimationClip clip, float clipStartTime)
	{
		return PlayPatchInternal(__instance);
	}

	public static bool PlayOverrideFpsPatch(tk2dSpriteAnimator __instance, tk2dSpriteAnimationClip clip, float clipStartTime, float overrideFps)
	{
		return PlayPatchInternal(__instance);
	}

	private static bool TryGetLiveSelected(out tk2dSpriteAnimator animator)
	{
		animator = null;
		if (SelectedAnimator != null && _entries.TryGetValue(SelectedAnimator, out var value) && (Object)(object)value.Live != (Object)null && (Object)(object)((Component)value.Live).gameObject != (Object)null)
		{
			animator = value.Live;
		}
		return (Object)(object)animator != (Object)null;
	}

	public static void Update()
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		if (!GUIHelper.IsTextFieldFocused)
		{
			if (Input.GetKeyDown(Plugin.Config.AnimationControllerPauseKey))
			{
				TogglePause();
			}
			if (Input.GetKeyDown(Plugin.Config.AnimationControllerFreezeKey))
			{
				ToggleFreeze();
			}
			if (Input.GetKeyDown(Plugin.Config.AnimationControllerNextFrameKey))
			{
				StepFrame(1);
			}
			if (Input.GetKeyDown(Plugin.Config.AnimationControllerPrevFrameKey))
			{
				StepFrame(-1);
			}
		}
		if (Frozen && TryGetLiveSelected(out var animator))
		{
			((Component)animator).gameObject.transform.position = FrozenPosition;
		}
		if (_previewPlaying)
		{
			tk2dSpriteAnimationClip previewClip = _previewClip;
			if (previewClip == null || previewClip.frames == null || previewClip.frames.Length == 0)
			{
				StopPreview();
			}
			else
			{
				int num = previewClip.frames.Length;
				float num2 = 1f / _previewFps;
				_previewClock += Time.unscaledDeltaTime;
				while (_previewClock >= num2)
				{
					_previewClock -= num2;
					_previewFrame = (_previewFrame + 1) % num;
				}
			}
		}
		foreach (AnimEntry value in _entries.Values)
		{
			tk2dSpriteAnimator live = value.Live;
			if ((Object)(object)live == (Object)null || (Object)(object)((Component)live).gameObject == (Object)null)
			{
				value.Live = null;
				MarkStale(value);
				continue;
			}
			if (!((Component)live).gameObject.activeSelf || live.CurrentClip == null || live.CurrentFrame < 0 || live.CurrentFrame >= live.CurrentClip.frames.Length)
			{
				MarkStale(value);
				continue;
			}
			RefreshSnapshot(value, live);
			value.Stale = false;
			value.ViewClip = null;
			value.LastSeenRealtime = Time.realtimeSinceStartup;
		}
		if (_entries.Count > 64)
		{
			EvictOldestStale();
		}
	}

	private static void RefreshSnapshot(AnimEntry e, tk2dSpriteAnimator a)
	{
		tk2dSpriteAnimationClip currentClip = a.CurrentClip;
		int currentFrame = a.CurrentFrame;
		tk2dSpriteAnimationFrame val = currentClip.frames[currentFrame];
		if (e.ClipName != currentClip.name)
		{
			e.RecentClips.Remove(currentClip.name);
			e.RecentClips.Insert(0, currentClip.name);
			if (e.RecentClips.Count > 5)
			{
				e.RecentClips.RemoveAt(5);
			}
		}
		e.Clip = currentClip;
		e.Frame = currentFrame;
		e.FrameColl = val.spriteCollection;
		e.SpriteId = val.spriteId;
		e.ClipName = currentClip.name;
		e.FrameCount = currentClip.frames.Length;
		e.Library = a.Library;
		if ((Object)(object)e.FrameColl != (Object)null && val.spriteId >= 0 && val.spriteId < e.FrameColl.spriteDefinitions.Length)
		{
			e.CollName = ((Object)e.FrameColl).name;
			e.SpriteName = e.FrameColl.spriteDefinitions[val.spriteId].name;
		}
	}

	private static void MarkStale(AnimEntry e)
	{
		e.Stale = true;
		if (e.ViewClip == null && e.Clip != null)
		{
			e.ViewClip = e.Clip;
			e.ViewFrame = e.Frame;
		}
	}

	private static void EvictOldestStale()
	{
		List<AnimEntry> list = (from e in _entries.Values
			where e.Stale && e.Name != SelectedAnimator && e.Name != "Hero_Hornet(Clone)"
			orderby e.LastSeenRealtime
			select e).ToList();
		int num = _entries.Count - 64;
		int num2 = 0;
		while (num2 < list.Count && num > 0)
		{
			_entries.Remove(list[num2].Name);
			num2++;
			num--;
		}
	}

	private static void SelectAnimator(AnimEntry e)
	{
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		Frozen = false;
		if (Paused && TryGetLiveSelected(out var animator))
		{
			animator.Resume();
		}
		Paused = false;
		SelectedAnimator = e.Name;
		_browseClips = true;
		_clipSearch = "";
		_clipScroll = Vector2.zero;
		ClearLens();
		StopPreview();
	}

	private static void TogglePause()
	{
		StopPreview();
		if (TryGetLiveSelected(out var animator))
		{
			Paused = !Paused;
			if (Paused)
			{
				animator.Pause();
			}
			else
			{
				animator.Resume();
			}
		}
	}

	private static void ToggleFreeze()
	{
		//IL_0022: 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)
		if (TryGetLiveSelected(out var animator))
		{
			Frozen = !Frozen;
			FrozenPosition = ((Component)animator).gameObject.transform.position;
		}
	}

	private static void StepFrame(int delta)
	{
		StopPreview();
		tk2dSpriteAnimator animator;
		if (SelectedAnimator != null && _entries.TryGetValue(SelectedAnimator, out var value) && (value.Stale || (Object)(object)value.Live == (Object)null))
		{
			if (value.ViewClip != null && value.ViewClip.frames != null && value.ViewClip.frames.Length != 0)
			{
				int num = value.ViewClip.frames.Length;
				value.ViewFrame = ((value.ViewFrame + delta) % num + num) % num;
			}
		}
		else if (TryGetLiveSelected(out animator) && Paused && animator.CurrentClip != null)
		{
			int num2 = animator.CurrentClip.frames.Length;
			if (num2 > 0)
			{
				int num3 = ((animator.CurrentFrame + delta) % num2 + num2) % num2;
				FrameChangeRequested = true;
				animator.PlayFromFrame(num3);
				animator.UpdateAnimation(Time.deltaTime);
				FrameChangeRequested = false;
			}
		}
	}

	private static float ResolvePreviewFps(AnimEntry e, tk2dSpriteAnimationClip clip)
	{
		return 12f;
	}

	private static void StopPreview()
	{
		_previewPlaying = false;
		_previewClip = null;
	}

	private static void ClearLens()
	{
		_lensColl = null;
		_lensSpriteId = -1;
		_lensSpriteName = null;
	}

	private static void SetLens(tk2dSpriteCollectionData coll, int spriteId, string spriteName)
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		_lensColl = coll;
		_lensSpriteId = spriteId;
		_lensSpriteName = spriteName;
		_browseClips = true;
		_clipScroll = Vector2.zero;
		_clipSearch = "";
	}

	private static AnimEntry SelectedEntry()
	{
		if (SelectedAnimator == null || !_entries.TryGetValue(SelectedAnimator, out var value))
		{
			return null;
		}
		return value;
	}

	public static void DrawPillarContent()
	{
		AnimEntry animEntry = SelectedEntry();
		GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandHeight(true) });
		GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
		if (_browseClips && animEntry != null && animEntry.ClipName != null)
		{
			DrawClipStage(animEntry);
		}
		else
		{
			DrawObjectStage();
		}
		GUILayout.EndVertical();
		float num = GUIHelper.Scaled(190f);
		GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(num) });
		DrawPreviewColumn(animEntry, num);
		GUILayout.EndVertical();
		GUILayout.EndHorizontal();
		GUIHelper.Space(4f);
		DrawConsole(animEntry);
		if (_pendingUiAction != null)
		{
			Action pendingUiAction = _pendingUiAction;
			_pendingUiAction = null;
			pendingUiAction();
		}
	}

	private static void DrawObjectStage()
	{
		//IL_0000: 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_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_0094: Unknown result type (might be due to invalid IL or missing references)
		Color backgroundColor = GUI.backgroundColor;
		GUI.backgroundColor = GUIHelper.ColConfirm;
		if (GUILayout.Button(Loc.T("Pick object in world"), GUIHelper.ButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUIHelper.Height(40f) }))
		{
			_pendingUiAction = delegate
			{
				WorldPickMode.Enter(WorldPickMode.Preset.Tk2d);
			};
		}
		GUI.backgroundColor = backgroundColor;
		if (_entries.Count == 0)
		{
			GUI.contentColor = GUIHelper.ColFaint;
			GUILayout.Label(Loc.T("No animators registered."), GUIHelper.LabelStyle, Array.Empty<GUILayoutOption>());
			GUI.contentColor = Color.white;
			return;
		}
		_objectScroll = GUILayout.BeginScrollView(_objectScroll, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandHeight(true) });
		foreach (AnimEntry item in from x in _entries.Values
			orderby (!(x.Name == "Hero_Hornet(Clone)")) ? 1 : 0, x.Seq
			select x)
		{
			if (item.ClipName != null)
			{
				DrawObjectRow(item);
			}
		}
		GUILayout.EndScrollView();
	}

	private static void DrawObjectRow(AnimEntry e)
	{
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ea: 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_00f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0172: Unknown result type (might be due to invalid IL or missing references)
		bool flag = SelectedAnimator == e.Name;
		bool flag2 = e.Stale || (Object)(object)e.Live == (Object)null;
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		float num = GUIHelper.Scaled(40f);
		DrawSpriteThumb(GUILayoutUtility.GetRect(num, num, (GUILayoutOption[])(object)new GUILayoutOption[2]
		{
			GUILayout.Width(num),
			GUILayout.Height(num)
		}), e.FrameColl, e.SpriteId, flag2);
		GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
		GUI.contentColor = (flag ? GUIHelper.ColConfirm : (flag2 ? ColStale : Color.white));
		if (GUILayout.Button(e.Name, GUIHelper.ButtonStyle, Array.Empty<GUILayoutOption>()))
		{
			_pendingUiAction = delegate
			{
				SelectAnimator(e);
			};
		}
		GUI.contentColor = Color.white;
		GUI.contentColor = (flag2 ? ColStale : GUIHelper.ColMuted);
		GUILayout.Label($"{e.ClipName}  ·  {e.Frame + 1}/{e.FrameCount}" + (flag2 ? ("   " + Loc.T("(stopped)")) : ""), GUIHelper.LabelStyle, Array.Empty<GUILayoutOption>());
		GUI.contentColor = Color.white;
		GUILayout.EndVertical();
		GUILayout.EndHorizontal();
		GUIHelper.Space(2f);
	}

	private static void DrawSpriteThumb(Rect r, tk2dSpriteCollectionData coll, int spriteId, bool dim)
	{
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
		//IL_0110: Unknown result type (might be due to invalid IL or missing references)
		//IL_0120: Unknown result type (might be due to invalid IL or missing references)
		//IL_0226: Unknown result type (might be due to invalid IL or missing references)
		//IL_0201: Unknown result type (might be due to invalid IL or missing references)
		//IL_0207: Unknown result type (might be due to invalid IL or missing references)
		//IL_021b: Unknown result type (might be due to invalid IL or missing references)
		EnsurePreviewWhite();
		GUI.color = GUIHelper.ColSurface2;
		GUI.DrawTexture(r, (Texture)(object)_previewWhite);
		GUI.color = Color.white;
		if ((Object)(object)coll == (Object)null || coll.spriteDefinitions == null || spriteId < 0 || spriteId >= coll.spriteDefinitions.Length)
		{
			return;
		}
		tk2dSpriteDefinition val = coll.spriteDefinitions[spriteId];
		Material val2 = (((Object)(object)val.materialInst != (Object)null) ? val.materialInst : val.material);
		Texture val3 = (((Object)(object)val2 != (Object)null) ? val2.mainTexture : null);
		Vector2[] uvs = val.uvs;
		if ((Object)(object)val3 == (Object)null || uvs == null || uvs.Length < 4)
		{
			return;
		}
		Rect container = default(Rect);
		((Rect)(ref container))..ctor(((Rect)(ref r)).x + 2f, ((Rect)(ref r)).y + 2f, ((Rect)(ref r)).width - 4f, ((Rect)(ref r)).height - 4f);
		GUI.color = (Color)(dim ? new Color(1f, 1f, 1f, 0.45f) : Color.white);
		Texture2D uprightThumb = GetUprightThumb(coll, spriteId, val, val3);
		if ((Object)(object)uprightThumb != (Object)null)
		{
			GUI.DrawTexture(ScaleToFitRect(container, ((Texture)uprightThumb).width, ((Texture)uprightThumb).height), (Texture)(object)uprightThumb);
		}
		else
		{
			float num = uvs.Min((Vector2 v) => v.x);
			float num2 = uvs.Max((Vector2 v) => v.x);
			float num3 = uvs.Min((Vector2 v) => v.y);
			float num4 = uvs.Max((Vector2 v) => v.y);
			int texW = Mathf.Max(1, Mathf.RoundToInt((num2 - num) * (float)val3.width));
			int texH = Mathf.Max(1, Mathf.RoundToInt((num4 - num3) * (float)val3.height));
			GUI.DrawTextureWithTexCoords(ScaleToFitRect(container, texW, texH), val3, new Rect(num, num3, num2 - num, num4 - num3), true);
		}
		GUI.color = Color.white;
	}

	private static void DrawClipStage(AnimEntry e)
	{
		//IL_009c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_010f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0183: Unknown result type (might be due to invalid IL or missing references)
		//IL_0188: Unknown result type (might be due to invalid IL or missing references)
		//IL_0368: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_0440: Unknown result type (might be due to invalid IL or missing references)
		//IL_0470: Unknown result type (might be due to invalid IL or missing references)
		//IL_04cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_04e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_04e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0515: Unknown result type (might be due to invalid IL or missing references)
		//IL_0539: Unknown result type (might be due to invalid IL or missing references)
		//IL_05ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_05d0: Unknown result type (might be due to invalid IL or missing references)
		bool flag = e.Stale || (Object)(object)e.Live == (Object)null;
		bool live = !flag && (Object)(object)e.Live != (Object)null && (Object)(object)((Component)e.Live).gameObject != (Object)null;
		if (GUILayout.Button("◂  " + e.Name + "   ·   " + Loc.T("click to change object"), GUIHelper.ButtonStyle, Array.Empty<GUILayoutOption>()))
		{
			_pendingUiAction = delegate
			{
				_browseClips = false;
			};
		}
		if (flag)
		{
			GUI.contentColor = ColStale;
			GUILayout.Label(Loc.T("(stopped — inspecting the snapshot)"), GUIHelper.LabelStyle, Array.Empty<GUILayoutOption>());
			GUI.contentColor = Color.white;
		}
		tk2dSpriteAnimation library = e.Library;
		if ((Object)(object)library == (Object)null || library.clips == null || library.clips.Length == 0)
		{
			GUI.contentColor = GUIHelper.ColFaint;
			GUILayout.Label(Loc.T("No clip library on this object."), GUIHelper.LabelStyle, Array.Empty<GUILayoutOption>());
			GUI.contentColor = Color.white;
			return;
		}
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		GUILayout.Label(Loc.T("Search:"), GUIHelper.LabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUIHelper.Width(60f) });
		_clipSearch = GUIHelper.TextField(_clipSearch, GUILayout.ExpandWidth(true), GUIHelper.Height(32f));
		GUILayout.EndHorizontal();
		if (_lensSpriteName != null)
		{
			Color backgroundColor = GUI.backgroundColor;
			GUI.backgroundColor = GUIHelper.ColWarn;
			if (GUILayout.Button(Loc.T("Reusing this sprite") + ": " + _lensSpriteName + "   ✕", GUIHelper.ButtonStyle, Array.Empty<GUILayoutOption>()))
			{
				_pendingUiAction = ClearLens;
			}
			GUI.backgroundColor = backgroundColor;
		}
		List<tk2dSpriteAnimationClip> list = library.clips.Where((tk2dSpriteAnimationClip c) => c != null && !string.IsNullOrEmpty(c.name)).ToList();
		IEnumerable<tk2dSpriteAnimationClip> enumerable = SecondaryLibClips(e, library);
		if (enumerable != null)
		{
			list.AddRange(enumerable);
		}
		HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
		HashSet<string> hashSet2 = new HashSet<string>(StringComparer.Ordinal);
		foreach (tk2dSpriteAnimationClip item in list)
		{
			if (!hashSet2.Add(item.name))
			{
				hashSet.Add(item.name);
			}
		}
		IEnumerable<tk2dSpriteAnimationClip> source = list;
		if (!string.IsNullOrEmpty(_clipSearch))
		{
			string q = _clipSearch;
			source = source.Where((tk2dSpriteAnimationClip c) => c.name.IndexOf(q, StringComparison.OrdinalIgnoreCase) >= 0);
		}
		if (_lensSpriteId >= 0)
		{
			source = source.Where((tk2dSpriteAnimationClip c) => ClipUsesSprite(c, _lensColl, _lensSpriteId));
		}
		List<tk2dSpriteAnimationClip> list2 = source.OrderBy<tk2dSpriteAnimationClip, string>((tk2dSpriteAnimationClip c) => c.name, StringComparer.OrdinalIgnoreCase).ToList();
		HashSet<tk2dSpriteAnimationClip> mainSet = new HashSet<tk2dSpriteAnimationClip>(library.clips ?? Array.Empty<tk2dSpriteAnimationClip>());
		int num = list2.Count((tk2dSpriteAnimationClip c) => !mainSet.Contains(c));
		int num2 = list2.Count - num;
		GUI.contentColor = GUIHelper.ColFaint;
		GUILayout.Label((num > 0) ? string.Format(Loc.T("{0} + {1} variants"), num2, num) : $"{num2} / {library.clips.Length}", GUIHelper.LabelStyle, Array.Empty<GUILayoutOption>());
		GUI.contentColor = Color.white;
		bool reserveSuffixCol = false;
		string dominantCollection = GetDominantCollection(library);
		foreach (tk2dSpriteAnimationClip item2 in list2)
		{
			string text = PrimaryCollectionName(item2);
			if (text != null && (hashSet.Contains(item2.name) || !string.Equals(text, dominantCollection, StringComparison.Ordinal)))
			{
				reserveSuffixCol = true;
				break;
			}
		}
		string dominantCollection2 = GetDominantCollection(library);
		if (dominantCollection2 != null)
		{
			GUI.contentColor = GUIHelper.ColMuted;
			GUILayout.Label(Loc.T("Collection") + ": " + dominantCollection2, GUIHelper.LabelStyle, Array.Empty<GUILayoutOption>());
			GUI.contentColor = Color.white;
		}
		DrawBatchRow(list2);
		tk2dSpriteAnimationClip val = ((!flag) ? e.Clip : ((e.ViewClip != null) ? e.ViewClip : e.Clip));
		string currentClip = ((!flag) ? e.ClipName : ((e.ViewClip != null) ? e.ViewClip.name : e.ClipName));
		_clipScroll = GUILayout.BeginScrollView(_clipScroll, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandHeight(true) });
		if (string.IsNullOrEmpty(_clipSearch) && _lensSpriteId < 0 && e.RecentClips.Count > 0)
		{
			GUI.contentColor = GUIHelper.ColMuted;
			GUILayout.Label(Loc.T("Recently played"), GUIHelper.LabelStyle, Array.Empty<GUILayoutOption>());
			GUI.contentColor = Color.white;
			foreach (string recentClip in e.RecentClips)
			{
				tk2dSpriteAnimationClip val2 = ((val != null && val.name == recentClip) ? val : FindClip(library, recentClip));
				if (val2 != null)
				{
					DrawClipRow(e, library, val2, val, currentClip, live, hashSet, reserveSuffixCol);
				}
			}
			GUI.contentColor = GUIHelper.ColMuted;
			GUILayout.Label(Loc.T("All clips"), GUIHelper.LabelStyle, Array.Empty<GUILayoutOption>());
			GUI.contentColor = Color.white;
		}
		foreach (tk2dSpriteAnimationClip item3 in list2)
		{
			DrawClipRow(e, library, item3, val, currentClip, live, hashSet, reserveSuffixCol);
		}
		GUILayout.EndScrollView();
	}

	private static void DrawBatchRow(List<tk2dSpriteAnimationClip> list)
	{
		//IL_0014: 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_00f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_012b: Unknown result type (might be due to invalid IL or missing references)
		if (AnimCanvasBatch.IsRunning)
		{
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUI.contentColor = GUIHelper.ColMuted;
			GUILayout.Label(string.Format(Loc.T("Batch: {0}/{1}"), AnimCanvasBatch.Processed, AnimCanvasBatch.Total) + " · " + AnimCanvasBatch.CurrentClip, GUIHelper.LabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
			GUI.contentColor = Color.white;
			if (GUILayout.Button(Loc.T("Cancel"), GUIHelper.ButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUIHelper.Width(80f) }))
			{
				AnimCanvasBatch.Cancel();
			}
			GUILayout.EndHorizontal();
			return;
		}
		if (Time.unscaledTime - _wsCountAt > 2f || _wsClips == null || list.Count != _wsListSize)
		{
			_wsClips = AnimCanvasBatch.WithWorkspace(list);
			_wsListSize = list.Count;
			_wsCountAt = Time.unscaledTime;
		}
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		GUI.contentColor = GUIHelper.ColMuted;
		GUILayout.Label(Loc.T("Canvas:"), GUIHelper.LabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUIHelper.Width(58f) });
		GUI.contentColor = Color.white;
		if (GUILayout.Button(string.Format(Loc.T("Extract {0} listed"), list.Count), GUIHelper.ButtonStyle, Array.Empty<GUILayoutOption>()))
		{
			AnimCanvasBatch.ExtractAll(list, fromCurrentRender: false);
		}
		if (GUILayout.Button(Loc.T("Extract As Rendered"), GUIHelper.ButtonStyle, Array.Empty<GUILayoutOption>()))
		{
			AnimCanvasBatch.ExtractAll(list, fromCurrentRender: true);
		}
		GUI.enabled = _wsClips.Count > 0;
		if (GUILayout.Button(string.Format(Loc.T("Compile {0} workspaces"), _wsClips.Count), GUIHelper.ButtonStyle, Array.Empty<GUILayoutOption>()))
		{
			AnimCanvasBatch.CompileAll(_wsClips);
		}
		GUI.enabled = true;
		GUILayout.EndHorizontal();
	}

	private static void DrawClipRow(AnimEntry e, tk2dSpriteAnimation lib, tk2dSpriteAnimationClip clip, tk2dSpriteAnimationClip currentObj, string currentClip, bool live, HashSet<string> dupNames, bool reserveSuffixCol)
	{
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_0136: Unknown result type (might be due to invalid IL or missing references)
		//IL_015e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0157: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_01de: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0231: Unknown result type (might be due to invalid IL or missing references)
		//IL_0289: Unknown result type (might be due to invalid IL or missing references)
		//IL_0282: Unknown result type (might be due to invalid IL or missing references)
		//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
		ClipCoverage coverage = GetCoverage(lib, clip);
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		Color color = ((coverage.Shared == 0) ? GUIHelper.ColBorderHi : ((coverage.SharedFromPack > 0) ? GUIHelper.ColPackBlue : GUIHelper.ColConfirm));
		string text = string.Format("{0}: {1}/{2}", Loc.T("shared replacements"), coverage.Shared, coverage.Frames);
		if (coverage.SharedFromPack > 0)
		{
			text = text + " · " + string.Format(Loc.T("{0} from pack"), coverage.SharedFromPack);
		}
		if (coverage.Shared > 0 && coverage.Shared < coverage.Frames && coverage.MissingShared.Count > 0)
		{
			text = text + "\n" + Loc.T("not found") + ": " + string.Join(", ", coverage.MissingShared) + ((coverage.Frames - coverage.Shared > coverage.MissingShared.Count) ? ", …" : "");
		}
		GUIHelper.StatusDotSlot(DotStateFor(coverage.Shared, coverage.Frames), color, text);
		GUIHelper.StatusDotSlot(DotStateFor(coverage.PerClip, coverage.Frames), (coverage.PerClip > 0) ? GUIHelper.ColAccent : GUIHelper.ColBorderHi, string.Format("{0}: {1}/{2}", Loc.T("per-clip (Appliqué)"), coverage.PerClip, coverage.Frames));
		bool flag = ((currentObj != null) ? (clip == currentObj) : (clip.name == currentClip));
		GUI.contentColor = (flag ? GUIHelper.ColConfirm : Color.white);
		if (GUILayout.Button(clip.name, GUIHelper.ButtonStyle, Array.Empty<GUILayoutOption>()))
		{
			PlayClip(e, clip, live);
		}
		GUI.contentColor = Color.white;
		GUI.contentColor = GUIHelper.ColFaint;
		GUILayout.Label($"×{((clip.frames != null) ? clip.frames.Length : 0)}", GUIHelper.LabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUIHelper.Width(40f) });
		GUI.contentColor = Color.white;
		if (reserveSuffixCol)
		{
			string text2 = PrimaryCollectionName(clip);
			bool flag2 = dupNames?.Contains(clip.name) ?? false;
			bool num = text2 != null && (flag2 || !string.Equals(text2, GetDominantCollection(lib), StringComparison.Ordinal));
			GUI.contentColor = (flag ? GUIHelper.ColConfirm : GUIHelper.ColFaint);
			GUILayout.Label((GUIContent)((!num) ? ((object)GUIContent.none) : ((object)new GUIContent("· " + text2, text2))), SuffixStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUIHelper.Width(132f) });
			GUI.contentColor = Color.white;
		}
		GUILayout.EndHorizontal();
	}

	private static void PlayClip(AnimEntry e, tk2dSpriteAnimationClip clip, bool live)
	{
		StopPreview();
		if (live && (Object)(object)e.Live != (Object)null)
		{
			tk2dSpriteAnimator live2 = e.Live;
			Paused = true;
			live2.Pause();
			FrameChangeRequested = true;
			live2.Play(clip);
			live2.UpdateAnimation(Time.deltaTime);
			FrameChangeRequested = false;
		}
		else
		{
			e.ViewClip = clip;
			e.ViewFrame = 0;
		}
	}

	private static tk2dSpriteAnimationClip FindClip(tk2dSpriteAnimation lib, string name)
	{
		tk2dSpriteAnimationClip[] clips = lib.clips;
		foreach (tk2dSpriteAnimationClip val in clips)
		{
			if (val != null && val.name == name)
			{
				return val;
			}
		}
		return null;
	}

	private static bool ClipUsesSprite(tk2dSpriteAnimationClip clip, tk2dSpriteCollectionData coll, int spriteId)
	{
		if (clip == null || clip.frames == null || (Object)(object)coll == (Object)null)
		{
			return false;
		}
		tk2dSpriteAnimationFrame[] frames = clip.frames;
		foreach (tk2dSpriteAnimationFrame val in frames)
		{
			if ((Object)(object)val.spriteCollection == (Object)(object)coll && val.spriteId == spriteId)
			{
				return true;
			}
		}
		return false;
	}

	private static void RefreshConfigOverrideLibs()
	{
		if (_heroConfigOverrideLib == null || Time.realtimeSinceStartup < _configLibsNextScan)
		{
			return;
		}
		_configLibsNextScan = Time.realtimeSinceStartup + 5f;
		_configOverrideLibs.Clear();
		Object[] array = Resources.FindObjectsOfTypeAll(_heroConfigType);
		foreach (Object val in array)
		{
			if (!(val == (Object)null))
			{
				object? value = _heroConfigOverrideLib.GetValue(val);
				tk2dSpriteAnimation val2 = (tk2dSpriteAnimation)((value is tk2dSpriteAnimation) ? value : null);
				if (val2 != null && (Object)(object)val2 != (Object)null && val2.clips != null && !_configOverrideLibs.Contains(val2))
				{
					_configOverrideLibs.Add(val2);
				}
			}
		}
	}

	private static IEnumerable<tk2dSpriteAnimationClip> SecondaryLibClips(AnimEntry e, tk2dSpriteAnimation mainLib)
	{
		if (e == null)
		{
			return null;
		}
		tk2dSpriteAnimator live = e.Live;
		if ((Object)(object)live == (Object)null)
		{
			return null;
		}
		HeroAnimationController component = ((Component)live).GetComponent<HeroAnimationController>();
		if ((Object)(object)component == (Object)null)
		{
			return null;
		}
		List<tk2dSpriteAnimation> list = new List<tk2dSpriteAnimation>();
		if (_windyLibField != null)
		{
			object? value = _windyLibField.GetValue(component);
			tk2dSpriteAnimation val = (tk2dSpriteAnimation)((value is tk2dSpriteAnimation) ? value : null);
			if (val != null && (Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)mainLib && val.clips != null)
			{
				list.Add(val);
			}
		}
		RefreshConfigOverrideLibs();
		foreach (tk2dSpriteAnimation configOverrideLib in _configOverrideLibs)
		{
			if ((Object)(object)configOverrideLib != (Object)null && (Object)(object)configOverrideLib != (Object)(object)mainLib && !list.Contains(configOverrideLib))
			{
				list.Add(configOverrideLib);
			}
		}
		if (list.Count == 0)
		{
			return null;
		}
		HashSet<tk2dSpriteAnimationClip> mainSet = new HashSet<tk2dSpriteAnimationClip>(mainLib.clips ?? Array.Empty<tk2dSpriteAnimationClip>());
		HashSet<tk2dSpriteAnimationClip> seen = new HashSet<tk2dSpriteAnimationClip>();
		return from c in list.SelectMany((tk2dSpriteAnimation l) => l.clips)
			where c != null && !string.IsNullOrEmpty(c.name) && !mainSet.Contains(c) && seen.Add(c)
			select c;
	}

	private static string GetDominantCollection(tk2dSpriteAnimation lib)
	{
		if (_dominantCollVersion != SpriteLoader.FileIndexVersion)
		{
			_libDominantColl.Clear();
			_dominantCollVersion = SpriteLoader.FileIndexVersion;
		}
		int instanceID = ((Object)lib).GetInstanceID();
		if (_libDominantColl.TryGetValue(instanceID, out var value))
		{
			return value;
		}
		Dictionary<string, int> dictionary = new Dictionary<string, int>();
		if (lib.clips != null)
		{
			tk2dSpriteAnimationClip[] clips = lib.clips;
			foreach (tk2dSpriteAnimationClip val in clips)
			{
				if (val == null || val.frames == null)
				{
					continue;
				}
				tk2dSpriteAnimationFrame[] frames = val.frames;
				for (int j = 0; j < frames.Length; j++)
				{
					tk2dSpriteCollectionData spriteCollection = frames[j].spriteCollection;
					if (!((Object)(object)spriteCollection == (Object)null))
					{
						dictionary[((Object)spriteCollection).name] = ((!dictionary.TryGetValue(((Object)spriteCollection).name, out var value2)) ? 1 : (value2 + 1));
					}
				}
			}
		}
		string text = null;
		int num = 0;
		foreach (KeyValuePair<string, int> item in dictionary)
		{
			if (item.Value > num)
			{
				num = item.Value;
				text = item.Key;
			}
		}
		_libDominantColl[instanceID] = text;
		return text;
	}

	private static string PrimaryCollectionName(tk2dSpriteAnimationClip clip)
	{
		if (clip.frames == null)
		{
			return null;
		}
		tk2dSpriteAnimationFrame[] frames = clip.frames;
		for (int i = 0; i < frames.Length; i++)
		{
			tk2dSpriteCollectionData spriteCollection = frames[i].spriteCollection;
			if ((Object)(object)spriteCollection != (Object)null)
			{
				return ((Object)spriteCollection).name;
			}
		}
		return null;
	}

	private static GUIHelper.DotState DotStateFor(int n, int total)
	{
		if (n > 0)
		{
			if (n < total)
			{
				return GUIHelper.DotState.Partial;
			}
			return GUIHelper.DotState.Full;
		}
		return GUIHelper.DotState.None;
	}

	private static ClipCoverage GetCoverage(tk2dSpriteAnimation lib, tk2dSpriteAnimationClip clip)
	{
		if (_coverageIndexVersion != SpriteLoader.FileIndexVersion)
		{
			_coverage.Clear();
			_coverageIndexVersion = SpriteLoader.FileIndexVersion;
		}
		(int, string, string) key = (((Object)lib).GetInstanceID(), clip.name, PrimaryCollectionName(clip));
		if (_coverage.TryGetValue(key, out var value))
		{
			return value;
		}
		value = new ClipCoverage();
		if (clip.frames != null)
		{
			tk2dSpriteAnimationFrame[] frames = clip.frames;
			foreach (tk2dSpriteAnimationFrame val in frames)
			{
				tk2dSpriteCollectionData spriteCollection = val.spriteCollection;
				if ((Object)(object)spriteCollection == (Object)null || spriteCollection.spriteDefinitions == null || val.spriteId < 0 || val.spriteId >= spriteCollection.spriteDefinitions.Length)
				{
					continue;
				}
				tk2dSpriteDefinition val2 = spriteCollection.spriteDefinitions[val.spriteId];
				if (!string.IsNullOrEmpty(val2.name))
				{
					value.Frames++;
					SpriteLoader.ReplacementSource spriteProvenance = SpriteLoader.GetSpriteProvenance(spriteCollection, val2);
					if (spriteProvenance != SpriteLoader.ReplacementSource.None)
					{
						value.Shared++;
					}
					else if (value.MissingShared.Count < 4)
					{
						string text = (((Object)(object)val2.material != (Object)null) ? ((Object)val2.material).name.Split(' ')[0] : "?");
						value.MissingShared.Add(val2.name + " (" + ((Object)spriteCollection).name + "/" + text + ")");
					}
					if (spriteProvenance == SpriteLoader.ReplacementSource.Pack)
					{
						value.SharedFromPack++;
					}
					if (AppliqueLoader.HasClipOverride(((Object)spriteCollection).name, clip.name, val2.name))
					{
						value.PerClip++;
					}
				}
			}
		}
		_coverage[key] = value;
		return value;
	}

	private static bool TryResolveDisplay(AnimEntry e, out tk2dSpriteAnimationClip clip, out tk2dSpriteCollectionData coll, out int spriteId, out int frame, out int frameCount)
	{
		clip = null;
		coll = null;
		spriteId = -1;
		frame = 0;
		frameCount = 0;
		if (e == null || e.ClipName == null)
		{
			return false;
		}
		if (_previewPlaying && _previewClip != null && _previewClip.frames != null && _previewClip.frames.Length != 0)
		{
			int num = _previewClip.frames.Length;
			int num2 = (_previewFrame % num + num) % num;
			tk2dSpriteAnimationFrame val = _previewClip.frames[num2];
			clip = _previewClip;
			coll = val.spriteCollection;
			spriteId = val.spriteId;
			frame = num2;
			frameCount = num;
			return true;
		}
		if ((e.Stale || (Object)(object)e.Live == (Object)null) && e.ViewClip != null && e.ViewClip.frames != null && e.ViewClip.frames.Length != 0)
		{
			int num3 = Mathf.Clamp(e.ViewFrame, 0, e.ViewClip.frames.Length - 1);
			tk2dSpriteAnimationFrame val2 = e.ViewClip.frames[num3];
			clip = e.ViewClip;
			coll = val2.spriteCollection;
			spriteId = val2.spriteId;
			frame = num3;
			frameCount = e.ViewClip.frames.Length;
		}
		else
		{
			clip = e.Clip;
			coll = e.FrameColl;
			spriteId = e.SpriteId;
			frame = e.Frame;
			frameCount = e.FrameCount;
		}
		return true;
	}

	private static void DrawPreviewColumn(AnimEntry e, float colW)
	{
		//IL_0015: 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_0064: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: 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_00fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_021a: Unknown result type (might be due to invalid IL or missing references)
		//IL_021f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0221: Unknown result type (might be due to invalid IL or missing references)
		//IL_0228: Unknown result type (might be due to invalid IL or missing references)
		//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0301: Unknown result type (might be due to invalid IL or missing references)
		//IL_0329: Unknown result type (might be due to invalid IL or missing references)
		//IL_032e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0330: Unknown result type (might be due to invalid IL or missing references)
		//IL_033c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0342: Invalid comparison between Unknown and I4
		//IL_023a: Unknown result type (might be due to invalid IL or missing references)
		//IL_024a: Unknown result type (might be due to invalid IL or missing references)
		//IL_024f: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_0579: Unknown result type (might be due to invalid IL or missing references)
		//IL_059d: Unknown result type (might be due to invalid IL or missing references)
		//IL_05e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_05db: Unknown result type (might be due to invalid IL or missing references)
		//IL_03bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_03da: Unknown result type (might be due to invalid IL or missing references)
		//IL_0363: Unknown result type (might be due to invalid IL or missing references)
		//IL_0373: Unknown result type (might be due to invalid IL or missing references)
		//IL_0378: Unknown result type (might be due to invalid IL or missing references)
		//IL_037a: Unknown result type (might be due to invalid IL or missing references)
		//IL_067a: Unknown result type (might be due to invalid IL or missing references)
		//IL_06af: Unknown result type (might be due to invalid IL or missing references)
		//IL_06e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_06e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0516: Unknown result type (might be due to invalid IL or missing references)
		//IL_0539: Unknown result type (might be due to invalid IL or missing references)
		//IL_0560: Unknown result type (might be due to invalid IL or missing references)
		//IL_056f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0724: Unknown result type (might be due to invalid IL or missing references)
		//IL_074f: Unknown result type (might be due to invalid IL or missing references)
		//IL_076e: Unknown result type (might be due to invalid IL or missing references)
		//IL_07a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_07a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_07c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_07f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0818: Unknown result type (might be due to invalid IL or missing references)
		//IL_086c: Unknown result type (might be due to invalid IL or missing references)
		if (e == null || !TryResolveDisplay(e, out var clip, out var coll, out var spriteId, out var frame, out var _))
		{
			GUI.contentColor = GUIHelper.ColFaint;
			GUILayout.Label(Loc.T("Select an object to preview."), GUIHelper.LabelStyle, Array.Empty<GUILayoutOption>());
			GUI.contentColor = Color.white;
			return;
		}
		if ((Object)(object)coll == (Object)null || coll.spriteDefinitions == null || spriteId < 0 || spriteId >= coll.spriteDefinitions.Length)
		{
			GUI.contentColor = GUIHelper.ColFaint;
			GUILayout.Label(Loc.T("Preview unavailable — the animator's atlas was unloaded."), GUIHelper.LabelStyle, Array.Empty<GUILayoutOption>());
			GUI.contentColor = Color.white;
			return;
		}
		tk2dSpriteDefinition val = coll.spriteDefinitions[spriteId];
		Material val2 = (((Object)(object)val.materialInst != (Object)null) ? val.materialInst : val.material);
		if ((Object)(object)val2 == (Object)null || (Object)(object)val2.mainTexture == (Object)null)
		{
			GUI.contentColor = GUIHelper.ColFaint;
			GUILayout.Label(Loc.T("Preview unavailable — material/texture released."), GUIHelper.LabelStyle, Array.Empty<GUILayoutOption>());
			GUI.contentColor = Color.white;
			return;
		}
		Texture mainTexture = val2.mainTexture;
		Vector2[] uvs = val.uvs;
		bool flag = uvs != null && uvs.Length >= 4;
		float num = 0f;
		float num2 = 1f;
		float num3 = 0f;
		float num4 = 1f;
		if (flag)
		{
			num = uvs.Min((Vector2 v) => v.x);
			num2 = uvs.Max((Vector2 v) => v.x);
			num3 = uvs.Min((Vector2 v) => v.y);
			num4 = uvs.Max((Vector2 v) => v.y);
		}
		float num5 = colW - GUIHelper.Scaled(8f);
		Rect rect = GUILayoutUtility.GetRect(num5, num5, (GUILayoutOption[])(object)new GUILayoutOption[2]
		{
			GUILayout.Width(num5),
			GUILayout.Height(num5)
		});
		GUIHelper.DrawPreviewBackdrop(rect);
		GUI.DrawTexture(rect, mainTexture, (ScaleMode)2, true);
		if (flag)
		{
			Rect val3 = ScaleToFitRect(rect, mainTexture.width, mainTexture.height);
			float num6 = ((Rect)(ref val3)).x + num * ((Rect)(ref val3)).width;
			float num7 = ((Rect)(ref val3)).y + (1f - num4) * ((Rect)(ref val3)).height;
			float num8 = (num2 - num) * ((Rect)(ref val3)).width;
			float num9 = (num4 - num3) * ((Rect)(ref val3)).height;
			EnsurePreviewWhite();
			GUI.color = new Color(1f, 1f, 0f, 0.4f);
			GUI.DrawTexture(new Rect(num6, num7, num8, num9), (Texture)(object)_previewWhite);
			GUI.color = Color.white;
		}
		GUI.contentColor = ColStale;
		GUILayout.Label(Loc.T("Atlas"), GUIHelper.LabelStyle, Array.Empty<GUILayoutOption>());
		GUI.contentColor = Color.white;
		Rect rect2 = GUILayoutUtility.GetRect(num5, num5, (GUILayoutOption[])(object)new GUILayoutOption[2]
		{
			GUILayout.Width(num5),
			GUILayout.Height(num5)
		});
		GUIHelper.DrawPreviewBackdrop(rect2);
		if ((int)Event.current.type == 7 && flag)
		{
			Texture2D uprightSpriteTex = GetUprightSpriteTex(coll, spriteId, val, mainTexture);
			Rect val4;
			if ((Object)(object)uprightSpriteTex != (Object)null)
			{
				val4 = ScaleToFitRect(rect2, ((Texture)uprightSpriteTex).width, ((Texture)uprightSpriteTex).height);
				GUI.DrawTexture(val4, (Texture)(object)uprightSpriteTex);
			}
			else
			{
				int texW = Mathf.Max(1, Mathf.RoundToInt((num2 - num) * (float)mainTexture.width));
				int texH = Mathf.Max(1, Mathf.RoundToInt((num4 - num3) * (float)mainTexture.height));
				val4 = ScaleToFitRect(rect2, texW, texH);
				GUI.DrawTextureWithTexCoords(val4, mainTexture, new Rect(num, num3, num2 - num, num4 - num3), true);
			}
			Vector3[] positions = val.positions;
			if (positions != null && positions.Length >= 4)
			{
				float num10 = positions.Min((Vector3 p) => p.x);
				float num11 = positions.Max((Vector3 p) => p.x);
				float num12 = positions.Min((Vector3 p) => p.y);
				float num13 = positions.Max((Vector3 p) => p.y);
				float num14 = num11 - num10;
				float num15 = num13 - num12;
				if (num14 > 1E-06f && num15 > 1E-06f)
				{
					float num16 = (0f - num10) / num14;
					float num17 = (0f - num12) / num15;
					float num18 = ((Rect)(ref val4)).x + num16 * ((Rect)(ref val4)).width;
					float num19 = ((Rect)(ref val4)).y + (1f - num17) * ((Rect)(ref val4)).height;
					EnsurePreviewWhite();
					GUI.color = new Color(1f, 0.15f, 0.8f, 0.95f);
					GUI.DrawTexture(new Rect(num18 - 6f, num19 - 0.5f, 13f, 1f), (Texture)(object)_previewWhite);
					GUI.DrawTexture(new Rect(num18 - 0.5f, num19 - 6f, 1f, 13f), (Texture)(object)_previewWhite);
					GUI.color = Color.white;
				}
			}
		}
		GUI.contentColor = ColStale;
		GUILayout.Label(Loc.T("Sprite ⊹ = pivot"), GUIHelper.LabelStyle, Array.Empty<GUILayoutOption>());
		GUI.contentColor = Color.white;
		GUIHelper.DrawBackdropSliderRow();
		GUIHelper.Space(4f);
		GUILayout.BeginVertical(GUI.skin.box, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
		GUI.contentColor = (_previewPlaying ? GUIHelper.ColConfirm : Color.white);
		if (GUILayout.Button(_previewPlaying ? ("▮▮ " + Loc.T("Preview")) : ("▶ " + Loc.T("Preview")), GUIHelper.ButtonStyle, Array.Empty<GUILayoutOption>()))
		{
			if (_previewPlaying)
			{
				StopPreview();
			}
			else if (clip != null && clip.frames != null && clip.frames.Length != 0)
			{
				_previewClip = clip;
				_previewFrame = frame;
				_previewClock = 0f;
				_previewFps = ResolvePreviewFps(e, clip);
				_previewPlaying = true;
			}
		}
		GUI.contentColor = Color.white;
		float num20 = GUIHelper.Scaled(38f);
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		if (GUILayout.Button(TransportLabel("|◀", Loc.T("Prev"), Plugin.Config.AnimationControllerPrevFrameKey), TransportStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(num20) }))
		{
			StepFrame(-1);
		}
		GUI.contentColor = (Paused ? GUIHelper.ColWarn : Color.white);
		if (GUILayout.Button(TransportLabel(Paused ? "▶" : "▮▮", Loc.T(Paused ? "Play" : "Pause"), Plugin.Config.AnimationControllerPauseKey), TransportStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(num20) }))
		{
			TogglePause();
		}
		GUI.contentColor = Color.white;
		if (GUILayout.Button(TransportLabel("▶|", Loc.T("Next"), Plugin.Config.AnimationControllerNextFrameKey), TransportStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(num20) }))
		{
			StepFrame(1);
		}
		GUI.contentColor = (Frozen ? Color.cyan : Color.white);
		if (GUILayout.Button(TransportLabel("❄", Loc.T("Freeze"), Plugin.Config.AnimationControllerFreezeKey), TransportStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(num20) }))
		{
			ToggleFreeze();
		}
		GUI.contentColor = Color.white;
		GUILayout.EndHorizontal();
		bool num21 = e.Stale || (Object)(object)e.Live == (Object)null;
		GUI.contentColor = GUIHelper.ColFaint;
		GUILayout.Label(num21 ? Loc.T("Stopped — stepping browses the snapshot.") : ((!Paused) ? Loc.T("Pause to step frames.") : " "), HintStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(GUIHelper.Scaled(30f)) });
		GUI.contentColor = Color.white;
		GUILayout.EndVertical();
	}

	private static string TransportLabel(string symbol, string word, KeyCode key)
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		return symbol + " " + word + "\n<color=#B78CFF>[" + KeyName(key) + "]</color>";
	}

	internal static void OpenSpriteForEdit(tk2dSpriteCollectionData coll, tk2dSpriteDefinition def)
	{
		if ((Object)(object)coll == (Object)null || def == null || string.IsNullOrEmpty(def.name))
		{
			return;
		}
		Material val = (((Object)(object)def.materialInst != (Object)null) ? def.materialInst : def.material);
		if ((Object)(object)val == (Object)null)
		{
			return;
		}
		string text = ((Object)val).name.Split(' ')[0];
		string text2 = SpriteLoader.FindWorkspaceSpriteFile(coll, def) ?? Path.Combine(SpriteLoader.LoadPath, ((Object)coll).name, text, def.name + ".png");
		if (!File.Exists(text2))
		{
			SpriteDumper.DumpSingleSprite(def, coll);
			string text3 = Path.Combine(SpriteDumper.DumpPath, ((Object)coll).name, text, def.name + ".png");
			if (!File.Exists(text3))
			{
				Plugin.Logger.LogError((object)("Failed to dump sprite for editing: " + ((Object)coll).name + "/" + text + "/" + def.name));
				return;
			}
			IOUtil.EnsureDirectoryExists(Path.Combine(SpriteLoader.LoadPath, ((Object)coll).name, text));
			File.Copy(text3, text2, overwrite: true);
		}
		IOUtil.OpenPath(text2);
		_anchorCacheKey = null;
	}

	internal static Texture2D GetUprightSpriteTexShared(tk2dSpriteCollectionData coll, int spriteId)
	{
		if ((Object)(object)coll == (Object)null || coll.spriteDefinitions == null || spriteId < 0 || spriteId >= coll.spriteDefinitions.Length)
		{
			return null;
		}
		tk2dSpriteDefinition val = coll.spriteDefinitions[spriteId];
		Material val2 = (((Object)(object)val.materialInst != (Object)null) ? val.materialInst : val.material);
		Texture val3 = (((Object)(object)val2 != (Object)null) ? val2.mainTexture : null);
		if ((Object)(object)val3 == (Object)null)
		{
			return null;
		}
		return GetUprightSpriteTex(coll, spriteId, val, val3);
	}

	private static Texture2D GetUprightSpriteTex(tk2dSpriteCollectionData coll, int spriteId, tk2dSpriteDefinition def, Texture atlas)
	{
		int instanceID = ((Object)coll).GetInstanceID();
		int fileIndexVersion = SpriteLoader.FileIndexVersion;
		if ((Object)(object)_spritePreviewTex != (Object)null && _spvCollId == instanceID && _spvSpriteId == spriteId && _spvFileVer == fileIndexVersion)
		{
			return _spritePreviewTex;
		}
		Texture2D val = RenderUprightNew(def, atlas, 2048);
		if ((Object)(object)val == (Object)null)
		{
			return null;
		}
		if ((Object)(object)_spritePreviewTex != (Object)null)
		{
			Object.Destroy((Object)(object)_spritePreviewTex);
		}
		_spritePreviewTex = val;
		_spvCollId = instanceID;
		_spvSpriteId = spriteId;
		_spvFileVer = fileIndexVersion;
		return _spritePreviewTex;
	}

	private static Texture2D RenderUprightNew(tk2dSpriteDefinition def, Texture atlas, int maxSize)
	{
		//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f5: Invalid comparison between Unknown and I4
		//IL_022f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0244: Unknown result type (might be due to invalid IL or missing references)
		//IL_0275: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_02fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_0303: Unknown result type (might be due to invalid IL or missing references)
		//IL_030d: Expected O, but got Unknown
		//IL_031f: Unknown result type (might be due to invalid IL or missing references)
		if (!TexUtil.RotateDrawAvailable)
		{
			return null;
		}
		if ((Object)(object)TexUtil.RotateMaterial == (Object)null || (Object)(object)atlas == (Object)null)
		{
			return null;
		}
		Vector2[] uvs = def.uvs;
		Vector3[] positions = def.positions;
		if (uvs == null || uvs.Length < 4 || positions == null || positions.Length < 4)
		{
			return null;
		}
		float num = uvs[0].x;
		float num2 = num;
		float num3 = uvs[0].y;
		float num4 = num3;
		for (int i = 1; i < 4; i++)
		{
			num = Mathf.Min(num, uvs[i].x);
			num2 = Mathf.Max(num2, uvs[i].x);
			num3 = Mathf.Min(num3, uvs[i].y);
			num4 = Mathf.Max(num4, uvs[i].y);
		}
		int num5 = Mathf.RoundToInt((num2 - num) * (float)atlas.width);
		int num6 = Mathf.RoundToInt((num4 - num3) * (float)atlas.height);
		bool num7 = (int)def.flipped > 0;
		int num8 = Mathf.Clamp(num7 ? num6 : num5, 1, 2048);
		int num9 = Mathf.Clamp(num7 ? num5 : num6, 1, 2048);
		if (Mathf.Max(num8, num9) > maxSize)
		{
			float num10 = (float)maxSize / (float)Mathf.Max(num8, num9);
			num8 = Mathf.Max(1, Mathf.RoundToInt((float)num8 * num10));
			num9 = Mathf.Max(1, Mathf.RoundToInt((float)num9 * num10));
		}
		float num11 = positions[0].x;
		float num12 = num11;
		float num13 = positions[0].y;
		float num14 = num13;
		for (int j = 1; j < 4; j++)
		{
			num11 = Mathf.Min(num11, positions[j].x);
			num12 = Mathf.Max(num12, positions[j].x);
			num13 = Mathf.Min(num13, positions[j].y);
			num14 = Mathf.Max(num14, positions[j].y);
		}
		float num15 = num12 - num11;
		float num16 = num14 - num13;
		if (num15 < 1E-06f || num16 < 1E-06f)
		{
			return null;
		}
		float num17 = (float)num8 / num15;
		float num18 = (float)num9 / num16;
		RenderTexture active = RenderTexture.active;
		RenderTexture temporary = RenderTexture.GetTemporary(num8, num9, 0, (RenderTextureFormat)0, TexUtil.ReadWriteForSource(atlas));
		Texture2D val;
		try
		{
			RenderTexture.active = temporary;
			GL.Clear(true, true, Color.clear);
			GL.PushMatrix();
			GL.LoadPixelMatrix(0f, (float)num8, 0f, (float)num9);
			TexUtil.SetPassTextured(atlas);
			GL.Begin(7);
			GL.Color(Color.white);
			int[] array = new int[4] { 0, 1, 3, 2 };
			foreach (int num19 in array)
			{
				GL.TexCoord(Vector2.op_Implicit(uvs[num19]));
				GL.Vertex3((positions[num19].x - num11) * num17, (positions[num19].y - num13) * num18, 0f);
			}
			GL.End();
			GL.PopMatrix();
			val = new Texture2D(num8, num9, (TextureFormat)4, false)
			{
				hideFlags = (HideFlags)32
			};
			val.ReadPixels(new Rect(0f, 0f, (float)num8, (float)num9), 0, 0);
			val.Apply();
		}
		finally
		{
			RenderTexture.active = active;
			RenderTexture.ReleaseTemporary(temporary);
		}
		FlipPreviewHorizontal(val, num8, num9);
		return val;
	}

	internal static void ClearThumbCache()
	{
		foreach (Texture2D value in _thumbCache.Values)
		{
			if ((Object)(object)value != (Object)null)
			{
				Object.Destroy((Object)(object)value);
			}
		}
		_thumbCache.Clear();
	}

	private static Texture2D GetUprightThumb(tk2dSpriteCollectionData coll, int spriteId, tk2dSpriteDefinition def, Texture atlas)
	{
		int fileIndexVersion = SpriteLoader.FileIndexVersion;
		if (fileIndexVersion != _thumbFileVer)
		{
			ClearThumbCache();
			_thumbFileVer = fileIndexVersion;
		}
		(int, int) key = (((Object)coll).GetInstanceID(), spriteId);
		if (_thumbCache.TryGetValue(key, out var value) && (Object)(object)value != (Object)null)
		{
			return value;
		}
		if (_thumbCache.Count >= 96)
		{
			ClearThumbCache();
		}
		Texture2D val = RenderUprightNew(def, atlas, 96);
		if ((Object)(object)val != (Object)null)
		{
			_thumbCache[key] = val;
		}
		return val;
	}

	private static void FlipPreviewHorizontal(Texture2D tex, int w, int h)
	{
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		Color32[] pixels = tex.GetPixels32();
		Color32[] array = (Color32[])(object)new Color32[pixels.Length];
		for (int i = 0; i < h; i++)
		{
			for (int j = 0; j < w; j++)
			{
				array[i * w + j] = pixels[i * w + (w - 1 - j)];
			}
		}
		tex.SetPixels32(array);
		tex.Apply();
	}

	private static void DrawConsole(AnimEntry e)
	{
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_0099: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0151: Unknown result type (might be due to invalid IL or missing references)
		//IL_0157: Invalid comparison between Unknown and I4
		//IL_0217: Unknown result type (might be due to invalid IL or missing references)
		//IL_023b: Unknown result type (might be due to invalid IL or missing references)
		//IL_024f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0273: Unknown result type (might be due to invalid IL or missing references)
		//IL_0284: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_03d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_03f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_04b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0504: Unknown result type (might be due to invalid IL or missing references)
		//IL_0559: Unknown result type (might be due to invalid IL or missing references)
		//IL_055f: Invalid comparison between Unknown and I4
		//IL_030f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0774: Unknown result type (might be due to invalid IL or missing references)
		//IL_0779: Unknown result type (might be due to invalid IL or missing references)
		//IL_077b: Unknown result type (might be due to invalid IL or missing references)
		//IL_079f: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_097c: Unknown result type (might be due to invalid IL or missing references)
		//IL_09af: Unknown result type (might be due to invalid IL or missing references)
		//IL_0a8a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0aae: Unknown result type (might be due to invalid IL or missing references)
		//IL_09d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0a04: Unknown result type (might be due to invalid IL or missing references)
		//IL_0a5a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0a7e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0aff: Unknown result type (might be due to invalid IL or missing references)
		//IL_0b23: Unknown result type (might be due to invalid IL or missing references)
		//IL_0e4d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0e9e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0fa7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0fac: Unknown result type (might be due to invalid IL or missing references)
		if (e == null || !TryResolveDisplay(e, out var clip, out var coll, out var spriteId, out var frame, out var frameCount) || (Object)(object)coll == (Object)null || coll.spriteDefinitions == null || spriteId < 0 || spriteId >= coll.spriteDefinitions.Length)
		{
			GUI.contentColor = GUIHelper.ColFaint;
			GUILayout.Label(Loc.T("Select an object to see its controls."), GUIHelper.LabelStyle, Array.Empty<GUILayoutOption>());
			GUI.contentColor = Color.white;
			return;
		}
		tk2dSpriteDefinition val = coll.spriteDefinitions[spriteId];
		Material val2 = (((Object)(object)val.materialInst != (Object)null) ? val.materialInst : val.material);
		if ((Object)(object)val2 == (Object)null)
		{
			GUI.contentColor = GUIHelper.ColFaint;
			GUILayout.Label(Loc.T("Preview unavailable — material/texture released."), GUIHelper.LabelStyle, Array.Empty<GUILayoutOption>());
			GUI.contentColor = Color.white;
			return;
		}
		string text = ((Object)val2).name.Split(' ')[0];
		bool flag = e.Stale || (Object)(object)e.Live == (Object)null;
		bool flag2 = !flag && (Object)(object)e.Live != (Object)null && (Object)(object)((Component)e.Live).gameObject != (Object)null;
		string text2 = ((Object)coll).GetInstanceID() + "/" + spriteId;
		if (_reuseCacheKey != text2 && (int)Event.current.type == 8)
		{
			_reuseCacheKey = text2;
			RecomputeReuse(e, coll, spriteId);
		}
		GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.MinHeight(GUIHelper.Scaled(28f)) });
		string text3 = ((clip != null) ? clip.name : (e.ClipName ?? "?"));
		GUILayout.Label(string.Format("{0}   ·   {1} {2}/{3}", text3, Loc.T("Frame"), frame + 1, frameCount) + (flag ? ("   " + Loc.T("(stopped)")) : ""), GUIHelper.LabelStyle, Array.Empty<GUILayoutOption>());
		if (Paused && flag2)
		{
			GUI.contentColor = GUIHelper.ColWarn;
			GUILayout.Label(Loc.T("[PAUSED]"), GUIHelper.LabelStyle, Array.Empty<GUILayoutOption>());
			GUI.contentColor = Color.white;
		}
		if (Frozen && flag2)
		{
			GUI.contentColor = Color.cyan;
			GUILayout.Label(Loc.T("[FROZEN]"), GUIHelper.LabelStyle, Array.Empty<GUILayoutOption>());
			GUI.contentColor = Color.white;
		}
		if (_previewPlaying)
		{
			GUI.contentColor = GUIHelper.ColConfirm;
			GUILayout.Label(Loc.T("[PREVIEW]"), GUIHelper.LabelStyle, Array.Empty<GUILayoutOption>());
			GUI.contentColor = Color.white;
		}
		GUILayout.FlexibleSpace();
		if (_reuseFrameCount > 1)
		{
			int num = 0;
			foreach (var reuseSource in _reuseSources)
			{
				if (reuseSource.Clip == clip)
				{
					num = reuseSource.Frames.Count;
					break;
				}
			}
			GUI.contentColor = GUIHelper.ColWarn;
			if (GUILayout.Button(string.Format("{0} ×{1} · ", Loc.T("Reused frames"), _reuseFrameCount) + string.Format(Loc.T("{0} clips@anim", "{0} clips"), _reuseClipCount) + ((num > 1) ? (" " + string.Format(Loc.T("({0} in this clip)"), num)) : ""), GUIHelper.ButtonStyle, Array.Empty<GUILayoutOption>()))
			{
				tk2dSpriteCollectionData lensColl = coll;
				int lensId = spriteId;
				string lensName = val.name;
				_pendingUiAction = delegate
				{
					SetLens(lensColl, lensId, lensName);
				};
			}
			GUI.contentColor = Color.white;
		}
		else
		{
			GUI.contentColor = GUIHelper.ColConfirm;
			GUILayout.Label(Loc.T("Only used here — safe to edit in isolation."), GUIHelper.LabelStyle, Array.Empty<GUILayoutOption>());
			GUI.contentColor = Color.white;
		}
		GUILayout.EndHorizontal();
		string text4 = "";
		if (clip != null && clip.fps > 0f)
		{
			text4 = "  ·  " + string.Format(Loc.T("clip {0:F0} fps"), clip.fps);
			tk2dSpriteAnimator live = e.Live;
			if ((Object)(object)live != (Object)null && live.CurrentClip == clip && live.ClipFps > 0f && Mathf.Abs(live.ClipFps - clip.fps) > 0.05f)
			{
				text4 += string.Format(Loc.T(" → {0:F0} live"), live.ClipFps);
			}
		}
		GUI.contentColor = GUIHelper.ColFaint;
		GUILayout.Label($"{((Object)coll).name}  ·  {text}  ·  {val.name}  ·  id {spriteId}{text4}", GUIHelper.LabelStyle, Array.Empty<GUILayoutOption>());
		GUI.contentColor = Color.white;
		string text5 = ((Object)coll).name + "/" + text + "/" + val.name;
		if (_anchorCacheKey != text5 && (int)Event.current.type == 8)
		{
			_anchorCacheKey = text5;
			_anchorReplExists = false;
			_anchorCurrent = null;
			_anchorFilePath = null;
			_anchorPackSource = null;
			foreach (string pluginPackPath in Plugin.PluginPackPaths)
			{
				if (FindTaggedOrPlain(Path.Combine(pluginPackPath, "Sprites", ((Object)coll).name, text), val.name) != null)
				{
					string path = pluginPackPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
					string fileName = Path.GetFileName(path);
					if (string.Equals(fileName, "Stitchwork", StringComparison.OrdinalIgnoreCase) || string.Equals(fileName, "Patchwork", StringComparison.OrdinalIgnoreCase))
					{
						fileName = Path.GetFileName(Path.GetDirectoryName(path));
					}
					_anchorPackSource = fileName;
					break;
				}
			}
			if (_anchorPackSource == null)
			{
				string text6 = FindTaggedOrPlain(Path.Combine(SpriteLoader.LoadPath, ((Object)coll).name, text), val.name);
				if (text6 != null)
				{
					_anchorReplExists = true;
					_anchorFilePath = text6;
					_anchorCurrent = IOUtil.ParseAnchorTag(Path.GetFileNameWithoutExtension(text6)).anchor;
				}
			}
		}
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		GUILayout.BeginVertical(GUI.skin.box, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
		GUILayout.Label(Loc.T("This Sprite"), GUIHelper.SectionHeaderStyle, Array.Empty<GUILayoutOption>());
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		if (GUILayout.Button(Loc.T(File.Exists(Path.Combine(SpriteLoader.LoadPath, ((Object)coll).name, text, val.name + ".png")) ? "Edit (opens your file)" : "Edit (new from vanilla)"), GUIHelper.ButtonStyle, Array.Empty<GUILayoutOption>()))
		{
			OpenSpriteForEdit(coll, val);
		}
		if (GUILayout.Button(Loc.T("Folder"), GUIHelper.ButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUIHelper.Width(64f) }))
		{
			IOUtil.OpenDeepestExisting(Path.Combine(SpriteLoader.LoadPath, ((Object)coll).name, text));
		}
		GUILayout.EndHorizontal();
		GUI.enabled = clip != null;
		Color backgroundColor = GUI.backgroundColor;
		GUI.backgroundColor = GUIHelper.ColAccent;
		bool num2 = GUILayout.Button(Loc.T("Detach for This Clip"), GUIHelper.ButtonStyle, Array.Empty<GUILayoutOption>());
		GUI.backgroundColor = backgroundColor;
		if (num2)
		{
			if (clip.name.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0)
			{
				Plugin.Logger.LogWarning((object)("[AnimCtrl] Detach: clip name '" + clip.name + "' isn't filesystem-safe."));
			}
			else
			{
				string text7 = Path.Combine(SpriteLoader.LoadPath, ((Object)coll).name, "Clips", clip.name);
				string text8 = Path.Combine(text7, val.name + ".png");
				if (!File.Exists(text8))
				{
					string text9 = Path.Combine(SpriteLoader.LoadPath, ((Object)coll).name, text, val.name + ".png");
					string text10 = (File.Exists(text9) ? text9 : null);
					if (text10 == null)
					{
						SpriteDumper.DumpSingleSprite(val, coll);
						string text11 = Path.Combine(SpriteDumper.DumpPath, ((Object)coll).name, text, val.name + ".png");
						if (File.Exists(text11))
						{
							text10 = text11;
						}
					}
					if (text10 == null)
					{
						Plugin.Logger.LogError((object)("[AnimCtrl] Detach: no source for " + ((Object)coll).name + "/" + text + "/" + val.name));
					}
					else
					{
						IOUtil.EnsureDirectoryExists(text7);
						File.Copy(text10, text8, overwrite: true);
						Plugin.Logger.LogInfo((object)("[AnimCtrl] Detached '" + val.name + "' for clip '" + clip.name + "' → " + text8));
					}
				}
				if (File.Exists(text8))
				{
					IOUtil.OpenPath(text8);
				}
			}
		}
		GUI.enabled = true;
		GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[2]
		{
			GUILayout.Height(GUIHelper.Scaled(48f)),
			GUILayout.ExpandWidth(true)
		});
		if (_anchorPackSource != null)
		{
			GUI.contentColor = GUIHelper.ColFaint;
			GUILayout.Label(Loc.T("Supplied by pack:") + " " + _anchorPackSource, GUIHelper.LabelStyle, Array.Empty<GUILayoutOption>());
			GUI.contentColor = Color.white;
		}
		else if (_anchorReplExists)
		{
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUI.contentColor = GUIHelper.ColMuted;
			GUILayout.Label(Loc.T("Anchor:"), GUIHelper.LabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUIHelper.Width(52f) });
			GUI.contentColor = Color.white;
			DrawAnchorButton("↑", "top-center");
			DrawAnchorButton("↓", null);
			DrawAnchorButton("←", "left-center");
			DrawAnchorButton("→", "right-center");
			DrawAnchorButton("◆", "center");
			GUILayout.EndHorizontal();
			GUI.contentColor = GUIHelper.ColFaint;
			GUILayout.Label(Loc.T("Anchor affects enlarged replacements only."), GUIHelper.LabelStyle, Array.Empty<GUILayoutOption>());
			GUI.contentColor = Color.white;
		}
		else
		{
			GUI.contentColor = GUIHelper.ColFaint;
			GUILayout.Label(Loc.T("No replacement file yet — Edit creates one."), GUIHelper.LabelStyle, Array.Empty<GUILayoutOption>());
			GUI.contentColor = Color.white;
		}
		GUILayout.FlexibleSpace();
		GUILayout.EndVertical();
		GUILayout.EndVertical();
		GUILayout.BeginVertical(GUI.skin.box, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
		GUILayout.Label(Loc.T("Whole Clip"), GUIHelper.SectionHeaderStyle, Array.Empty<GUILayoutOption>());
		GUI.contentColor = GUIHelper.ColFaint;
		GUILayout.Label(Loc.T("Animation canvas — whole-clip workflow:"), GUIHelper.LabelStyle, Array.Empty<GUILayoutOption>());
		GUI.contentColor = Color.white;
		GUI.enabled = clip != null && !AnimCanvasBatch.IsRunning;
		if (GUILayout.Button(Loc.T("Ready All for Edit"), GUIHelper.ButtonStyle, Array.Empty<GUILayoutOption>()))
		{
			int num3 = 0;
			for (int num4 = 0; num4 < clip.frames.Length; num4++)
			{
				tk2dSpriteAnimationFrame val3 = clip.frames[num4];
				tk2dSpriteCollectionData spriteCollection = val3.spriteCollection;
				if ((Object)(object)spriteCollection == (Object)null || val3.spriteId < 0 || val3.spriteId >= spriteCollection.spriteDefinitions.Length)
				{
					continue;
				}
				tk2dSpriteDefinition val4 = spriteCollection.spriteDefinitions[val3.spriteId];
				if (string.IsNullOrEmpty(val4.name))
				{
					continue;
				}
				string text12 = ((Object)(((Object)(object)val4.materialInst != (Object)null) ? val4.materialInst : val4.material)).name.Split(' ')[0];
				string text13 = Path.Combine(SpriteLoader.LoadPath, ((Object)spriteCollection).name, text12, val4.name + ".png");
				if (File.Exists(text13))
				{
					num3++;
					continue;
				}
				SpriteDumper.DumpSingleSprite(val4, spriteCollection);
				string text14 = Path.Combine(SpriteDumper.DumpPath, ((Object)spriteCollection).name, text12, val4.name + ".png");
				if (!File.Exists(text14))
				{
					Plugin.Logger.LogError((object)("Failed to dump: " + ((Object)spriteCollection).name + "/" + text12 + "/" + val4.name));
				}
				else
				{
					IOUtil.EnsureDirectoryExists(Path.Combine(SpriteLoader.LoadPath, ((Object)spriteCollection).name, text12));
					File.Copy(text14, text13, overwrite: true);
					num3++;
				}
			}
			Plugin.Logger.LogInfo((object)$"[AnimCtrl] Copied {num3} sprites from '{clip.name}' ({clip.frames.Length} frames) to {SpriteLoader.LoadPath}");
			for (int num5 = 0; num5 < clip.frames.Length; num5++)
			{
				tk2dSpriteAnimationFrame val5 = clip.frames[num5];
				tk2dSpriteCollectionData spriteCollection2 = val5.spriteCollection;
				if ((Object)(object)spriteCollection2 == (Object)null || val5.spriteId < 0 || val5.spriteId >= spriteCollection2.spriteDefinitions.Length)
				{
					continue;
				}
				tk2dSpriteDefinition val6 = spriteCollection2.spriteDefinitions[val5.spriteId];
				if (!string.IsNullOrEmpty(val6.name))
				{
					string path2 = ((Object)(((Object)(object)val6.materialInst != (Object)null) ? val6.materialInst : val6.material)).name.Split(' ')[0];
					string path3 = Path.Combine(SpriteLoader.LoadPath, ((Object)spriteCollection2).name, path2, val6.name + ".png");
					if (File.Exists(path3))
					{
						IOUtil.OpenPath(path3);
					}
				}
			}
			_anchorCacheKey = null;
		}
		string text15 = AnimCanvasAuthoring.WipDirFor(clip);
		if (text15 != null)
		{
			string fileName2 = Path.GetFileName(Path.GetDirectoryName(text15));
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUI.contentColor = GUIHelper.ColMuted;
			GUILayout.Label(Loc.T("Workspace") + ": " + fileName2 + "/" + Path.GetFileName(text15), GUIHelper.LabelStyle, Array.Empty<GUILayoutOption>());
			GUI.contentColor = Color.white;
			if (GUILayout.Button(Loc.T("Open"), GUIHelper.ButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUIHelper.Width(52f) }))
			{
				IOUtil.OpenDeepestExisting(text15);
			}
			GUILayout.EndHorizontal();
		}
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		if (GUILayout.Button(Loc.T("Extract Vanilla"), GUIHelper.ButtonStyle, Array.Empty<GUILayoutOption>()))
		{
			AnimCanvasAuthoring.ExtractClip(clip);
			string text16 = AnimCanvasAuthoring.WipDirFor(clip);
			if (text16 != null && Directory.Exists(text16))
			{
				IOUtil.OpenPath(text16);
			}
		}
		if (GUILayout.Button(Loc.T("Extract As Rendered"), GUIHelper.ButtonStyle, Array.Empty<GUILayoutOption>()))
		{
			AnimCanvasAuthoring.ExtractClip(clip, 0.5f, 0, fromCurrentRender: true);
			string text17 = AnimCanvasAuthoring.WipDirFor(clip);
			if (text17 != null && Directory.Exists(text17))
			{
				IOUtil.OpenPath(text17);
			}
		}
		GUILayout.EndHorizontal();
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		if (GUILayout.Button(Loc.T("Compile Animation from Workspace"), GUIHelper.ButtonStyle, Array.Empty<GUILayoutOption>()))
		{
			AnimCanvasCompile.CompileClip(clip);
		}
		Color backgroundColor2 = GUI.backgroundColor;
		GUI.backgroundColor = GUIHelper.ColAccent;
		if (GUILayout.Button(Loc.T("Compile for This Clip"), GUIHelper.ButtonStyle, Array.Empty<GUILayoutOption>()))
		{
			AnimCanvasCompile.CompileClip(clip, forClipOnly: true);
		}
		GUI.backgroundColor = backgroundColor2;
		GUILayout.EndHorizontal();
		if (GUILayout.Button(Loc.T("Export GIF"), GUIHelper.ButtonStyle, Array.Empty<GUILayoutOption>()))
		{
			int width;
			int height;
			List<Color32[]> list = AnimCanvasAuthoring.RenderClipSequence(clip, fromCurrentRender: true, 0.1f, out width, out height);
			if (list == null)
			{
				Plugin.Logger.LogWarning((object)("[Showcase] '" + clip.name + "': no renderable frames — GIF not written."));
			}
			else
			{
				string text18 = Path.Combine(Plugin.BasePath, "Showcase");
				IOUtil.EnsureDirectoryExists(text18);
				string text19 = Path.Combine(text18, T2DUtil.SanitizeForFilesystem(clip.name) + ".gif");
				int num6 = Mathf.Max(2, Mathf.RoundToInt(100f / Mathf.Max(1f, _previewFps)));
				try
				{
					GifEncoder.Write(text19, width, height, list, num6);
					Plugin.Logger.LogInfo((object)$"[Showcase] GIF: {list.Count} frame(s) {width}×{height} @ {num6} cs/frame → {text19}");
					IOUtil.OpenPath(text19);
				}
				catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException)
				{
					Plugin.Logger.LogError((object)("[Showcase] GIF write failed: " + ex.Message));
				}
			}
		}
		GUI.enabled = true;
		GUILayout.EndVertical();
		GUILayout.EndHorizontal();
	}

	private unsafe static string KeyName(KeyCode k)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0003: Invalid comparison between Unknown and I4
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Expected I4, but got Unknown
		if ((int)k != 127)
		{
			return (k - 277) switch
			{
				3 => "PgUp", 
				4 => "PgDn", 
				0 => "Ins", 
				_ => ((object)(*(KeyCode*)(&k))/*cast due to .constrained prefix*/).ToString(), 
			};
		}
		return "Del";
	}

	private static void EnsurePreviewWhite()
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Expected O, but got Unknown
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)_previewWhite != (Object)null))
		{
			_previewWhite = new Texture2D(1, 1)
			{
				hideFlags = (HideFlags)32
			};
			_previewWhite.SetPixel(0, 0, Color.white);
			_previewWhite.Apply();
		}
	}

	private static Rect ScaleToFitRect(Rect container, int texW, int texH)
	{
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		if (texW <= 0 || texH <= 0)
		{
			return container;
		}
		float num = Mathf.Min(((Rect)(ref container)).width / (float)texW, ((Rect)(ref container)).height / (float)texH);
		float num2 = (float)texW * num;
		float num3 = (float)texH * num;
		return new Rect(((Rect)(ref container)).x + (((Rect)(ref container)).width - num2) * 0.5f, ((Rect)(ref container)).y + (((Rect)(ref container)).height - num3) * 0.5f, num2, num3);
	}

	private static void RecomputeReuse(AnimEntry e, tk2dSpriteCollectionData coll, int spriteId)
	{
		_reuseFrameCount = 0;
		_reuseClipCount = 0;
		_reuseSources.Clear();
		tk2dSpriteAnimation val = e?.Library;
		if ((Object)(object)val == (Object)null || val.clips == null || (Object)(object)coll == (Object)null)
		{
			return;
		}
		tk2dSpriteAnimationClip[] clips = val.clips;
		foreach (tk2dSpriteAnimationClip val2 in clips)
		{
			if (val2 == null || val2.frames == null)
			{
				continue;
			}
			List<int> list = null;
			for (int j = 0; j < val2.frames.Length; j++)
			{
				tk2dSpriteAnimationFrame val3 = val2.frames[j];
				if ((Object)(object)val3.spriteCollection == (Object)(object)coll && val3.spriteId == spriteId)
				{
					(list ?? (list = new List<int>())).Add(j);
				}
			}
			if (list != null)
			{
				_reuseFrameCount += list.Count;
				_reuseClipCount++;
				_reuseSources.Add((val2, list));
			}
		}
	}

	private static void DrawAnchorButton(string label, string anchor)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		GUI.contentColor = ((_anchorCurrent == anchor) ? GUIHelper.ColConfirm : Color.white);
		if (GUILayout.Button(label, GUIHelper.ButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUIHelper.Width(30f) }))
		{
			SetAnchorByRename(anchor);
		}
		GUI.contentColor = Color.white;
	}

	private static string FindTaggedOrPlain(string dir, string spriteName)
	{
		if (!Directory.Exists(dir))
		{
			return null;
		}
		string text = Path.Combine(dir, spriteName + ".png");
		if (File.Exists(text))
		{
			return text;
		}
		string[] array = new string[5] { "@t", "@b", "@l", "@r", "@c" };
		foreach (string text2 in array)
		{
			string text3 = Path.Combine(dir, spriteName + text2 + ".png");
			if (File.Exists(text3))
			{
				return text3;
			}
		}
		return null;
	}

	private static void SetAnchorByRename(string anchor)
	{
		if (_anchorFilePath == null)
		{
			return;
		}
		string directoryName = Path.GetDirectoryName(_anchorFilePath);
		string item = IOUtil.ParseAnchorTag(Path.GetFileNameWithoutExtension(_anchorFilePath)).name;
		string text = Path.Combine(directoryName, item + anchor switch
		{
			"top-center" => "@t", 
			"left-center" => "@l", 
			"right-center" => "@r", 
			"center" => "@c", 
			_ => "", 
		} + ".png");
		if (string.Equals(text, _anchorFilePath, StringComparison.OrdinalIgnoreCase))
		{
			return;
		}
		if (File.Exists(text))
		{
			Plugin.Logger.LogWarning((object)("[Anchor] Can't set anchor: '" + Path.GetFileName(text) + "' already exists - remove the duplicate first (multiple anchor-tagged files for one sprite)."));
			return;
		}
		try
		{
			File.Move(_anchorFilePath, text);
			_anchorFilePath = text;
			_anchorCurrent = anchor;
			_anchorCacheKey = null;
			Plugin.Logger.LogInfo((object)("[Anchor] " + Path.GetFileName(text) + " anchor set to " + (anchor ?? "bottom (default)")));
		}
		catch (Exception ex)
		{
			Plugin.Logger.LogWarning((object)("[Anchor] rename failed: " + ex.Message));
		}
	}
}
public class DialogueHandler
{
	private sealed class StoredCopyBridge
	{
		public Type Type;

		public MethodInfo Refresh;

		public FieldInfo KeyField;
	}

	private static string _cachedLangString;

	private static bool _gameLanguageAlive;

	public static Dictionary<string, Dictionary<string, Dictionary<string, string>>> TextCache = new Dictionary<string, Dictionary<string, Dictionary<string, string>>>();

	private static readonly HashSet<string> RequestedOverrideKeys = new HashSet<string>();

	private static readonly HashSet<string> AllOverrideKeys = new HashSet<string>();

	private static bool _staleKeysReported;

	private static bool _dumpInProgress;

	private static FieldInfo _entrySheetsField;

	private static bool _entrySheetsResolved;

	private static object _lastDictInstance;

	private static readonly Dictionary<(string sheet, string key), (bool existed, string value)> _dictOriginals = new Dictionary<(string, string), (bool, string)>();

	private static List<StoredCopyBridge> _storedCopyBridges;

	public static string TextDumpPath => Path.Combine(Plugin.BasePath, "TextDumps");

	public static string TextLoadPath => Path.Combine(Plugin.BasePath, "Text");

	public static string CurrentLangCode => CurrentLangStringCached();

	public static int StaleKeyCount { get; private set; }

	public static int CachedSheetCount
	{
		get
		{
			int num = 0;
			foreach (Dictionary<string, Dictionary<string, string>> value in TextCache.Values)
			{
				num += value.Count;
			}
			return num;
		}
	}

	public static int CachedKeyCount
	{
		get
		{
			int num = 0;
			foreach (Dictionary<string, Dictionary<string, string>> value in TextCache.Values)
			{
				foreach (Dictionary<string, string> value2 in value.Values)
				{
					num += value2.Count;
				}
			}
			return num;
		}
	}

	public static event Action<string, string, string> OnTextAccessed;

	private static string CurrentLangStringCached()
	{
		//IL_001b: 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)
		if (_cachedLangString != null)
		{
			return _cachedLangString;
		}
		if (!_gameLanguageAlive)
		{
			return "EN";
		}
		try
		{
			return _cachedLangString = ((object)Language.CurrentLanguage()/*cast due to .constrained prefix*/).ToString();
		}
		catch (TypeInitializationException)
		{
			return "EN";
		}
	}

	public static void DumpText()
	{
		string text = CurrentLangStringCached();
		_dumpInProgress = true;
		try
		{
			foreach (object value in Enum.GetValues(typeof(SupportedLanguages)))
			{
				string text2 = value.ToString();
				Plugin.Logger.LogDebug((object)("Dumping text for language code " + text2 + "..."));
				Language.SwitchLanguage(text2);
				int num = 0;
				int num2 = 0;
				foreach (string sheet in Language.GetSheets())
				{
					IOUtil.EnsureDirectoryExists(Path.Combine(TextDumpPath, sheet));
					using StreamWriter streamWriter = new StreamWriter(Path.Combine(TextDumpPath, sheet, text2 + ".yml"));
					foreach (string key in Language.GetKeys(sheet))
					{
						string text3 = Language.Get(key, sheet);
						streamWriter.WriteLine(key + ": \"" + text3.Replace("\"", "\\\"") + "\"");
						num++;
					}
					streamWriter.Flush();
					streamWriter.Close();
					num2++;
				}
				Plugin.Logger.LogDebug((object)$"Finished dumping text for language code {text2}. Dumped {num} keys in {num2} sheets.");
			}
			Plugin.Logger.LogInfo((object)("[Stitchwork] Text dump complete (vanilla source) → " + TextDumpPath));
		}
		finally
		{
			_dumpInProgress = false;
			Language.SwitchLanguage(text);
		}
	}

	public static void InvalidateCache(string sheet, string lang)
	{
		if (TextCache.TryGetValue(lang, out var value) && value.Remove(sheet))
		{
			Plugin.Logger.LogDebug((object)("Invalidating text cache for sheet: " + sheet + ", lang: " + lang));
		}
	}

	public static IEnumerable<(string Sheet, string Key, string Value)> SearchCache(string filter, HashSet<string> skipKeys = null)
	{
		if (string.IsNullOrEmpty(filter) || !TextCache.TryGetValue(CurrentLangCode, out var value))
		{
			yield break;
		}
		foreach (KeyValuePair<string, Dictionary<string, string>> item in value)
		{
			string sheet = item.Key;
			bool sheetMatch = sheet.IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0;
			foreach (KeyValuePair<string, string> item2 in item.Value)
			{
				if ((skipKeys == null || !skipKeys.Contains(sheet + "|" + item2.Key)) && (sheetMatch || item2.Key.IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0 || item2.Value.IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0))
				{
					yield return (Sheet: sheet, Key: item2.Key, Value: item2.Value);
				}
			}
		}
	}

	public static void Reload()
	{
		ConflictTracker.ClearTypes("text");
		TextCache.Clear();
		RequestedOverrideKeys.Clear();
		AllOverrideKeys.Clear();
		StaleKeyCount = 0;
		_staleKeysReported = false;
		Language.SwitchLanguage(CurrentLangStringCached());
		Plugin.Logger.LogDebug((object)"[Stitchwork] Text hot-reload: cleared cache and re-switched language to force refresh.");
	}

	public static void ApplyPatches(Harmony harmony)
	{
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Expected O, but got Unknown
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: Expected O, but got Unknown
		harmony.Patch((MethodBase)AccessTools.Method(typeof(Language), "Get", new Type[2]
		{
			typeof(string),
			typeof(string)
		}, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(DialogueHandler), "GetTextPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		try
		{
			int num = 0;
			MethodInfo[] methods = typeof(Language).GetMethods(BindingFlags.Static | BindingFlags.Public);
			foreach (MethodInfo methodInfo in methods)
			{
				if (!(methodInfo.Name != "SwitchLanguage") && !methodInfo.IsGenericMethod)
				{
					try
					{
						harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(DialogueHandler), "SwitchLanguagePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						num++;
					}
					catch (Exception ex)
					{
						Plugin.Logger.LogWarning((object)("[DialogueHandler] Failed to patch Language.SwitchLanguage overload " + $"({methodInfo}): {ex.Message}"));
					}
				}
			}
			if (num == 0)
			{
				Plugin.Logger.LogWarning((object)"[DialogueHandler] No Language.SwitchLanguage overloads were patched. Language-change cache invalidation will be skipped; stale CurrentLangCode is possible until next scene/reload.");
			}
		}
		catch (Exception ex2)
		{
			Plugin.Logger.LogError((object)("[DialogueHandler] SwitchLanguage enumeration threw: " + ex2.Message + ". Cache invalidation patches skipped; downstream patches continue."));
		}
	}

	private static void SwitchLanguagePostfix()
	{
		_gameLanguageAlive = true;
		_cachedLangString = null;
		Loc.OnGameLanguageChanged();
		SyncGameLanguageDict();
	}

	private static void GetTextPostfix(string key, string sheetTitle, ref string __result)
	{
		if (!_gameLanguageAlive)
		{
			_gameLanguageAlive = true;
			Loc.OnGameLanguageChanged();
		}
		if (_dumpInProgress)
		{
			return;
		}
		long heapBefore = DevProfiler.SnapshotHeapBytes();
		try
		{
			string text = CurrentLangStringCached();
			if (GetOrLoad