Decompiled source of Stitchwork v0.8.0

plugins/StitchworkRoot/Stitchwork.dll

Decompiled 3 days 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 TeamCherry.Cinematics;
using TeamCherry.Localization;
using Unity.Mathematics;
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.UI;
using UnityEngine.Video;

[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.0.0")]
[assembly: AssemblyInformationalVersion("0.8.0+0475ee1ae4a7529149d6d3ad4b00f66006b5e890")]
[assembly: AssemblyProduct("Stitchwork")]
[assembly: AssemblyTitle("Stitchwork")]
[assembly: AssemblyMetadata("GameLibsPin", "1.2.0-silksong1.0.30000")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.8.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
[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 PerClip;
	}

	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 readonly Dictionary<(int libId, string clip), ClipCoverage> _coverage = new Dictionary<(int, string), ClipCoverage>();

	private static int _coverageIndexVersion = -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 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)
	{
		tk2dSpriteAnimator val = e?.Live;
		if ((Object)(object)val != (Object)null && val.CurrentClip == clip && val.ClipFps > 0f)
		{
			return val.ClipFps;
		}
		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;
	}

	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_00e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_0104: Unknown result type (might be due to invalid IL or missing references)
		//IL_0114: 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_01f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_020f: 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 = 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_0096: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0109: Unknown result type (might be due to invalid IL or missing references)
		//IL_017d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0182: Unknown result type (might be due to invalid IL or missing references)
		//IL_029d: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_030b: Unknown result type (might be due to invalid IL or missing references)
		//IL_031f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0324: Unknown result type (might be due to invalid IL or missing references)
		//IL_0354: 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_03cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_03f1: 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;
		}
		IEnumerable<tk2dSpriteAnimationClip> source = library.clips.Where((tk2dSpriteAnimationClip c) => c != null && !string.IsNullOrEmpty(c.name));
		if (!string.IsNullOrEmpty(_clipSearch))
		{
			source = source.Where((tk2dSpriteAnimationClip c) => c.name.ToLower().Contains(_clipSearch.ToLower()));
		}
		if (_lensSpriteId >= 0)
		{
			source = source.Where((tk2dSpriteAnimationClip c) => ClipUsesSprite(c, _lensColl, _lensSpriteId));
		}
		List<tk2dSpriteAnimationClip> list = source.OrderBy<tk2dSpriteAnimationClip, string>((tk2dSpriteAnimationClip c) => c.name, StringComparer.OrdinalIgnoreCase).ToList();
		GUI.contentColor = GUIHelper.ColFaint;
		GUILayout.Label($"{list.Count} / {library.clips.Length}", GUIHelper.LabelStyle, Array.Empty<GUILayoutOption>());
		GUI.contentColor = Color.white;
		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 val = FindClip(library, recentClip);
				if (val != null)
				{
					DrawClipRow(e, library, val, currentClip, live);
				}
			}
			GUI.contentColor = GUIHelper.ColMuted;
			GUILayout.Label(Loc.T("All clips"), GUIHelper.LabelStyle, Array.Empty<GUILayoutOption>());
			GUI.contentColor = Color.white;
		}
		foreach (tk2dSpriteAnimationClip item in list)
		{
			DrawClipRow(e, library, item, currentClip, live);
		}
		GUILayout.EndScrollView();
	}

	private static void DrawClipRow(AnimEntry e, tk2dSpriteAnimation lib, tk2dSpriteAnimationClip clip, string currentClip, bool live)
	{
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: Expected O, but got Unknown
		//IL_009a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0093: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_0102: Expected O, but got Unknown
		//IL_0102: Unknown result type (might be due to invalid IL or missing references)
		//IL_0121: Unknown result type (might be due to invalid IL or missing references)
		//IL_011a: Unknown result type (might be due to invalid IL or missing references)
		//IL_014b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0155: Unknown result type (might be due to invalid IL or missing references)
		//IL_019e: Unknown result type (might be due to invalid IL or missing references)
		ClipCoverage coverage = GetCoverage(lib, clip);
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		GUI.contentColor = ((coverage.Shared > 0) ? GUIHelper.ColConfirm : GUIHelper.ColBorderHi);
		GUILayout.Label(new GUIContent(DotFor(coverage.Shared, coverage.Frames), string.Format("{0}: {1}/{2}", Loc.T("shared replacements"), coverage.Shared, coverage.Frames)), GUIHelper.LabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUIHelper.Width(16f) });
		GUI.contentColor = ((coverage.PerClip > 0) ? GUIHelper.ColAccent : GUIHelper.ColBorderHi);
		GUILayout.Label(new GUIContent(DotFor(coverage.PerClip, coverage.Frames), string.Format("{0}: {1}/{2}", Loc.T("per-clip (Appliqué)"), coverage.PerClip, coverage.Frames)), GUIHelper.LabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUIHelper.Width(16f) });
		GUI.contentColor = Color.white;
		GUI.contentColor = ((clip.name == currentClip) ? 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;
		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 string DotFor(int n, int total)
	{
		if (n > 0)
		{
			if (n < total)
			{
				return "◐";
			}
			return "●";
		}
		return "○";
	}

	private static ClipCoverage GetCoverage(tk2dSpriteAnimation lib, tk2dSpriteAnimationClip clip)
	{
		if (_coverageIndexVersion != SpriteLoader.FileIndexVersion)
		{
			_coverage.Clear();
			_coverageIndexVersion = SpriteLoader.FileIndexVersion;
		}
		(int, string) key = (((Object)lib).GetInstanceID(), clip.name);
		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++;
					if (SpriteLoader.HasSpriteReplacement(spriteCollection, val2))
					{
						value.Shared++;
					}
					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_00ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_020d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0212: Unknown result type (might be due to invalid IL or missing references)
		//IL_0214: 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)
		//IL_02d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_031c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0321: Unknown result type (might be due to invalid IL or missing references)
		//IL_0323: Unknown result type (might be due to invalid IL or missing references)
		//IL_032f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0335: Invalid comparison between Unknown and I4
		//IL_022d: Unknown result type (might be due to invalid IL or missing references)
		//IL_023d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0242: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_056c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0590: Unknown result type (might be due to invalid IL or missing references)
		//IL_05d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_05ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_03ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_03b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_03b9: 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_03cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0356: Unknown result type (might be due to invalid IL or missing references)
		//IL_0366: Unknown result type (might be due to invalid IL or missing references)
		//IL_036b: Unknown result type (might be due to invalid IL or missing references)
		//IL_036d: Unknown result type (might be due to invalid IL or missing references)
		//IL_066d: Unknown result type (might be due to invalid IL or missing references)
		//IL_06a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_06dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_06d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0509: Unknown result type (might be due to invalid IL or missing references)
		//IL_052c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0553: Unknown result type (might be due to invalid IL or missing references)
		//IL_0562: Unknown result type (might be due to invalid IL or missing references)
		//IL_0717: Unknown result type (might be due to invalid IL or missing references)
		//IL_0742: Unknown result type (might be due to invalid IL or missing references)
		//IL_0761: Unknown result type (might be due to invalid IL or missing references)
		//IL_079b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0794: Unknown result type (might be due to invalid IL or missing references)
		//IL_07ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_07e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_080b: Unknown result type (might be due to invalid IL or missing references)
		//IL_084c: 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 = 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, Array.Empty<GUILayoutOption>());
		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 = def.materialInst ?? def.material;
		if ((Object)(object)val == (Object)null)
		{
			return;
		}
		string text = ((Object)val).name.Split(' ')[0];
		string text2 = 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);
		}
		Process.Start(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_00e6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ec: Invalid comparison between Unknown and I4
		//IL_0236: Unknown result type (might be due to invalid IL or missing references)
		//IL_0278: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_032d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0332: Unknown result type (might be due to invalid IL or missing references)
		//IL_033c: Expected O, but got Unknown
		//IL_034e: Unknown result type (might be due to invalid IL or missing references)
		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, (RenderTextureReadWrite)1);
		Texture2D val;
		try
		{
			RenderTexture.active = temporary;
			GL.Clear(true, true, Color.clear);
			GL.PushMatrix();
			GL.LoadPixelMatrix(0f, (float)num8, 0f, (float)num9);
			TexUtil.RotateMaterial.SetVector("_Basis", new Vector4(1f, 0f, 0f, 1f));
			TexUtil.RotateMaterial.SetTexture("_MainTex", atlas);
			TexUtil.RotateMaterial.SetPass(0);
			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_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_0144: Unknown result type (might be due to invalid IL or missing references)
		//IL_014a: Invalid comparison between Unknown and I4
		//IL_01f7: 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)
		//IL_022f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0253: Unknown result type (might be due to invalid IL or missing references)
		//IL_0264: Unknown result type (might be due to invalid IL or missing references)
		//IL_0288: Unknown result type (might be due to invalid IL or missing references)
		//IL_03b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_03d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0495: Unknown result type (might be due to invalid IL or missing references)
		//IL_04e6: Unknown result type (might be due to invalid IL or missing references)
		//IL_053b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0541: Invalid comparison between Unknown and I4
		//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_08a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_08d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_09ae: 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_08f6: Unknown result type (might be due to invalid IL or missing references)
		//IL_0928: Unknown result type (might be due to invalid IL or missing references)
		//IL_097e: Unknown result type (might be due to invalid IL or missing references)
		//IL_09a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0a19: Unknown result type (might be due to invalid IL or missing references)
		//IL_0a3d: Unknown result type (might be due to invalid IL or missing references)
		//IL_03a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0de5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0dea: 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 = 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(Array.Empty<GUILayoutOption>());
		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 + 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>());
		if (GUILayout.Button(Loc.T("Edit Current Sprite"), GUIHelper.ButtonStyle, Array.Empty<GUILayoutOption>()))
		{
			OpenSpriteForEdit(coll, val);
		}
		GUI.enabled = clip != null;
		if (GUILayout.Button(Loc.T("Detach for This Clip"), GUIHelper.ButtonStyle, Array.Empty<GUILayoutOption>()))
		{
			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))
				{
					Process.Start(text8);
				}
			}
		}
		GUI.enabled = 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.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;
		if (GUILayout.Button(Loc.T("Ready All for Edit"), GUIHelper.ButtonStyle, Array.Empty<GUILayoutOption>()))
		{
			int num2 = 0;
			for (int num3 = 0; num3 < clip.frames.Length; num3++)
			{
				tk2dSpriteAnimationFrame val3 = clip.frames[num3];
				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)(val4.materialInst ?? val4.material)).name.Split(' ')[0];
				string text13 = Path.Combine(SpriteLoader.LoadPath, ((Object)spriteCollection).name, text12, val4.name + ".png");
				if (File.Exists(text13))
				{
					num2++;
					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);
					num2++;
				}
			}
			Plugin.Logger.LogInfo((object)$"[AnimCtrl] Copied {num2} sprites from '{clip.name}' ({clip.frames.Length} frames) to {SpriteLoader.LoadPath}");
			for (int num4 = 0; num4 < clip.frames.Length; num4++)
			{
				tk2dSpriteAnimationFrame val5 = clip.frames[num4];
				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)(val6.materialInst ?? val6.material)).name.Split(' ')[0];
					string text15 = Path.Combine(SpriteLoader.LoadPath, ((Object)spriteCollection2).name, path2, val6.name + ".png");
					if (File.Exists(text15))
					{
						Process.Start(text15);
					}
				}
			}
			_anchorCacheKey = null;
		}
		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))
			{
				Process.Start(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))
			{
				Process.Start(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 backgroundColor = 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 = backgroundColor;
		GUILayout.EndHorizontal();
		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 static string _cachedLangString;

	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;

	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_0009: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		return _cachedLangString ?? (_cachedLangString = ((object)Language.CurrentLanguage()/*cast due to .constrained prefix*/).ToString());
	}

	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.ContainsKey(lang) && TextCache[lang].ContainsKey(sheet))
		{
			Plugin.Logger.LogDebug((object)("Invalidating text cache for sheet: " + sheet + ", lang: " + lang));
			TextCache[lang].Remove(sheet);
		}
	}

	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()
	{
		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()
	{
		_cachedLangString = null;
		Loc.OnGameLanguageChanged();
	}

	private static void GetTextPostfix(string key, string sheetTitle, ref string __result)
	{
		if (_dumpInProgress)
		{
			return;
		}
		long heapBefore = DevProfiler.SnapshotHeapBytes();
		try
		{
			string text = CurrentLangStringCached();
			if (!TextCache.TryGetValue(text, out var value))
			{
				value = new Dictionary<string, Dictionary<string, string>>();
				TextCache[text] = value;
			}
			if (!value.TryGetValue(sheetTitle, out var value2))
			{
				value2 = (value[sheetTitle] = LoadTextSheet(sheetTitle, text));
			}
			if (value2.TryGetValue(key, out var value3))
			{
				__result = value3;
				RequestedOverrideKeys.Add(text + "|" + sheetTitle + "|" + key);
			}
			DialogueHandler.OnTextAccessed?.Invoke(sheetTitle, key, __result);
		}
		finally
		{
			DevProfiler.AddOpPositiveNetHeapDelta("Postfix.Language.Get", heapBefore);
		}
	}

	private static Dictionary<string, string> LoadTextSheet(string sheetTitle, string lang)
	{
		Dictionary<string, string> dictionary = new Dictionary<string, string>();
		foreach (string pluginPackPath in Plugin.PluginPackPaths)
		{
			foreach (KeyValuePair<string, string> item in LoadTextSheet(sheetTitle, lang, Path.Combine(pluginPackPath, "Text")))
			{
				if (!dictionary.ContainsKey(item.Key))
				{
					dictionary[item.Key] = item.Value;
				}
			}
		}
		foreach (KeyValuePair<string, string> item2 in LoadTextSheet(sheetTitle, lang, TextLoadPath))
		{
			dictionary[item2.Key] = item2.Value;
		}
		foreach (string key in dictionary.Keys)
		{
			AllOverrideKeys.Add(lang + "|" + sheetTitle + "|" + key);
		}
		return dictionary;
	}

	public static void CheckForStaleKeys()
	{
		if (_staleKeysReported)
		{
			return;
		}
		int num = 0;
		foreach (string allOverrideKey in AllOverrideKeys)
		{
			if (!RequestedOverrideKeys.Contains(allOverrideKey))
			{
				string[] array = allOverrideKey.Split('|', 3);
				string text = array[0];
				string text2 = array[1];
				string text3 = array[2];
				string text4 = CurrentLangStringCached();
				if (!(text != text4))
				{
					num++;
					Plugin.Logger.LogWarning((object)("[Stitchwork] Text override key \"" + text3 + "\" in sheet \"" + text2 + "\" (" + text + ") was never requested by the game — key may have been renamed by a game update. Consider re-dumping text with DumpText enabled."));
				}
			}
		}
		StaleKeyCount = num;
		_staleKeysReported = true;
		if (num > 0)
		{
			Plugin.Logger.LogWarning((object)$"[Stitchwork] {num} stale text override key(s) detected. These overrides are not being applied.");
		}
	}

	private static Dictionary<string, string> LoadTextSheet(string sheetTitle, string lang, string basePath)
	{
		return ParseSheetFile(Path.Combine(basePath, sheetTitle, lang + ".yml"));
	}

	internal static Dictionary<string, string> ParseSheetFile(string filePath)
	{
		Dictionary<string, string> dictionary = new Dictionary<string, string>();
		if (!File.Exists(filePath))
		{
			return dictionary;
		}
		string[] array = File.ReadAllLines(filePath);
		foreach (string text in array)
		{
			if (!text.StartsWith("#") && !string.IsNullOrWhiteSpace(text))
			{
				int num = text.IndexOf(':');
				if (num != -1)
				{
					string key = text.Substring(0, num).Trim();
					string value = text.Substring(num + 1).Trim().Trim('"')
						.Replace("\\\"", "\"");
					dictionary[key] = value;
				}
			}
		}
		return dictionary;
	}
}
namespace System.Runtime.CompilerServices
{
	internal static class IsExternalInit
	{
	}
}
namespace Stitchwork
{
	[BepInPlugin("Stitchwork", "Stitchwork", "0.8.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Logger;

		internal static StitchworkConfig Config;

		internal static SpriteFileWatcher SpriteFileWatcher;

		internal static AudioFileWatcher AudioFileWatcher;

		internal static TextFileWatcher TextFileWatcher;

		private bool _isInert;

		private static bool _inertToastDismissed;

		public static bool ShowPackManager = false;

		public static bool ShowDevHub = false;

		private const float MenuSceneDeferDelay = 1f;

		private static readonly string[] MenuScenePatterns = new string[3] { "menu", "title", "mode_select" };

		private const float DeferredReapplyDelay = 0.1f;

		private static int _conditionPollFrames = 0;

		private const int ConditionPollInterval = 120;

		private int _focusRegainReloadFrame = -1;

		private const int FocusRegainReloadDelayFrames = 3;

		private static GUIStyle _inertTitleStyle;

		private static GUIStyle _inertBodyStyle;

		private static GUIStyle _inertBoxStyle;

		private static string _noticeTitle;

		private static string _noticeBody;

		internal static Harmony HarmonyInstance { get; private set; }

		public static Plugin Instance { get; private set; }

		public static string BasePath => Path.GetDirectoryName(typeof(Plugin).Assembly.Location);

		public static IEnumerable<string> PluginPackPaths => PackManager.ActivePackPaths;

		public static bool ShowStatusOverlay
		{
			get
			{
				return Config?.ShowStatusOverlay ?? true;
			}
			set
			{
				if (Config != null)
				{
					Config.ShowStatusOverlay = value;
				}
			}
		}

		public static int DevHubTab
		{
			get
			{
				return Config?.DevHubTab ?? 0;
			}
			set
			{
				if (Config != null)
				{
					Config.DevHubTab = value;
				}
			}
		}

		private void Awake()
		{
			//IL_03b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b7: Expected O, but got Unknown
			Instance = this;
			Logger = ((BaseUnityPlugin)this).Logger;
			if (Chainloader.PluginInfos.ContainsKey("Patchwork"))
			{
				Logger.LogWarning((object)"════════════════════════════════════════════════════════");
				Logger.LogWarning((object)"[Stitchwork] Upstream Patchwork detected.");
				Logger.LogWarning((object)"");
				Logger.LogWarning((object)"  Stitchwork is a fork that supersedes Patchwork. Running");
				Logger.LogWarning((object)"  both at the same time will produce duplicate Harmony");
				Logger.LogWarning((object)"  patches on sprite/texture setters and unpredictable");
				Logger.LogWarning((object)"  asset-swap behaviour.");
				Logger.LogWarning((object)"");
				Logger.LogWarning((object)"  Stitchwork is INERT this session.");
				Logger.LogWarning((object)"  Uninstall Patchwork.dll from BepInEx/plugins/ to enable");
				Logger.LogWarning((object)"  Stitchwork.");
				Logger.LogWarning((object)"════════════════════════════════════════════════════════");
				_isInert = true;
				return;
			}
			Config = new StitchworkConfig(((BaseUnityPlugin)this).Config);
			if (Config.DiagnosticMode)
			{
				Logger.LogWarning((object)"════════════════════════════════════════════════════════");
				Logger.LogWarning((object)"[Stitchwork] DiagnosticMode ACTIVE");
				Logger.LogWarning((object)"  - No Harmony patches applied");
				Logger.LogWarning((object)"  - No packs loaded");
				Logger.LogWarning((object)"  - No replacements will work");
				Logger.LogWarning((object)"  - DevProfiler [Mem] logging continues");
				Logger.LogWarning((object)"  - Use this for vanilla allocation-rate measurement only");
				Logger.LogWarning((object)"  - Toggle DiagnosticMode=false in BepInEx config to restore");
				Logger.LogWarning((object)"════════════════════════════════════════════════════════");
				DevProfiler.Initialize();
				GCUtil.InitBridge();
				return;
			}
			Logger.LogInfo((object)"Stitchwork is loaded! Version: 0.8.0");
			Loc.Init();
			int num = ((Config.HeapReserveMB < 0) ? GCUtil.SuggestReserveMB() : Config.HeapReserveMB);
			if (num > 0)
			{
				Logger.LogInfo((object)$"[GC] Pre-warming Mono heap: {num} MB (system RAM: {SystemInfo.systemMemorySize} MB)");
				GCUtil.PrewarmHeap((long)num * 1024L * 1024);
			}
			switch (BootConfigGC.Sync(Config.AutoEnableIncrementalGC))
			{
			case BootConfigGC.Result.KeyWritten:
				QueueNoticeToast(Loc.T("#toast.gc-enable.title", "Stitchwork — one restart to smoother performance"), Loc.T("#toast.gc-enable.body", "Incremental garbage collection has been enabled for Silksong (one line in boot.config; the original is backed up). This removes the game's periodic GC stutter.\n\nIt takes effect on the NEXT game launch — restart when convenient.\nOpt out anytime: AutoEnableIncrementalGC = false in Stitchwork's config."));
				break;
			case BootConfigGC.Result.KeyRemoved:
				QueueNoticeToast(Loc.T("#toast.gc-revert.title", "Stitchwork — restart to finish reverting"), Loc.T("#toast.gc-revert.body", "AutoEnableIncrementalGC is off — the incremental-GC line was removed from boot.config. The game's default GC behaviour returns on the next launch."));
				break;
			}
			foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos)
			{
				string key = pluginInfo.Key;
				PluginInfo value = pluginInfo.Value;
				object obj;
				if (value == null)
				{
					obj = null;
				}
				else
				{
					BepInPlugin metadata = value.Metadata;
					obj = ((metadata != null) ? metadata.Name : null);
				}
				if (obj == null)
				{
					obj = key;
				}
				string text = (string)obj;
				if (key.IndexOf("Customizer", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Customizer", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					Logger.LogError((object)("[Stitchwork] Conflicting plugin detected: '" + text + "' (GUID: " + key + "). Both mods patch sprite hooks and will conflict, causing broken sprite loading and enemy AI issues. Remove this plugin — Stitchwork replaces Customizer's functionality."));
				}
			}
			LogInstallRoot();
			PackManager.Initialize();
			TexUtil.Initialize();
			InitializeFolders();
			AudioFileWatcher = new AudioFileWatcher();
			SpriteFileWatcher = new SpriteFileWatcher();
			TextFileWatcher = new TextFileWatcher();
			DevProfiler.Initialize();
			T2DLoader.PreloadAllTextures();
			FileCache.BeginCycle();
			try
			{
				VideoHandler.Reload();
			}
			finally
			{
				FileCache.EndCycle();
			}
			FileCache.BeginCycle();
			try
			{
				AudioHandler.Reload();
			}
			finally
			{
				FileCache.EndCycle();
			}
			SceneManager.sceneLoaded += OnSceneLoaded;
			SceneManager.sceneUnloaded += OnSceneUnloaded;
			Harmony val = (HarmonyInstance = new Harmony("Stitchwork"));
			val.PatchAll();
			AudioHandler.ApplyPatches(val);
			AnimationController.ApplyPatches(val);
			SpriteLoader.ApplyPatches(val);
			VideoHandler.ApplyPatches(val);
			GUIHelper.InitInputBlocking();
			DialogueHandler.OnTextAccessed += delegate(string sheet, string key2, string text2)
			{
				TextLog.LogText(sheet, key2, text2);
			};
			DialogueHandler.OnTextAccessed += delegate(string sheet, string key2, string text2)
			{
				if (ShowDevHub)
				{
					DialogueEditor.TrackText(sheet, key2, text2);
				}
			};
			AudioHandler.OnAudioPlayed += delegate(AudioClip clip, AudioSource src)
			{
				AudioLog.LogAudio(clip, src);
			};
			T2DLoader.OnT2DTrigger += delegate(string raw, string clean, string sprite)
			{
				T2DLog.LogTrigger(raw, clean, sprite);
			};
			VideoHandler.OnCinematicTriggered += delegate(string name, bool replaced)
			{
				VideoPillar.LogCinematic(name, replaced);
			};
			GCUtil.OnTCGCStutter += delegate
			{
				DevProfiler.RecordSpike("TC GCManager stutter — threshold bumped 10%", 0f);
			};
			RawKeyboardLeakBlocker.ApplyPatches(val);
			((MonoBehaviour)this).StartCoroutine((IEnumerator)AwakeDelayed(val));
		}

		private IEnumerator<object> AwakeDelayed(Harmony harmony)
		{
			yield return null;
			DialogueHandler.ApplyPatches(harmony);
			DialogueFlagTracker.ApplyPatches(harmony);
			GUIHelper.InitCursor();
			if (Config.DumpText)
			{
				DialogueHandler.DumpText();
			}
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			GCUtil.InitBridge();
			GameBridge.InitBridge();
			SpriteAtlasBridge.Init();
			HealthCheck.LogBootSummaryOnce();
			if (SceneTraverser.IsTraversing)
			{
				SceneTraverser.NotifySceneLoaded();
			}
			else if (Config.DumpSprites)
			{
				Logger.LogInfo((object)("Dumping sprites for scene " + ((Scene)(ref scene)).name));
				tk2dSpriteCollectionData[] array = Resources.FindObjectsOfTypeAll<tk2dSpriteCollectionData>();
				for (int i = 0; i < array.Length; i++)
				{
					SpriteDumper.DumpCollection(array[i]);
				}
				T2DDumper.DumpAllT2DSprites();
				SceneTraverser.OnDumpCompleted();
				Logger.LogInfo((object)("Finished dumping sprites for scene " + ((Scene)(ref scene)).name));
			}
			T2DLoader.ApplyReplacementsInScene();
			if (IsMenuScene(((Scene)(ref scene)).name))
			{
				((MonoBehaviour)this).StartCoroutine(DeferredMenuApply());
			}
			((MonoBehaviour)this).StartCoroutine(DelayedReapply());
			FileCache.BeginCycle();
			try
			{
				AudioHandler.PrimeForScene();
			}
			finally
			{
				FileCache.EndCycle();
			}
			AnimationController.ClearAnimators();
			DialogueHandler.CheckForStaleKeys();
			PackManager.OnSceneLoaded(((Scene)(ref scene)).name);
			T2DLoader.OnSceneLoaded();
			T2DLoader.CheckForUninitializedSprites();
		}

		private void OnSceneUnloaded(Scene scene)
		{
			T2DLoader.PruneStaleOriginals();
			T2DLoader.PruneSceneState();
			T2DLoader.ResetSceneSeed();
		}

		private static bool IsMenuScene(string sceneName)
		{
			if (string.IsNullOrEmpty(sceneName))
			{
				return false;
			}
			string[] menuScenePatterns = MenuScenePatterns;
			foreach (string value in menuScenePatterns)
			{
				if (sceneName.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return true;
				}
			}
			return false;
		}

		private IEnumerator DeferredMenuApply()
		{
			yield return (object)new WaitForSeconds(1f);
			Logger.LogDebug((object)"[MenuDefer] Running deferred ApplyReplacementsInScene for menu scene.");
			T2DLoader.ApplyReplacementsInScene();
		}

		private IEnumerator DelayedReapply()
		{
			yield return (object)new WaitForSeconds(0.1f);
			Logger.LogDebug((object)"[SceneLoad] Running deferred ApplyReplacementsInScene (100 ms post-load).");
			T2DLoader.ApplyReplacementsInScene();
		}

		public static void ScheduleDeferredApplyPasses()
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)Instance == (Object)null))
			{
				((MonoBehaviour)Instance).StartCoroutine(Instance.DelayedReapply());
				Scene activeScene = SceneManager.GetActiveScene();
				if (IsMenuScene(((Scene)(ref activeScene)).name))
				{
					((MonoBehaviour)Instance).StartCoroutine(Instance.DeferredMenuApply());
				}
			}
		}

		private void LogInstallRoot()
		{
			Logger.LogInfo((object)("[Stitchwork] Install root: " + BasePath));
		}

		private void Update()
		{
			if (!_isInert)
			{
				DevProfiler.RecordFrame();
				DevProfiler.BeginUpdateTiming();
				long heapBefore = DevProfiler.SnapshotHeapBytes();
				T2DLoader.AdvanceSetterTracking();
				DevProfiler.StartOp();
				T2DLoader.CheckForUninitializedSprites();
				DevProfiler.RecordUninitMs(DevProfiler.StopOp("UninitCheck"));
				T2DLoader.ScanForLogTriggers();
				if (PackManager.HasHotReloadPacks && ++_conditionPollFrames >= 120)
				{
					_conditionPollFrames = 0;
					PackManager.PollHotReloadConditions();
				}
				GUIHelper.UpdateInputBlocking();
				HotkeyController.Poll();
				ReloadCoordinator.Poll();
				if (_focusRegainReloadFrame > 0 && Time.frameCount >= _focusRegainReloadFrame)
				{
					_focusRegainReloadFrame = -1;
					Logger.LogDebug((object)"[Plugin] Focus regained; re-running SpriteLoader.Reload + T2D reload to refresh atlas RT contents.");
					SpriteLoader.Reload();
					T2DLoader.ReloadSpritesInScene();
				}
				AnimationController.Update();
				DevProfiler.AddOpPositiveNetHeapDelta("Plugin.Update.Total", heapBefore);
				DevProfiler.EndUpdateTiming();
			}
		}

		private void LateUpdate()
		{
			long heapBefore = DevProfiler.SnapshotHeapBytes();
			if (ShowDevHub || ShowPackManager || CanvasPackManager.IsVisible || WorldPickMode.Active)
			{
				GUIHelper.ShowCursorForWindow();
			}
			DevProfil