Decompiled source of Getondabar v0.1.1

plugins/GetondabarMod.dll

Decompiled 20 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("GetondabarMod")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.1.0")]
[assembly: AssemblyInformationalVersion("0.1.1+63acee2b0d5a777474e0023d306e230c75106e5f")]
[assembly: AssemblyProduct("GetondabarMod")]
[assembly: AssemblyTitle("GetondabarMod")]
[assembly: AssemblyVersion("0.1.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace GetondabarMod
{
	[BepInPlugin("Therunner.Getondabar", "Getondabar", "0.1.1")]
	public sealed class Plugin : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(Tameable), "Interact")]
		public static class PetPatch
		{
			public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> source)
			{
				List<CodeInstruction> list = source.ToList();
				MethodInfo message = AccessTools.Method(typeof(Character), "Message", (Type[])null, (Type[])null);
				MethodInfo command = AccessTools.Method(typeof(Tameable), "Command", (Type[])null, (Type[])null);
				if (list.Count((CodeInstruction i) => CodeInstructionExtensions.Calls(i, message)) != 1 || list.Count((CodeInstruction i) => CodeInstructionExtensions.Calls(i, command)) != 1)
				{
					throw new InvalidOperationException("Valheim petting code changed; Getondabar refuses an unsafe patch.");
				}
				foreach (CodeInstruction instruction in list)
				{
					if (CodeInstructionExtensions.Calls(instruction, message))
					{
						CodeInstruction val = new CodeInstruction(OpCodes.Ldarg_0, (object)null);
						val.labels.AddRange(instruction.labels);
						instruction.labels.Clear();
						val.blocks.AddRange(instruction.blocks);
						instruction.blocks.Clear();
						yield return val;
						instruction.opcode = OpCodes.Call;
						instruction.operand = AccessTools.Method(typeof(Plugin), "PetMessage", (Type[])null, (Type[])null);
					}
					else if (CodeInstructionExtensions.Calls(instruction, command))
					{
						instruction.opcode = OpCodes.Call;
						instruction.operand = AccessTools.Method(typeof(Plugin), "PetCommand", (Type[])null, (Type[])null);
					}
					yield return instruction;
				}
			}
		}

		[HarmonyPatch(typeof(Player), "TakeInput")]
		private static class InputPatch
		{
			private static void Postfix(ref bool __result)
			{
				if (EditorOpen)
				{
					__result = false;
				}
			}
		}

		[HarmonyPatch(typeof(PlayerController), "TakeInput")]
		private static class ControllerInputPatch
		{
			private static void Postfix(ref bool __result)
			{
				if (EditorOpen)
				{
					__result = false;
				}
			}
		}

		[HarmonyPatch(typeof(ZInput), "GetMouseScrollWheel")]
		private static class ScrollPatch
		{
			private static void Postfix(ref float __result)
			{
				if (EditorOpen)
				{
					__result = 0f;
				}
			}
		}

		[HarmonyPatch(typeof(Menu), "Update")]
		private static class MenuPatch
		{
			private static bool Prefix()
			{
				if (!EditorOpen)
				{
					if (!((Object)(object)Instance == (Object)null))
					{
						return Instance.menuBlockFrame != Time.frameCount;
					}
					return true;
				}
				return false;
			}
		}

		[HarmonyPatch(typeof(GameCamera), "UpdateMouseCapture")]
		private static class CursorPatch
		{
			private static bool Prefix()
			{
				if (!EditorOpen)
				{
					return true;
				}
				ZCursor.LockState = (CursorLockMode)0;
				ZCursor.Show();
				return false;
			}
		}

		public const string Id = "Therunner.Getondabar";

		internal static Plugin Instance = null;

		internal RuleStore Store;

		internal RuleEditor Editor;

		private Harmony harmony;

		private ConfigEntry<KeyboardShortcut> shortcut;

		private ConfigEntry<bool> messagesEnabled;

		private static readonly MethodInfo TakeInputMethod = AccessTools.Method(typeof(Player), "TakeInput", (Type[])null, (Type[])null);

		private int menuBlockFrame = -1;

		internal static bool EditorOpen
		{
			get
			{
				if ((Object)(object)Instance != (Object)null && Instance.Editor != null)
				{
					return Instance.Editor.IsOpen;
				}
				return false;
			}
		}

		private void Awake()
		{
			//IL_0042: 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: Expected O, but got Unknown
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			messagesEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Show saved custom petting messages. The editor remains available when disabled.");
			shortcut = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Interface", "EditorShortcut", new KeyboardShortcut((KeyCode)288, Array.Empty<KeyCode>()), "Open or close the pet response editor while in a world.");
			Store = new RuleStore(Path.Combine(Paths.ConfigPath, "Therunner.Getondabar.rules.json"));
			Store.Load();
			if (Store.LoadError != null)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)Store.LoadError);
			}
			Editor = new RuleEditor(this);
			harmony = new Harmony("Therunner.Getondabar");
			harmony.PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Getondabar 0.1.1 loaded. Idea and inspiration: ThreadMenace. Press " + ((object)shortcut.Value/*cast due to .constrained prefix*/).ToString() + " to edit pet responses."));
		}

		private void Update()
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut value;
			if (!Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				Editor.Close();
			}
			else if (Editor.IsOpen)
			{
				if (!Input.GetKeyDown((KeyCode)27))
				{
					value = shortcut.Value;
					if (!((KeyboardShortcut)(ref value)).IsDown())
					{
						return;
					}
				}
				menuBlockFrame = Time.frameCount;
				Editor.Close();
			}
			else
			{
				value = shortcut.Value;
				if (((KeyboardShortcut)(ref value)).IsDown() && (bool)TakeInputMethod.Invoke(Player.m_localPlayer, null))
				{
					Editor.Open();
				}
			}
		}

		private void OnGUI()
		{
			Editor?.Draw();
		}

		private void OnDestroy()
		{
			Editor?.Dispose();
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
		}

		internal static string? Response(Tameable pet)
		{
			if ((Object)(object)Instance == (Object)null || !Instance.messagesEnabled.Value || !Object.op_Implicit((Object)(object)pet) || !pet.IsTamed() || !Object.op_Implicit((Object)(object)((Component)pet).GetComponent<Character>()))
			{
				return null;
			}
			string text = pet.GetText();
			string prefabName = Utils.GetPrefabName(((Component)pet).gameObject);
			return RuleEngine.Match(Instance.Store.Document.Rules, text, prefabName);
		}

		public static void PetMessage(Character user, MessageType type, string text, int amount, Sprite icon, bool showWhileDead, Tameable pet)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			user.Message(type, Response(pet) ?? text, amount, icon, showWhileDead);
		}

		public static void PetCommand(Tameable pet, Humanoid user, bool showMessage)
		{
			pet.Command(user, showMessage);
			string text = Response(pet);
			if (text != null)
			{
				((Character)user).Message((MessageType)2, text, 0, (Sprite)null, false);
			}
		}
	}
	internal sealed class RuleEditor
	{
		private sealed class CreatureChoice
		{
			public string Id = "";

			public string Label = "";

			public Sprite? Icon;
		}

		private readonly Plugin plugin;

		private PetRule? draft;

		private int editIndex = -1;

		private int deleteIndex = -1;

		private bool allTypes;

		private string search = "";

		private string error = "";

		private Vector2 listScroll;

		private Vector2 editorScroll;

		private readonly List<CreatureChoice> catalog = new List<CreatureChoice>();

		private GUISkin? skin;

		private readonly List<Texture2D> textures = new List<Texture2D>();

		private readonly Color accent = new Color(0.95f, 0.72f, 0.35f);

		public bool IsOpen { get; private set; }

		public RuleEditor(Plugin plugin)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			this.plugin = plugin;
		}

		public void Open()
		{
			IsOpen = true;
			error = plugin.Store.LoadError ?? "";
			DiscoverCreatures();
			draft = null;
			deleteIndex = -1;
			ZCursor.LockState = (CursorLockMode)0;
			ZCursor.Show();
		}

		public void Close()
		{
			IsOpen = false;
			draft = null;
			deleteIndex = -1;
		}

		private void DiscoverCreatures()
		{
			catalog.Clear();
			if (Object.op_Implicit((Object)(object)ZNetScene.instance))
			{
				foreach (GameObject prefab2 in ZNetScene.instance.m_prefabs)
				{
					if (Object.op_Implicit((Object)(object)prefab2) && Object.op_Implicit((Object)(object)prefab2.GetComponent<Tameable>()))
					{
						Character component = prefab2.GetComponent<Character>();
						if (Object.op_Implicit((Object)(object)component))
						{
							string label = Localization.instance.Localize(component.m_name);
							string text = ((((Object)prefab2).name == "Hen" || ((Object)prefab2).name == "Chicken") ? "ChickenMeat" : ("Trophy" + ((Object)prefab2).name));
							GameObject prefab = ZNetScene.instance.GetPrefab(text);
							ItemDrop val = (Object.op_Implicit((Object)(object)prefab) ? prefab.GetComponent<ItemDrop>() : null);
							Sprite[] array = (Object.op_Implicit((Object)(object)val) ? val.m_itemData.m_shared.m_icons : null);
							catalog.Add(new CreatureChoice
							{
								Id = ((Object)prefab2).name,
								Label = label,
								Icon = array?.FirstOrDefault()
							});
						}
					}
				}
			}
			foreach (string id in plugin.Store.Document.Rules.SelectMany((PetRule r) => r.Creatures).Distinct())
			{
				if (!catalog.Any((CreatureChoice c) => c.Id == id))
				{
					catalog.Add(new CreatureChoice
					{
						Id = id,
						Label = id + " (unavailable)"
					});
				}
			}
			catalog.Sort((CreatureChoice a, CreatureChoice b) => string.Compare(a.Label, b.Label, StringComparison.OrdinalIgnoreCase));
		}

		private Texture2D Fill(Color color)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(1, 1);
			val.SetPixel(0, 0, color);
			val.Apply();
			textures.Add(val);
			return val;
		}

		private void CreateSkin()
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Expected O, but got Unknown
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: 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_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Expected O, but got Unknown
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Expected O, but got Unknown
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0239: Unknown result type (might be due to invalid IL or missing references)
			//IL_0259: Unknown result type (might be due to invalid IL or missing references)
			//IL_025e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0265: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Expected O, but got Unknown
			skin = Object.Instantiate<GUISkin>(GUI.skin);
			skin.label.fontSize = 15;
			skin.label.normal.textColor = new Color(0.9f, 0.91f, 0.93f);
			skin.label.wordWrap = true;
			skin.label.richText = false;
			skin.button.fontSize = 15;
			skin.button.padding = new RectOffset(12, 12, 8, 8);
			skin.button.normal.background = Fill(new Color(0.17f, 0.21f, 0.26f));
			skin.button.hover.background = Fill(new Color(0.25f, 0.3f, 0.36f));
			skin.button.active.background = Fill(new Color(0.34f, 0.3f, 0.22f));
			skin.button.normal.textColor = Color.white;
			skin.button.richText = false;
			skin.box.normal.background = Fill(new Color(0.075f, 0.09f, 0.12f, 0.98f));
			skin.box.padding = new RectOffset(20, 20, 18, 18);
			skin.textField.fontSize = 17;
			skin.textField.padding = new RectOffset(10, 10, 8, 8);
			skin.textField.normal.textColor = Color.white;
			skin.textField.normal.background = Fill(new Color(0.13f, 0.16f, 0.2f));
			skin.textField.focused.background = Fill(new Color(0.2f, 0.23f, 0.28f));
			skin.textArea = new GUIStyle(skin.textField)
			{
				wordWrap = true,
				richText = false
			};
			skin.toggle.fontSize = 15;
		}

		public void Draw()
		{
			//IL_028a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0290: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: 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_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Expected O, but got Unknown
			if (!IsOpen)
			{
				return;
			}
			if ((Object)(object)skin == (Object)null)
			{
				CreateSkin();
			}
			GUISkin val = GUI.skin;
			Matrix4x4 matrix = GUI.matrix;
			Color color = GUI.color;
			bool enabled = GUI.enabled;
			float num = Mathf.Min(1.25f, Mathf.Min((float)Screen.width / 940f, (float)Screen.height / 720f));
			GUI.matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(num, num, 1f));
			GUI.skin = skin;
			try
			{
				float num2 = (float)Screen.width / num;
				float num3 = (float)Screen.height / num;
				GUI.Box(new Rect(0f, 0f, num2, num3), GUIContent.none);
				GUILayout.BeginArea(new Rect((num2 - 900f) / 2f, (num3 - 680f) / 2f, 900f, 680f), GUIContent.none, skin.box);
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				GUIStyle val2 = new GUIStyle(skin.label)
				{
					fontSize = 28,
					fontStyle = (FontStyle)1
				};
				GUILayout.Label("GETONDABAR", val2, Array.Empty<GUILayoutOption>());
				if (GUILayout.Button("Close", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(85f) }))
				{
					Close();
					GUIUtility.ExitGUI();
				}
				GUILayout.EndHorizontal();
				GUILayout.Label("Pet responses · Idea and inspiration by ThreadMenace", Array.Empty<GUILayoutOption>());
				GUILayout.Space(14f);
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				DrawList();
				GUILayout.Space(20f);
				GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(520f) });
				if (draft == null)
				{
					DrawError();
					GUILayout.Label("Give your pets something to say", val2, Array.Empty<GUILayoutOption>());
					GUILayout.Space(12f);
					GUILayout.Label("Add a rule or choose one on the left. Match an exact pet name, select any combination of creature types, then write its response.", Array.Empty<GUILayoutOption>());
					GUILayout.Space(12f);
					GUILayout.Label("Names are case-sensitive. Specific creature rules take priority over an all-creatures rule for the same name.", Array.Empty<GUILayoutOption>());
					GUILayout.Space(12f);
					GUILayout.Label("Only Save changes a rule. Cancel, Close, Escape and your editor shortcut discard an unsaved draft.", Array.Empty<GUILayoutOption>());
					GUI.enabled = plugin.Store.LoadError == null;
					if (GUILayout.Button("Create a response", Array.Empty<GUILayoutOption>()))
					{
						BeginEdit(-1);
					}
					GUI.enabled = true;
				}
				else
				{
					DrawDraft();
				}
				GUILayout.EndVertical();
				GUILayout.EndHorizontal();
				GUILayout.FlexibleSpace();
				GUILayout.Label("Local to your profile · Vanilla pet effects and follow/stay commands are preserved", Array.Empty<GUILayoutOption>());
				GUILayout.EndArea();
			}
			finally
			{
				GUI.skin = val;
				GUI.matrix = matrix;
				GUI.color = color;
				GUI.enabled = enabled;
			}
		}

		private void DrawList()
		{
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//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)
			GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(300f) });
			GUILayout.Label("SAVED RESPONSES (" + plugin.Store.Document.Rules.Count + ")", Array.Empty<GUILayoutOption>());
			GUI.enabled = plugin.Store.LoadError == null && draft == null;
			if (GUILayout.Button("+ Add response", Array.Empty<GUILayoutOption>()))
			{
				BeginEdit(-1);
			}
			listScroll = GUILayout.BeginScrollView(listScroll, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(445f) });
			for (int i = 0; i < plugin.Store.Document.Rules.Count; i++)
			{
				PetRule petRule = plugin.Store.Document.Rules[i];
				string text = ((petRule.Creatures.Count == 0) ? "All creatures" : string.Join(", ", petRule.Creatures.Select((string id) => catalog.FirstOrDefault((CreatureChoice c) => c.Id == id)?.Label ?? id)));
				GUILayout.Space(8f);
				if (GUILayout.Button(petRule.Name + "\n" + text, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.MinHeight(58f) }))
				{
					BeginEdit(i);
				}
				if (deleteIndex == i)
				{
					GUILayout.Label("Delete this saved response?", Array.Empty<GUILayoutOption>());
					GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
					if (GUILayout.Button("Delete", Array.Empty<GUILayoutOption>()))
					{
						Delete(i);
					}
					if (GUILayout.Button("Keep", Array.Empty<GUILayoutOption>()))
					{
						deleteIndex = -1;
						GUIUtility.ExitGUI();
					}
					GUILayout.EndHorizontal();
				}
				else if (GUILayout.Button("Remove", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(85f) }))
				{
					deleteIndex = i;
					GUIUtility.ExitGUI();
				}
			}
			GUILayout.EndScrollView();
			GUI.enabled = true;
			GUILayout.EndVertical();
		}

		private void BeginEdit(int index)
		{
			//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)
			editIndex = index;
			deleteIndex = -1;
			draft = ((index < 0) ? new PetRule() : plugin.Store.Document.Rules[index].Copy());
			allTypes = draft.Creatures.Count == 0;
			search = "";
			editorScroll = Vector2.zero;
			error = plugin.Store.LoadError ?? "";
			GUIUtility.ExitGUI();
		}

		private void DrawDraft()
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			//IL_0282: Unknown result type (might be due to invalid IL or missing references)
			//IL_0287: Unknown result type (might be due to invalid IL or missing references)
			//IL_0289: Unknown result type (might be due to invalid IL or missing references)
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_0313: Unknown result type (might be due to invalid IL or missing references)
			//IL_0373: Unknown result type (might be due to invalid IL or missing references)
			//IL_03df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0425: Unknown result type (might be due to invalid IL or missing references)
			//IL_0436: Unknown result type (might be due to invalid IL or missing references)
			editorScroll = GUILayout.BeginScrollView(editorScroll, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(450f) });
			DrawError();
			GUILayout.Label((editIndex < 0) ? "NEW RESPONSE" : "EDIT RESPONSE", Array.Empty<GUILayoutOption>());
			GUILayout.Label("Exact pet name", Array.Empty<GUILayoutOption>());
			draft.Name = GUILayout.TextField(draft.Name, 100, Array.Empty<GUILayoutOption>());
			GUILayout.Space(8f);
			GUILayout.Label("Message · use {name} wherever the pet’s name should appear", Array.Empty<GUILayoutOption>());
			draft.Message = GUILayout.TextArea(draft.Message, 300, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(65f) });
			GUI.color = accent;
			GUILayout.Label("Preview: " + draft.Message.Replace("{name}", draft.Name), Array.Empty<GUILayoutOption>());
			GUI.color = Color.white;
			GUILayout.Space(8f);
			bool flag = GUILayout.Toggle(allTypes, "All creature types (including modded creatures)", Array.Empty<GUILayoutOption>());
			if (flag != allTypes)
			{
				allTypes = flag;
				draft.Creatures.Clear();
			}
			GUILayout.Label(allTypes ? "Turn off All creature types to choose specific creatures." : "Choose one or more types · selected cards are gold", Array.Empty<GUILayoutOption>());
			string text = GUILayout.TextField(search, 80, Array.Empty<GUILayoutOption>());
			if (text != search)
			{
				search = text;
				GUIUtility.ExitGUI();
			}
			GUILayout.Label("Filter by creature name or prefab ID", Array.Empty<GUILayoutOption>());
			List<CreatureChoice> list = catalog.Where((CreatureChoice c) => c.Label.IndexOf(search, StringComparison.OrdinalIgnoreCase) >= 0 || c.Id.IndexOf(search, StringComparison.OrdinalIgnoreCase) >= 0).ToList();
			GUI.enabled = !allTypes;
			for (int num = 0; num < list.Count; num += 3)
			{
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				foreach (CreatureChoice item in list.Skip(num).Take(3))
				{
					bool flag2 = allTypes || draft.Creatures.Contains(item.Id);
					GUI.color = (Color)((flag2 && !allTypes) ? accent : new Color(0.6f, 0.65f, 0.7f));
					Rect rect = GUILayoutUtility.GetRect(148f, 72f, (GUILayoutOption[])(object)new GUILayoutOption[2]
					{
						GUILayout.Width(148f),
						GUILayout.Height(72f)
					});
					if (GUI.Button(rect, GUIContent.none))
					{
						if (flag2)
						{
							draft.Creatures.Remove(item.Id);
						}
						else
						{
							draft.Creatures.Add(item.Id);
						}
					}
					if (Object.op_Implicit((Object)(object)item.Icon))
					{
						Sprite icon = item.Icon;
						Rect textureRect = icon.textureRect;
						GUI.DrawTextureWithTexCoords(new Rect(((Rect)(ref rect)).x + 8f, ((Rect)(ref rect)).y + 8f, 30f, 30f), (Texture)(object)icon.texture, new Rect(((Rect)(ref textureRect)).x / (float)((Texture)icon.texture).width, ((Rect)(ref textureRect)).y / (float)((Texture)icon.texture).height, ((Rect)(ref textureRect)).width / (float)((Texture)icon.texture).width, ((Rect)(ref textureRect)).height / (float)((Texture)icon.texture).height));
					}
					else
					{
						GUI.Label(new Rect(((Rect)(ref rect)).x + 10f, ((Rect)(ref rect)).y + 8f, 28f, 28f), item.Label.Substring(0, 1));
					}
					GUI.Label(new Rect(((Rect)(ref rect)).x + 44f, ((Rect)(ref rect)).y + 8f, 100f, 28f), (flag2 && !allTypes) ? "Selected" : "");
					GUI.Label(new Rect(((Rect)(ref rect)).x + 8f, ((Rect)(ref rect)).y + 39f, 134f, 30f), item.Label);
					GUI.color = Color.white;
				}
				GUILayout.EndHorizontal();
			}
			GUI.enabled = true;
			if (list.Count == 0)
			{
				GUILayout.Label("No matching creature types.", Array.Empty<GUILayoutOption>());
			}
			GUILayout.EndScrollView();
			GUILayout.Space(10f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUI.enabled = plugin.Store.LoadError == null;
			if (GUILayout.Button("Save response", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(40f) }))
			{
				SaveDraft();
			}
			GUI.enabled = true;
			if (GUILayout.Button("Cancel", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(40f) }))
			{
				draft = null;
				error = plugin.Store.LoadError ?? "";
				GUIUtility.ExitGUI();
			}
			GUILayout.EndHorizontal();
		}

		private void DrawError()
		{
			//IL_001d: 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)
			if (error.Length != 0)
			{
				GUI.color = new Color(1f, 0.65f, 0.55f);
				GUILayout.Label(error, Array.Empty<GUILayoutOption>());
				GUI.color = Color.white;
			}
		}

		private void SaveDraft()
		{
			if (!allTypes && draft.Creatures.Count == 0)
			{
				error = "Select at least one creature type, or enable All creature types.";
				GUIUtility.ExitGUI();
				return;
			}
			RuleDocument ruleDocument = new RuleDocument
			{
				Rules = plugin.Store.Document.Rules.Select((PetRule r) => r.Copy()).ToList()
			};
			PetRule petRule = draft.Copy();
			if (allTypes)
			{
				petRule.Creatures.Clear();
			}
			if (editIndex < 0)
			{
				ruleDocument.Rules.Add(petRule);
			}
			else
			{
				ruleDocument.Rules[editIndex] = petRule;
			}
			try
			{
				plugin.Store.Save(ruleDocument);
				draft = null;
				error = "";
			}
			catch (Exception ex)
			{
				error = ((ex is InvalidDataException) ? ex.Message : "Could not save the response. Check that the profile config folder is writable.");
			}
			GUIUtility.ExitGUI();
		}

		private void Delete(int index)
		{
			RuleDocument ruleDocument = new RuleDocument
			{
				Rules = plugin.Store.Document.Rules.Select((PetRule r) => r.Copy()).ToList()
			};
			ruleDocument.Rules.RemoveAt(index);
			try
			{
				plugin.Store.Save(ruleDocument);
				deleteIndex = -1;
				error = "";
			}
			catch (Exception)
			{
				error = "Could not delete the response. Check that the profile config folder is writable.";
			}
			GUIUtility.ExitGUI();
		}

		public void Dispose()
		{
			Close();
			foreach (Texture2D texture in textures)
			{
				Object.Destroy((Object)(object)texture);
			}
			if (Object.op_Implicit((Object)(object)skin))
			{
				Object.Destroy((Object)(object)skin);
			}
		}
	}
	public sealed class PetRule
	{
		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public string Name { get; set; } = "Getondabar";

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public string Message { get; set; } = "{name} thinks you are an ugo";

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public List<string> Creatures { get; set; } = new List<string>();

		public PetRule Copy()
		{
			return new PetRule
			{
				Name = Name,
				Message = Message,
				Creatures = new List<string>(Creatures)
			};
		}
	}
	public sealed class RuleDocument
	{
		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public int SchemaVersion { get; set; } = 1;

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public List<PetRule> Rules { get; set; } = new List<PetRule>
		{
			new PetRule()
		};
	}
	public static class RuleEngine
	{
		public static string? Match(IEnumerable<PetRule> rules, string name, string prefab)
		{
			if (string.IsNullOrEmpty(name))
			{
				return null;
			}
			IEnumerable<PetRule> source = rules.Where((PetRule r) => string.Equals(r.Name, name, StringComparison.Ordinal));
			return (source.FirstOrDefault((PetRule r) => r.Creatures.Contains<string>(prefab, StringComparer.Ordinal)) ?? source.FirstOrDefault((PetRule r) => r.Creatures.Count == 0))?.Message.Replace("{name}", name);
		}

		public static void Validate(RuleDocument document)
		{
			if (document == null || document.SchemaVersion != 1 || document.Rules == null)
			{
				throw new InvalidDataException("Unsupported or incomplete rules file.");
			}
			for (int i = 0; i < document.Rules.Count; i++)
			{
				PetRule rule = document.Rules[i];
				if (rule == null || string.IsNullOrWhiteSpace(rule.Name) || rule.Name.Length > 100 || rule.Name.IndexOfAny(new char[4] { '\r', '\n', '<', '>' }) >= 0)
				{
					throw new InvalidDataException("Enter an exact pet name (1–100 characters, no markup or line breaks).");
				}
				if (string.IsNullOrWhiteSpace(rule.Message) || rule.Message.Length > 300 || rule.Message.IndexOfAny(new char[4] { '\r', '\n', '<', '>' }) >= 0)
				{
					throw new InvalidDataException("Enter a message (1–300 characters, no markup or line breaks).");
				}
				if (rule.Creatures == null || rule.Creatures.Any(string.IsNullOrWhiteSpace) || rule.Creatures.Distinct<string>(StringComparer.Ordinal).Count() != rule.Creatures.Count)
				{
					throw new InvalidDataException("Creature selections must be unique prefab IDs.");
				}
				foreach (PetRule item in from r in document.Rules.Take(i)
					where r.Name == rule.Name
					select r)
				{
					if ((rule.Creatures.Count == 0 && item.Creatures.Count == 0) || rule.Creatures.Intersect<string>(item.Creatures, StringComparer.Ordinal).Any())
					{
						throw new InvalidDataException("This name already has a rule for one of these creature types. Edit that rule or choose other types.");
					}
				}
			}
		}
	}
	public sealed class RuleStore
	{
		private readonly string path;

		public RuleDocument Document { get; private set; } = new RuleDocument();

		public string? LoadError { get; private set; }

		public RuleStore(string path)
		{
			this.path = path;
		}

		public void Load()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			try
			{
				if (!File.Exists(path))
				{
					Save(new RuleDocument());
					return;
				}
				RuleDocument document = JsonConvert.DeserializeObject<RuleDocument>(File.ReadAllText(path), new JsonSerializerSettings
				{
					MissingMemberHandling = (MissingMemberHandling)1,
					ObjectCreationHandling = (ObjectCreationHandling)2
				});
				RuleEngine.Validate(document);
				Document = document;
				LoadError = null;
			}
			catch (Exception)
			{
				Document = new RuleDocument
				{
					Rules = new List<PetRule>()
				};
				LoadError = "Rules could not be loaded. Custom messages are disabled. Repair or move the rules JSON and restart; the original file was preserved.";
			}
		}

		public void Save(RuleDocument document)
		{
			if (LoadError != null)
			{
				throw new InvalidOperationException(LoadError);
			}
			RuleEngine.Validate(document);
			Directory.CreateDirectory(Path.GetDirectoryName(path));
			string sourceFileName = path + ".tmp";
			try
			{
				File.WriteAllText(sourceFileName, JsonConvert.SerializeObject((object)document, (Formatting)1));
				if (File.Exists(path))
				{
					File.Replace(sourceFileName, path, path + ".bak");
				}
				else
				{
					File.Move(sourceFileName, path);
				}
				Document = new RuleDocument
				{
					Rules = document.Rules.Select((PetRule r) => r.Copy()).ToList()
				};
			}
			finally
			{
				if (File.Exists(sourceFileName))
				{
					File.Delete(sourceFileName);
				}
			}
		}
	}
	internal static class GeneratedVersion
	{
		public const string Value = "0.1.1";
	}
}