using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Jotunn; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("0.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace Armory { [BepInPlugin("GBahns.Armory", "Armory", "1.0.0")] [BepInProcess("valheim.exe")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class ArmoryMod : BaseUnityPlugin { public const string ModGuid = "GBahns.Armory"; private readonly Harmony _harmony = new Harmony("GBahns.Armory"); public static ArmoryMod Instance; public static ConfigEntry ModEnabled; private bool _initialized; public static ConfigEntry PauseGameWhileOpen; public static ConfigEntry ShowSummaryText; public static ConfigEntry ShowIcons; public static ConfigEntry PanelPosX; public static ConfigEntry PanelPosY; private void Awake() { Instance = this; ModEnabled = ((BaseUnityPlugin)this).Config.Bind("General", "Mod Enabled", true, "Master toggle for the entire mod. Set to false to disable the Armory Rack piece, the UI, and all Harmony patches without removing the DLL. Useful for quickly isolating mod conflicts. Requires a game restart to take effect."); PauseGameWhileOpen = ((BaseUnityPlugin)this).Config.Bind("General", "Pause Game While Armory Open", false, "Pause the game (Time.timeScale = 0) while the Armory Rack panel is open. Intended for singleplayer — in multiplayer this only pauses your local clock, which can desync you from the server."); ShowSummaryText = ((BaseUnityPlugin)this).Config.Bind("UI", "Show Summary Text", true, "Show the textual list of items below each loadout's name (Helm:..., Chest:..., etc)."); ShowIcons = ((BaseUnityPlugin)this).Config.Bind("UI", "Show Icons", true, "Show the row of item icons at the bottom of each loadout row."); PanelPosX = ((BaseUnityPlugin)this).Config.Bind("Window", "Panel Position X", 380f, "Saved horizontal panel position (auto-updated when you close the rack)."); PanelPosY = ((BaseUnityPlugin)this).Config.Bind("Window", "Panel Position Y", 0f, "Saved vertical panel position (auto-updated when you close the rack)."); if (!ModEnabled.Value) { Logger.LogInfo((object)"[Armory] Mod Enabled = false in config — skipping piece registration and Harmony patches."); return; } _initialized = true; _harmony.PatchAll(); CustomLocalization localization = LocalizationManager.Instance.GetLocalization(); string text = "English"; localization.AddTranslation(ref text, new Dictionary { ["armory_rack_name"] = "Armory Rack", ["armory_rack_desc"] = "A masterwork rack for storing and instantly recalling named equipment sets." }); PrefabManager.OnVanillaPrefabsAvailable += ArmoryPieces.CreatePiece; PieceManager.OnPiecesRegistered += ArmoryPieces.ConfigureAndRegister; } private void Update() { if (_initialized) { ArmoryUI.Tick(); } } private void OnDestroy() { if (_initialized) { _harmony.UnpatchSelf(); } } } [HarmonyPatch(typeof(Player), "TakeInput")] internal static class Player_TakeInput_Patch { private static bool Prefix() { return !ArmoryUI.IsOpen; } } [HarmonyPatch(typeof(Player), "SetMouseLook")] internal static class Player_SetMouseLook_Patch { private static bool Prefix() { return !ArmoryUI.IsOpen; } } [HarmonyPatch(typeof(Chat), "HasFocus")] internal static class Chat_HasFocus_Patch { private static void Postfix(ref bool __result) { if (ArmoryUI.IsEditing) { __result = true; } } } internal static class ArmoryPieces { private const string PieceName = "armory_rack"; private const string BasePrefab = "piece_chest_blackmetal"; private const string PieceTable = "_HammerPieceTable"; private const string Category = "Furniture"; private static GameObject _clone; private static bool _clonesCreated; private static bool _piecesConfigured; private static readonly FieldInfo _namedPrefabsField = AccessTools.Field(typeof(ZNetScene), "m_namedPrefabs"); private static Dictionary GetNamedPrefabs() { if (!((Object)(object)ZNetScene.instance != (Object)null)) { return null; } return _namedPrefabsField?.GetValue(ZNetScene.instance) as Dictionary; } internal static void CreatePiece() { if (_clonesCreated) { return; } _clonesCreated = true; GameObject prefab = PrefabManager.Instance.GetPrefab("piece_chest_blackmetal"); if ((Object)(object)prefab == (Object)null) { Logger.LogError((object)"[Armory] Base prefab 'piece_chest_wood' not found."); return; } _clone = PrefabManager.Instance.CreateClonedPrefab("armory_rack", prefab); Dictionary namedPrefabs = GetNamedPrefabs(); if (namedPrefabs != null) { namedPrefabs[StringExtensionMethods.GetStableHashCode(((Object)_clone).name)] = _clone; } Container component = _clone.GetComponent(); if ((Object)(object)component != (Object)null) { Object.DestroyImmediate((Object)(object)component); } _clone.AddComponent(); BuildArmoireMesh(_clone); Piece obj = _clone.GetComponent() ?? _clone.AddComponent(); obj.m_name = "$armory_rack_name"; obj.m_description = "$armory_rack_desc"; obj.m_groundOnly = false; obj.m_groundPiece = false; obj.m_resources = (Requirement[])(object)new Requirement[0]; Logger.LogInfo((object)"[Armory] Phase 1 — cloned armory_rack"); } private static void BuildArmoireMesh(GameObject parent) { //IL_0117: 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_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0233: 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_0284: Unknown result type (might be due to invalid IL or missing references) //IL_02aa: Unknown result type (might be due to invalid IL or missing references) //IL_02c3: Unknown result type (might be due to invalid IL or missing references) //IL_02e2: Unknown result type (might be due to invalid IL or missing references) //IL_032b: Unknown result type (might be due to invalid IL or missing references) //IL_0350: Unknown result type (might be due to invalid IL or missing references) Renderer[] componentsInChildren = parent.GetComponentsInChildren(); Renderer[] array = componentsInChildren; for (int i = 0; i < array.Length; i++) { array[i].enabled = false; } GameObject prefab = PrefabManager.Instance.GetPrefab("wood_floor_1x1"); if ((Object)(object)prefab == (Object)null) { Logger.LogWarning((object)"[Armory] wood_floor_1x1 unavailable — reverting to chest visual."); array = componentsInChildren; for (int i = 0; i < array.Length; i++) { array[i].enabled = true; } return; } GameObject val = null; string text = null; string[] array2 = new string[4] { "wood_shutter", "wood_shutter_closed", "wood_window_shutter", "wood_window" }; foreach (string text2 in array2) { val = PrefabManager.Instance.GetPrefab(text2); if ((Object)(object)val != (Object)null) { text = text2; break; } } if ((Object)(object)val == (Object)null) { val = prefab; text = "wood_floor_1x1 (shutter unavailable)"; } Logger.LogInfo((object)("[Armory] BuildArmoireMesh: door prefab = '" + text + "'.")); for (int j = 0; j < 2; j++) { for (int k = 0; k < 3; k++) { AddPanel(parent, prefab, new Vector3(-0.5f + (float)j, 0.5f + (float)k, -0.5f), Quaternion.Euler(-90f, 0f, 0f)); } } for (int l = 0; l < 3; l++) { AddPanel(parent, prefab, new Vector3(-1f, 0.5f + (float)l, 0f), Quaternion.Euler(0f, 0f, -90f)); } for (int m = 0; m < 3; m++) { AddPanel(parent, prefab, new Vector3(1f, 0.5f + (float)m, 0f), Quaternion.Euler(0f, 0f, 90f)); } for (int n = 0; n < 2; n++) { AddPanel(parent, prefab, new Vector3(-0.5f + (float)n, 3f, 0f), Quaternion.identity); } for (int num = 0; num < 2; num++) { AddPanel(parent, prefab, new Vector3(-0.5f + (float)num, 0f, 0f), Quaternion.Euler(180f, 0f, 0f)); } BuildDoor(parent, val, "ArmoryDoorLeft", new Vector3(-1f, 0f, 0.5f), 0f, flipped: true); BuildDoor(parent, val, "ArmoryDoorRight", new Vector3(1f, 0f, 0.5f), 0f, flipped: false); BoxCollider obj = parent.AddComponent(); obj.center = new Vector3(0f, 1.5f, 0f); obj.size = new Vector3(2f, 3f, 1f); ApplyTint(parent.transform, new Color(0.5f, 0.5f, 0.5f)); Transform val2 = parent.transform.Find("ArmoryDoorLeft"); Transform val3 = parent.transform.Find("ArmoryDoorRight"); if ((Object)(object)val2 != (Object)null) { ApplyTint(val2, new Color(0.75f, 0.75f, 0.75f)); } if ((Object)(object)val3 != (Object)null) { ApplyTint(val3, new Color(0.75f, 0.75f, 0.75f)); } Logger.LogInfo((object)"[Armory] BuildArmoireMesh: composed 16 wood panels + 2 doors (panels 50%, shutters 75%)."); } private static void ApplyTint(Transform root, Color tint) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) Renderer[] componentsInChildren = ((Component)root).GetComponentsInChildren(); foreach (Renderer val in componentsInChildren) { if (!val.enabled) { continue; } Material[] materials = val.materials; foreach (Material val2 in materials) { if (val2.HasProperty("_Color")) { val2.color = tint; } } } } private static void BuildDoor(GameObject parent, GameObject panelSrc, string hingeName, Vector3 hingeLocalPos, float panelOffsetX, bool flipped) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(hingeName); val.transform.SetParent(parent.transform, false); val.transform.localPosition = hingeLocalPos; val.transform.localRotation = Quaternion.identity; Vector3 localScale = (Vector3)(flipped ? new Vector3(-1f, 1f, 1f) : Vector3.one); for (int i = 0; i < 3; i++) { GameObject obj = Object.Instantiate(panelSrc, val.transform); obj.transform.localPosition = new Vector3(panelOffsetX, 0.5f + (float)i, 0f); obj.transform.localRotation = Quaternion.identity; obj.transform.localScale = localScale; ((Object)obj).name = ((Object)panelSrc).name + "_panel"; StripChildComponents(obj); } } private static void StripChildComponents(GameObject visual) { Door[] componentsInChildren = visual.GetComponentsInChildren(); for (int i = 0; i < componentsInChildren.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren[i]); } Piece[] componentsInChildren2 = visual.GetComponentsInChildren(); for (int i = 0; i < componentsInChildren2.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren2[i]); } WearNTear[] componentsInChildren3 = visual.GetComponentsInChildren(); for (int i = 0; i < componentsInChildren3.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren3[i]); } ZNetView[] componentsInChildren4 = visual.GetComponentsInChildren(); for (int i = 0; i < componentsInChildren4.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren4[i]); } ZSyncTransform[] componentsInChildren5 = visual.GetComponentsInChildren(); for (int i = 0; i < componentsInChildren5.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren5[i]); } Collider[] componentsInChildren6 = visual.GetComponentsInChildren(); for (int i = 0; i < componentsInChildren6.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren6[i]); } SnapToGround[] componentsInChildren7 = visual.GetComponentsInChildren(); for (int i = 0; i < componentsInChildren7.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren7[i]); } } private static void AddPanel(GameObject parent, GameObject source, Vector3 localPos, Quaternion localRot) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) GameObject obj = Object.Instantiate(source, parent.transform); obj.transform.localPosition = localPos; obj.transform.localRotation = localRot; ((Object)obj).name = ((Object)source).name + "_panel"; StripChildComponents(obj); } internal static void ConfigureAndRegister() { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Expected O, but got Unknown //IL_0264: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Expected O, but got Unknown if (_piecesConfigured) { return; } _piecesConfigured = true; if ((Object)(object)_clone == (Object)null) { Logger.LogError((object)"[Armory] Phase 2: no clone from Phase 1 — Armory Rack unavailable."); return; } Piece component = _clone.GetComponent(); if ((Object)(object)component == (Object)null) { return; } GameObject prefab = PrefabManager.Instance.GetPrefab("piece_chest_blackmetal"); WearNTear val = ((prefab != null) ? prefab.GetComponent() : null); WearNTear val2 = _clone.GetComponent() ?? _clone.AddComponent(); val2.m_health = 500f; val2.m_materialType = (MaterialType)0; if ((Object)(object)val != (Object)null) { val2.m_destroyedEffect = val.m_destroyedEffect; val2.m_hitEffect = val.m_hitEffect; } List requirements = new List(); AddReq("FineWood", 8); AddReq("RoundLog", 4); AddReq("BronzeNails", 4); AddReq("Bronze", 2); AddReq("DeerHide", 2); component.m_resources = requirements.ToArray(); GameObject prefab2 = PrefabManager.Instance.GetPrefab("piece_workbench"); component.m_craftingStation = ((prefab2 != null) ? prefab2.GetComponent() : null); object obj = LoadEmbeddedIcon("armory.png"); if (obj == null) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("ArmorLeatherChest"); if (itemPrefab == null) { obj = null; } else { ItemDrop component2 = itemPrefab.GetComponent(); if (component2 == null) { obj = null; } else { ItemData itemData = component2.m_itemData; if (itemData == null) { obj = null; } else { SharedData shared = itemData.m_shared; if (shared == null) { obj = null; } else { Sprite[] icons = shared.m_icons; obj = ((icons != null) ? icons[0] : null); } } } } } component.m_icon = (Sprite)obj; GameObject prefab3 = PrefabManager.Instance.GetPrefab("piece_chest_blackmetal"); Piece val3 = ((prefab3 != null) ? prefab3.GetComponent() : null); if ((Object)(object)val3 != (Object)null) { component.m_placeEffect = val3.m_placeEffect; } if ((Object)(object)_clone.GetComponent() == (Object)null) { Container val4 = _clone.AddComponent(); GameObject prefab4 = PrefabManager.Instance.GetPrefab("piece_chest_blackmetal"); Container val5 = ((prefab4 != null) ? prefab4.GetComponent() : null); if ((Object)(object)val5 != (Object)null) { val4.m_bkg = val5.m_bkg; val4.m_destroyedLootPrefab = val5.m_destroyedLootPrefab; } val4.m_name = "$armory_rack_name"; val4.m_width = 8; val4.m_height = 4; } PieceConfig val6 = new PieceConfig { Name = "Armory Rack", PieceTable = "_HammerPieceTable", Category = "Furniture" }; PieceManager.Instance.AddPiece(new CustomPiece(_clone, false, val6)); Logger.LogInfo((object)"[Armory] Phase 2 — registered armory_rack"); EnsureInPieceTable(); EnsureInNamedPrefabs(); void AddReq(string prefabName, int amount) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown GameObject itemPrefab2 = ObjectDB.instance.GetItemPrefab(prefabName); ItemDrop val7 = ((itemPrefab2 != null) ? itemPrefab2.GetComponent() : null); if ((Object)(object)val7 != (Object)null) { requirements.Add(new Requirement { m_resItem = val7, m_amount = amount, m_recover = true }); } else { Logger.LogWarning((object)("[Armory] Recipe ingredient '" + prefabName + "' not found in ObjectDB — skipped.")); } } } private static void EnsureInPieceTable() { if (!((Object)(object)_clone == (Object)null)) { ObjectDB instance = ObjectDB.instance; object obj; if (instance == null) { obj = null; } else { GameObject itemPrefab = instance.GetItemPrefab("Hammer"); obj = ((itemPrefab == null) ? null : itemPrefab.GetComponent()?.m_itemData?.m_shared?.m_buildPieces); } PieceTable val = (PieceTable)obj; if ((Object)(object)val == (Object)null) { Logger.LogInfo((object)"[Armory] EnsureInPieceTable: Hammer not accessible yet."); return; } if (val.m_pieces.Contains(_clone)) { Logger.LogInfo((object)"[Armory] EnsureInPieceTable: armory_rack already present."); return; } val.m_pieces.Add(_clone); Logger.LogInfo((object)"[Armory] EnsureInPieceTable: inserted armory_rack."); } } private static Sprite LoadEmbeddedIcon(string fileName) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Expected O, but got Unknown //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) try { Assembly executingAssembly = Assembly.GetExecutingAssembly(); string text = Array.Find(executingAssembly.GetManifestResourceNames(), (string n) => n.EndsWith(fileName)); if (text == null) { return null; } using Stream stream = executingAssembly.GetManifestResourceStream(text); if (stream == null) { return null; } byte[] array = new byte[stream.Length]; stream.Read(array, 0, array.Length); Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); if (!UnityLoadImage(val, array)) { return null; } return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), (float)((Texture)val).width); } catch (Exception ex) { Logger.LogWarning((object)("[Armory] Failed to load embedded icon '" + fileName + "': " + ex.Message)); return null; } } private static bool UnityLoadImage(Texture2D tex, byte[] bytes) { try { MethodInfo methodInfo = Type.GetType("UnityEngine.ImageConversion, UnityEngine.ImageConversionModule")?.GetMethod("LoadImage", new Type[2] { typeof(Texture2D), typeof(byte[]) }); return methodInfo != null && (bool)methodInfo.Invoke(null, new object[2] { tex, bytes }); } catch { return false; } } private static void EnsureInNamedPrefabs() { if ((Object)(object)_clone == (Object)null) { return; } Dictionary namedPrefabs = GetNamedPrefabs(); if (namedPrefabs != null) { int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)_clone).name); if (!namedPrefabs.ContainsKey(stableHashCode)) { namedPrefabs[stableHashCode] = _clone; Logger.LogInfo((object)"[Armory] EnsureInNamedPrefabs: added armory_rack."); } } } } public class ArmoryRack : MonoBehaviour, Hoverable, Interactable { private ZNetView m_nview; private Transform _leftHinge; private Transform _rightHinge; private float _doorAngle01; private const float DoorOpenRate = 4f; private const float DoorOpenDegrees = 95f; private void Awake() { m_nview = ((Component)this).GetComponent(); if ((Object)(object)m_nview != (Object)null) { m_nview.Register("ArmoryRPC_SetData", (Action)RPC_SetData); } _leftHinge = ((Component)this).transform.Find("ArmoryDoorLeft"); _rightHinge = ((Component)this).transform.Find("ArmoryDoorRight"); } public Container GetStorage() { return ((Component)this).GetComponent(); } public Inventory GetStorageInventory() { Container storage = GetStorage(); if (storage == null) { return null; } return storage.GetInventory(); } private void Update() { //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_leftHinge == (Object)null) && !((Object)(object)_rightHinge == (Object)null)) { float num = ((ArmoryUI.IsOpen && (Object)(object)ArmoryUI.CurrentRack == (Object)(object)this) ? 1f : 0f); _doorAngle01 = Mathf.MoveTowards(_doorAngle01, num, 4f * Time.deltaTime); float num2 = _doorAngle01 * 95f; _leftHinge.localRotation = Quaternion.Euler(0f, 0f - num2, 0f); _rightHinge.localRotation = Quaternion.Euler(0f, num2, 0f); } } public string GetHoverName() { return "Armory"; } public float GetHoverOffset() { return 0f; } public string GetHoverText() { if ((Object)(object)m_nview == (Object)null || !m_nview.IsValid()) { return string.Empty; } return LocalizeText("Armory\n[$KEY_Use] Manage Loadouts\nSave and recall named equipment sets."); } private static string LocalizeText(string text) { try { Type type = AccessTools.TypeByName("Localization"); if (type == null) { return text; } object obj = AccessTools.Property(type, "instance")?.GetValue(null) ?? AccessTools.Field(type, "instance")?.GetValue(null); if (obj == null) { return text; } return (AccessTools.Method(type, "Localize", new Type[1] { typeof(string) }, (Type[])null)?.Invoke(obj, new object[1] { text }) as string) ?? text; } catch { return text; } } public bool Interact(Humanoid user, bool hold, bool alt) { if (hold || !(user is Player)) { return false; } ArmoryUI.Open(this); return true; } public bool UseItem(Humanoid user, ItemData item) { return false; } public ArmoryData GetData() { if ((Object)(object)m_nview == (Object)null || !m_nview.IsValid()) { Logger.LogWarning((object)"[Armory] GetData: ZNetView not valid, returning empty data"); return new ArmoryData(); } string text = m_nview.GetZDO().GetString("armory_data", ""); Logger.LogInfo((object)$"[Armory] GetData: read {text.Length} bytes from ZDO"); if (string.IsNullOrEmpty(text)) { return new ArmoryData(); } try { ArmoryData armoryData = ArmorySerializer.Deserialize(text); Logger.LogInfo((object)$"[Armory] GetData: parsed {armoryData.Slots.Count} slot(s)"); return armoryData; } catch (Exception ex) { Logger.LogError((object)("[Armory] GetData parse error: " + ex.Message)); return new ArmoryData(); } } public void SaveData(ArmoryData data) { if ((Object)(object)m_nview == (Object)null || !m_nview.IsValid()) { Logger.LogWarning((object)"[Armory] SaveData: ZNetView not valid, dropping save"); return; } string text = ArmorySerializer.Serialize(data); if (m_nview.IsOwner()) { m_nview.GetZDO().Set("armory_data", text); Logger.LogInfo((object)$"[Armory] SaveData: direct write ({text.Length} bytes) — isOwner=true"); } else { m_nview.InvokeRPC("ArmoryRPC_SetData", new object[1] { text }); Logger.LogInfo((object)$"[Armory] SaveData: RPC to owner ({text.Length} bytes) — isOwner=false"); } } private void RPC_SetData(long sender, string json) { if (m_nview.IsOwner()) { m_nview.GetZDO().Set("armory_data", json); Logger.LogInfo((object)$"[Armory] RPC_SetData: applied {json.Length} bytes"); } } } internal static class ArmoryUI { private class SlotRowRefs { public GameObject Root; public GameObject NameLabelGo; public Text NameLabel; public GameObject NameInputGo; public InputField NameInput; public Button LoadButton; public Text LoadButtonLabel; public Color LoadButtonDefaultColor; public Button CompareButton; public Button ClearButton; public Text Summary; public GameObject IconsContainer; } [CompilerGenerated] private static class <>O { public static UnityAction <0>__Close; public static UnityAction <1>__OnAddSlotClicked; public static UnityAction <2>__CloseConfirmModal; public static UnityAction <3>__ToggleCompareOff; } private static ArmoryRack _rack; private static ArmoryData _data; private static bool _isOpen; private static Vector2? _savedMainPos; private static Vector2? _savedComparePos; private static bool _pausedGame; private static float _previousTimeScale; private static float _lastIconRefresh; private const int DefaultSlotCount = 5; private const int MaxSlotCount = 10; private const float MaxInteractDistance = 5f; private static int _editingSlot = -1; private static int _compareSlot = -1; private static GameObject _mainPanel; private static GameObject _comparePanel; private static GameObject _confirmModal; private static RectTransform _slotsContent; private static readonly List _rows = new List(); private const string SaveIcon = "↓"; private const string LoadIcon = "↑"; private const float TitleAreaPx = 70f; private const float FooterAreaPx = 70f; private const float TopRowPx = 48f; private const float SummaryRowPx = 22f; private const float IconStripPx = 66f; private const float RowPaddingPx = 8f; private const float RowSpacingPx = 2f; private const float ScrollListPadPx = 8f; private const float ScrollListGapPx = 4f; private static bool? _lastShowSummary; private static bool? _lastShowIcons; private static RectTransform _scrollRT; private const float IconSize = 60f; private static GameObject _tooltipGo; private static Text _tooltipText; private static RectTransform _tooltipRT; public static bool IsOpen => _isOpen; public static ArmoryRack CurrentRack => _rack; public static bool IsEditing { get { if (_isOpen) { return _editingSlot >= 0; } return false; } } public static void Open(ArmoryRack rack) { if (_isOpen) { Close(); } _rack = rack; _data = rack.GetData(); LoadoutManager.EnsureSlots(_data, 5); Logger.LogInfo((object)$"[Armory] Open: rack instance {((Object)rack).GetInstanceID()}, slots loaded={_data.Slots.Count}"); for (int i = 0; i < _data.Slots.Count; i++) { Logger.LogInfo((object)$"[Armory] slot {i}: name='{_data.Slots[i].Name}' empty={_data.Slots[i].IsEmpty()}"); } _editingSlot = -1; _compareSlot = -1; _isOpen = true; BuildUI(); LoadoutManager.MigrateOutOfBoundsItems(rack.GetStorageInventory()); if ((Object)(object)InventoryGui.instance != (Object)null) { InventoryGui.instance.Show(rack.GetStorage(), 1); } bool flag = ArmoryMod.PauseGameWhileOpen != null && ArmoryMod.PauseGameWhileOpen.Value; Logger.LogInfo((object)$"[Armory] Open: PauseGameWhileOpen={flag}, currentTimeScale={Time.timeScale}"); if (flag) { _previousTimeScale = ((Time.timeScale > 0f) ? Time.timeScale : 1f); Time.timeScale = 0f; _pausedGame = true; Logger.LogInfo((object)$"[Armory] Open: paused — previousTimeScale={_previousTimeScale}, newTimeScale={Time.timeScale}"); } } public static void Close() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) _isOpen = false; _editingSlot = -1; _compareSlot = -1; if ((Object)(object)_mainPanel != (Object)null) { RectTransform component = _mainPanel.GetComponent(); if ((Object)(object)component != (Object)null) { _savedMainPos = component.anchoredPosition; if (ArmoryMod.PanelPosX != null) { ArmoryMod.PanelPosX.Value = component.anchoredPosition.x; } if (ArmoryMod.PanelPosY != null) { ArmoryMod.PanelPosY.Value = component.anchoredPosition.y; } } Object.Destroy((Object)(object)_mainPanel); _mainPanel = null; } if ((Object)(object)_tooltipGo != (Object)null) { Object.Destroy((Object)(object)_tooltipGo); _tooltipGo = null; _tooltipText = null; _tooltipRT = null; } CloseConfirmModal(); if ((Object)(object)_comparePanel != (Object)null) { RectTransform component2 = _comparePanel.GetComponent(); if ((Object)(object)component2 != (Object)null) { _savedComparePos = component2.anchoredPosition; } Object.Destroy((Object)(object)_comparePanel); _comparePanel = null; } _slotsContent = null; _rows.Clear(); _lastShowSummary = null; _lastShowIcons = null; _rack = null; if ((Object)(object)InventoryGui.instance != (Object)null) { InventoryGui.instance.Hide(); } if (_pausedGame) { Time.timeScale = ((_previousTimeScale > 0f) ? _previousTimeScale : 1f); _pausedGame = false; Logger.LogInfo((object)$"[Armory] Close: restored timeScale={Time.timeScale}"); } } public static void Tick() { //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) if (!_isOpen) { return; } if ((Object)(object)_confirmModal != (Object)null && Input.GetKeyDown((KeyCode)27)) { CloseConfirmModal(); return; } if ((Object)(object)InventoryGui.instance == (Object)null || !InventoryGui.IsVisible()) { Close(); return; } if (_editingSlot >= 0 && (Input.GetKeyDown((KeyCode)13) || Input.GetKeyDown((KeyCode)271))) { CommitPendingEdit(); return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)_rack == (Object)null) { Close(); return; } if (Vector3.Distance(((Component)localPlayer).transform.position, ((Component)_rack).transform.position) > 5f) { ((Character)localPlayer).Message((MessageType)2, "Moved too far from the Armory Rack.", 0, (Sprite)null, false); Close(); return; } bool flag = ArmoryMod.ShowSummaryText?.Value ?? true; bool flag2 = ArmoryMod.ShowIcons?.Value ?? true; if (_lastShowSummary != flag || _lastShowIcons != flag2) { _lastShowSummary = flag; _lastShowIcons = flag2; ResizeMainPanel(); } for (int i = 0; i < _rows.Count && i < _data.Slots.Count; i++) { SlotRowRefs slotRowRefs = _rows[i]; LoadoutSlot slot = _data.Slots[i]; UpdateRowEmptyState(slotRowRefs, slot); if ((Object)(object)slotRowRefs.Summary != (Object)null) { slotRowRefs.Summary.text = BuildSummary(slot); if (((Component)slotRowRefs.Summary).gameObject.activeSelf != flag) { ((Component)slotRowRefs.Summary).gameObject.SetActive(flag); } } if ((Object)(object)slotRowRefs.IconsContainer != (Object)null && slotRowRefs.IconsContainer.activeSelf != flag2) { slotRowRefs.IconsContainer.SetActive(flag2); } } if (flag2 && Time.unscaledTime - _lastIconRefresh > 0.5f) { _lastIconRefresh = Time.unscaledTime; for (int j = 0; j < _rows.Count && j < _data.Slots.Count; j++) { RebuildIcons(_rows[j], _data.Slots[j]); } } if (_pausedGame && Time.timeScale != 0f) { Time.timeScale = 0f; } } private static void BuildUI() { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) if (GUIManager.Instance != null && !((Object)(object)GUIManager.CustomGUIFront == (Object)null)) { Transform transform = GUIManager.CustomGUIFront.transform; Vector2 val = (Vector2)(((??)_savedMainPos) ?? new Vector2(ArmoryMod.PanelPosX?.Value ?? 380f, ArmoryMod.PanelPosY?.Value ?? 0f)); _mainPanel = GUIManager.Instance.CreateWoodpanel(transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), val, 760f, ComputePanelHeight(), true); BuildMainPanel(_mainPanel.transform); } } private static void BuildMainPanel(Transform panel) { //IL_0015: 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) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0126: 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_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Expected O, but got Unknown //IL_02e9: Unknown result type (might be due to invalid IL or missing references) //IL_02f3: Expected O, but got Unknown //IL_0348: Unknown result type (might be due to invalid IL or missing references) //IL_0357: Unknown result type (might be due to invalid IL or missing references) //IL_0366: Unknown result type (might be due to invalid IL or missing references) //IL_0394: Unknown result type (might be due to invalid IL or missing references) //IL_0399: Unknown result type (might be due to invalid IL or missing references) //IL_039f: Expected O, but got Unknown GUIManager.Instance.CreateText("Armory Rack", panel, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -32f), GUIManager.Instance.AveriaSerifBold, 24, GUIManager.Instance.ValheimOrange, true, Color.black, 400f, 40f, false); ButtonClickedEvent onClick = GUIManager.Instance.CreateButton("x", panel, new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(-32f, -32f), 36f, 36f).GetComponent