Decompiled source of FehuHeraldry v420.101.3

FehuHeraldry.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using FehuHeraldry.Assets;
using FehuHeraldry.Core;
using FehuHeraldry.Rendering;
using FehuHeraldry.UI;
using HarmonyLib;
using UnityEngine;

[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("FehuHeraldry")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("420.101.3.0")]
[assembly: AssemblyInformationalVersion("420.101.3")]
[assembly: AssemblyProduct("FehuHeraldry")]
[assembly: AssemblyTitle("FehuHeraldry")]
[assembly: AssemblyVersion("420.101.3.0")]
namespace FehuHeraldry
{
	[BepInPlugin("net.forteca.fehuheraldry", "Fehu Heraldry", "420.101.3")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "net.forteca.fehuheraldry";

		private HeraldryWindow _window;

		private HeraldryRenderer _renderer;

		private HeraldryEmblemLibrary _emblems;

		private ConfigEntry<KeyboardShortcut> _toggleKey;

		private ConfigEntry<KeyboardShortcut> _targetKey;

		private ShipHeraldryHotkeys _hotkeys;

		private CapeHeraldryRuntime _cape;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Invalid comparison between Unknown and I4
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: 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_00ba: Invalid comparison between Unknown and I4
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Expected O, but got Unknown
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			_toggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("UI", "ToggleKey", new KeyboardShortcut((KeyCode)289, Array.Empty<KeyCode>()), "Key used to open Fehu Heraldry. F7 is reserved and cannot be used.");
			_targetKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("UI", "TargetKey", new KeyboardShortcut((KeyCode)290, Array.Empty<KeyCode>()), "Key used to target a supported Heraldry ship. F7 is reserved and cannot be used.");
			KeyboardShortcut value = _toggleKey.Value;
			if ((int)((KeyboardShortcut)(ref value)).MainKey == 288)
			{
				_toggleKey.Value = new KeyboardShortcut((KeyCode)289, Array.Empty<KeyCode>());
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Migrated the old Heraldry F7 panel shortcut to F8.");
			}
			value = _targetKey.Value;
			if ((int)((KeyboardShortcut)(ref value)).MainKey == 288)
			{
				_targetKey.Value = new KeyboardShortcut((KeyCode)290, Array.Empty<KeyCode>());
			}
			HeraldryAssetLoader heraldryAssetLoader = new HeraldryAssetLoader(Paths.PluginPath, ((BaseUnityPlugin)this).Logger);
			HeraldryRegistry registry = heraldryAssetLoader.LoadRegistry();
			_emblems = new HeraldryEmblemLibrary(Paths.ConfigPath, registry, ((BaseUnityPlugin)this).Logger);
			HeraldrySaveManager heraldrySaveManager = new HeraldrySaveManager(Paths.ConfigPath, registry, ((BaseUnityPlugin)this).Logger);
			_renderer = new HeraldryRenderer(registry, heraldryAssetLoader, _emblems);
			HeraldryRuntime.Log = ((BaseUnityPlugin)this).Logger;
			HeraldryRuntime.Compositor = _renderer;
			HeraldryRuntime.Saves = heraldrySaveManager;
			HeraldryRuntime.SelectionStore = new HeraldrySelectionStore
			{
				Sail = heraldrySaveManager.Get("Sail").Clone()
			};
			_cape = ((Component)this).gameObject.AddComponent<CapeHeraldryRuntime>();
			_cape.Configure(heraldrySaveManager, _renderer);
			_harmony = new Harmony("net.forteca.fehuheraldry");
			_harmony.PatchAll(typeof(Plugin).Assembly);
			_window = new HeraldryWindow(registry, heraldrySaveManager, _renderer, _emblems);
			_hotkeys = ((Component)this).gameObject.AddComponent<ShipHeraldryHotkeys>();
			_hotkeys.Configure(_targetKey);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Fehu Heraldry 420.101.3 loaded. Shared cape/sail/banner pipeline; local appearance only. Panel default F8; ship target default F9; ClanWarfare emblems preferred.");
		}

		private void Update()
		{
			//IL_0006: 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_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Invalid comparison between Unknown and I4
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut value = _toggleKey.Value;
			if ((int)((KeyboardShortcut)(ref value)).MainKey != 288 && HeraldryInput.AllowsShortcut())
			{
				value = _toggleKey.Value;
				if (((KeyboardShortcut)(ref value)).IsDown())
				{
					_window.Toggle();
				}
			}
			_renderer.UpdatePreview();
		}

		private void OnDestroy()
		{
			ShipHeraldryTarget.RestoreAll();
			BannerHeraldryTarget.RestoreAll();
			if (_harmony != null)
			{
				_harmony.UnpatchSelf();
			}
			if ((Object)(object)_cape != (Object)null)
			{
				_cape.Shutdown();
			}
			HeraldryRuntime.SelectionStore = null;
			HeraldryRuntime.Compositor = null;
			HeraldryRuntime.Saves = null;
			if (_renderer != null)
			{
				_renderer.Dispose();
			}
			if (_emblems != null)
			{
				_emblems.Dispose();
			}
		}

		private void OnGUI()
		{
			_window.Draw();
		}
	}
}
namespace FehuHeraldry.UI
{
	public sealed class HeraldryWindow
	{
		private readonly HeraldryRegistry _registry;

		private readonly HeraldrySaveManager _saves;

		private readonly HeraldryRenderer _renderer;

		private readonly HeraldryEmblemLibrary _emblems;

		private readonly string[] _types = new string[3] { "Sail", "Banner", "Cape" };

		private readonly Dictionary<string, HeraldrySelection> _drafts = new Dictionary<string, HeraldrySelection>();

		private bool _visible;

		private int _tab;

		private Rect _window = new Rect(180f, 100f, 720f, 500f);

		private Vector2 _scroll;

		private string _draftTarget;

		private string _message;

		public HeraldryWindow(HeraldryRegistry registry, HeraldrySaveManager saves, HeraldryRenderer renderer, HeraldryEmblemLibrary emblems)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			_registry = registry;
			_saves = saves;
			_renderer = renderer;
			_emblems = emblems;
		}

		public void Toggle()
		{
			_visible = !_visible;
			if (_visible)
			{
				BeginEdit();
			}
		}

		private void BeginEdit()
		{
			_drafts.Clear();
			string[] types = _types;
			foreach (string text in types)
			{
				_drafts[text] = _saves.Get(text).Clone();
			}
			_draftTarget = null;
			_message = null;
		}

		public void Draw()
		{
			//IL_000f: 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_002f: Expected O, but got Unknown
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			if (_visible)
			{
				_window = GUILayout.Window(811024, _window, new WindowFunction(DrawWindow), "Fehu Heraldry", Array.Empty<GUILayoutOption>());
			}
		}

		private void DrawWindow(int id)
		{
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0308: 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_07f2: Unknown result type (might be due to invalid IL or missing references)
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			for (int i = 0; i < _types.Length; i++)
			{
				if (GUILayout.Toggle(_tab == i, _types[i], GUI.skin.button, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(110f) }))
				{
					_tab = i;
				}
			}
			GUILayout.EndHorizontal();
			string text = _types[_tab];
			GUILayout.Label("EMBLEM LIBRARY: " + _emblems.Count + " | ClanWarfare + local Emblems", Array.Empty<GUILayoutOption>());
			if (text == "Banner" && GUILayout.Button("Target Banner (crosshair, 15 m)", Array.Empty<GUILayoutOption>()))
			{
				BannerHeraldryTarget.SelectCrosshair();
			}
			IHeraldryTarget target = ResolveTarget(text);
			string reason = ((text == "Sail") ? "Select a supported ship with F9." : ((text == "Banner") ? "Aim at a vanilla banner and click Target Banner." : "Equip a supported cape."));
			bool flag = target != null && target.CanApply(out reason);
			string text2 = text + "|" + ((target == null) ? "none" : (((Object)target).GetInstanceID() + "|" + target.DisplayName));
			if (_draftTarget != text2)
			{
				_draftTarget = text2;
				_drafts[text] = ((target == null || target.SavedSelection == null) ? _saves.Get(text) : target.SavedSelection).Clone();
				_message = null;
			}
			HeraldryStyleDef[] array = _registry.Styles(text).ToArray();
			Ship val = ((text == "Sail" && HeraldryRuntime.SelectionStore != null) ? HeraldryRuntime.SelectionStore.Target : null);
			HeraldryProfileDef shipProfile = (((Object)(object)val == (Object)null) ? null : HeraldryRuntime.ProfileForShip(HeraldryRuntime.NormalizePrefabIdentity(((Object)val).name)));
			if (text == "Sail" && shipProfile != null)
			{
				array = array.Where((HeraldryStyleDef x) => x.profileId == shipProfile.profileId).ToArray();
			}
			if (text == "Cape" && flag)
			{
				array = array.Where((HeraldryStyleDef x) => x.prefabName == target.DisplayName).ToArray();
			}
			if (text == "Banner" && flag)
			{
				array = array.Where((HeraldryStyleDef x) => x.prefabName == ((WorldHeraldryTarget)target).Prefab).ToArray();
			}
			HeraldrySelection draft = _drafts[text];
			if (array.Length != 0 && !array.Any((HeraldryStyleDef x) => x.styleId == draft.styleId))
			{
				draft.styleId = array[0].styleId;
				draft.placementId = array[0].profileId;
			}
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
			_scroll = GUILayout.BeginScrollView(_scroll, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(420f),
				GUILayout.Height(305f)
			});
			Field("Style", array.Cast<object>().ToArray(), draft, 0);
			Field("Emblem", _registry.Emblems.Cast<object>().ToArray(), draft, 1);
			Field("Emblem Color", _registry.Colors.Cast<object>().ToArray(), draft, 3);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("Emblem Scale", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(130f) });
			if (GUILayout.Button("-", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(36f) }))
			{
				draft.emblemScale = Mathf.Clamp(draft.emblemScale - 0.1f, 0.4f, 2f);
			}
			GUILayout.Label(draft.emblemScale.ToString("0.0"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(45f) });
			if (GUILayout.Button("+", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(36f) }))
			{
				draft.emblemScale = Mathf.Clamp(draft.emblemScale + 0.1f, 0.4f, 2f);
			}
			GUILayout.EndHorizontal();
			GUILayout.Label("PNG colors and original fabric are preserved. Emblem Color affects built-in symbols.", Array.Empty<GUILayoutOption>());
			GUILayout.EndScrollView();
			GUILayout.EndVertical();
			GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(250f) });
			GUILayout.Label("Preview", GUI.skin.box, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(28f) });
			Texture2D val2 = (flag ? target.Preview(draft) : null);
			if ((Object)(object)val2 != (Object)null)
			{
				GUILayout.Label((Texture)(object)val2, (GUILayoutOption[])(object)new GUILayoutOption[2]
				{
					GUILayout.Width(220f),
					GUILayout.Height(220f)
				});
			}
			else
			{
				GUILayout.Label((_registry.Emblem(draft.emblemId) == null) ? ("Missing: " + draft.emblemId) : "Select a live target to preview original fabric + emblem.", Array.Empty<GUILayoutOption>());
			}
			if (GUILayout.Button("Reload Emblems", Array.Empty<GUILayoutOption>()))
			{
				_emblems.Reload();
				_renderer.Invalidate();
				if ((Object)(object)CapeHeraldryRuntime.Instance != (Object)null)
				{
					CapeHeraldryRuntime.Instance.EmblemsReloaded();
				}
				WorldHeraldryTarget.RefreshAll();
			}
			GUILayout.Label("Local appearance; multiplayer synchronization is pending.", Array.Empty<GUILayoutOption>());
			GUILayout.EndVertical();
			GUILayout.EndHorizontal();
			GUILayout.Label(((text == "Cape") ? "CURRENT CAPE: " : "TARGET: ") + ((target == null) ? "none" : target.DisplayName), Array.Empty<GUILayoutOption>());
			GUILayout.Label("SELECTED EMBLEM: " + ((_registry.Emblem(draft.emblemId) == null) ? "Missing: " : "") + draft.emblemId, Array.Empty<GUILayoutOption>());
			if (!flag)
			{
				GUILayout.Label(reason, Array.Empty<GUILayoutOption>());
			}
			if (!string.IsNullOrEmpty(_message))
			{
				GUILayout.Label(_message, Array.Empty<GUILayoutOption>());
			}
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("Reset", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(32f) }))
			{
				_drafts[text] = ((array.Length != 0) ? _registry.DefaultForStyle(array[0]) : _registry.Default(text));
			}
			GUI.enabled = flag && _registry.Validate(text, draft);
			if (GUILayout.Button("Apply", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(32f) }))
			{
				if (target.Apply(draft, out var reason2))
				{
					_message = text + " heraldry applied.";
					if (text == "Sail")
					{
						HeraldryRuntime.SelectionStore.Sail = draft.Clone();
					}
				}
				else
				{
					_message = reason2;
				}
			}
			GUI.enabled = flag;
			if (GUILayout.Button("Restore Original", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(32f) }))
			{
				_message = (target.RestoreOriginal(out var reason3) ? "Original appearance restored; saved assignment removed." : reason3);
			}
			GUI.enabled = true;
			if (GUILayout.Button("Cancel", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(32f) }))
			{
				BeginEdit();
				_visible = false;
			}
			GUILayout.EndHorizontal();
			GUI.DragWindow(new Rect(0f, 0f, 10000f, 22f));
		}

		private static IHeraldryTarget ResolveTarget(string type)
		{
			if (type == "Cape")
			{
				return CapeHeraldryRuntime.Instance;
			}
			if (type == "Banner")
			{
				return BannerHeraldryTarget.Selected;
			}
			Ship val = ((HeraldryRuntime.SelectionStore == null) ? null : HeraldryRuntime.SelectionStore.Target);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			ShipHeraldryTarget component = ((Component)val).GetComponent<ShipHeraldryTarget>();
			if (!((Object)(object)component == (Object)null))
			{
				return component;
			}
			return ((Component)val).gameObject.AddComponent<ShipHeraldryTarget>();
		}

		private void Field(string label, object[] items, HeraldrySelection selection, int field)
		{
			if (items.Length == 0)
			{
				GUILayout.Label(label + " — None", Array.Empty<GUILayoutOption>());
				return;
			}
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label(label, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(130f) });
			if (GUILayout.Button("<", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(34f) }))
			{
				Move(selection, field, items, -1);
			}
			GUILayout.Label(CurrentName(selection, field, items), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(190f) });
			if (GUILayout.Button(">", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(34f) }))
			{
				Move(selection, field, items, 1);
			}
			GUILayout.EndHorizontal();
		}

		private static string CurrentId(HeraldrySelection s, int f)
		{
			return f switch
			{
				3 => s.secondaryColorId, 
				2 => s.primaryColorId, 
				1 => s.emblemId, 
				0 => s.styleId, 
				_ => s.trimColorId, 
			};
		}

		private static string CurrentName(HeraldrySelection s, int f, object[] items)
		{
			string text = CurrentId(s, f);
			foreach (object obj in items)
			{
				if (obj is HeraldryStyleDef heraldryStyleDef && heraldryStyleDef.styleId == text)
				{
					return heraldryStyleDef.displayName;
				}
				if (obj is HeraldryEmblemDef heraldryEmblemDef && heraldryEmblemDef.emblemId == text)
				{
					return heraldryEmblemDef.displayName + " — " + heraldryEmblemDef.category + " (" + (string.IsNullOrEmpty(heraldryEmblemDef.source) ? "Built-in" : heraldryEmblemDef.source) + ")";
				}
				if (obj is HeraldryColorDef heraldryColorDef && heraldryColorDef.colorId == text)
				{
					return heraldryColorDef.displayName;
				}
			}
			if (f != 1)
			{
				return text;
			}
			return "Missing: " + text;
		}

		private static void Move(HeraldrySelection s, int field, object[] items, int delta)
		{
			if (items.Length != 0)
			{
				int num = Array.FindIndex(items, (object x) => IdOf(x) == CurrentId(s, field));
				if (num < 0)
				{
					num = 0;
				}
				num = (num + delta + items.Length) % items.Length;
				string text = IdOf(items[num]);
				if (field == 0)
				{
					s.styleId = text;
					s.placementId = ((HeraldryStyleDef)items[num]).profileId;
				}
				else if (field == 1)
				{
					s.emblemId = text;
				}
				else if (field == 2)
				{
					s.primaryColorId = text;
				}
				else if (field == 3)
				{
					s.secondaryColorId = text;
				}
				else
				{
					s.trimColorId = text;
				}
			}
		}

		private static string IdOf(object value)
		{
			if (value is HeraldryStyleDef heraldryStyleDef)
			{
				return heraldryStyleDef.styleId;
			}
			if (!(value is HeraldryEmblemDef heraldryEmblemDef))
			{
				return ((HeraldryColorDef)value).colorId;
			}
			return heraldryEmblemDef.emblemId;
		}
	}
}
namespace FehuHeraldry.Rendering
{
	public sealed class BannerHeraldryTarget : WorldHeraldryTarget
	{
		private static readonly HashSet<BannerHeraldryTarget> Active = new HashSet<BannerHeraldryTarget>();

