Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Getondabar v0.1.1
plugins/GetondabarMod.dll
Decompiled 20 hours agousing 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"; } }