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 Kin Catalysts v1.0.0
Kin Catalysts.dll
Decompiled 2 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("Kin Catalysts")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Kin Catalysts")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("49675f29-b978-40ba-8ed5-9dd05d738982")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] namespace DynamicTrophyAttractors; [Serializable] public class HatOffset { public string key = ""; public Vector3 pos = Vector3.zero; public Vector3 rot = Vector3.zero; public float scale = 1f; } public class HatAdjustGui : MonoBehaviour { public const string DefaultKey = "__default__"; private static readonly HatOffset[] BuiltinDefaults = new HatOffset[70] { new HatOffset { key = "__default__", pos = new Vector3(0f, 0f, 0f), rot = new Vector3(0f, 0f, 0f), scale = 1f }, new HatOffset { key = "Hat_Lox", pos = new Vector3(0f, -0.17858f, -0.15476f), rot = new Vector3(0f, 0f, 0f), scale = 0.78333f }, new HatOffset { key = "Hat_Surtling", pos = new Vector3(0f, -0.0119f, -0.0031f), rot = new Vector3(0f, 0f, 0f), scale = 1.43333f }, new HatOffset { key = "Hat_Neck", pos = new Vector3(0f, -0.03f, -0.0119f), rot = new Vector3(-66.42857f, 0f, 0f), scale = 1f }, new HatOffset { key = "Hat_Fenring", pos = new Vector3(-0.01f, 0.36405f, 0f), rot = new Vector3(180f, 0f, 0f), scale = 0.95f }, new HatOffset { key = "Hat_GreydwarfBrute", pos = new Vector3(0f, 0.02381f, -0.0031f), rot = new Vector3(0f, 0f, 0f), scale = 1.68333f }, new HatOffset { key = "Hat_Greydwarf", pos = new Vector3(0f, 0.03f, -0.015f), rot = new Vector3(2f, 0f, 0f), scale = 0.9f }, new HatOffset { key = "Hat_GreydwarfShaman", pos = new Vector3(0f, 0.055f, -0.03f), rot = new Vector3(0f, 0f, 0f), scale = 1.6f }, new HatOffset { key = "Hat_Blob_Lava", pos = new Vector3(0f, -0.04f, -0.05762f), rot = new Vector3(-28f, 0f, 0f), scale = 0.8f }, new HatOffset { key = "Hat_Ulv", pos = new Vector3(-0.13286f, -0.12595f, 0.04762f), rot = new Vector3(-7.85714f, -6.42857f, 153.5714f), scale = 1.1f }, new HatOffset { key = "Hat_Leech", pos = new Vector3(-0.01f, 0.065f, 0.005f), rot = new Vector3(-93f, 4.28571f, -8.57143f), scale = 1.1f }, new HatOffset { key = "Hat_Bjorn", pos = new Vector3(0f, -0.01f, 0.165f), rot = new Vector3(79.28571f, 0f, 0f), scale = 0.9f }, new HatOffset { key = "Hat_FrostTroll", pos = new Vector3(0.01881f, -0.17286f, 0.1f), rot = new Vector3(-72.85714f, 0f, 0f), scale = 0.95f }, new HatOffset { key = "Hat_Writhan", pos = new Vector3(0.015f, 0.04f, 0.04f), rot = new Vector3(17.14286f, 87.85714f, 90f), scale = 1f }, new HatOffset { key = "Hat_Barka", pos = new Vector3(0f, 0.07f, -0.05381f), rot = new Vector3(0f, 0f, 0f), scale = 0.95f }, new HatOffset { key = "Hat_Deer", pos = new Vector3(0.015f, -0.01f, -0.09952f), rot = new Vector3(-90f, 0f, 180f), scale = 1.61667f }, new HatOffset { key = "Hat_DeerWhite", pos = new Vector3(0.015f, -0.015f, -0.105f), rot = new Vector3(-90f, 0f, 180f), scale = 1.66667f }, new HatOffset { key = "Hat_CharredMage", pos = new Vector3(0f, -0.00262f, -0.06524f), rot = new Vector3(-12.57142f, 0f, 0f), scale = 0.95f }, new HatOffset { key = "Hat_TheElder", pos = new Vector3(-0.005f, 0.05714f, -0.025f), rot = new Vector3(10f, 0f, 0f), scale = 1.1f }, new HatOffset { key = "Hat_Skeleton", pos = new Vector3(0f, 0.01f, -0.04262f), rot = new Vector3(0f, 0f, 0f), scale = 0.71667f }, new HatOffset { key = "Hat_Blob_Frost", pos = new Vector3(0f, 0f, -0.02f), rot = new Vector3(-30f, 0f, 0f), scale = 0.7f }, new HatOffset { key = "Hat_Wolf", pos = new Vector3(0.02f, -0.04f, -0.03f), rot = new Vector3(0f, 0f, 0f), scale = 0.6f }, new HatOffset { key = "Hat_Ghost", pos = new Vector3(0f, -0.15167f, 0.05143f), rot = new Vector3(95f, 0f, 180f), scale = 1f }, new HatOffset { key = "Hat_Blob_Morkhalla", pos = new Vector3(0f, 0.09f, -0.03f), rot = new Vector3(-112f, 0f, 0f), scale = 0.45f }, new HatOffset { key = "Hat_Blob", pos = new Vector3(-0.0119f, 0.015f, -0.01667f), rot = new Vector3(-19f, -3f, 0f), scale = 0.68333f }, new HatOffset { key = "Hat_BjornUndead", pos = new Vector3(0f, 0.19429f, -0.11071f), rot = new Vector3(-16f, 0f, 0f), scale = 0.86667f }, new HatOffset { key = "Hat_BonemawSerpent", pos = new Vector3(0f, -0.16f, -0.08167f), rot = new Vector3(-63.28571f, 0f, 0f), scale = 1.1f }, new HatOffset { key = "Hat_CharredArcher", pos = new Vector3(0f, 0.17357f, -0.015f), rot = new Vector3(40.71429f, 0f, 180f), scale = 1.05f }, new HatOffset { key = "Hat_Bonemass", pos = new Vector3(0.025f, 0.22048f, -0.10333f), rot = new Vector3(-13f, -7f, 0f), scale = 1.05f }, new HatOffset { key = "Hat_DraugrFem", pos = new Vector3(0f, 0f, -0.055f), rot = new Vector3(-15f, 0f, 0f), scale = 1.25f }, new HatOffset { key = "Hat_Elaking", pos = new Vector3(0f, -0.00952f, 0.16976f), rot = new Vector3(58.57142f, 0f, 0f), scale = 6.35834f }, new HatOffset { key = "Hat_DragonQueen", pos = new Vector3(0f, -0.065f, -0.08f), rot = new Vector3(-40f, 0f, 0f), scale = 1.4f }, new HatOffset { key = "Hat_Eikthyr", pos = new Vector3(0f, -0.13524f, -0.09452f), rot = new Vector3(-35f, 0f, 0f), scale = 2.4f }, new HatOffset { key = "Hat_Dvergr", pos = new Vector3(0f, -0.0119f, 0.04762f), rot = new Vector3(-81.42857f, 0f, 0f), scale = 0.55f }, new HatOffset { key = "Hat_Cultist_Hildir", pos = new Vector3(0f, -0.035f, -0.12786f), rot = new Vector3(0f, 0f, 0f), scale = 0.95f }, new HatOffset { key = "Hat_CharredMelee", pos = new Vector3(0f, 0.03071f, -0.05643f), rot = new Vector3(0f, 0f, 0f), scale = 0.73333f }, new HatOffset { key = "Hat_DraugrElite", pos = new Vector3(0f, 0.03f, -0.075f), rot = new Vector3(-5f, 0f, 0f), scale = 0.9f }, new HatOffset { key = "Hat_Serpent", pos = new Vector3(0f, 0.11762f, -0.15024f), rot = new Vector3(-6f, 0f, 0f), scale = 0.9f }, new HatOffset { key = "Hat_SGolem", pos = new Vector3(0.015f, 0.04f, -0.025f), rot = new Vector3(0f, 0f, -1f), scale = 0.8f }, new HatOffset { key = "Hat_Deathsquito", pos = new Vector3(0f, 0f, -0.02f), rot = new Vector3(0f, 0f, 0f), scale = 1.05f }, new HatOffset { key = "Hat_Draugr", pos = new Vector3(0f, 0f, -0.07143f), rot = new Vector3(0f, 0f, 0f), scale = 1.05f }, new HatOffset { key = "Hat_Boar", pos = new Vector3(0f, -0.005f, 0.01f), rot = new Vector3(-6.42857f, 0f, 0f), scale = 0.78333f }, new HatOffset { key = "Hat_Wraith", pos = new Vector3(0f, 0f, 0.025f), rot = new Vector3(-5f, 0f, 2f), scale = 1f }, new HatOffset { key = "Hat_GoblinBrute", pos = new Vector3(0f, -0.055f, -0.07143f), rot = new Vector3(-48.85714f, 0f, 0f), scale = 1.01667f }, new HatOffset { key = "Hat_Abomination", pos = new Vector3(0f, 0.08333f, -0.10714f), rot = new Vector3(6.42857f, 0f, -15f), scale = 1.5f }, new HatOffset { key = "Hat_Cultist", pos = new Vector3(0f, -0.01f, -0.14595f), rot = new Vector3(2f, 0f, 0f), scale = 1f }, new HatOffset { key = "Hat_Mole", pos = new Vector3(-0.005f, 0.20381f, 0f), rot = new Vector3(-90f, 0f, 0f), scale = 0.7f }, new HatOffset { key = "Hat_Morgen", pos = new Vector3(0f, -0.10214f, -0.10619f), rot = new Vector3(-55.71429f, 0f, 0f), scale = 0.63333f }, new HatOffset { key = "Hat_Hatchling", pos = new Vector3(0.01f, -0.015f, -0.095f), rot = new Vector3(0f, 0f, 0f), scale = 1.5f }, new HatOffset { key = "Hat_Growth", pos = new Vector3(0f, 0.035f, -0.025f), rot = new Vector3(-27.85714f, 0f, 0f), scale = 0.95f }, new HatOffset { key = "Hat_Goblin", pos = new Vector3(0f, -0.01f, -0.08f), rot = new Vector3(7f, 0f, 0f), scale = 1.05f }, new HatOffset { key = "Hat_GoblinBruteBrosShaman", pos = new Vector3(0f, -0.07143f, -0.04762f), rot = new Vector3(-68.57143f, 0f, 0f), scale = 0.9f }, new HatOffset { key = "Hat_FallenValkyrie", pos = new Vector3(0f, -0.03f, 0.02381f), rot = new Vector3(-68.57143f, 0f, 0f), scale = 0.95f }, new HatOffset { key = "Hat_Hare", pos = new Vector3(0f, -0.09024f, 0.09024f), rot = new Vector3(0f, 0f, -180f), scale = 0.2f }, new HatOffset { key = "Hat_Kvastur", pos = new Vector3(0f, 0.07143f, -0.05262f), rot = new Vector3(105f, 165f, 0f), scale = 0.71667f }, new HatOffset { key = "Hat_Moose", pos = new Vector3(0f, 0.04024f, -0.17476f), rot = new Vector3(60f, 0f, 0f), scale = 2.33333f }, new HatOffset { key = "Hat_GoblinKing", pos = new Vector3(0f, -0.015f, -0.05952f), rot = new Vector3(-49f, 0f, 0f), scale = 0.7f }, new HatOffset { key = "Hat_GoblinBruteBrosBrute", pos = new Vector3(0f, -0.11214f, -0.03095f), rot = new Vector3(-51.42857f, 0f, 0f), scale = 0.95f }, new HatOffset { key = "Hat_GoblinShaman", pos = new Vector3(0f, -0.01643f, 0f), rot = new Vector3(-70.42857f, 0f, 0f), scale = 0.9f }, new HatOffset { key = "Hat_Asksvin", pos = new Vector3(0f, 0.03f, 0.15476f), rot = new Vector3(72.85714f, 0f, 0f), scale = 0.8f }, new HatOffset { key = "Hat_Gjall", pos = new Vector3(0f, 0f, 0.15476f), rot = new Vector3(92.42857f, 0f, 0f), scale = 0.61667f }, new HatOffset { key = "Hat_Fader", pos = new Vector3(0f, -0.10714f, -0.13762f), rot = new Vector3(-10f, 0f, 180f), scale = 0.85f }, new HatOffset { key = "Hat_Seal", pos = new Vector3(-0.01f, 0.02071f, 0.12476f), rot = new Vector3(68.57143f, 0f, 0f), scale = 3f }, new HatOffset { key = "Hat_Tick", pos = new Vector3(-0.015f, -0.06071f, 0.07786f), rot = new Vector3(-84f, 180f, 0f), scale = 1.4f }, new HatOffset { key = "Hat_SkeletonPoison", pos = new Vector3(0f, 0.03f, -0.05952f), rot = new Vector3(4.28571f, 0f, 0f), scale = 0.58333f }, new HatOffset { key = "Hat_JotunWitch", pos = new Vector3(0f, -0.05381f, 0.11095f), rot = new Vector3(55.57143f, 0f, 0f), scale = 3.8f }, new HatOffset { key = "Hat_JotunWarrior", pos = new Vector3(0f, -0.0231f, 0.05952f), rot = new Vector3(51.42857f, 0f, 0f), scale = 3.57857f }, new HatOffset { key = "Hat_SeekerBrute", pos = new Vector3(0f, 0.075f, 0f), rot = new Vector3(0f, 0f, 0f), scale = 1.05f }, new HatOffset { key = "Hat_Volture", pos = new Vector3(0f, 0.08905f, -0.11905f), rot = new Vector3(90f, 0f, 0f), scale = 1.35f }, new HatOffset { key = "Hat_SeekerQueen", pos = new Vector3(0f, -0.18405f, -0.2131f), rot = new Vector3(0f, 0f, 180f), scale = 1f } }; private static readonly FieldInfo FiInstance = AccessTools.Field(typeof(VisEquipment), "m_helmetItemInstance"); private static readonly FieldInfo FiHash = AccessTools.Field(typeof(VisEquipment), "m_currentHelmetItemHash"); private readonly Dictionary<string, HatOffset> _offsets = new Dictionary<string, HatOffset>(); private string _savePath; private GameObject _lastInstance; private Vector3 _baselinePos; private Quaternion _baselineRot = Quaternion.identity; private Vector3 _baselineScale = Vector3.one; private string _currentHatKey; private bool _open; private bool _editThisHat = true; private Rect _window = new Rect(24f, 24f, 370f, 0f); private const int WindowId = 1262698836; private static GUIStyle _richLabel; private void Awake() { _savePath = Path.Combine(Paths.ConfigPath, "KinCatalysts_HatOffsets.cfg"); Debug.Log((object)("[KinCatalysts] Hat offsets file: " + _savePath)); HatOffset[] builtinDefaults = BuiltinDefaults; foreach (HatOffset hatOffset in builtinDefaults) { _offsets[hatOffset.key] = Clone(hatOffset); } Load(); if (!_offsets.ContainsKey("__default__")) { _offsets["__default__"] = new HatOffset { key = "__default__" }; } } private void Update() { //IL_0032: Unknown result type (might be due to invalid IL or missing references) if (Plugin.HatEditorEnabled != null && !Plugin.HatEditorEnabled.Value) { if (_open) { SetOpen(open: false); } } else if (Plugin.HatEditorToggleKey != null && Input.GetKeyDown(Plugin.HatEditorToggleKey.Value)) { SetOpen(!_open); } } private void SetOpen(bool open) { _open = open; try { GUIManager.BlockInput(open); } catch { } if (!open) { Save(); } } private static VisEquipment GetLocalVisEquipment() { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null)) { return ((Component)localPlayer).GetComponentInChildren<VisEquipment>(); } return null; } private void LateUpdate() { //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010e: 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_0124: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) VisEquipment localVisEquipment = GetLocalVisEquipment(); if ((Object)(object)localVisEquipment == (Object)null || FiInstance == null || FiHash == null) { _lastInstance = null; _currentHatKey = null; return; } object? value = FiInstance.GetValue(localVisEquipment); GameObject val = (GameObject)((value is GameObject) ? value : null); int key = (int)FiHash.GetValue(localVisEquipment); string value2; string text = (Plugin.HelmetHashToHatName.TryGetValue(key, out value2) ? value2 : null); if ((Object)(object)val == (Object)null || text == null) { _lastInstance = null; _currentHatKey = null; return; } _currentHatKey = text; if ((Object)(object)val != (Object)(object)_lastInstance) { _baselinePos = val.transform.localPosition; _baselineRot = val.transform.localRotation; _baselineScale = val.transform.localScale; _lastInstance = val; } HatOffset hatOffset = Resolve(text); float num = ((hatOffset.scale <= 0.0001f) ? 1f : hatOffset.scale); val.transform.localPosition = _baselinePos + hatOffset.pos; val.transform.localRotation = _baselineRot * Quaternion.Euler(hatOffset.rot); val.transform.localScale = _baselineScale * num; } private static HatOffset Clone(HatOffset o) { //IL_0013: 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_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) return new HatOffset { key = o.key, pos = o.pos, rot = o.rot, scale = o.scale }; } private static HatOffset FindBuiltin(string key) { HatOffset[] builtinDefaults = BuiltinDefaults; foreach (HatOffset hatOffset in builtinDefaults) { if (hatOffset.key == key) { return hatOffset; } } return null; } private HatOffset Resolve(string key) { if (key != null && _offsets.TryGetValue(key, out var value)) { return value; } return _offsets["__default__"]; } private HatOffset GetOrCreate(string key) { if (!_offsets.TryGetValue(key, out var value)) { value = new HatOffset { key = key }; _offsets[key] = value; } return value; } private void OnGUI() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) if (_open) { _window = GUILayout.Window(1262698836, _window, new WindowFunction(DrawWindow), "Kin Catalysts — Hat Editor", Array.Empty<GUILayoutOption>()); } } private void DrawWindow(int id) { //IL_0308: 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_036b: Unknown result type (might be due to invalid IL or missing references) //IL_0370: Unknown result type (might be due to invalid IL or missing references) //IL_0378: Unknown result type (might be due to invalid IL or missing references) //IL_037d: 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_0320: 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_043c: Unknown result type (might be due to invalid IL or missing references) //IL_0325: Unknown result type (might be due to invalid IL or missing references) GUILayout.Label((_currentHatKey != null) ? ("Worn hat: <b>" + _currentHatKey + "</b>") : "<i>No mod hat worn — editing Default.</i>", RichLabel(), Array.Empty<GUILayoutOption>()); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); bool flag = (GUI.enabled = _currentHatKey != null); if (GUILayout.Toggle(_editThisHat && flag, " This hat", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(110f) }) && flag) { _editThisHat = true; } GUI.enabled = true; if (GUILayout.Toggle(!(_editThisHat && flag), " Default (all hats)", Array.Empty<GUILayoutOption>())) { _editThisHat = false; } GUILayout.EndHorizontal(); string text = ((_editThisHat && _currentHatKey != null) ? _currentHatKey : "__default__"); bool flag3 = text != "__default__"; HatOffset orCreate = GetOrCreate(text); GUILayout.Space(4f); GUILayout.Label("<b>Editing:</b> " + (flag3 ? text : "Default"), RichLabel(), Array.Empty<GUILayoutOption>()); if (flag3 && _offsets.ContainsKey("__default__")) { GUILayout.Label("<size=10>This hat ignores the Default offset.</size>", RichLabel(), Array.Empty<GUILayoutOption>()); } GUILayout.Space(6f); GUILayout.Label("<b>Position (m)</b>", RichLabel(), Array.Empty<GUILayoutOption>()); orCreate.pos.x = Row("X", orCreate.pos.x, -1f, 1f, 0.005f); orCreate.pos.y = Row("Y", orCreate.pos.y, -1f, 1f, 0.005f); orCreate.pos.z = Row("Z", orCreate.pos.z, -1f, 1f, 0.005f); GUILayout.Space(6f); GUILayout.Label("<b>Rotation (deg)</b>", RichLabel(), Array.Empty<GUILayoutOption>()); orCreate.rot.x = Row("X", orCreate.rot.x, -180f, 180f, 1f); orCreate.rot.y = Row("Y", orCreate.rot.y, -180f, 180f, 1f); orCreate.rot.z = Row("Z", orCreate.rot.z, -180f, 180f, 1f); GUILayout.Space(6f); GUILayout.Label("<b>Size (×)</b>", RichLabel(), Array.Empty<GUILayoutOption>()); orCreate.scale = Row("S", orCreate.scale, 0.2f, 10f, 0.05f); GUILayout.Space(8f); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); if (GUILayout.Button("Reset", Array.Empty<GUILayoutOption>())) { HatOffset hatOffset = FindBuiltin(text); orCreate.pos = hatOffset?.pos ?? Vector3.zero; orCreate.rot = hatOffset?.rot ?? Vector3.zero; orCreate.scale = hatOffset?.scale ?? 1f; } if (flag3 && GUILayout.Button("Copy Default", Array.Empty<GUILayoutOption>())) { HatOffset hatOffset2 = _offsets["__default__"]; orCreate.pos = hatOffset2.pos; orCreate.rot = hatOffset2.rot; orCreate.scale = hatOffset2.scale; } if (flag3 && GUILayout.Button("Delete override", Array.Empty<GUILayoutOption>())) { _offsets.Remove(text); _editThisHat = false; } GUILayout.EndHorizontal(); GUILayout.Space(4f); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); if (GUILayout.Button("Save", Array.Empty<GUILayoutOption>())) { Save(); } if (GUILayout.Button("Close", Array.Empty<GUILayoutOption>())) { SetOpen(open: false); } GUILayout.EndHorizontal(); GUILayout.Label($"<size=10>Overrides saved: {CountSpecific()} • auto-saves on Close</size>", RichLabel(), Array.Empty<GUILayoutOption>()); GUI.DragWindow(new Rect(0f, 0f, 100000f, 24f)); } private int CountSpecific() { int num = 0; foreach (string key in _offsets.Keys) { if (key != "__default__") { num++; } } return num; } private static GUIStyle RichLabel() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown if (_richLabel == null) { _richLabel = new GUIStyle(GUI.skin.label) { richText = true }; } return _richLabel; } private static float Row(string label, float val, float min, float max, float step) { GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label(label, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(16f) }); if (GUILayout.Button("−", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(26f) })) { val -= step; } val = GUILayout.HorizontalSlider(val, min, max, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(180f) }); if (GUILayout.Button("+", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(26f) })) { val += step; } val = Mathf.Clamp(val, min, max); GUILayout.Label(val.ToString("0.###"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(52f) }); GUILayout.EndHorizontal(); return val; } private void Load() { //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) try { if (!File.Exists(_savePath)) { return; } int num = 0; string[] array = File.ReadAllLines(_savePath); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length == 0 || text[0] == '#') { continue; } string[] array2 = text.Split(new char[1] { '|' }); if (array2.Length < 4) { continue; } string text2 = array2[0].Trim(); if (text2.Length != 0) { HatOffset hatOffset = new HatOffset { key = text2, pos = ParseVector3(array2[1]), rot = ParseVector3(array2[2]), scale = ParseFloat(array2[3], 1f) }; if (hatOffset.scale <= 0.0001f) { hatOffset.scale = 1f; } _offsets[text2] = hatOffset; num++; } } Debug.Log((object)$"[KinCatalysts] Loaded {num} hat offset(s) from {_savePath}"); } catch (Exception ex) { Debug.LogWarning((object)("[KinCatalysts] Failed to load hat offsets: " + ex.Message)); } } private void Save() { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) try { List<string> list = new List<string> { "# Kin Catalysts hat offsets", "# key | posX,posY,posZ | rotX,rotY,rotZ | scale" }; foreach (HatOffset value in _offsets.Values) { list.Add(value.key + "|" + FormatVector3(value.pos) + "|" + FormatVector3(value.rot) + "|" + value.scale.ToString("0.#####", CultureInfo.InvariantCulture)); } File.WriteAllLines(_savePath, list.ToArray()); Debug.Log((object)$"[KinCatalysts] Saved {_offsets.Count} hat offset(s) to {_savePath}"); } catch (Exception ex) { Debug.LogWarning((object)("[KinCatalysts] Failed to save hat offsets: " + ex.Message)); } } private static Vector3 ParseVector3(string s) { //IL_005e: Unknown result type (might be due to invalid IL or missing references) string[] array = s.Split(new char[1] { ',' }); return new Vector3((array.Length != 0) ? ParseFloat(array[0], 0f) : 0f, (array.Length > 1) ? ParseFloat(array[1], 0f) : 0f, (array.Length > 2) ? ParseFloat(array[2], 0f) : 0f); } private static float ParseFloat(string s, float fallback) { if (!float.TryParse(s.Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { return fallback; } return result; } private static string FormatVector3(Vector3 v) { return v.x.ToString("0.#####", CultureInfo.InvariantCulture) + "," + v.y.ToString("0.#####", CultureInfo.InvariantCulture) + "," + v.z.ToString("0.#####", CultureInfo.InvariantCulture); } } [HarmonyPatch(typeof(SpawnSystem), "UpdateSpawnList")] public static class SpawnSystem_UpdateSpawnList_Patch { private static readonly Dictionary<SpawnData, (float chance, int maxSpawned, float interval)> originalValues = new Dictionary<SpawnData, (float, int, float)>(); [HarmonyPrefix] public static void Prefix(SpawnSystem __instance, List<SpawnData> spawners) { if ((Object)(object)__instance == (Object)null || spawners == null) { return; } originalValues.Clear(); foreach (SpawnData spawner in spawners) { if (spawner == null || (Object)(object)spawner.m_prefab == (Object)null) { continue; } string name = ((Object)spawner.m_prefab).name; foreach (KeyValuePair<string, StatusEffect> item in Plugin.CreatureToStatusEffect) { if (!name.StartsWith(item.Key, StringComparison.OrdinalIgnoreCase)) { continue; } StatusEffect value = item.Value; if (!((Object)(object)value == (Object)null) && IsAnyPlayerBoosting(value)) { if (!originalValues.ContainsKey(spawner)) { originalValues[spawner] = (spawner.m_spawnChance, spawner.m_maxSpawned, spawner.m_spawnInterval); } spawner.m_spawnChance = Mathf.Clamp(spawner.m_spawnChance + Plugin.SpawnChanceFlatBonus.Value, 0f, 100f); spawner.m_maxSpawned = Mathf.Max(1, Mathf.RoundToInt((float)spawner.m_maxSpawned * Plugin.SpawnChanceMultiplier.Value)); float num = Mathf.Clamp(Plugin.SpawnIntervalReduction.Value, 0f, 100f); spawner.m_spawnInterval *= 1f - num / 100f; } break; } } } [HarmonyPostfix] public static void Postfix() { foreach (KeyValuePair<SpawnData, (float, int, float)> originalValue in originalValues) { if (originalValue.Key != null) { originalValue.Key.m_spawnChance = originalValue.Value.Item1; originalValue.Key.m_maxSpawned = originalValue.Value.Item2; originalValue.Key.m_spawnInterval = originalValue.Value.Item3; } } originalValues.Clear(); } private static bool IsAnyPlayerBoosting(StatusEffect requiredEffect) { foreach (Player allPlayer in Player.GetAllPlayers()) { if (!((Object)(object)allPlayer == (Object)null) && !((Character)allPlayer).IsDead()) { SEMan sEMan = ((Character)allPlayer).GetSEMan(); if (sEMan != null && sEMan.HaveStatusEffect(requiredEffect)) { return true; } } } return false; } } [HarmonyPatch(typeof(CharacterDrop), "GenerateDropList")] public static class CharacterDrop_GenerateDropList_Patch { [HarmonyPostfix] public static void Postfix(CharacterDrop __instance, ref List<KeyValuePair<GameObject, int>> __result) { //IL_007f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || __result == null || __instance.m_drops == null) { return; } string text = ((Object)((Component)__instance).gameObject).name.Replace("(Clone)", "").Trim(); foreach (KeyValuePair<string, StatusEffect> item in Plugin.CreatureToStatusEffect) { string key = item.Key; StatusEffect value = item.Value; if (!text.StartsWith(key, StringComparison.OrdinalIgnoreCase)) { continue; } if ((Object)(object)value == (Object)null || !IsAnyPlayerBoosting(((Component)__instance).transform.position, value)) { break; } float value2 = Plugin.TrophyDropMultiplier.Value; float value3 = Plugin.TrophyDropFlatBonus.Value; List<KeyValuePair<GameObject, int>> list = new List<KeyValuePair<GameObject, int>>(); bool flag = false; for (int i = 0; i < __result.Count; i++) { KeyValuePair<GameObject, int> keyValuePair = __result[i]; if (!((Object)(object)keyValuePair.Key != (Object)null) || !((Object)keyValuePair.Key).name.StartsWith("Trophy", StringComparison.OrdinalIgnoreCase)) { continue; } flag = true; if (value2 > 1f) { int num = Mathf.RoundToInt((float)keyValuePair.Value * (value2 - 1f)); if (num > 0) { list.Add(new KeyValuePair<GameObject, int>(keyValuePair.Key, num)); } } } if (!flag && value3 > 0f && Random.Range(0f, 100f) <= value3) { foreach (Drop drop in __instance.m_drops) { if ((Object)(object)drop.m_prefab != (Object)null && ((Object)drop.m_prefab).name.StartsWith("Trophy", StringComparison.OrdinalIgnoreCase)) { list.Add(new KeyValuePair<GameObject, int>(drop.m_prefab, 1)); break; } } } if (list.Count > 0) { __result.AddRange(list); } break; } } private static bool IsAnyPlayerBoosting(Vector3 killPosition, StatusEffect requiredEffect) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) float value = Plugin.AttractionRadius.Value; foreach (Player allPlayer in Player.GetAllPlayers()) { if (!((Object)(object)allPlayer == (Object)null) && !((Character)allPlayer).IsDead() && (!(value > 0f) || !(Vector3.Distance(((Component)allPlayer).transform.position, killPosition) > value))) { SEMan sEMan = ((Character)allPlayer).GetSEMan(); if (sEMan != null && sEMan.HaveStatusEffect(requiredEffect)) { return true; } } } return false; } } [BepInPlugin("com.teamjacob.kincatalysts", "Kin Catalysts", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { private readonly Harmony harmony = new Harmony("com.teamjacob.kincatalysts"); public static ConfigFile CustomConfig; public static ConfigEntry<float> SpawnChanceMultiplier; public static ConfigEntry<float> SpawnChanceFlatBonus; public static ConfigEntry<float> SpawnIntervalReduction; public static ConfigEntry<float> TrophyDropMultiplier; public static ConfigEntry<float> TrophyDropFlatBonus; public static ConfigEntry<float> AttractionRadius; public static ConfigEntry<bool> HatEditorEnabled; public static ConfigEntry<KeyCode> HatEditorToggleKey; public static Dictionary<string, StatusEffect> CreatureToStatusEffect = new Dictionary<string, StatusEffect>(StringComparer.OrdinalIgnoreCase); public static Dictionary<int, string> HelmetHashToHatName = new Dictionary<int, string>(); private static Vector3 boarReferenceSize = Vector3.zero; private void Awake() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown CustomConfig = new ConfigFile(Path.Combine(Paths.ConfigPath, "KinCatalysts.cfg"), true); SpawnChanceMultiplier = CustomConfig.Bind<float>("General", "SpawnMultiplier", 2f, "Multiplier applied to the maximum number of creatures that can spawn when wearing the matching trophy hat."); SpawnChanceFlatBonus = CustomConfig.Bind<float>("General", "SpawnChanceFlatBonus", 0f, "Flat percentage bonus added to spawn chance (e.g. 25 = +25% chance, capped at 100%). Set to 0 to disable."); SpawnIntervalReduction = CustomConfig.Bind<float>("General", "SpawnIntervalReduction", 0f, "Percentage the countdown between creature spawns is reduced by when wearing the matching trophy hat (e.g. 25 = spawns come 25% sooner). Set to 0 to disable."); TrophyDropMultiplier = CustomConfig.Bind<float>("General", "TrophyDropMultiplier", 2f, "Multiplier applied to trophy drop quantities when wearing the matching trophy hat."); TrophyDropFlatBonus = CustomConfig.Bind<float>("General", "TrophyDropFlatBonus", 0f, "Flat percentage bonus chance to drop a trophy on kill (e.g. 25 = +25% chance). Set to 0 to disable."); AttractionRadius = CustomConfig.Bind<float>("General", "AttractionRadius", 100f, "Distance in meters around the player where spawn rates and drop boosts are active."); HatEditorEnabled = CustomConfig.Bind<bool>("HatEditor", "Enabled", true, "Enables the in-game hat position/rotation/size editor. When disabled, the hotkey does nothing (hats are still placed with their saved offsets)."); HatEditorToggleKey = CustomConfig.Bind<KeyCode>("HatEditor", "ToggleKey", (KeyCode)287, "Key that opens/closes the in-game hat editor."); PrefabManager.OnPrefabsRegistered += GenerateDynamicTrophyHats; ((Component)this).gameObject.AddComponent<HatAdjustGui>(); harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Kin Catalysts Mod initialized!"); } private void GenerateDynamicTrophyHats() { //IL_002c: 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) PrefabManager.OnPrefabsRegistered -= GenerateDynamicTrophyHats; GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("TrophyBoar"); if ((Object)(object)itemPrefab != (Object)null) { boarReferenceSize = GetPrefabBoundsSize(itemPrefab); } foreach (GameObject item in ObjectDB.instance.m_items) { ItemDrop component = item.GetComponent<ItemDrop>(); if (!((Object)(object)component == (Object)null) && component.m_itemData != null) { string name = ((Object)item).name; if (name.StartsWith("Trophy", StringComparison.OrdinalIgnoreCase) && name.Length > 6) { string creaturePrefabName = name.Substring(6); RegisterAttractorHat(name, creaturePrefabName, component); } } } } private string FormatDisplayName(string rawName) { if (string.IsNullOrEmpty(rawName)) { return rawName; } return Regex.Replace(rawName.Replace('_', ' '), "([a-z])([A-Z])", "$1 $2").Trim(); } private void RegisterAttractorHat(string trophyPrefabName, string creaturePrefabName, ItemDrop trophyItem) { //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Expected O, but got Unknown //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_0226: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_0258: Unknown result type (might be due to invalid IL or missing references) //IL_0261: Expected O, but got Unknown //IL_0267: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Expected O, but got Unknown //IL_027b: Unknown result type (might be due to invalid IL or missing references) //IL_0285: Expected O, but got Unknown //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Expected O, but got Unknown //IL_02a3: Unknown result type (might be due to invalid IL or missing references) //IL_02d7: Unknown result type (might be due to invalid IL or missing references) //IL_02dc: Unknown result type (might be due to invalid IL or missing references) //IL_0305: Unknown result type (might be due to invalid IL or missing references) //IL_030a: Unknown result type (might be due to invalid IL or missing references) //IL_0359: Unknown result type (might be due to invalid IL or missing references) //IL_0363: Unknown result type (might be due to invalid IL or missing references) //IL_036d: Unknown result type (might be due to invalid IL or missing references) //IL_03f5: Unknown result type (might be due to invalid IL or missing references) //IL_03fc: Unknown result type (might be due to invalid IL or missing references) //IL_03d5: Unknown result type (might be due to invalid IL or missing references) //IL_03dc: Unknown result type (might be due to invalid IL or missing references) string text = "Hat_" + creaturePrefabName; string name = "SE_Attract_" + creaturePrefabName; string text2 = FormatDisplayName(creaturePrefabName); string text3 = $"{SpawnChanceMultiplier.Value:0.#}x"; string text4 = $"+{SpawnChanceFlatBonus.Value:0.#}%"; string text5 = $"-{SpawnIntervalReduction.Value:0.#}%"; string text6 = ""; text6 = ((TrophyDropMultiplier.Value > 1f && TrophyDropFlatBonus.Value > 0f) ? $"{TrophyDropMultiplier.Value:0.#}x + {TrophyDropFlatBonus.Value:0.#}%" : ((!(TrophyDropFlatBonus.Value > 0f)) ? $"{TrophyDropMultiplier.Value:0.#}x" : $"+{TrophyDropFlatBonus.Value:0.#}%")); string tooltip = "• " + text2 + " Spawn Count: <color=yellow>" + text3 + "</color>\n• " + text2 + " Spawn Chance: <color=yellow>" + text4 + "</color>\n• " + text2 + " Spawn Timer: <color=yellow>" + text5 + "</color>\n• " + text2 + " Trophy Drops: <color=yellow>" + text6 + "</color>\n\n"; StatusEffect val = ScriptableObject.CreateInstance<StatusEffect>(); ((Object)val).name = name; val.m_name = text2 + " Magnet"; val.m_tooltip = tooltip; val.m_icon = ((trophyItem.m_itemData.m_shared.m_icons.Length != 0) ? trophyItem.m_itemData.m_shared.m_icons[0] : null); ItemManager.Instance.AddStatusEffect(new CustomStatusEffect(val, true)); StatusEffect val2 = ObjectDB.instance.GetStatusEffect(val.NameHash()) ?? val; CreatureToStatusEffect[creaturePrefabName] = val2; ItemConfig val3 = new ItemConfig { Name = text2 + " Mask", Description = "<color=grey><i>\"When you wear this, you can hear the cries of fallen " + text2 + " kin...\"</i></color>", CraftingStation = CraftingStations.Workbench, MinStationLevel = 1 }; val3.AddRequirement(new RequirementConfig(trophyPrefabName, 1, 0, true)); val3.AddRequirement(new RequirementConfig("LeatherScraps", 5, 0, true)); CustomItem val4 = new CustomItem(text, trophyPrefabName, val3); SharedData shared = val4.ItemDrop.m_itemData.m_shared; shared.m_itemType = (ItemType)6; shared.m_equipStatusEffect = val2; shared.m_armor = 1f; shared.m_armorPerLevel = 0.5f; shared.m_maxStackSize = 1; shared.m_weight = 5f; if (boarReferenceSize != Vector3.zero && (Object)(object)val4.ItemPrefab != (Object)null) { Vector3 prefabBoundsSize = GetPrefabBoundsSize(val4.ItemPrefab); if (((Vector3)(ref prefabBoundsSize)).magnitude > 0.001f) { float num = Mathf.Max(new float[3] { boarReferenceSize.x, boarReferenceSize.y, boarReferenceSize.z }); float num2 = Mathf.Max(new float[3] { prefabBoundsSize.x, prefabBoundsSize.y, prefabBoundsSize.z }); float num3 = num / num2; num3 = Mathf.Clamp(num3, 0.2f, 1.5f); Transform val5 = val4.ItemPrefab.transform.Find("attach") ?? val4.ItemPrefab.transform.Find("attach_skin"); if ((Object)(object)val5 != (Object)null) { val5.localScale *= num3; } else { Transform transform = val4.ItemPrefab.transform; transform.localScale *= num3; } } } HelmetHashToHatName[StringExtensionMethods.GetStableHashCode(text)] = text; ItemManager.Instance.AddItem(val4); } private Vector3 GetPrefabBoundsSize(GameObject prefab) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: 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_0023: 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) Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(); if (componentsInChildren.Length == 0) { return Vector3.one; } Bounds bounds = componentsInChildren[0].bounds; for (int i = 1; i < componentsInChildren.Length; i++) { ((Bounds)(ref bounds)).Encapsulate(componentsInChildren[i].bounds); } return ((Bounds)(ref bounds)).size; } }