		public static BannerHeraldryTarget Selected { get; private set; }

		public override string TargetType => "Banner";

		private void Awake()
		{
			Active.Add(this);
		}

		public static bool Supported(string prefab)
		{
			if (prefab != null && prefab.StartsWith("piece_banner", StringComparison.Ordinal) && prefab.Length == 14 && int.TryParse(prefab.Substring(12), out var result) && result >= 1)
			{
				return result <= 11;
			}
			return false;
		}

		public static void SelectCrosshair()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			Selected = null;
			RaycastHit val = default(RaycastHit);
			if ((Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)GameCamera.instance == (Object)null || !Physics.Raycast(((Component)GameCamera.instance).transform.position, ((Component)GameCamera.instance).transform.forward, ref val, 15f))
			{
				return;
			}
			Piece componentInParent = ((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<Piece>();
			if (!((Object)(object)componentInParent == (Object)null) && Supported(HeraldryRuntime.NormalizePrefabIdentity(((Object)componentInParent).name)))
			{
				Selected = ((Component)componentInParent).GetComponent<BannerHeraldryTarget>();
				if ((Object)(object)Selected == (Object)null)
				{
					Selected = ((Component)componentInParent).gameObject.AddComponent<BannerHeraldryTarget>();
				}
			}
		}

		public static void RestoreAll()
		{
			BannerHeraldryTarget[] array = Active.ToArray();
			foreach (BannerHeraldryTarget bannerHeraldryTarget in array)
			{
				if ((Object)(object)bannerHeraldryTarget != (Object)null)
				{
					bannerHeraldryTarget.Restore();
				}
			}
			Selected = null;
		}

		protected override void OnDestroy()
		{
			base.OnDestroy();
			Active.Remove(this);
			if ((Object)(object)Selected == (Object)(object)this)
			{
				Selected = null;
			}
		}

		protected override bool Resolve(out List<HeraldrySurface> surfaces, out string reason)
		{
			surfaces = new List<HeraldrySurface>();
			if (!Ready(out reason))
			{
				return false;
			}
			if (!Supported(base.Prefab))
			{
				reason = "Target a vanilla banner (piece_banner01 through piece_banner11).";
				return false;
			}
			WearNTear component = ((Component)this).GetComponent<WearNTear>();
			Transform[] source = (Transform[])(((Object)(object)component == (Object)null || component.m_fragmentRoots == null) ? ((Array)new Transform[0]) : ((Array)(from x in component.m_fragmentRoots
				where (Object)(object)x != (Object)null
				select x.transform).ToArray()));
			Renderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<Renderer>(true);
			foreach (Renderer renderer in componentsInChildren)
			{
				if ((!(renderer is MeshRenderer) && !(renderer is SkinnedMeshRenderer)) || source.Any((Transform x) => (Object)(object)((Component)renderer).transform == (Object)(object)x || ((Component)renderer).transform.IsChildOf(x)))
				{
					continue;
				}
				MeshFilter component2 = ((Component)renderer).GetComponent<MeshFilter>();
				if (!(renderer is SkinnedMeshRenderer) && ((Object)(object)component2 == (Object)null || (Object)(object)component2.sharedMesh == (Object)null))
				{
					continue;
				}
				Material[] sharedMaterials = renderer.sharedMaterials;
				for (int num2 = 0; num2 < sharedMaterials.Length; num2++)
				{
					Material val = Materials.Source(renderer, num2);
					if (!((Object)(object)val == (Object)null) && !((Object)(object)val.shader == (Object)null) && !(((Object)val.shader).name != "Custom/Vegetation"))
					{
						string text = HeraldryAlbedo.Property(val);
						if (text != null)
						{
							surfaces.Add(new HeraldrySurface
							{
								Renderer = renderer,
								Slot = num2,
								Property = text
							});
						}
					}
				}
			}
			reason = ((surfaces.Count == 0) ? "No supported live banner cloth albedo surface was found." : null);
			return surfaces.Count > 0;
		}
	}
	[HarmonyPatch(typeof(Piece), "Awake")]
	internal static class HeraldryBannerLifecyclePatch
	{
		[HarmonyPostfix]
		private static void Postfix(Piece __instance)
		{
			if (BannerHeraldryTarget.Supported(HeraldryRuntime.NormalizePrefabIdentity(((Object)__instance).name)) && (Object)(object)((Component)__instance).GetComponent<BannerHeraldryTarget>() == (Object)null)
			{
				((Component)__instance).gameObject.AddComponent<BannerHeraldryTarget>();
			}
		}
	}
	public sealed class CapeHeraldryRuntime : MonoBehaviour, IHeraldryTarget
	{
		private static readonly FieldInfo Shoulder = AccessTools.Field(typeof(Humanoid), "m_shoulderItem");

		private static readonly FieldInfo Instances = AccessTools.Field(typeof(VisEquipment), "m_shoulderItemInstances");

		private static readonly FieldInfo CurrentHash = AccessTools.Field(typeof(VisEquipment), "m_currentShoulderItemHash");

		private static readonly HashSet<string> Supported = new HashSet<string>(StringComparer.Ordinal) { "CapeLinen", "CapeDeerHide", "CapeTrollHide", "CapeWolf", "CapeLox", "CapeFeather", "CapeAsksvin" };

		private static readonly Dictionary<string, string> ClothRenderers = new Dictionary<string, string>(StringComparer.Ordinal)
		{
			{ "CapeLinen", "cape1" },
			{ "CapeDeerHide", "cape2" },
			{ "CapeTrollHide", "cape2" },
			{ "CapeWolf", "WolfCape_cloth" },
			{ "CapeLox", "LoxCape" },
			{ "CapeFeather", "MageCape" },
			{ "CapeAsksvin", "Asksvincape" }
		};

		private HeraldryMaterialController _materials;

		private readonly HashSet<string> _diagnosed = new HashSet<string>();

		private HeraldrySaveManager _saves;

		private HeraldryRenderer _compositor;

		private Player _player;

		private string _prefab;

		private string _appliedKey;

		private string _previewKey;

		private string _lastError;

		private long _playerId;

		private GameObject[] _roots = (GameObject[])(object)new GameObject[0];

		private float _nextCheck;

		private Texture2D _preview;

		private Coroutine _reapply;

		public static CapeHeraldryRuntime Instance { get; private set; }

		public string CurrentCape => _prefab ?? "none";

		public string DisplayName => CurrentCape;

		public HeraldrySelection SavedSelection
		{
			get
			{
				if (_saves != null)
				{
					return _saves.GetCape(_playerId, _prefab);
				}
				return null;
			}
		}

		public bool RestoreOriginal(out string reason)
		{
			return Remove(out reason);
		}

		public void Configure(HeraldrySaveManager saves, HeraldryRenderer compositor)
		{
			_saves = saves;
			_compositor = compositor;
			_materials = new HeraldryMaterialController(compositor);
			Instance = this;
		}

		public static bool IsLocalShoulder(VisEquipment equipment, int itemHash)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Invalid comparison between Unknown and I4
			Player localPlayer = Player.m_localPlayer;
			ItemData val = (ItemData)(((Object)(object)localPlayer == (Object)null || Shoulder == null) ? null : /*isinst with value type is only supported in some contexts*/);
			if ((Object)(object)localPlayer != (Object)null && (Object)(object)equipment == (Object)(object)((Humanoid)localPlayer).GetVisEquipment() && val != null && (Object)(object)val.m_dropPrefab != (Object)null && (int)val.m_shared.m_itemType == 17 && Supported.Contains(((Object)val.m_dropPrefab).name))
			{
				return StringExtensionMethods.GetStableHashCode(((Object)val.m_dropPrefab).name) == itemHash;
			}
			return false;
		}

		public void EquipmentAttached()
		{
			if (_reapply != null)
			{
				((MonoBehaviour)this).StopCoroutine(_reapply);
			}
			_reapply = ((MonoBehaviour)this).StartCoroutine(ReapplyAfterInitialization());
		}

		private IEnumerator ReapplyAfterInitialization()
		{
			yield return null;
			Refresh();
			yield return (object)new WaitForEndOfFrame();
			Refresh();
			yield return (object)new WaitForSecondsRealtime(0.15f);
			Refresh();
			yield return (object)new WaitForSecondsRealtime(0.85f);
			Refresh();
			_reapply = null;
		}

		private void Update()
		{
			if (_saves != null && !(Time.unscaledTime < _nextCheck))
			{
				_nextCheck = Time.unscaledTime + 0.5f;
				Refresh();
			}
		}

		private bool Resolve(out List<Renderer> renderers, out string reason)
		{
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Invalid comparison between Unknown and I4
			renderers = new List<Renderer>();
			reason = null;
			Player localPlayer = Player.m_localPlayer;
			ItemData val = (ItemData)(((Object)(object)localPlayer == (Object)null || Shoulder == null) ? null : /*isinst with value type is only supported in some contexts*/);
			string prefab = ((val == null || (Object)(object)val.m_dropPrefab == (Object)null) ? null : ((Object)val.m_dropPrefab).name);
			long num = (((Object)(object)localPlayer == (Object)null) ? 0 : localPlayer.GetPlayerID());
			VisEquipment val2 = (((Object)(object)localPlayer == (Object)null) ? null : ((Humanoid)localPlayer).GetVisEquipment());
			List<GameObject> list = (((Object)(object)val2 == (Object)null || Instances == null) ? null : (Instances.GetValue(val2) as List<GameObject>));
			GameObject[] array = (GameObject[])((list == null) ? ((Array)new GameObject[0]) : ((Array)list.Where((GameObject x) => (Object)(object)x != (Object)null).ToArray()));
			if ((Object)(object)_player != (Object)(object)localPlayer || _playerId != num || _prefab != prefab || !_roots.SequenceEqual(array))
			{
				_materials.Restore();
				ClearPreview();
				_appliedKey = null;
				_player = localPlayer;
				_playerId = num;
				_prefab = prefab;
				_roots = array;
			}
			if (Shoulder == null || Instances == null || CurrentHash == null)
			{
				reason = "Installed equipment API is unsupported.";
				return false;
			}
			if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead() || num == 0L || val == null)
			{
				reason = "Equip a supported cape on the local player.";
				return false;
			}
			if (!Supported.Contains(prefab) || (int)val.m_shared.m_itemType != 17)
			{
				reason = "Unsupported cape: " + prefab;
				return false;
			}
			if ((Object)(object)val2 == (Object)null || (int)CurrentHash.GetValue(val2) != StringExtensionMethods.GetStableHashCode(prefab) || array.Length == 0)
			{
				reason = "Waiting for the equipped cape visual.";
				return false;
			}
			renderers.AddRange((from x in array.SelectMany((GameObject x) => x.GetComponentsInChildren<SkinnedMeshRenderer>(true))
				where (Object)(object)x.sharedMesh != (Object)null && ((Object)x).name == ClothRenderers[prefab]
				select x).Cast<Renderer>().Distinct());
			if (!renderers.Any((Renderer x) => x.sharedMaterials.Any((Material m) => (Object)(object)m != (Object)null && HeraldryAlbedo.Property(m) != null)))
			{
				reason = "No supported skinned cape albedo material was found.";
				return false;
			}
			return true;
		}

		public bool CanApply(out string reason)
		{
			List<Renderer> renderers;
			return Resolve(out renderers, out reason);
		}

		public Texture2D Preview(HeraldrySelection selection)
		{
			if (!Resolve(out var renderers, out var _) || !_compositor.Registry.ValidateTarget("Cape", _prefab, selection))
			{
				ClearPreview();
				return null;
			}
			HeraldrySurface surface = Surfaces(renderers).First();
			Texture val = _materials.SourceTexture(surface);
			string text = ((Object)val).GetInstanceID() + "|" + Key(selection);
			if (_previewKey == text && (Object)(object)_preview != (Object)null)
			{
				return _preview;
			}
			ClearPreview();
			try
			{
				_preview = _compositor.ComposeCapeBaseAware(val, selection);
				_previewKey = text;
			}
			catch (Exception ex)
			{
				Report("Cape preview failed: " + ex.Message);
			}
			return _preview;
		}

		public bool Apply(HeraldrySelection selection, out string reason)
		{
			if (!Resolve(out var renderers, out reason) || !_compositor.Registry.ValidateTarget("Cape", _prefab, selection))
			{
				if (reason == null)
				{
					reason = "Select an available emblem and a valid Cape style.";
				}
				return false;
			}
			HeraldrySelection savedSelection = SavedSelection;
			if (!ApplyMaterials(renderers, selection, out reason))
			{
				return false;
			}
			try
			{
				_saves.SetCape(_playerId, _prefab, selection);
			}
			catch (Exception ex)
			{
				_materials.Restore();
				_appliedKey = null;
				_saves.RevertCapeInMemory(_playerId, _prefab, savedSelection);
				Refresh();
				reason = "Cape save failed: " + ex.Message;
				return false;
			}
			_appliedKey = Key(selection);
			HeraldryRuntime.Log.LogInfo((object)("Cape Apply: prefab=" + _prefab + " player=" + _playerId + " emblem=" + selection.emblemId + " slots=" + _materials.Count));
			return true;
		}

		public bool Remove(out string reason)
		{
			reason = null;
			if (_playerId == 0L || string.IsNullOrEmpty(_prefab))
			{
				reason = "Equip a cape first.";
				return false;
			}
			HeraldrySelection savedSelection = SavedSelection;
			try
			{
				_saves.SetCape(_playerId, _prefab, null);
			}
			catch (Exception ex)
			{
				_saves.RevertCapeInMemory(_playerId, _prefab, savedSelection);
				reason = "Cape restore save failed: " + ex.Message;
				return false;
			}
			_materials.Restore();
			ClearPreview();
			_appliedKey = null;
			HeraldryRuntime.Log.LogInfo((object)("Cape Restore Original: prefab=" + _prefab + " player=" + _playerId));
			return true;
		}

		public void EmblemsReloaded()
		{
			ClearPreview();
			_appliedKey = null;
			Refresh();
		}

		private string Key(HeraldrySelection selection)
		{
			return _compositor.CacheRevision + "|" + selection.styleId + "|" + selection.emblemId + "|" + selection.secondaryColorId + "|" + selection.emblemScale.ToString(CultureInfo.InvariantCulture);
		}

		private void Refresh()
		{
			try
			{
				if (!Resolve(out var renderers, out var reason))
				{
					_materials.Restore();
					_appliedKey = null;
					return;
				}
				HeraldrySelection savedSelection = SavedSelection;
				if (savedSelection == null)
				{
					_materials.Restore();
					_appliedKey = null;
					return;
				}
				if (!_compositor.Registry.ValidateTarget("Cape", _prefab, savedSelection))
				{
					_materials.Restore();
					_appliedKey = null;
					Report("Cape emblem/style unavailable; saved ID retained: " + savedSelection.emblemId);
					return;
				}
				bool flag = _materials.Count == 0 || _materials.HasChanged();
				if (!(_appliedKey == Key(savedSelection)) || flag)
				{
					if (ApplyMaterials(renderers, savedSelection, out reason))
					{
						_appliedKey = Key(savedSelection);
						_lastError = null;
						HeraldryRuntime.Log.LogInfo((object)("Cape Reapply: prefab=" + _prefab + " emblem=" + savedSelection.emblemId + " slots=" + _materials.Count));
					}
					else
					{
						Report(reason);
					}
				}
			}
			catch (Exception ex)
			{
				Report("Cape refresh failed: " + ex.Message);
			}
		}

		private IEnumerable<HeraldrySurface> Surfaces(List<Renderer> renderers)
		{
			foreach (Renderer renderer in renderers)
			{
				Material[] materials = renderer.sharedMaterials;
				for (int i = 0; i < materials.Length; i++)
				{
					Material val = _materials.Source(renderer, i);
					string text = HeraldryAlbedo.Property(val);
					if (text != null)
					{
						HeraldrySurface heraldrySurface = new HeraldrySurface
						{
							Renderer = renderer,
							Slot = i,
							Property = text
						};
						if (_diagnosed.Add(_prefab + "|" + ((Object)renderer).name + "|" + i + "|" + ((Object)val).name))
						{
							HeraldryAlbedo.Diagnose(((Component)_player).gameObject, _prefab, heraldrySurface, val);
						}
						yield return heraldrySurface;
					}
				}
			}
		}

		private bool ApplyMaterials(List<Renderer> renderers, HeraldrySelection selection, out string reason)
		{
			return _materials.Apply(Surfaces(renderers), (Texture texture) => _compositor.ComposeCapeBaseAware(texture, selection), out reason);
		}

		private void ClearPreview()
		{
			if ((Object)(object)_preview != (Object)null && _compositor != null)
			{
				_compositor.ReleaseGenerated((Texture)(object)_preview);
			}
			_preview = null;
			_previewKey = null;
		}

		private void Report(string message)
		{
			if (!(_lastError == message))
			{
				_lastError = message;
				HeraldryRuntime.Log.LogWarning((object)message);
			}
		}

		public void Shutdown()
		{
			((MonoBehaviour)this).StopAllCoroutines();
			_reapply = null;
			if (_materials != null)
			{
				_materials.Restore();
			}
			ClearPreview();
			_saves = null;
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
		}

		private void OnDestroy()
		{
			Shutdown();
		}
	}
	[HarmonyPatch(typeof(VisEquipment), "AttachArmor")]
	internal static class CapeArmorAttachmentPatch
	{
		[HarmonyPostfix]
		[HarmonyPriority(0)]
		private static void Postfix(VisEquipment __instance, int itemHash, List<GameObject> __result)
		{
			try
			{
				CapeHeraldryRuntime instance = CapeHeraldryRuntime.Instance;
				if ((Object)(object)instance != (Object)null && __result != null && CapeHeraldryRuntime.IsLocalShoulder(__instance, itemHash))
				{
					instance.EquipmentAttached();
				}
			}
			catch (Exception ex)
			{
				if (HeraldryRuntime.Log != null)
				{
					HeraldryRuntime.Log.LogWarning((object)("Cape attachment hook failed: " + ex.Message));
				}
			}
		}
	}
	public sealed class HeraldrySurface
	{
		public Renderer Renderer;

		public int Slot;

		public string Property;
	}
	public sealed class HeraldryMaterialController : IDisposable
	{
		private sealed class State
		{
			public HeraldrySurface Surface;

			public Material Original;

			public Material Owned;

			public Texture OriginalTexture;

			public Texture Generated;

			public MaterialPropertyBlock OriginalSlot;

			public bool OverridesSlot;
		}

		private List<State> _states = new List<State>();

		private readonly HeraldryRenderer _compositor;

		public int Count => _states.Count;

		public HeraldryMaterialController(HeraldryRenderer compositor)
		{
			_compositor = compositor;
		}

		public Material Source(Renderer renderer, int slot)
		{
			Material[] materials = renderer.sharedMaterials;
			if (slot < 0 || slot >= materials.Length)
			{
				return null;
			}
			State state = _states.FirstOrDefault((State x) => (Object)(object)x.Surface.Renderer == (Object)(object)renderer && x.Surface.Slot == slot && (Object)(object)x.Owned == (Object)(object)materials[slot]);
			if (state != null)
			{
				return state.Original;
			}
			return materials[slot];
		}

		public Texture SourceTexture(HeraldrySurface surface)
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Expected O, but got Unknown
			State state = _states.FirstOrDefault((State x) => (Object)(object)x.Surface.Renderer == (Object)(object)surface.Renderer && x.Surface.Slot == surface.Slot && surface.Slot < surface.Renderer.sharedMaterials.Length && (Object)(object)x.Owned == (Object)(object)surface.Renderer.sharedMaterials[surface.Slot]);
			if (state != null)
			{
				return state.OriginalTexture;
			}
			Material val = Source(surface.Renderer, surface.Slot);
			if ((Object)(object)val == (Object)null || !val.HasProperty(surface.Property))
			{
				return null;
			}
			MaterialPropertyBlock val2 = new MaterialPropertyBlock();
			surface.Renderer.GetPropertyBlock(val2, surface.Slot);
			if (val2.isEmpty)
			{
				surface.Renderer.GetPropertyBlock(val2);
			}
			return val2.GetTexture(surface.Property) ?? val.GetTexture(surface.Property);
		}

		public bool HasChanged()
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			foreach (State state in _states)
			{
				Renderer renderer = state.Surface.Renderer;
				if ((Object)(object)renderer == (Object)null)
				{
					return true;
				}
				Material[] sharedMaterials = renderer.sharedMaterials;
				if (state.Surface.Slot >= sharedMaterials.Length || (Object)(object)sharedMaterials[state.Surface.Slot] != (Object)(object)state.Owned)
				{
					return true;
				}
				if (state.OverridesSlot)
				{
					MaterialPropertyBlock val = new MaterialPropertyBlock();
					renderer.GetPropertyBlock(val, state.Surface.Slot);
					if ((Object)(object)val.GetTexture(state.Surface.Property) != (Object)(object)state.Generated)
					{
						return true;
					}
				}
			}
			return false;
		}

		public bool Apply(IEnumerable<HeraldrySurface> surfaces, Func<Texture, Texture2D> compose, out string reason)
		{
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Expected O, but got Unknown
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Expected O, but got Unknown
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Expected O, but got Unknown
			reason = null;
			List<State> list = new List<State>();
			try
			{
				foreach (HeraldrySurface surface in surfaces)
				{
					Material val = Source(surface.Renderer, surface.Slot);
					Texture val2 = SourceTexture(surface);
					if (!((Object)(object)val == (Object)null) && !((Object)(object)val2 == (Object)null))
					{
						State state = new State
						{
							Surface = surface,
							Original = val,
							OriginalTexture = val2
						};
						list.Add(state);
						state.Generated = (Texture)(object)compose(val2);
						if ((Object)(object)state.Generated == (Object)null)
						{
							throw new InvalidOperationException("Composition returned no texture.");
						}
						state.Owned = new Material(val)
						{
							name = "FehuHeraldry_" + ((Object)surface.Renderer).GetInstanceID() + "_" + surface.Slot
						};
						state.Owned.SetTexture(surface.Property, state.Generated);
					}
				}
				if (list.Count == 0)
				{
					throw new InvalidOperationException("No supported albedo surface was found.");
				}
			}
			catch (Exception ex)
			{
				foreach (State item in list)
				{
					Release(item);
				}
				reason = ex.Message;
				return false;
			}
			Restore();
			_states = list;
			try
			{
				foreach (State state2 in _states)
				{
					Renderer renderer = state2.Surface.Renderer;
					Material[] sharedMaterials = renderer.sharedMaterials;
					state2.OriginalSlot = new MaterialPropertyBlock();
					renderer.GetPropertyBlock(state2.OriginalSlot, state2.Surface.Slot);
					MaterialPropertyBlock val3 = new MaterialPropertyBlock();
					renderer.GetPropertyBlock(val3, state2.Surface.Slot);
					if (val3.isEmpty)
					{
						renderer.GetPropertyBlock(val3);
					}
					state2.OverridesSlot = (Object)(object)val3.GetTexture(state2.Surface.Property) != (Object)null;
					if (state2.OverridesSlot)
					{
						val3.SetTexture(state2.Surface.Property, state2.Generated);
					}
					sharedMaterials[state2.Surface.Slot] = state2.Owned;
					renderer.sharedMaterials = sharedMaterials;
					if (state2.OverridesSlot)
					{
						renderer.SetPropertyBlock(val3, state2.Surface.Slot);
					}
				}
				return true;
			}
			catch (Exception ex2)
			{
				Restore();
				reason = ex2.Message;
				return false;
			}
		}

		public void Restore()
		{
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Expected O, but got Unknown
			foreach (State state in _states)
			{
				Renderer renderer = state.Surface.Renderer;
				if ((Object)(object)renderer != (Object)null)
				{
					Material[] sharedMaterials = renderer.sharedMaterials;
					if (state.Surface.Slot < sharedMaterials.Length && (Object)(object)sharedMaterials[state.Surface.Slot] == (Object)(object)state.Owned)
					{
						sharedMaterials[state.Surface.Slot] = state.Original;
						renderer.sharedMaterials = sharedMaterials;
					}
					MaterialPropertyBlock val = new MaterialPropertyBlock();
					renderer.GetPropertyBlock(val, state.Surface.Slot);
					if (state.OverridesSlot && (Object)(object)val.GetTexture(state.Surface.Property) == (Object)(object)state.Generated)
					{
						renderer.SetPropertyBlock((state.OriginalSlot == null || state.OriginalSlot.isEmpty) ? null : state.OriginalSlot, state.Surface.Slot);
					}
				}
				Release(state);
			}
			_states.Clear();
		}

		private void Release(State state)
		{
			if ((Object)(object)state.Generated != (Object)null)
			{
				_compositor.ReleaseGenerated(state.Generated);
			}
			if ((Object)(object)state.Owned != (Object)null)
			{
				Object.Destroy((Object)(object)state.Owned);
			}
		}

		public void Dispose()
		{
			Restore();
		}
	}
	public static class HeraldryAlbedo
	{
		public static string Property(Material material)
		{
			if ((Object)(object)material == (Object)null)
			{
				return null;
			}
			if (material.HasProperty("_UseStyles") && material.GetFloat("_UseStyles") > 0.5f && material.HasProperty("_StyleTex") && (Object)(object)material.GetTexture("_StyleTex") != (Object)null)
			{
				return "_StyleTex";
			}
			return new string[3] { "_BaseMap", "_BaseColorMap", "_MainTex" }.FirstOrDefault((string x) => material.HasProperty(x) && (Object)(object)material.GetTexture(x) != (Object)null);
		}

		public static void Diagnose(GameObject target, string prefab, HeraldrySurface surface, Material source)
		{
			HeraldryRuntime.Log.LogInfo((object)("Heraldry target=" + ((Object)target).GetInstanceID() + " prefab=" + prefab + " path=" + HeraldryRuntime.HierarchyPath(target.transform, ((Component)surface.Renderer).transform) + " renderer=" + ((object)surface.Renderer).GetType().Name + " material=" + ((Object)source).name + " slot=" + surface.Slot + " shader=" + (((Object)(object)source.shader == (Object)null) ? "<none>" : ((Object)source.shader).name) + " albedo=" + surface.Property + " properties=" + string.Join(",", source.GetTexturePropertyNames())));
		}
	}
	public static class HeraldryPixelComposer
	{
		public static Color32 Blend(Color32 fabric, Color32 emblem, float opacity)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: 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_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: 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)
			if (fabric.a == 0 || emblem.a == 0 || opacity <= 0f)
			{
				return fabric;
			}
			float amount = Math.Min(1f, opacity) * (float)(int)emblem.a / 255f;
			float num = 0.5f + 0.5f * (0.2126f * (float)(int)fabric.r + 0.7152f * (float)(int)fabric.g + 0.0722f * (float)(int)fabric.b) / 255f;
			return new Color32(Channel((int)fabric.r, (float)(int)emblem.r * num, amount), Channel((int)fabric.g, (float)(int)emblem.g * num, amount), Channel((int)fabric.b, (float)(int)emblem.b * num, amount), fabric.a);
		}

		private static byte Channel(float original, float art, float amount)
		{
			return (byte)Math.Max(0.0, Math.Min(255.0, Math.Round(original + (art - original) * amount)));
		}

		public static void Overlay(Color32[] pixels, int width, int height, Color32[] art, int artWidth, int artHeight, HeraldryProfileDef profile, float scale)
		{
			//IL_026f: Unknown result type (might be due to invalid IL or missing references)
			//IL_027d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0285: Unknown result type (might be due to invalid IL or missing references)
			//IL_028a: Unknown result type (might be due to invalid IL or missing references)
			int num = Math.Max(1, profile.styleGrid);
			double num2 = Math.Max(0.001, profile.uvMaxX - profile.uvMinX);
			double num3 = Math.Max(0.001, profile.uvMaxY - profile.uvMinY);
			double num4 = ((profile.surfaceAspect > 0f) ? ((double)profile.surfaceAspect) : (num2 * (double)width / (num3 * (double)height)));
			double num5 = Math.Max(0.001, profile.emblemScale * scale);
			double num6 = num5 * num4 * (double)artHeight / (double)artWidth;
			double num7 = (double)profile.emblemRotation * Math.PI / 180.0;
			double num8 = Math.Cos(num7);
			double num9 = Math.Sin(num7);
			double num10 = Math.Max(0f, Math.Min(1f, profile.emblemOpacity));
			for (int i = 0; i < height; i++)
			{
				for (int j = 0; j < width; j++)
				{
					double num11 = ((double)j + 0.5) / (double)width;
					double num12 = ((double)i + 0.5) / (double)height;
					num11 = (num11 * (double)num % 1.0 - (double)profile.uvMinX) / num2;
					num12 = (num12 * (double)num % 1.0 - (double)profile.uvMinY) / num3;
					if (!(num11 < 0.0) && !(num11 > 1.0) && !(num12 < 0.0) && !(num12 > 1.0))
					{
						if (profile.mirrorU)
						{
							num11 = 1.0 - num11;
						}
						if (profile.mirrorV)
						{
							num12 = 1.0 - num12;
						}
						double num13 = (num11 - (double)profile.emblemCenterX) * num4;
						double num14 = num12 - (double)profile.emblemCenterY;
						double num15 = (num13 * num8 + num14 * num9) / (num5 * num4) + 0.5;
						double num16 = ((0.0 - num13) * num9 + num14 * num8) / num6 + 0.5;
						if (!(num15 < 0.0) && !(num15 > 1.0) && !(num16 < 0.0) && !(num16 > 1.0))
						{
							int num17 = Math.Min(artWidth - 1, (int)(num15 * (double)artWidth));
							int num18 = Math.Min(artHeight - 1, (int)(num16 * (double)artHeight));
							int num19 = i * width + j;
							pixels[num19] = Blend(pixels[num19], art[num18 * artWidth + num17], (float)num10);
						}
					}
				}
			}
		}

		public static void OverlayNormalized(Color32[] pixels, int width, int height, Color32[] art, int artWidth, int artHeight)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < height; i++)
			{
				for (int j = 0; j < width; j++)
				{
					int num = i * width + j;
					pixels[num] = Blend(pixels[num], art[i * artHeight / height * artWidth + j * artWidth / width], 1f);
				}
			}
		}
	}
	public sealed class HeraldryRenderer : IDisposable
	{
		private sealed class GeneratedTexture
		{
			public Texture2D Texture;

			public int References;
		}

		private const int Size = 128;

		private readonly HeraldryRegistry _registry;

		private readonly HeraldryAssetLoader _assets;

		private readonly HeraldryEmblemLibrary _emblems;

		private Texture2D _previewTexture;

		private Texture2D _composedTexture;

		private Texture2D _emblemMask;

		private string _lastKey;

		private Renderer _targetRenderer;

		private Material _originalMaterial;

		private Material _previewMaterial;

		private int _cacheRevision;

		private readonly Dictionary<string, GeneratedTexture> _baseCache = new Dictionary<string, GeneratedTexture>();

		public Texture2D PreviewTexture => _previewTexture;

		public Texture2D ComposedTexture => _composedTexture;

		public HeraldryRegistry Registry => _registry;

		public int CacheRevision => _cacheRevision;

		public HeraldryRenderer(HeraldryRegistry registry, HeraldryAssetLoader assets, HeraldryEmblemLibrary emblems)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Expected O, but got Unknown
			_registry = registry;
			_assets = assets;
			_emblems = emblems;
			_previewTexture = new Texture2D(128, 128, (TextureFormat)4, false);
			_composedTexture = new Texture2D(128, 128, (TextureFormat)4, false);
			_emblemMask = new Texture2D(128, 128, (TextureFormat)4, false);
		}

		public void UpdatePreview()
		{
		}

		public void Invalidate()
		{
			_lastKey = null;
			_cacheRevision++;
		}

		public void Compose(string type, HeraldrySelection selection)
		{
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: 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_032d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0347: Unknown result type (might be due to invalid IL or missing references)
			//IL_034c: Unknown result type (might be due to invalid IL or missing references)
			//IL_025f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0266: Unknown result type (might be due to invalid IL or missing references)
			//IL_0280: Unknown result type (might be due to invalid IL or missing references)
			//IL_0285: 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_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			if (selection == null)
			{
				return;
			}
			string text = string.Join("|", type, selection.styleId, selection.emblemId, selection.primaryColorId, selection.secondaryColorId, selection.trimColorId, selection.placementId, selection.emblemScale.ToString(CultureInfo.InvariantCulture));
			if (_lastKey == text)
			{
				return;
			}
			_lastKey = text;
			HeraldryStyleDef heraldryStyleDef = _registry.Style(selection.styleId);
			HeraldryProfileDef heraldryProfileDef = ((heraldryStyleDef == null) ? null : _registry.Profile(heraldryStyleDef.profileId));
			HeraldryEmblemDef heraldryEmblemDef = _registry.Emblem(selection.emblemId) ?? _registry.Emblem("fehu_rune") ?? _registry.Emblems.FirstOrDefault();
			HeraldryColorDef heraldryColorDef = _registry.Color(selection.primaryColorId);
			HeraldryColorDef heraldryColorDef2 = _registry.Color(selection.secondaryColorId);
			HeraldryColorDef heraldryColorDef3 = _registry.Color(selection.trimColorId);
			if (heraldryStyleDef == null || heraldryProfileDef == null || heraldryEmblemDef == null || heraldryColorDef == null || heraldryColorDef2 == null || heraldryColorDef3 == null)
			{
				return;
			}
			Color32[] array = (Color32[])(object)new Color32[16384];
			Color32 val = ToColor(heraldryColorDef);
			for (int i = 0; i < 128; i++)
			{
				for (int j = 0; j < 128; j++)
				{
					float num = (float)j / 127f;
					float num2 = (float)i / 127f;
					Color32 val2 = val;
					if (heraldryProfileDef.supportsTrim && (num2 < 0.11f || num2 > 0.89f))
					{
						val2 = ToColor(heraldryColorDef3);
					}
					else if (Math.Abs(num - 0.13f) < 0.035f || Math.Abs(num - 0.87f) < 0.035f)
					{
						val2 = ToColor(heraldryColorDef2);
					}
					if (heraldryProfileDef.mirrorU && num > 0.5f)
					{
						val2 = array[i * 128 + (127 - j)];
					}
					array[i * 128 + j] = val2;
				}
			}
			Color32[] array2 = _assets.LoadMask(heraldryProfileDef.maskAsset, 128, 128);
			if (array2 != null)
			{
				for (int k = 0; k < array.Length; k++)
				{
					if (array2[k].a > 0)
					{
						array[k] = Color32.Lerp(array[k], ToColor(heraldryColorDef2), (float)(int)array2[k].a / 255f);
					}
				}
			}
			_emblemMask.SetPixels32((Color32[])(object)new Color32[16384]);
			Color32[] array3 = (Color32[])array.Clone();
			DrawEmblem(array, heraldryEmblemDef, heraldryProfileDef, ToColor(heraldryColorDef2), selection.emblemScale);
			_emblemMask.Apply(false, false);
			_composedTexture.SetPixels32(array);
			_composedTexture.Apply(false, false);
			Color32[] pixels = _emblemMask.GetPixels32();
			for (int l = 0; l < pixels.Length; l++)
			{
				if (pixels[l].a > 0)
				{
					array3[l] = Color32.Lerp(array3[l], array[l], (float)(int)pixels[l].a / 255f);
				}
			}
			_previewTexture.SetPixels32(array3);
			_previewTexture.Apply(false, false);
			ApplyToTarget();
		}

		public Texture2D ComposeBaseAware(Texture baseTexture, Texture2D overlay, HeraldrySelection selection)
		{
			return ComposeOverlay(selection.objectType, baseTexture, selection);
		}

		public Texture2D ComposeCapeBaseAware(Texture baseTexture, HeraldrySelection selection)
		{
			return ComposeOverlay("Cape", baseTexture, selection);
		}

		public string SelectionKey(string type, HeraldrySelection selection)
		{
			return string.Join("|", type, _cacheRevision, selection.styleId, selection.emblemId, selection.secondaryColorId, selection.emblemScale.ToString(CultureInfo.InvariantCulture));
		}

		public Texture2D ComposeOverlay(string type, Texture baseTexture, HeraldrySelection selection)
		{
			//IL_02de: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0301: Unknown result type (might be due to invalid IL or missing references)
			//IL_030b: Unknown result type (might be due to invalid IL or missing references)
			//IL_030d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0317: Unknown result type (might be due to invalid IL or missing references)
			//IL_0325: Expected O, but got Unknown
			//IL_0337: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)baseTexture == (Object)null || !_registry.Validate(type, selection))
			{
				return null;
			}
			string key = "overlay|" + ((Object)baseTexture).GetInstanceID() + "|" + SelectionKey(type, selection);
			if (_baseCache.TryGetValue(key, out var value) && (Object)(object)value.Texture != (Object)null)
			{
				value.References++;
				return value.Texture;
			}
			HeraldryStyleDef heraldryStyleDef = _registry.Style(selection.styleId);
			HeraldryProfileDef heraldryProfileDef = _registry.Profile(heraldryStyleDef.profileId);
			HeraldryEmblemDef heraldryEmblemDef = _registry.Emblem(selection.emblemId);
			Texture2D texture = _emblems.GetTexture(heraldryEmblemDef);
			if ((Object)(object)texture == (Object)null && string.IsNullOrEmpty(heraldryEmblemDef.shape))
			{
				return null;
			}
			int num;
			Color32[] art;
			int num2;
			if ((Object)(object)texture != (Object)null)
			{
				art = texture.GetPixels32();
				num = ((Texture)texture).width;
				num2 = ((Texture)texture).height;
			}
			else
			{
				Compose(type, selection);
				art = _composedTexture.GetPixels32();
				Color32[] pixels = _emblemMask.GetPixels32();
				for (int i = 0; i < art.Length; i++)
				{
					art[i].a = pixels[i].a;
				}
				num2 = 128;
				int num3 = 128;
				int num4 = 128;
				int num5 = -1;
				int num6 = -1;
				for (int j = 0; j < 128; j++)
				{
					for (int k = 0; k < 128; k++)
					{
						if (art[j * 128 + k].a > 0)
						{
							num3 = Math.Min(num3, k);
							num4 = Math.Min(num4, j);
							num5 = Math.Max(num5, k);
							num6 = Math.Max(num6, j);
						}
					}
				}
				if (num5 < num3)
				{
					return null;
				}
				num = num5 - num3 + 1;
				num2 = num6 - num4 + 1;
				Color32[] array = (Color32[])(object)new Color32[num * num2];
				for (int l = 0; l < num2; l++)
				{
					Array.Copy(art, (num4 + l) * 128 + num3, array, l * num, num);
				}
				art = array;
			}
			int num7 = baseTexture.width;
			int num8 = baseTexture.height;
			if (num7 < 1 || num8 < 1 || num7 > 4096 || num8 > 4096)
			{
				throw new InvalidOperationException("Unsupported base texture dimensions.");
			}
			int num9 = Math.Max(0, Math.Min(2048, heraldryProfileDef.minimumResolution));
			if (Math.Max(num7, num8) < num9)
			{
				float num10 = (float)num9 / (float)Math.Max(num7, num8);
				num7 = (int)((float)num7 * num10);
				num8 = (int)((float)num8 * num10);
			}
			RenderTexture temporary = RenderTexture.GetTemporary(num7, num8, 0, (RenderTextureFormat)0);
			RenderTexture active = RenderTexture.active;
			Texture2D val = null;
			try
			{
				Graphics.Blit(baseTexture, temporary);
				RenderTexture.active = temporary;
				val = new Texture2D(num7, num8, (TextureFormat)4, true)
				{
					name = "FehuHeraldry_" + type + "_" + ((Object)baseTexture).name,
					wrapMode = baseTexture.wrapMode,
					filterMode = baseTexture.filterMode,
					anisoLevel = baseTexture.anisoLevel
				};
				val.ReadPixels(new Rect(0f, 0f, (float)num7, (float)num8), 0, 0, false);
				Color32[] pixels2 = val.GetPixels32();
				HeraldryPixelComposer.Overlay(pixels2, num7, num8, art, num, num2, heraldryProfileDef, selection.emblemScale);
				val.SetPixels32(pixels2);
				val.Apply(true, true);
				_baseCache[key] = new GeneratedTexture
				{
					Texture = val,
					References = 1
				};
				return val;
			}
			catch
			{
				if ((Object)(object)val != (Object)null)
				{
					Object.Destroy((Object)(object)val);
				}
				throw;
			}
			finally
			{
				RenderTexture.active = active;
				RenderTexture.ReleaseTemporary(temporary);
			}
		}

		public void ReleaseGenerated(Texture texture)
		{
			if ((Object)(object)texture == (Object)null)
			{
				return;
			}
			string text = null;
			foreach (KeyValuePair<string, GeneratedTexture> item in _baseCache)
			{
				if ((Object)(object)item.Value.Texture == (Object)(object)texture)
				{
					text = item.Key;
					break;
				}
			}
			if (text != null)
			{
				GeneratedTexture generatedTexture = _baseCache[text];
				generatedTexture.References = Math.Max(0, generatedTexture.References - 1);
				if (generatedTexture.References == 0)
				{
					_baseCache.Remove(text);
					Object.Destroy((Object)(object)generatedTexture.Texture);
				}
			}
		}

		public void Bind(Renderer target)
		{
			RestoreTarget();
			_targetRenderer = target;
			_originalMaterial = (((Object)(object)target == (Object)null) ? null : target.sharedMaterial);
			ApplyToTarget();
		}

		private void ApplyToTarget()
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			if (!((Object)(object)_targetRenderer == (Object)null) && !((Object)(object)_composedTexture == (Object)null))
			{
				if ((Object)(object)_previewMaterial == (Object)null)
				{
					_previewMaterial = new Material(_targetRenderer.sharedMaterial);
				}
				_previewMaterial.mainTexture = (Texture)(object)_composedTexture;
				_targetRenderer.material = _previewMaterial;
			}
		}

		private void RestoreTarget()
		{
			if ((Object)(object)_targetRenderer != (Object)null && (Object)(object)_originalMaterial != (Object)null)
			{
				_targetRenderer.sharedMaterial = _originalMaterial;
			}
			_targetRenderer = null;
			_originalMaterial = null;
		}

		private void DrawEmblem(Color32[] pixels, HeraldryEmblemDef emblem, HeraldryProfileDef profile, Color32 color, float scale)
		{
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_034e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0350: Unknown result type (might be due to invalid IL or missing references)
			//IL_035f: Unknown result type (might be due to invalid IL or missing references)
			int num = Mathf.Clamp(Mathf.RoundToInt(128f * scale * profile.emblemScale * 0.5f), 5, 60);
			int num2 = Mathf.RoundToInt(profile.emblemCenterX * 127f);
			int num3 = Mathf.RoundToInt(profile.emblemCenterY * 127f);
			Texture2D texture = _emblems.GetTexture(emblem);
			if ((Object)(object)texture != (Object)null)
			{
				Color32[] pixels2 = texture.GetPixels32();
				int width = ((Texture)texture).width;
				int height = ((Texture)texture).height;
				for (int i = -num; i <= num; i++)
				{
					for (int j = -num; j <= num; j++)
					{
						if (Math.Abs(j) > num || Math.Abs(i) > num)
						{
							continue;
						}
						int num4 = num2 + j;
						int num5 = num3 + i;
						if (profile.mirrorU && num4 >= 64)
						{
							num4 = num2 - j;
						}
						if (profile.mirrorV)
						{
							num5 = 127 - num5;
						}
						if (num4 >= 0 && num4 < 128 && num5 >= 0 && num5 < 128)
						{
							int num6 = Mathf.Clamp((j + num) * width / (num * 2 + 1), 0, width - 1);
							int num7 = Mathf.Clamp((i + num) * height / (num * 2 + 1), 0, height - 1);
							Color32 val = pixels2[num7 * width + num6];
							if (val.a != 0)
							{
								int num8 = num5 * 128 + num4;
								pixels[num8] = val;
								_emblemMask.SetPixel(num4, num5, Color32.op_Implicit(new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, val.a)));
							}
						}
					}
				}
			}
			else
			{
				if (string.IsNullOrEmpty(emblem.shape))
				{
					return;
				}
				for (int k = -num; k <= num; k++)
				{
					for (int l = -num; l <= num; l++)
					{
						float num9 = (float)l / (float)num;
						float num10 = (float)k / (float)num;
						bool num11 = ((emblem.shape == "diamond") ? (Math.Abs(num9) + Math.Abs(num10) < 0.9f) : ((!(emblem.shape == "cross")) ? ((!(emblem.shape == "chevron")) ? ((emblem.shape == "ring") ? (Math.Abs(Math.Sqrt(num9 * num9 + num10 * num10) - 0.6200000047683716) < 0.1599999964237213) : (num9 * num9 + num10 * num10 < 0.72f)) : (Math.Abs(num10 + 0.7f + Math.Abs(num9) * 0.9f) < 0.16f || Math.Abs(num9) < 0.13f)) : ((Math.Abs(num9) < 0.23f || Math.Abs(num10) < 0.23f) && Math.Abs(num9) + Math.Abs(num10) < 1.1f)));
						int num12 = ((profile.mirrorU && num2 + l >= 64) ? (num2 - l) : (num2 + l));
						int num13 = (profile.mirrorV ? (127 - (num3 + k)) : (num3 + k));
						if (num11 && num12 >= 0 && num12 < 128 && num13 >= 0 && num13 < 128)
						{
							pixels[num13 * 128 + num12] = color;
							_emblemMask.SetPixel(num12, num13, Color.white);
						}
					}
				}
			}
		}

		private static Color32 ToColor(HeraldryColorDef def)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			float[] rgba = def.rgba;
			return Color32.op_Implicit(new Color(rgba[0], rgba[1], rgba[2], (rgba.Length > 3) ? rgba[3] : 1f));
		}

		public void Dispose()
		{
			RestoreTarget();
			if ((Object)(object)_previewTexture != (Object)null)
			{
				Object.Destroy((Object)(object)_previewTexture);
			}
			if ((Object)(object)_composedTexture != (Object)null)
			{
				Object.Destroy((Object)(object)_composedTexture);
			}
			if ((Object)(object)_emblemMask != (Object)null)
			{
				Object.Destroy((Object)(object)_emblemMask);
			}
			foreach (GeneratedTexture value in _baseCache.Values)
			{
				if ((Object)(object)value.Texture != (Object)null)
				{
					Object.Destroy((Object)(object)value.Texture);
				}
			}
			_baseCache.Clear();
			if ((Object)(object)_previewMaterial != (Object)null)
			{
				Object.Destroy((Object)(object)_previewMaterial);
			}
		}
	}
	public static class HeraldryRuntime
	{
		public static ManualLogSource Log;

		public static HeraldrySelectionStore SelectionStore;

		public static HeraldryRenderer Compositor;

		public static HeraldrySaveManager Saves;

		public static void AuditPrefab(Ship ship)
		{
			if (!((Object)(object)ship == (Object)null))
			{
				string text = NormalizePrefabIdentity(((Object)((Component)ship).gameObject).name);
				HeraldryProfileDef heraldryProfileDef = ProfileForShip(text);
				Log.LogInfo((object)("Normalized ship identity: " + text));
				Log.LogInfo((object)((heraldryProfileDef == null) ? ("Unsupported Sail target=" + ((Object)((Component)ship).gameObject).name) : ("Supported Sail profile matched: " + heraldryProfileDef.prefabName)));
				if (heraldryProfileDef != null)
				{
					Renderer resolved;
					string reason;
					bool flag = ShipHeraldryTarget.CanApply(ship, heraldryProfileDef, out resolved, out reason);
					Log.LogInfo((object)(flag ? "Renderer validation PASS; Sail Apply ready." : ("Renderer validation failed: " + reason)));
				}
			}
		}

		public static IEnumerable<GameObject> FindVanillaShipPrefabs()
		{
			ZNetScene instance = ZNetScene.instance;
			if ((Object)(object)instance == (Object)null || instance.m_prefabs == null)
			{
				yield break;
			}
			foreach (GameObject prefab in instance.m_prefabs)
			{
				if ((Object)(object)prefab != (Object)null && (Object)(object)prefab.GetComponent<Ship>() != (Object)null)
				{
					yield return prefab;
				}
			}
		}

		public static void AuditLoadedPrefabs()
		{
		}

		public static string NormalizePrefabIdentity(string runtimeName)
		{
			if (string.IsNullOrEmpty(runtimeName) || !runtimeName.EndsWith("(Clone)", StringComparison.Ordinal))
			{
				return runtimeName;
			}
			return runtimeName.Substring(0, runtimeName.Length - "(Clone)".Length);
		}

		public static HeraldryProfileDef ProfileForShip(string instanceName)
		{
			if (string.IsNullOrEmpty(instanceName) || Compositor == null)
			{
				return null;
			}
			string prefabName = instanceName;
			HeraldryRegistry registry = Compositor.Registry;
			return (from x in registry.Styles("Sail")
				select registry.Profile(x.profileId)).FirstOrDefault((HeraldryProfileDef x) => x != null && x.prefabName == prefabName);
		}

		public static string HierarchyPath(Transform root, Transform child)
		{
			if ((Object)(object)root == (Object)null || (Object)(object)child == (Object)null)
			{
				return "<null>";
			}
			List<string> list = new List<string>();
			Transform val = child;
			while ((Object)(object)val != (Object)null)
			{
				list.Add(((Object)val).name);
				if ((Object)(object)val == (Object)(object)root)
				{
					break;
				}
				val = val.parent;
			}
			list.Reverse();
			return string.Join("/", list);
		}

		public static string TextureDescription(Texture texture)
		{
			if (!((Object)(object)texture == (Object)null))
			{
				return ((Object)texture).name + " " + texture.width + "x" + texture.height + " " + ((object)texture).GetType().Name + " id=" + ((Object)texture).GetInstanceID();
			}
			return "<null>";
		}
	}
	public sealed class ShipSailAudit : MonoBehaviour
	{
		private int _lastActive = -1;

		private void LateUpdate()
		{
			if (!((Object)(object)((Component)this).GetComponent<Ship>() == (Object)null))
			{
				int num = ((Component)this).GetComponentsInChildren<Renderer>(true).Count((Renderer x) => x.enabled && ((Component)x).gameObject.activeInHierarchy);
				if (_lastActive != num)
				{
					_lastActive = num;
					HeraldryRuntime.Log.LogInfo((object)("Sail renderer visibility changed ship=" + ((Object)((Component)this).gameObject).name + " activeRenderers=" + num));
				}
			}
		}
	}
	public sealed class HeraldrySelectionStore
	{
		public HeraldrySelection Sail;

		public Ship Target;
	}
	public static class HeraldryInput
	{
		public static bool AllowsShortcut()
		{
			if ((Object)(object)Player.m_localPlayer != (Object)null && ((Object)(object)Chat.instance == (Object)null || !Chat.instance.HasFocus()) && !Console.IsVisible() && !TextInput.IsVisible() && !Menu.IsVisible() && !InventoryGui.IsVisible())
			{
				return !Minimap.InTextInput();
			}
			return false;
		}
	}
	public sealed class ShipHeraldryHotkeys : MonoBehaviour
	{
		private ConfigEntry<KeyboardShortcut> _targetKey;

		public void Configure(ConfigEntry<KeyboardShortcut> targetKey)
		{
			_targetKey = targetKey;
		}

		private void Update()
		{
			//IL_001d: 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_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Invalid comparison between Unknown and I4
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			if (HeraldryRuntime.SelectionStore == null || _targetKey == null || !HeraldryInput.AllowsShortcut())
			{
				return;
			}
			KeyboardShortcut value = _targetKey.Value;
			if ((int)((KeyboardShortcut)(ref value)).MainKey == 288)
			{
				return;
			}
			value = _targetKey.Value;
			if (!((KeyboardShortcut)(ref value)).IsDown())
			{
				return;
			}
			Ship val = FindLookTarget(Player.m_localPlayer);
			HeraldryRuntime.SelectionStore.Target = val;
			if ((Object)(object)val != (Object)null)
			{
				HeraldryRuntime.AuditPrefab(val);
				if ((Object)(object)((Component)val).GetComponent<ShipSailAudit>() == (Object)null)
				{
					((Component)val).gameObject.AddComponent<ShipSailAudit>();
				}
				HeraldryRuntime.Log.LogInfo((object)("Targeted one ship using Heraldry target hotkey: " + ((Object)((Component)val).gameObject).name + " instance=" + ((Object)val).GetInstanceID()));
			}
			else
			{
				HeraldryRuntime.Log.LogInfo((object)"Heraldry targeting found no vanilla ship under player crosshair.");
			}
		}

		private static Ship FindLookTarget(Player player)
		{
			//IL_0019: 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)GameCamera.instance == (Object)null)
			{
				return null;
			}
			RaycastHit val = default(RaycastHit);
			if (!Physics.Raycast(((Component)GameCamera.instance).transform.position, ((Component)GameCamera.instance).transform.forward, ref val, 15f))
			{
				return null;
			}
			return ((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<Ship>();
		}
	}
	public sealed class ShipHeraldryTarget : WorldHeraldryTarget
	{
		private static readonly HashSet<ShipHeraldryTarget> Active = new HashSet<ShipHeraldryTarget>();

		public override string TargetType => "Sail";

		private void Awake()
		{
			Active.Add(this);
		}

		public static void RestoreAll()
		{
			ShipHeraldryTarget[] array = Active.ToArray();
			foreach (ShipHeraldryTarget shipHeraldryTarget in array)
			{
				if ((Object)(object)shipHeraldryTarget != (Object)null)
				{
					shipHeraldryTarget.Restore();
				}
			}
		}

		protected override void OnDestroy()
		{
			base.OnDestroy();
			Active.Remove(this);
		}

		public static bool CanApply(Ship ship, HeraldryProfileDef profile, out Renderer resolved, out string reason)
		{
			resolved = null;
			reason = null;
			if ((Object)(object)ship == (Object)null || profile == null || HeraldryRuntime.NormalizePrefabIdentity(((Object)((Component)ship).gameObject).name) != profile.prefabName)
			{
				reason = "Target a supported ship with F9.";
				return false;
			}
			if (profile.rendererPaths == null || profile.rendererPaths.Length != 1 || string.IsNullOrEmpty(profile.materialProperty))
			{
				reason = "Sail profile is incomplete.";
				return false;
			}
			Renderer[] array = (from x in ((Component)ship).GetComponentsInChildren<Renderer>(true)
				where HeraldryRuntime.HierarchyPath(((Component)ship).transform, ((Component)x).transform) == profile.rendererPaths[0]
				select x).ToArray();
			if (array.Length != 1)
			{
				reason = "Verified sail renderer path was not found or is ambiguous.";
				return false;
			}
			Renderer val = array[0];
			if (((object)val).GetType().Name != profile.rendererType)
			{
				reason = "Sail renderer type mismatch.";
				return false;
			}
			ShipHeraldryTarget component = ((Component)ship).GetComponent<ShipHeraldryTarget>();
			Material val2 = (((Object)(object)component == (Object)null || component.Materials == null) ? val.sharedMaterial : component.Materials.Source(val, 0));
			if ((Object)(object)val2 == (Object)null || (Object)(object)val2.shader == (Object)null || ((Object)val2.shader).name != profile.shaderName || ((Object)val2).name != profile.materialName)
			{
				reason = "Sail material or shader mismatch.";
				return false;
			}
			if (!val2.HasProperty(profile.materialProperty))
			{
				reason = "Verified sail albedo property is missing.";
				return false;
			}
			Texture texture = val2.GetTexture(profile.materialProperty);
			if ((Object)(object)texture == (Object)null || ((Object)texture).name != profile.sourceTextureName || texture.width != profile.sourceTextureWidth || texture.height != profile.sourceTextureHeight)
			{
				reason = "Sail source texture mismatch.";
				return false;
			}
			resolved = val;
			return true;
		}

		protected override bool Resolve(out List<HeraldrySurface> surfaces, out string reason)
		{
			surfaces = new List<HeraldrySurface>();
			if (!Ready(out reason))
			{
				return false;
			}
			HeraldryProfileDef heraldryProfileDef = HeraldryRuntime.ProfileForShip(base.Prefab);
			if (!CanApply(((Component)this).GetComponent<Ship>(), heraldryProfileDef, out var resolved, out reason))
			{
				return false;
			}
			surfaces.Add(new HeraldrySurface
			{
				Renderer = resolved,
				Slot = 0,
				Property = heraldryProfileDef.materialProperty
			});
			return true;
		}
	}
	[HarmonyPatch(typeof(Ship), "Awake")]
	internal static class HeraldryShipLifecyclePatch
	{
		[HarmonyPostfix]
		private static void Postfix(Ship __instance)
		{
			if (HeraldryRuntime.ProfileForShip(HeraldryRuntime.NormalizePrefabIdentity(((Object)__instance).name)) != null && (Object)(object)((Component)__instance).GetComponent<ShipHeraldryTarget>() == (Object)null)
			{
				((Component)__instance).gameObject.AddComponent<ShipHeraldryTarget>();
			}
		}
	}
	public interface IHeraldryTarget
	{
		string DisplayName { get; }

		HeraldrySelection SavedSelection { get; }

		bool CanApply(out string reason);

		bool Apply(HeraldrySelection selection, out string reason);

		bool RestoreOriginal(out string reason);

		Texture2D Preview(HeraldrySelection selection);
	}
	public abstract class WorldHeraldryTarget : MonoBehaviour, IHeraldryTarget
	{
		private static readonly HashSet<WorldHeraldryTarget> Active = new HashSet<WorldHeraldryTarget>();

		protected HeraldryMaterialController Materials;

		private float _nextCheck;

		private string _appliedKey;

		private string _previewKey;

		private string _lastWarning;

		private Texture2D _preview;

		private readonly HashSet<string> _diagnosed = new HashSet<string>();

		public abstract string TargetType { get; }

		public string Prefab => HeraldryRuntime.NormalizePrefabIdentity(((Object)((Component)this).gameObject).name);

		public string DisplayName => Prefab + " (single instance)";

		public HeraldrySelection SavedSelection
		{
			get
			{
				if (HeraldryRuntime.Saves == null || !Identity(out var worldId, out var objectId))
				{
					return null;
				}
				return HeraldryRuntime.Saves.GetWorld(worldId, objectId, Prefab, TargetType);
			}
		}

		private void OnEnable()
		{
			Active.Add(this);
		}

		public static void RefreshAll()
		{
			WorldHeraldryTarget[] array = Active.ToArray();
			foreach (WorldHeraldryTarget worldHeraldryTarget in array)
			{
				if ((Object)(object)worldHeraldryTarget != (Object)null)
				{
					worldHeraldryTarget.Refresh();
				}
			}
		}

		protected abstract bool Resolve(out List<HeraldrySurface> surfaces, out string reason);

		private unsafe bool Identity(out long worldId, out string objectId)
		{
			//IL_0054: 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_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			worldId = 0L;
			objectId = null;
			ZNetView component = ((Component)this).GetComponent<ZNetView>();
			if ((Object)(object)ZNet.instance == (Object)null || ZNet.instance.GetWorld() == null || (Object)(object)component == (Object)null || !component.IsValid() || component.GetZDO() == null)
			{
				return false;
			}
			worldId = ZNet.instance.GetWorldUID();
			ZDOID uid = component.GetZDO().m_uid;
			if (worldId == 0L || uid == ZDOID.None)
			{
				return false;
			}
			objectId = ((object)(*(ZDOID*)(&uid))/*cast due to .constrained prefix*/).ToString();
			return true;
		}

		protected bool Ready(out string reason)
		{
			reason = null;
			if (HeraldryRuntime.Compositor == null || HeraldryRuntime.Saves == null)
			{
				reason = "Heraldry is not initialized.";
				return false;
			}
			if (Materials == null)
			{
				Materials = new HeraldryMaterialController(HeraldryRuntime.Compositor);
			}
			return true;
		}

		public bool CanApply(out string reason)
		{
			if (!Ready(out reason) || !Resolve(out var _, out reason))
			{
				return false;
			}
			if (!Identity(out var _, out var _))
			{
				reason = "Waiting for world object identity.";
				return false;
			}
			return true;
		}

		public bool Apply(HeraldrySelection selection, out string reason)
		{
			reason = null;
			if (!CanApply(out reason) || !HeraldryRuntime.Compositor.Registry.ValidateTarget(TargetType, Prefab, selection))
			{
				if (reason == null)
				{
					reason = "Select an available emblem and valid style.";
				}
				return false;
			}
			if (!Resolve(out var surfaces, out reason) || !ApplyVisual(surfaces, selection, out reason))
			{
				return false;
			}
			Identity(out var worldId, out var objectId);
			HeraldrySelection savedSelection = SavedSelection;
			try
			{
				HeraldryRuntime.Saves.SetWorld(worldId, objectId, Prefab, TargetType, selection);
			}
			catch (Exception ex)
			{
				Materials.Restore();
				_appliedKey = null;
				HeraldryRuntime.Saves.RevertWorldInMemory(worldId, objectId, Prefab, TargetType, savedSelection);
				reason = "Heraldry save failed: " + ex.Message;
				Refresh();
				return false;
			}
			_appliedKey = HeraldryRuntime.Compositor.SelectionKey(TargetType, selection);
			HeraldryRuntime.Log.LogInfo((object)(TargetType + " Apply: prefab=" + Prefab + " object=" + objectId + " emblem=" + selection.emblemId));
			return true;
		}

		public bool RestoreOriginal(out string reason)
		{
			reason = null;
			if (!Ready(out reason) || !Identity(out var worldId, out var objectId))
			{
				reason = "Waiting for world object identity.";
				return false;
			}
			HeraldrySelection savedSelection = SavedSelection;
			try
			{
				HeraldryRuntime.Saves.SetWorld(worldId, objectId, Prefab, TargetType, null);
			}
			catch (Exception ex)
			{
				HeraldryRuntime.Saves.RevertWorldInMemory(worldId, objectId, Prefab, TargetType, savedSelection);
				reason = ex.Message;
				return false;
			}
			Restore();
			HeraldryRuntime.Log.LogInfo((object)(TargetType + " Restore Original: prefab=" + Prefab + " object=" + objectId));
			return true;
		}

		public Texture2D Preview(HeraldrySelection selection)
		{
			if (!Ready(out var reason) || !Resolve(out var surfaces, out reason) || !HeraldryRuntime.Compositor.Registry.ValidateTarget(TargetType, Prefab, selection))
			{
				ClearPreview();
				return null;
			}
			Texture val = Materials.SourceTexture(surfaces[0]);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			string text = ((Object)val).GetInstanceID() + "|" + HeraldryRuntime.Compositor.SelectionKey(TargetType, selection);
			if ((Object)(object)_preview != (Object)null && text == _previewKey)
			{
				return _preview;
			}
			ClearPreview();
			try
			{
				_preview = HeraldryRuntime.Compositor.ComposeOverlay(TargetType, val, selection);
				_previewKey = text;
			}
			catch (Exception ex)
			{
				Warn("Preview failed: " + ex.Message);
			}
			return _preview;
		}

		private bool ApplyVisual(List<HeraldrySurface> surfaces, HeraldrySelection selection, out string reason)
		{
			foreach (HeraldrySurface surface in surfaces)
			{
				Material val = Materials.Source(surface.Renderer, surface.Slot);
				if (_diagnosed.Add(((Object)surface.Renderer).name + "|" + surface.Slot + "|" + ((Object)val).name))
				{
					HeraldryAlbedo.Diagnose(((Component)this).gameObject, Prefab, surface, val);
				}
			}
			return Materials.Apply(surfaces, (Texture texture) => HeraldryRuntime.Compositor.ComposeOverlay(TargetType, texture, selection), out reason);
		}

		private void Update()
		{
			if (!(Time.unscaledTime < _nextCheck))
			{
				_nextCheck = Time.unscaledTime + 0.5f;
				Refresh();
			}
		}

		public void Refresh()
		{
			try
			{
				if (!Ready(out var reason))
				{
					return;
				}
				HeraldrySelection savedSelection = SavedSelection;
				if (savedSelection == null)
				{
					if (Materials.Count > 0 || _appliedKey != null)
					{
						Restore();
					}
					return;
				}
				if (!HeraldryRuntime.Compositor.Registry.ValidateTarget(TargetType, Prefab, savedSelection))
				{
					Restore();
					Warn("Missing emblem/style; saved ID retained: " + savedSelection.emblemId);
					return;
				}
				string text = HeraldryRuntime.Compositor.SelectionKey(TargetType, savedSelection);
				if (!(_appliedKey == text) || Materials.Count <= 0 || Materials.HasChanged())
				{
					if (!Resolve(out var surfaces, out reason))
					{
						Restore();
						Warn(reason);
					}
					else if (ApplyVisual(surfaces, savedSelection, out reason))
					{
						_appliedKey = text;
						_lastWarning = null;
						HeraldryRuntime.Log.LogInfo((object)(TargetType + " Reapply: " + Prefab + " emblem=" + savedSelection.emblemId));
					}
					else
					{
						Warn(reason);
					}
				}
			}
			catch (Exception ex)
			{
				Warn("Refresh failed: " + ex.Message);
			}
		}

		private void Warn(string reason)
		{
			if (!(_lastWarning == reason))
			{
				_lastWarning = reason;
				HeraldryRuntime.Log.LogWarning((object)(TargetType + ": " + reason));
			}
		}

		private void ClearPreview()
		{
			if ((Object)(object)_preview != (Object)null && HeraldryRuntime.Compositor != null)
			{
				HeraldryRuntime.Compositor.ReleaseGenerated((Texture)(object)_preview);
			}
			_preview = null;
			_previewKey = null;
		}

		public void Restore()
		{
			if (Materials != null)
			{
				Materials.Restore();
			}
			ClearPreview();
			_appliedKey = null;
		}

		protected virtual void OnDestroy()
		{
			Restore();
			Active.Remove(this);
		}
	}
}
namespace FehuHeraldry.Core
{
	public enum HeraldryObjectType
	{
		Sail,
		Banner,
		Cape
	}
	[Serializable]
	public sealed class HeraldryRegistryDef
	{
		public int schemaVersion = 1;

		public HeraldryStyleDef[] styles = new HeraldryStyleDef[0];

		public HeraldryEmblemDef[] emblems = new HeraldryEmblemDef[0];

		public HeraldryColorDef[] colors = new HeraldryColorDef[0];

		public HeraldryProfileDef[] profiles = new HeraldryProfileDef[0];
	}
	[Serializable]
	public sealed class HeraldryStyleDef
	{
		public string styleId;

		public string displayName;

		public string objectType;

		public string profileId;

		public string prefabName;

		public bool enabled = true;

		public bool allowHeraldry = true;

		public string baseColorId = "natural";
	}
	[Serializable]
	public sealed class HeraldryEmblemDef
	{
		public string emblemId;

		public string displayName;

		public string category;

		public string shape;

		public string source;

		[NonSerialized]
		public Texture2D texture;

		[NonSerialized]
		public bool ownsTexture;

		[NonSerialized]
		public string texturePath;

		public bool enabled = true;
	}
	[Serializable]
	public sealed class HeraldryColorDef
	{
		public string colorId;

		public string displayName;

		public float[] rgba;

		public bool enabled = true;
	}
	[Serializable]
	public sealed class HeraldryProfileDef
	{
		public string profileId;

		public string objectType;

		public string rendererName;

		public string prefabName;

		public string rendererType;

		public string materialName;

		public string shaderName;

		public string sourceTextureName;

		public int sourceTextureWidth;

		public int sourceTextureHeight;

		public string[] rendererPaths = new string[0];

		public string materialProperty = "_MainTex";

		public string maskAsset;

		public float emblemCenterX = 0.5f;

		public float emblemCenterY = 0.5f;

		public float emblemScale = 0.28f;

		public float emblemRotation;

		public float emblemOpacity = 1f;

		public float uvMinX;

		public float uvMinY;

		public float uvMaxX = 1f;

		public float uvMaxY = 1f;

		public float surfaceAspect;

		public int styleGrid = 1;

		public int minimumResolution;

		public bool tintPrimary = true;

		public bool supportsTrim = true;

		public bool mirrorU;

		public bool mirrorV;
	}
	[Serializable]
	public sealed class HeraldrySelection
	{
		public string styleId;

		public string emblemId;

		public string primaryColorId;

		public string secondaryColorId;

		public string trimColorId;

		public string placementId;

		public string objectType = "Sail";

		public float emblemScale = 1f;

		public HeraldrySelection Clone()
		{
			return (HeraldrySelection)MemberwiseClone();
		}
	}
	[Serializable]
	public sealed class PlayerHeraldrySave
	{
		public int schemaVersion = 1;

		public HeraldrySelection sail;

		public HeraldrySelection banner;

		public HeraldrySelection cape;

		public CapeHeraldryAssignment[] capeAssignments = new CapeHeraldryAssignment[0];

		public WorldHeraldryAssignment[] worldAssignments = new WorldHeraldryAssignment[0];
	}
	[Serializable]
	public sealed class CapeHeraldryAssignment
	{
		public long playerId;

		public string prefabName;

		public HeraldrySelection selection;
	}
	[Serializable]
	public sealed class WorldHeraldryAssignment
	{
		public long worldId;

		public string objectId;

		public string prefabName;

		public string objectType;

		public HeraldrySelection selection;
	}
	public sealed class HeraldryRegistry
	{
		private HeraldryEmblemDef[] _externalEmblems = new HeraldryEmblemDef[0];

		public HeraldryRegistryDef Data { get; private set; }

		public IEnumerable<HeraldryEmblemDef> Emblems => from x in (from x in _externalEmblems.Concat(Data.emblems)
				where x.enabled
				select x).GroupBy<HeraldryEmblemDef, string>((HeraldryEmblemDef x) => x.emblemId, StringComparer.OrdinalIgnoreCase)
			select x.First();

		public IEnumerable<HeraldryColorDef> Colors => Data.colors.Where((HeraldryColorDef x) => x.enabled);

		public HeraldryRegistry(HeraldryRegistryDef data)
		{
			Data = data;
		}

		public IEnumerable<HeraldryStyleDef> Styles(string type)
		{
			return Data.styles.Where((HeraldryStyleDef x) => x.enabled && x.allowHeraldry && x.objectType == type && Profile(x.profileId) != null);
		}

		public HeraldryStyleDef Style(string id)
		{
			return Data.styles.FirstOrDefault((HeraldryStyleDef x) => x.styleId == id && x.enabled);
		}

		public HeraldryEmblemDef Emblem(string id)
		{
			return Emblems.FirstOrDefault((HeraldryEmblemDef x) => string.Equals(x.emblemId, id, StringComparison.OrdinalIgnoreCase));
		}

		public void SetExternalEmblems(IEnumerable<HeraldryEmblemDef> emblems)
		{
			_externalEmblems = (emblems ?? Enumerable.Empty<HeraldryEmblemDef>()).ToArray();
		}

		public HeraldryColorDef Color(string id)
		{
			return Data.colors.FirstOrDefault((HeraldryColorDef x) => x.colorId == id && x.enabled);
		}

		public HeraldryProfileDef Profile(string id)
		{
			return Data.profiles.FirstOrDefault((HeraldryProfileDef x) => x.profileId == id);
		}

		public HeraldrySelection Default(string type)
		{
			HeraldryStyleDef heraldryStyleDef = Styles(type).FirstOrDefault();
			HeraldryColorDef[] array = Colors.ToArray();
			HeraldryEmblemDef heraldryEmblemDef = Emblems.FirstOrDefault();
			return new HeraldrySelection
			{
				objectType = type,
				styleId = ((heraldryStyleDef == null) ? "" : heraldryStyleDef.styleId),
				emblemId = ((heraldryEmblemDef == null) ? "" : heraldryEmblemDef.emblemId),
				primaryColorId = ((array.Length > 1) ? array[1].colorId : "natural"),
				secondaryColorId = ((array.Length > 2) ? array[2].colorId : "white"),
				trimColorId = ((array.Length > 3) ? array[3].colorId : "gold"),
				placementId = ((heraldryStyleDef == null) ? "" : heraldryStyleDef.profileId),
				emblemScale = 1f
			};
		}

		public HeraldrySelection DefaultForStyle(HeraldryStyleDef style)
		{
			HeraldrySelection heraldrySelection = Default(style.objectType);
			heraldrySelection.styleId = style.styleId;
			heraldrySelection.placementId = style.profileId;
			heraldrySelection.primaryColorId = ((Color("red") != null) ? "red" : heraldrySelection.primaryColorId);
			heraldrySelection.secondaryColorId = ((Color("black") != null) ? "black" : heraldrySelection.secondaryColorId);
			heraldrySelection.trimColorId = ((Color("black") != null) ? "black" : heraldrySelection.trimColorId);
			heraldrySelection.emblemId = ((Emblem("fehu_rune") != null) ? "fehu_rune" : heraldrySelection.emblemId);
			heraldrySelection.emblemScale = 1.5f;
			return heraldrySelection;
		}

		public bool Validate(string type, HeraldrySelection s)
		{
			if (ValidateExceptEmblem(type, s))
			{
				return Emblem(s.emblemId) != null;
			}
			return false;
		}

		public bool ValidateTarget(string type, string prefab, HeraldrySelection selection)
		{
			HeraldryStyleDef heraldryStyleDef = ((selection == null) ? null : Style(selection.styleId));
			if (Validate(type, selection))
			{
				return heraldryStyleDef.prefabName == prefab;
			}
			return false;
		}

		public bool ValidateExceptEmblem(string type, HeraldrySelection s)
		{
			HeraldryStyleDef heraldryStyleDef = ((s == null) ? null : Style(s.styleId));
			if (heraldryStyleDef != null && s.objectType == type && heraldryStyleDef.objectType == type && Profile(heraldryStyleDef.profileId) != null && Color(s.primaryColorId) != null && Color(s.secondaryColorId) != null && Color(s.trimColorId) != null && s.emblemScale >= 0.4f)
			{
				return s.emblemScale <= 2f;
			}
			return false;
		}
	}
	public sealed class HeraldrySaveManager
	{
		private readonly string _path;

		private readonly HeraldryRegistry _registry;

		private readonly ManualLogSource _log;

		public PlayerHeraldrySave Current { get; private set; }

		public HeraldrySaveManager(string configPath, HeraldryRegistry registry, ManualLogSource log)
		{
			_path = Path.Combine(configPath, "FehuHeraldry", "player-heraldry.json");
			_registry = registry;
			_log = log;
			Load();
		}

		private PlayerHeraldrySave Defaults()
		{
			return new PlayerHeraldrySave
			{
				sail = _registry.Default("Sail"),
				banner = _registry.Default("Banner"),
				cape = _registry.Default("Cape")
			};
		}

		private void Load()
		{
			if (!File.Exists(_path))
			{
				Current = Defaults();
				return;
			}
			try
			{
				Current = JsonUtility.FromJson<PlayerHeraldrySave>(File.ReadAllText(_path)) ?? Defaults();
				if (!_registry.ValidateExceptEmblem("Sail", Current.sail))
				{
					Current.sail = _registry.Default("Sail");
				}
				else
				{
					WarnMissingEmblem("Sail", Current.sail);
				}
				if (!_registry.ValidateExceptEmblem("Banner", Current.banner))
				{
					Current.banner = _registry.Default("Banner");
				}
				else
				{
					WarnMissingEmblem("Banner", Current.banner);
				}
				if (!_registry.ValidateExceptEmblem("Cape", Current.cape))
				{
					Current.cape = _registry.Default("Cape");
				}
				else
				{
					WarnMissingEmblem("Cape", Current.cape);
				}
			}
			catch (Exception ex)
			{
				_log.LogWarning((object)("Heraldry save could not be loaded; defaults are active. " + ex.Message));
				Current = Defaults();
			}
		}

		private void WarnMissingEmblem(string type, HeraldrySelection selection)
		{
			if (_registry.Emblem(selection.emblemId) == null)
			{
				_log.LogWarning((object)("Saved " + type + " emblem is unavailable; retaining its ID until the library is restored."));
			}
		}

		public void Save()
		{
			Directory.CreateDirectory(Path.GetDirectoryName(_path));
			string text = _path + ".tmp";
			File.WriteAllText(text, JsonUtility.ToJson((object)Current, true));
			if (File.Exists(_path))
			{
				File.Replace(text, _path, _path + ".bak");
			}
			else
			{
				File.Move(text, _path);
			}
		}

		public HeraldrySelection Get(string type)
		{
			if (!(type == "Banner"))
			{
				if (!(type == "Cape"))
				{
					return Current.sail;
				}
				return Current.cape;
			}
			return Current.banner;
		}

		public void Set(string type, HeraldrySelection selection)
		{
			if (type == "Banner")
			{
				Current.banner = selection;
			}
			else if (type == "Cape")
			{
				Current.cape = selection;
			}
			else
			{
				Current.sail = selection;
			}
			Save();
		}

		public HeraldrySelection GetCape(long playerId, string prefab)
		{
			return (Current.capeAssignments ?? new CapeHeraldryAssignment[0]).FirstOrDefault((CapeHeraldryAssignment x) => x != null && x.playerId == playerId && x.prefabName == prefab)?.selection;
		}

		public void RevertCapeInMemory(long playerId, string prefab, HeraldrySelection selection)
		{
			List<CapeHeraldryAssignment> list = (Current.capeAssignments ?? new CapeHeraldryAssignment[0]).Where((CapeHeraldryAssignment x) => x != null && (x.playerId != playerId || !(x.prefabName == prefab))).ToList();
			if (selection != null)
			{
				list.Add(new CapeHeraldryAssignment
				{
					playerId = playerId,
					prefabName = prefab,
					selection = selection.Clone()
				});
			}
			Current.capeAssignments = list.ToArray();
		}

		public void SetCape(long playerId, string prefab, HeraldrySelection selection)
		{
			if (playerId == 0L || string.IsNullOrEmpty(prefab))
			{
				throw new ArgumentException("A real local character and cape are required.");
			}
			RevertCapeInMemory(playerId, prefab, selection);
			Save();
		}

		public HeraldrySelection GetWorld(long worldId, string objectId, string prefab, string type)
		{
			return (Current.worldAssignments ?? new WorldHeraldryAssignment[0]).FirstOrDefault((WorldHeraldryAssignment x) => x != null && x.worldId == worldId && x.objectId == objectId && x.prefabName == prefab && x.objectType == type)?.selection;
		}

		public void RevertWorldInMemory(long worldId, string objectId, string prefab, string type, HeraldrySelection selection)
		{
			List<WorldHeraldryAssignment> list = (Current.worldAssignments ?? new WorldHeraldryAssignment[0]).Where((WorldHeraldryAssignment x) => x != null && (x.worldId != worldId || !(x.objectId == objectId) || !(x.prefabName == prefab) || !(x.objectType == type))).ToList();
			if (selection != null)
			{
				list.Add(new WorldHeraldryAssignment
				{
					worldId = worldId,
					objectId = objectId,
					prefabName = prefab,
					objectType = type,
					selection = selection.Clone()
				});
			}
			Current.worldAssignments = list.ToArray();
		}

		public void SetWorld(long worldId, string objectId, string prefab, string type, HeraldrySelection selection)
		{
			if (worldId == 0L || string.IsNullOrEmpty(objectId) || string.IsNullOrEmpty(prefab))
			{
				throw new ArgumentException("A real world object identity is required.");
			}
			RevertWorldInMemory(worldId, objectId, prefab, type, selection);
			Save();
		}
	}
}
namespace FehuHeraldry.Assets
{
	public sealed class HeraldryAssetLoader
	{
		private readonly string _assetPath;

		private readonly ManualLogSource _log;

		public HeraldryAssetLoader(string pluginPath, ManualLogSource log)
		{
			_assetPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			_log = log;
		}

		public HeraldryRegistry LoadRegistry()
		{
			string text = Path.Combine(_assetPath, "Config", "registry.json");
			if (!File.Exists(text))
			{
				Directory.CreateDirectory(Path.GetDirectoryName(text));
				File.WriteAllText(text, JsonUtility.ToJson((object)new HeraldryRegistryDef(), true));
				_log.LogWarning((object)("Registry missing; created empty registry at " + text));
			}
			HeraldryRegistryDef heraldryRegistryDef = JsonUtility.FromJson<HeraldryRegistryDef>(File.ReadAllText(text));
			if (heraldryRegistryDef == null || heraldryRegistryDef.schemaVersion != 1)
			{
				throw new InvalidDataException("Unsupported Heraldry registry schema at " + text);
			}
			return new HeraldryRegistry(heraldryRegistryDef);
		}

		public Color32[] LoadMask(string relativePath, int width, int height)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Expected O, but got Unknown
			if (string.IsNullOrEmpty(relativePath))
			{
				return null;
			}
			string fullPath = Path.GetFullPath(_assetPath + Path.DirectorySeparatorChar);
			string fullPath2 = Path.GetFullPath(Path.Combine(_assetPath, relativePath));
			if (!fullPath2.StartsWith(fullPath, StringComparison.OrdinalIgnoreCase) || !File.Exists(fullPath2))
			{
				return null;
			}
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
			if (!ImageCo