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 GearHeim v1.0.0
plugins/GearHeim.dll
Decompiled 4 days agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("assembly_valheim")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("GearHeim")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("GearHeim")] [assembly: AssemblyTitle("GearHeim")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [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 GearHeim { public enum RangeMode { Workbench, Distance } internal class BaseArea { private const string WorkbenchName = "$piece_workbench"; private readonly Vector3 _origin; private readonly float _distance; private readonly List<CraftingStation> _workbenches; public bool IsValid { get { if (_workbenches != null) { return _workbenches.Count > 0; } return true; } } private BaseArea(Vector3 origin, float distance, List<CraftingStation> workbenches) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) _origin = origin; _distance = distance; _workbenches = workbenches; } public static BaseArea For(Vector3 position) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) if (GearHeimPlugin.Mode.Value == RangeMode.Distance) { return new BaseArea(position, GearHeimPlugin.Range.Value, null); } return new BaseArea(position, 0f, ConnectedWorkbenches(position)); } public bool Contains(Vector3 point) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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) if (_workbenches == null) { return Vector3.Distance(_origin, point) <= _distance; } return _workbenches.Any((CraftingStation w) => (Object)(object)w != (Object)null && Vector3.Distance(((Component)w).transform.position, point) <= w.GetStationBuildRange()); } public float DistanceFrom(Vector3 point) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) return Vector3.Distance(_origin, point); } public string Describe() { if (_workbenches != null) { return "in this base"; } return $"within {GearHeimPlugin.Range.Value:0} m"; } private static List<CraftingStation> ConnectedWorkbenches(Vector3 position) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) List<CraftingStation> list = CraftingStation.m_allStations.Where((CraftingStation s) => (Object)(object)s != (Object)null && s.m_name == "$piece_workbench").ToList(); List<CraftingStation> list2 = list.Where((CraftingStation s) => Vector3.Distance(((Component)s).transform.position, position) <= s.GetStationBuildRange()).ToList(); Queue<CraftingStation> queue = new Queue<CraftingStation>(list2); while (queue.Count > 0) { CraftingStation val = queue.Dequeue(); foreach (CraftingStation item in list) { if (!list2.Contains(item)) { float num = val.GetStationBuildRange() + item.GetStationBuildRange(); if (Vector3.Distance(((Component)val).transform.position, ((Component)item).transform.position) <= num) { list2.Add(item); queue.Enqueue(item); } } } } return list2; } } internal static class ChestSupply { public static int Take(Player player, BaseArea area, LoadoutEntry entry, int worldLevel, int amount, out ItemData template) { template = null; if (amount <= 0) { return 0; } int num = 0; foreach (Container item in Sources(player, area)) { Inventory inventory = item.GetInventory(); if (!inventory.m_inventory.Any((ItemData i) => Matches(i, entry, worldLevel))) { continue; } if (!item.m_nview.IsOwner()) { item.m_nview.ClaimOwnership(); item.Load(); } foreach (ItemData item2 in inventory.m_inventory.ToList()) { if (Matches(item2, entry, worldLevel)) { int num2 = Mathf.Min(amount - num, item2.m_stack); if (template == null) { template = item2.Clone(); } inventory.RemoveItem(item2, num2); num += num2; if (num >= amount) { return num; } } } } return num; } private static bool Matches(ItemData item, LoadoutEntry entry, int worldLevel) { if ((Object)(object)item.m_dropPrefab != (Object)null && ((Object)item.m_dropPrefab).name == entry.Prefab && item.m_quality == entry.Quality && (worldLevel < 0 || item.m_worldLevel == worldLevel)) { return Tags.LoadoutOf(item) == null; } return false; } private static IEnumerable<Container> Sources(Player player, BaseArea area) { long playerId = player.GetPlayerID(); return from c in Object.FindObjectsByType<Container>((FindObjectsSortMode)0) where IsUsable(c, playerId) && area.Contains(((Component)c).transform.position) orderby area.DistanceFrom(((Component)c).transform.position) select c; } private static bool IsUsable(Container c, long playerId) { //IL_00aa: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)c == (Object)null || (Object)(object)c.m_nview == (Object)null || !c.m_nview.IsValid()) { return false; } if (c.GetInventory() == null) { return false; } if ((Object)(object)((Component)c).GetComponent<TombStone>() != (Object)null) { return false; } if ((Object)(object)c.m_rootObjectOverride != (Object)null) { return false; } if ((Object)(object)((Component)c).GetComponentInParent<Ship>() != (Object)null || (Object)(object)((Component)c).GetComponentInParent<Vagon>() != (Object)null) { return false; } if (c.IsInUse() || c.m_nview.GetZDO().GetInt(ZDOVars.s_inUse, 0) == 1) { return false; } if (!c.CheckAccess(playerId)) { return false; } if (c.m_checkGuardStone && !PrivateArea.CheckAccess(((Component)c).transform.position, 0f, false, false)) { return false; } return true; } } [BepInPlugin("mbaya.GearHeim", "GearHeim", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public class GearHeimPlugin : BaseUnityPlugin { public const string Guid = "mbaya.GearHeim"; public const string Name = "GearHeim"; public const string Version = "1.0.0"; public const string ChestPrefab = "piece_gearheim_loadoutchest"; private const string ChestBasePrefab = "piece_chest"; internal static ManualLogSource Log; internal static ConfigEntry<RangeMode> Mode; internal static ConfigEntry<float> Range; internal static ConfigEntry<bool> RefillFromChests; internal static ConfigEntry<KeyboardShortcut> MenuKey; internal static ConfigEntry<KeyboardShortcut>[] QuickKeys; private Harmony _harmony; private void Awake() { //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_00de: 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_012a: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Mode = ((BaseUnityPlugin)this).Config.Bind<RangeMode>("General", "RangeMode", RangeMode.Workbench, "Where GearHeim works. Workbench = inside your base: within build range of the workbench you're near (workbenches with overlapping ranges count as one base). Distance = within 'Range' meters of you."); Range = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Range", 50f, "Used when RangeMode is Distance: how far (in meters, straight line including height) Loadout Chests and restocking chests can be."); RefillFromChests = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "RefillFromChests", true, "Top up food, potions, ammo and other stackables to their saved amounts from ordinary chests in the same base."); MenuKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Hotkeys", "OpenMenu", new KeyboardShortcut((KeyCode)108, Array.Empty<KeyCode>()), "Open the loadout menu (works anywhere in a base with a Loadout Chest)."); QuickKeys = new ConfigEntry<KeyboardShortcut>[5]; for (int i = 0; i < QuickKeys.Length; i++) { QuickKeys[i] = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Hotkeys", $"SwitchToLoadout{i + 1}", new KeyboardShortcut((KeyCode)(49 + i), (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), $"Switch straight to loadout #{i + 1} as listed in the loadout menu."); } PrefabManager.OnVanillaPrefabsAvailable += AddLoadoutChest; _harmony = new Harmony("mbaya.GearHeim"); _harmony.PatchAll(typeof(GearHeimPlugin).Assembly); Log.LogInfo((object)"GearHeim 1.0.0 loaded"); } private void AddLoadoutChest() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown PrefabManager.OnVanillaPrefabsAvailable -= AddLoadoutChest; PieceConfig val = new PieceConfig(); val.Name = "Loadout Chest"; val.Description = "Holds your gear loadouts. Switch loadouts from anywhere within range."; val.PieceTable = "Hammer"; val.Category = "Furniture"; val.Requirements = (RequirementConfig[])(object)new RequirementConfig[2] { new RequirementConfig("FineWood", 10, 0, true), new RequirementConfig("Bronze", 2, 0, true) }; CustomPiece val2 = new CustomPiece("piece_gearheim_loadoutchest", "piece_chest", val); GameObject piecePrefab = val2.PiecePrefab; if ((Object)(object)piecePrefab == (Object)null) { Log.LogError((object)"Could not clone piece_chest; Loadout Chest disabled."); return; } Container component = piecePrefab.GetComponent<Container>(); if ((Object)(object)component != (Object)null) { Object.DestroyImmediate((Object)(object)component); } piecePrefab.AddComponent<LoadoutChest>(); PieceManager.Instance.AddPiece(val2); } private void Update() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: 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_004e: Unknown result type (might be due to invalid IL or missing references) LoadoutMenu.Update(); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || LoadoutMenu.IsTyping()) { return; } KeyboardShortcut value = MenuKey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { LoadoutMenu.Toggle(); } else { if (LoadoutMenu.IsOpen) { return; } for (int i = 0; i < QuickKeys.Length; i++) { value = QuickKeys[i].Value; if (((KeyboardShortcut)(ref value)).IsDown()) { LoadoutService.SwitchToListed(localPlayer, i); break; } } } } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } public class LoadoutChest : MonoBehaviour, Hoverable, Interactable { private const string DataKey = "GearHeim.Loadouts"; private const string LockKey = "GearHeim.LockHolder"; private const string LockTimeKey = "GearHeim.LockTime"; private const string RpcRequest = "GearHeim_RequestAccess"; private const string RpcResponse = "GearHeim_AccessResponse"; private static readonly TimeSpan LockTimeout = TimeSpan.FromSeconds(15.0); private const float ResponseTimeout = 10f; internal static readonly List<LoadoutChest> All = new List<LoadoutChest>(); private ZNetView _nview; private Action _pending; private float _pendingSince; private bool _granted; private uint _grantedRevision; private bool _corrupt; internal bool IsValid { get { if ((Object)(object)_nview != (Object)null) { return _nview.IsValid(); } return false; } } internal Vector3 Position => ((Component)this).transform.position; internal bool IsCorrupt => _corrupt; private void Awake() { _nview = ((Component)this).GetComponent<ZNetView>(); if (!((Object)(object)_nview == (Object)null) && _nview.GetZDO() != null) { All.Add(this); _nview.Register<long>("GearHeim_RequestAccess", (Action<long, long>)RPC_RequestAccess); _nview.Register<bool, long>("GearHeim_AccessResponse", (Action<long, bool, long>)RPC_AccessResponse); WearNTear component = ((Component)this).GetComponent<WearNTear>(); if ((Object)(object)component != (Object)null) { component.m_onDestroyed = (Action)Delegate.Combine(component.m_onDestroyed, new Action(OnDestroyed)); } } } private void OnDestroy() { All.Remove(this); } private void Update() { if (_pending == null) { return; } if (_granted && IsValid && _nview.IsOwner() && _nview.GetZDO().DataRevision >= _grantedRevision) { RunPending(); } else if (Time.time - _pendingSince > 10f) { _pending = null; _granted = false; if ((Object)(object)Player.m_localPlayer != (Object)null) { LoadoutService.Message(Player.m_localPlayer, "The Loadout Chest didn't respond. Try again."); } } } internal void WithAccess(Action action) { if (IsValid) { if (_pending != null) { LoadoutService.Message(Player.m_localPlayer, "Still waiting on the Loadout Chest..."); return; } _pending = action; _pendingSince = Time.time; _granted = false; _nview.InvokeRPC("GearHeim_RequestAccess", new object[1] { Game.instance.GetPlayerProfile().GetPlayerID() }); } } private void RPC_RequestAccess(long sender, long playerId) { //IL_00b4: Unknown result type (might be due to invalid IL or missing references) if (_nview.IsOwner()) { ZDO zDO = _nview.GetZDO(); long num = zDO.GetLong("GearHeim.LockHolder", 0L); DateTime time = ZNet.instance.GetTime(); DateTime dateTime = new DateTime(zDO.GetLong("GearHeim.LockTime", 0L)); if (num != 0L && num != sender && time - dateTime < LockTimeout) { _nview.InvokeRPC(sender, "GearHeim_AccessResponse", new object[2] { false, 0L }); return; } zDO.Set("GearHeim.LockHolder", sender); zDO.Set("GearHeim.LockTime", time.Ticks); ZDOMan.instance.ForceSendZDO(sender, zDO.m_uid); zDO.SetOwner(sender); _nview.InvokeRPC(sender, "GearHeim_AccessResponse", new object[2] { true, (long)zDO.DataRevision }); } } private void RPC_AccessResponse(long sender, bool granted, long revision) { if (_pending == null) { return; } if (!granted || !IsValid) { _pending = null; if ((Object)(object)Player.m_localPlayer != (Object)null) { LoadoutService.Message(Player.m_localPlayer, "Someone else is using that Loadout Chest."); } } else { _granted = true; _grantedRevision = (uint)revision; Update(); } } private void RunPending() { Action pending = _pending; _pending = null; _granted = false; try { pending(); } catch (Exception arg) { GearHeimPlugin.Log.LogError((object)$"Loadout action failed: {arg}"); } finally { if (IsValid && _nview.IsOwner()) { _nview.GetZDO().Set("GearHeim.LockHolder", 0L); } LoadoutMenu.Refresh(); } } internal List<StoredLoadout> Load() { return Read(withItems: true); } internal List<StoredLoadout> Peek() { return Read(withItems: false); } private List<StoredLoadout> Read(bool withItems) { if (!IsValid) { return new List<StoredLoadout>(); } try { return LoadoutStorage.Read(_nview.GetZDO().GetByteArray("GearHeim.Loadouts", (byte[])null), withItems); } catch (Exception arg) { if (!_corrupt) { GearHeimPlugin.Log.LogError((object)$"Loadout Chest data is unreadable; leaving it untouched. {arg}"); } _corrupt = true; return new List<StoredLoadout>(); } } internal bool Save(List<StoredLoadout> loadouts) { if (!IsValid || !_nview.IsOwner() || _corrupt) { return false; } _nview.GetZDO().Set("GearHeim.Loadouts", LoadoutStorage.Write(loadouts)); return true; } internal bool HasStoredItems() { if (!_corrupt) { return Peek().Any((StoredLoadout l) => l.ItemCount > 0); } return true; } internal bool CanAccess(bool flash) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return PrivateArea.CheckAccess(Position, 0f, flash, false); } internal static List<LoadoutChest> InArea(BaseArea area) { return (from c in All where (Object)(object)c != (Object)null && c.IsValid && area.Contains(c.Position) orderby area.DistanceFrom(c.Position) select c).ToList(); } public string GetHoverText() { if (!IsValid) { return ""; } if (!CanAccess(flash: false)) { return Localization.instance.Localize("Loadout Chest\n$piece_noaccess"); } int count = Peek().Count; string text = (_corrupt ? "data unreadable" : ((count == 1) ? "1 loadout" : $"{count} loadouts")); return Localization.instance.Localize("Loadout Chest ( " + text + " )\n[<color=yellow><b>$KEY_Use</b></color>] Manage loadouts"); } public string GetHoverName() { return "Loadout Chest"; } public float GetHoverOffset() { return 0f; } public bool Interact(Humanoid user, bool hold, bool alt) { if (hold || !IsValid) { return false; } if (!CanAccess(flash: true)) { return true; } LoadoutMenu.Open(this); return true; } public bool UseItem(Humanoid user, ItemData item) { return false; } private void OnDestroyed() { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0082: 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) if (!IsValid || !_nview.IsOwner() || _corrupt) { return; } foreach (StoredLoadout item in Load()) { foreach (ItemData item2 in item.Items) { Tags.Clear(item2); Vector3 val = Random.insideUnitSphere * 0.5f; val.y = Mathf.Abs(val.y) + 0.5f; ItemDrop.DropItem(item2, item2.m_stack, Position + val, Quaternion.identity); } } _nview.GetZDO().Set("GearHeim.Loadouts", new byte[0]); } } internal class LoadoutEntry { public string Prefab; public int Quality; public int Variant; public bool Equipped; public int HotbarX = -1; public int Target; public bool Stackable; public void Write(ZPackage pkg) { pkg.Write(Prefab ?? ""); pkg.Write(Quality); pkg.Write(Variant); pkg.Write(Equipped); pkg.Write(HotbarX); pkg.Write(Target); pkg.Write(Stackable); } public static LoadoutEntry Read(ZPackage pkg) { return new LoadoutEntry { Prefab = pkg.ReadString(), Quality = pkg.ReadInt(), Variant = pkg.ReadInt(), Equipped = pkg.ReadBool(), HotbarX = pkg.ReadInt(), Target = pkg.ReadInt(), Stackable = pkg.ReadBool() }; } } internal class LoadoutDef { public string Id; public string Name; public long Owner; public List<LoadoutEntry> Entries = new List<LoadoutEntry>(); public static string NewId() { return Guid.NewGuid().ToString("N").Substring(0, 12); } public void Write(ZPackage pkg) { pkg.Write(Id); pkg.Write(Name); pkg.Write(Owner); pkg.Write(Entries.Count); foreach (LoadoutEntry entry in Entries) { entry.Write(pkg); } } public static LoadoutDef Read(ZPackage pkg) { LoadoutDef loadoutDef = new LoadoutDef { Id = pkg.ReadString(), Name = pkg.ReadString(), Owner = pkg.ReadLong() }; int num = pkg.ReadInt(); for (int i = 0; i < num; i++) { loadoutDef.Entries.Add(LoadoutEntry.Read(pkg)); } return loadoutDef; } public string ToBase64() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown ZPackage val = new ZPackage(); Write(val); return Convert.ToBase64String(val.GetArray()); } public static LoadoutDef FromBase64(string s) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown if (string.IsNullOrEmpty(s)) { return null; } try { return Read(new ZPackage(Convert.FromBase64String(s))); } catch (Exception ex) { GearHeimPlugin.Log.LogWarning((object)("Could not read worn loadout: " + ex.Message)); return null; } } } internal class StoredLoadout { public LoadoutDef Def; public List<ItemData> Items = new List<ItemData>(); public bool CheckedOut; public int ItemCount; } internal static class Tags { public const string Loadout = "GearHeim.Loadout"; public const string Entry = "GearHeim.Entry"; public static string LoadoutOf(ItemData item) { if (!item.m_customData.TryGetValue("GearHeim.Loadout", out var value)) { return null; } return value; } public static int EntryOf(ItemData item) { if (!item.m_customData.TryGetValue("GearHeim.Entry", out var value) || !int.TryParse(value, out var result)) { return -1; } return result; } public static void Set(ItemData item, string loadoutId, int entry) { item.m_customData["GearHeim.Loadout"] = loadoutId; item.m_customData["GearHeim.Entry"] = entry.ToString(); } public static void Clear(ItemData item) { item.m_customData.Remove("GearHeim.Loadout"); item.m_customData.Remove("GearHeim.Entry"); } } internal static class LoadoutStorage { private const int Version = 1; private const int ScratchWidth = 8; private const int ScratchHeight = 32; public static byte[] Write(List<StoredLoadout> loadouts) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write(1); val.Write(loadouts.Count); foreach (StoredLoadout loadout in loadouts) { loadout.Def.Write(val); val.Write(loadout.CheckedOut); val.Write(SaveItems(loadout.Items)); } return val.GetArray(); } public static List<StoredLoadout> Read(byte[] data, bool withItems = true) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown List<StoredLoadout> list = new List<StoredLoadout>(); if (data == null || data.Length == 0) { return list; } ZPackage val = new ZPackage(data); int num = val.ReadInt(); if (num != 1) { throw new InvalidOperationException($"Unknown loadout data version {num} (made by a newer GearHeim?)"); } int num2 = val.ReadInt(); for (int i = 0; i < num2; i++) { LoadoutDef def = LoadoutDef.Read(val); bool checkedOut = val.ReadBool(); byte[] data2 = val.ReadByteArray(); List<ItemData> list2 = (withItems ? LoadItems(data2) : new List<ItemData>()); list.Add(new StoredLoadout { Def = def, CheckedOut = checkedOut, Items = list2, ItemCount = (withItems ? list2.Count : CountItems(data2)) }); } return list; } private static byte[] SaveItems(List<ItemData> items) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Expected O, but got Unknown //IL_002e: 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_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown Inventory val = new Inventory("GearHeim", (Sprite)null, 8, 32); for (int i = 0; i < items.Count; i++) { ItemData val2 = items[i].Clone(); val2.m_equipped = false; val2.m_gridPos = new Vector2i(i % 8, i / 8); val.m_inventory.Add(val2); } ZPackage val3 = new ZPackage(); val.Save(val3); return val3.GetArray(); } private static int CountItems(byte[] data) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) if (data == null || data.Length < 6) { return 0; } ZPackage val = new ZPackage(data); val.ReadInt(); return val.ReadUShort(); } private static List<ItemData> LoadItems(byte[] data) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Expected O, but got Unknown //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown Inventory val = new Inventory("GearHeim", (Sprite)null, 8, 32); if (data != null && data.Length != 0) { val.Load(new ZPackage(data)); } return val.m_inventory.ToList(); } } internal static class LoadoutMenu { private const float Width = 600f; private const float RowHeight = 40f; private const int MaxRows = 8; private static GameObject _panel; private static InputField _nameField; private static LoadoutChest _chest; private static string _confirmDeleteId; public static bool IsOpen { get { if ((Object)(object)_panel != (Object)null) { return _panel.activeSelf; } return false; } } public static void Toggle() { if (IsOpen) { Close(); } else { Open(null); } } public static void Open(LoadoutChest chest) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)GUIManager.CustomGUIFront == (Object)null) { return; } BaseArea baseArea = BaseArea.For(((Component)localPlayer).transform.position); if ((Object)(object)chest == (Object)null) { if (!baseArea.IsValid) { LoadoutService.Message(localPlayer, "You need to be in your base (near a workbench) to change loadouts."); return; } List<LoadoutChest> list = LoadoutChest.InArea(baseArea); if (list.Count == 0) { LoadoutService.Message(localPlayer, "No Loadout Chest in this base."); return; } chest = list[0]; } _chest = chest; _confirmDeleteId = null; Rebuild(); GUIManager.BlockInput(true); } public static void Close() { if ((Object)(object)_panel != (Object)null) { Object.Destroy((Object)(object)_panel); } _panel = null; _nameField = null; _chest = null; GUIManager.BlockInput(false); } public static void Refresh() { if (IsOpen) { Rebuild(); } } public static void ClearName() { if ((Object)(object)_nameField != (Object)null) { _nameField.text = ""; } } public static void Update() { if (IsOpen && (Input.GetKeyDown((KeyCode)27) || (Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)_chest == (Object)null || !_chest.IsValid)) { Close(); } } public static bool IsTyping() { if ((!((Object)(object)_nameField != (Object)null) || !_nameField.isFocused) && (!((Object)(object)Chat.instance != (Object)null) || !Chat.instance.HasFocus()) && !Console.IsVisible() && !TextInput.IsVisible()) { return Menu.IsVisible(); } return true; } private static void Rebuild() { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_00be: 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_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_034c: Unknown result type (might be due to invalid IL or missing references) //IL_035b: Unknown result type (might be due to invalid IL or missing references) //IL_0367: Unknown result type (might be due to invalid IL or missing references) //IL_0318: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } string text = (((Object)(object)_nameField != (Object)null) ? _nameField.text : ""); if ((Object)(object)_panel != (Object)null) { Object.Destroy((Object)(object)_panel); } BaseArea baseArea = BaseArea.For(((Component)localPlayer).transform.position); List<LoadoutListing> list = (baseArea.IsValid ? LoadoutService.List(localPlayer, baseArea) : new List<LoadoutListing>()); LoadoutDef worn = LoadoutService.GetWorn(localPlayer); int num = Mathf.Max(1, Mathf.Min(list.Count, 8)); float num2 = 190f + (float)num * 40f + 150f; GUIManager instance = GUIManager.Instance; _panel = instance.CreateWoodpanel(GUIManager.CustomGUIFront.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, 600f, num2, false); float num3 = -30f; Text("Loadouts", num3, 28, instance.ValheimOrange); num3 -= 34f; Text((worn != null) ? ("Wearing: " + worn.Name) : "Not wearing a saved loadout", num3, 18, instance.ValheimBeige); num3 -= 44f; if (list.Count == 0) { Text("No loadouts yet. Name one below and save your current gear.", num3, 16, Color.white); num3 -= 40f; } for (int i = 0; i < list.Count && i < 8; i++) { LoadoutListing listing = list[i]; string text2 = ((i < GearHeimPlugin.QuickKeys.Length) ? ((object)GearHeimPlugin.QuickKeys[i].Value/*cast due to .constrained prefix*/).ToString() : ""); string text3 = (listing.Worn ? "worn" : (listing.Stored ? $"{listing.ItemCount} items" : "elsewhere")); RowText(listing.Def.Name + " <color=#a0a0a0>(" + text3 + ((text2.Length > 0) ? (", " + text2) : "") + ")</color>", num3); if (listing.Stored) { Button("Equip", 110f, num3, 90f, delegate { LoadoutService.Switch(Player.m_localPlayer, listing.Def.Id); }); } Button((_confirmDeleteId == listing.Def.Id) ? "Sure?" : "Delete", 210f, num3, 90f, delegate { if (_confirmDeleteId != listing.Def.Id) { _confirmDeleteId = listing.Def.Id; } else { _confirmDeleteId = null; LoadoutService.Delete(Player.m_localPlayer, listing); } Rebuild(); }); num3 -= 40f; } if (list.Count > 8) { Text($"+{list.Count - 8} more (use the hotkeys or delete some)", num3, 14, Color.gray); num3 -= 40f; } num3 -= 16f; _nameField = instance.CreateInputField(_panel.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(-95f, num3), (ContentType)0, "New loadout name", 18, 360f, 34f).GetComponent<InputField>(); _nameField.characterLimit = 32; _nameField.text = text; Button("Save gear as new", 195f, num3, 180f, delegate { LoadoutService.SaveNew(Player.m_localPlayer, _chest, _nameField.text); }); num3 -= 48f; if (worn != null) { Button("Save changes to '" + Shorten(worn.Name) + "'", -140f, num3, 270f, delegate { LoadoutService.UpdateWorn(Player.m_localPlayer, _chest); }); Button("Store it", 120f, num3, 150f, delegate { LoadoutService.StoreWorn(Player.m_localPlayer, _chest); }); } Button("Close", 235f, num3, 100f, Close); } private static string Shorten(string s) { if (s.Length > 14) { return s.Substring(0, 13) + "…"; } return s; } private static void Text(string text, float y, int size, Color color) { //IL_001a: 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_0034: 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) //IL_0046: Unknown result type (might be due to invalid IL or missing references) GUIManager.Instance.CreateText(text, _panel.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, y), GUIManager.Instance.AveriaSerifBold, size, color, true, Color.black, 560f, 30f, false).GetComponent<Text>().alignment = (TextAnchor)4; } private static void RowText(string text, float y) { //IL_001a: 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_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) Text component = GUIManager.Instance.CreateText(text, _panel.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(-100f, y), GUIManager.Instance.AveriaSerifBold, 18, Color.white, true, Color.black, 360f, 32f, false).GetComponent<Text>(); component.alignment = (TextAnchor)3; component.supportRichText = true; } private static void Button(string label, float x, float y, float width, Action onClick) { //IL_0028: 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) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown ((UnityEvent)GUIManager.Instance.CreateButton(label, _panel.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(x, y), width, 34f).GetComponent<Button>().onClick).AddListener((UnityAction)delegate { onClick(); }); } } internal class LoadoutListing { public LoadoutDef Def; public LoadoutChest Chest; public bool Stored; public bool Worn; public int ItemCount; } internal static class LoadoutService { private class Placement { public readonly List<(ItemData item, Vector2i pos)> Moves = new List<(ItemData, Vector2i)>(); public readonly List<(ItemData item, Vector2i pos)> Incoming = new List<(ItemData, Vector2i)>(); } private const string WornKey = "GearHeim.Worn"; private const string LastWornName = "Last worn"; public static LoadoutDef GetWorn(Player player) { if (!player.m_customData.TryGetValue("GearHeim.Worn", out var value)) { return null; } return LoadoutDef.FromBase64(value); } private static void SetWorn(Player player, LoadoutDef def) { if (def == null) { player.m_customData.Remove("GearHeim.Worn"); } else { player.m_customData["GearHeim.Worn"] = def.ToBase64(); } } public static List<LoadoutListing> List(Player player, BaseArea area) { long playerID = player.GetPlayerID(); Dictionary<string, LoadoutListing> dictionary = new Dictionary<string, LoadoutListing>(); foreach (LoadoutChest item in LoadoutChest.InArea(area)) { foreach (StoredLoadout item2 in item.Peek()) { if (item2.Def.Owner == playerID) { bool flag = !item2.CheckedOut; if (!dictionary.TryGetValue(item2.Def.Id, out var value) || (!value.Stored && flag)) { dictionary[item2.Def.Id] = new LoadoutListing { Def = item2.Def, Chest = item, Stored = flag, ItemCount = item2.ItemCount }; } } } } LoadoutDef worn = GetWorn(player); if (worn != null) { if (!dictionary.TryGetValue(worn.Id, out var value2)) { value2 = (dictionary[worn.Id] = new LoadoutListing()); } value2.Def = worn; value2.Worn = true; value2.Stored = false; } return dictionary.Values.OrderBy<LoadoutListing, string>((LoadoutListing l) => l.Def.Name, StringComparer.CurrentCultureIgnoreCase).ToList(); } public static void SwitchToListed(Player player, int index) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) BaseArea area = BaseArea.For(((Component)player).transform.position); if (RequireArea(player, area)) { List<LoadoutListing> list = List(player, area); if (index < 0 || index >= list.Count) { Message(player, $"No loadout #{index + 1} here."); } else { Switch(player, list[index].Def.Id); } } } public static void Switch(Player player, string targetId) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) if (!CanAct(player)) { return; } BaseArea area = BaseArea.For(((Component)player).transform.position); if (!RequireArea(player, area)) { return; } LoadoutDef worn = GetWorn(player); if (worn != null && worn.Id == targetId) { Message(player, "You're already wearing '" + worn.Name + "'."); return; } LoadoutListing loadoutListing = List(player, area).FirstOrDefault((LoadoutListing l) => l.Def.Id == targetId && l.Stored); if (loadoutListing == null) { Message(player, "That loadout isn't stored in a Loadout Chest in this base."); return; } LoadoutChest chest = loadoutListing.Chest; chest.WithAccess(delegate { DoSwitch(player, chest, targetId); }); } private static void DoSwitch(Player player, LoadoutChest chest, string targetId) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) if (!CanAct(player)) { return; } BaseArea baseArea = BaseArea.For(((Component)player).transform.position); if (!baseArea.IsValid || !baseArea.Contains(chest.Position)) { Message(player, "You've left the base."); return; } List<StoredLoadout> list = chest.Load(); StoredLoadout storedLoadout = list.FirstOrDefault((StoredLoadout l) => l.Def.Id == targetId && !l.CheckedOut && l.Def.Owner == player.GetPlayerID()); if (chest.IsCorrupt || storedLoadout == null) { Message(player, "That loadout is no longer in the chest."); return; } LoadoutDef worn = GetWorn(player); ClearOrphanTags(player, worn); Inventory inventory = ((Humanoid)player).GetInventory(); List<ItemData> items = storedLoadout.Items; LoadoutDef loadoutDef; List<ItemData> list2; if (worn != null) { loadoutDef = worn; list2 = inventory.m_inventory.Where((ItemData i) => Tags.LoadoutOf(i) == worn.Id).ToList(); } else { list2 = CurrentGear(player); loadoutDef = ((list2.Count > 0) ? NewDef(player, UniqueName(player, baseArea, "Last worn")) : null); } if (!PlanPlacement(player, storedLoadout.Def, items, list2, MissingStackEntries(storedLoadout.Def, items), out var _, out var why)) { Message(player, why); return; } if (loadoutDef != null && worn == null) { Capture(loadoutDef, list2); } List<ItemData> list3 = new List<ItemData>(); List<string> missing = new List<string>(); if (loadoutDef != null) { Restock(player, baseArea, loadoutDef, list2, missing, list3, trackTopUps: false); } List<string> missing2 = new List<string>(); Restock(player, baseArea, storedLoadout.Def, items, missing2, list3, trackTopUps: true); Placement plan2 = null; bool flag = PlanPlacement(player, storedLoadout.Def, items, list2, 0, out plan2, out why); storedLoadout.CheckedOut = true; storedLoadout.Items = new List<ItemData>(); if (loadoutDef != null) { Upsert(list, loadoutDef, list2); } if (!flag || !chest.Save(list)) { if (loadoutDef != null && worn == null) { foreach (ItemData item in list2) { Tags.Clear(item); } } GiveOrDrop(player, list3); Message(player, flag ? "Couldn't write to the Loadout Chest; nothing was changed." : why); return; } SetWorn(player, storedLoadout.Def); try { RemoveFromPlayer(player, list2); ((Humanoid)player).ClearActionQueue(); Apply(player, storedLoadout.Def, plan2); } catch (Exception arg) { GearHeimPlugin.Log.LogError((object)$"Switch failed after saving: {arg}"); GiveOrDrop(player, items.Where((ItemData i) => !((Humanoid)player).GetInventory().m_inventory.Contains(i)).ToList()); } Message(player, "Switched to '" + storedLoadout.Def.Name + "'."); Report(player, loadoutDef, missing, "stored"); Report(player, storedLoadout.Def, missing2, "equipped"); } public static void SaveNew(Player player, LoadoutChest chest, string name) { if (!CanAct(player)) { return; } LoadoutDef worn = GetWorn(player); if (worn != null) { Message(player, "You're wearing '" + worn.Name + "'. Store it or save your changes to it first."); return; } name = (name ?? "").Trim(); if (name.Length == 0) { Message(player, "Give the loadout a name first."); return; } chest.WithAccess(delegate { //IL_004a: Unknown result type (might be due to invalid IL or missing references) if (CanAct(player)) { ClearOrphanTags(player, null); List<ItemData> list = CurrentGear(player); if (list.Count == 0) { Message(player, "Equip some gear or fill your hotbar first."); } else { BaseArea area = BaseArea.For(((Component)player).transform.position); LoadoutDef loadoutDef = NewDef(player, UniqueName(player, area, name)); Capture(loadoutDef, list); List<StoredLoadout> loadouts = chest.Load(); Upsert(loadouts, loadoutDef, list); if (!chest.Save(loadouts)) { foreach (ItemData item in list) { Tags.Clear(item); } Message(player, "Couldn't write to the Loadout Chest; nothing was changed."); } else { RemoveFromPlayer(player, list); LoadoutMenu.ClearName(); Message(player, $"Saved '{loadoutDef.Name}' ({list.Count} items)."); } } } }); } public static void StoreWorn(Player player, LoadoutChest chest) { if (!CanAct(player)) { return; } if (GetWorn(player) == null) { Message(player, "You aren't wearing a saved loadout."); return; } chest.WithAccess(delegate { //IL_004a: Unknown result type (might be due to invalid IL or missing references) if (CanAct(player)) { LoadoutDef worn = GetWorn(player); if (worn != null) { ClearOrphanTags(player, worn); BaseArea area = BaseArea.For(((Component)player).transform.position); List<ItemData> items = ((Humanoid)player).GetInventory().m_inventory.Where((ItemData i) => Tags.LoadoutOf(i) == worn.Id).ToList(); List<string> missing = new List<string>(); List<ItemData> list = new List<ItemData>(); Restock(player, area, worn, items, missing, list, trackTopUps: false); List<StoredLoadout> loadouts = chest.Load(); Upsert(loadouts, worn, items); if (!chest.Save(loadouts)) { GiveOrDrop(player, list); Message(player, "Couldn't write to the Loadout Chest; nothing was changed."); } else { RemoveFromPlayer(player, items); SetWorn(player, null); Message(player, "Stored '" + worn.Name + "'."); Report(player, worn, missing, "stored"); } } } }); } public static void UpdateWorn(Player player, LoadoutChest chest) { if (!CanAct(player)) { return; } if (GetWorn(player) == null) { Message(player, "Equip a loadout first, change your gear, then save the changes here."); return; } chest.WithAccess(delegate { if (CanAct(player)) { LoadoutDef worn = GetWorn(player); if (worn != null) { ClearOrphanTags(player, worn); List<ItemData> list = CurrentGear(player); Dictionary<ItemData, Dictionary<string, string>> dictionary = list.ToDictionary((ItemData i) => i, (ItemData i) => new Dictionary<string, string>(i.m_customData)); LoadoutDef loadoutDef = new LoadoutDef { Id = worn.Id, Name = worn.Name, Owner = worn.Owner }; Capture(loadoutDef, list); List<StoredLoadout> loadouts = chest.Load(); Upsert(loadouts, loadoutDef, list); if (!chest.Save(loadouts)) { foreach (KeyValuePair<ItemData, Dictionary<string, string>> item in dictionary) { item.Key.m_customData = item.Value; } Message(player, "Couldn't write to the Loadout Chest; nothing was changed."); } else { foreach (ItemData item2 in ((Humanoid)player).GetInventory().m_inventory) { if (Tags.LoadoutOf(item2) == worn.Id && !list.Contains(item2)) { Tags.Clear(item2); } } RemoveFromPlayer(player, list); SetWorn(player, null); Message(player, $"Updated and stored '{loadoutDef.Name}' ({list.Count} items)."); } } } }); } public static void Delete(Player player, LoadoutListing listing) { if (!CanAct(player)) { return; } if ((Object)(object)listing.Chest == (Object)null) { ForgetWorn(player, listing.Def); Message(player, "Deleted '" + listing.Def.Name + "'."); return; } LoadoutChest chest = listing.Chest; chest.WithAccess(delegate { //IL_0109: 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) Inventory inventory = ((Humanoid)player).GetInventory(); List<StoredLoadout> list = chest.Load(); StoredLoadout storedLoadout = list.FirstOrDefault((StoredLoadout l) => l.Def.Id == listing.Def.Id && l.Def.Owner == player.GetPlayerID()); if (storedLoadout == null) { ForgetWorn(player, listing.Def); } else { List<Vector2i> list2 = FreeBagSlots(inventory, new HashSet<ItemData>()); if (list2.Count < storedLoadout.Items.Count) { Message(player, $"Need {storedLoadout.Items.Count - list2.Count} more free inventory slots to take '{listing.Def.Name}' apart."); } else { List<ItemData> items = storedLoadout.Items; list.Remove(storedLoadout); if (!chest.Save(list)) { Message(player, "Couldn't write to the Loadout Chest; nothing was changed."); } else { for (int num = 0; num < items.Count; num++) { ItemData val = items[num]; Tags.Clear(val); val.m_equipped = false; val.m_gridPos = list2[num]; inventory.m_inventory.Add(val); } inventory.Changed(false, false); ForgetWorn(player, listing.Def); Message(player, "Deleted '" + listing.Def.Name + "'."); } } } }); } private static void ForgetWorn(Player player, LoadoutDef def) { LoadoutDef worn = GetWorn(player); if (worn == null || worn.Id != def.Id) { return; } foreach (ItemData item in ((Humanoid)player).GetInventory().m_inventory) { if (Tags.LoadoutOf(item) == def.Id) { Tags.Clear(item); } } SetWorn(player, null); } private static IEnumerable<ItemData> EquippedItems(Player p) { return ((IEnumerable<ItemData>)(object)new ItemData[11] { ((Humanoid)p).m_rightItem, ((Humanoid)p).m_leftItem, ((Humanoid)p).m_hiddenRightItem, ((Humanoid)p).m_hiddenLeftItem, ((Humanoid)p).m_helmetItem, ((Humanoid)p).m_chestItem, ((Humanoid)p).m_legItem, ((Humanoid)p).m_shoulderItem, ((Humanoid)p).m_utilityItem, ((Humanoid)p).m_trinketItem, ((Humanoid)p).m_ammoItem }).Where((ItemData i) => i != null).Distinct(); } private static List<ItemData> CurrentGear(Player player) { List<ItemData> list = EquippedItems(player).ToList(); foreach (ItemData item in ((Humanoid)player).GetInventory().m_inventory) { if (item.m_gridPos.y == 0 && !list.Contains(item)) { list.Add(item); } } list.RemoveAll((ItemData i) => (Object)(object)i.m_dropPrefab == (Object)null); return list; } private static void ClearOrphanTags(Player player, LoadoutDef worn) { foreach (ItemData item in ((Humanoid)player).GetInventory().m_inventory) { string text = Tags.LoadoutOf(item); if (text != null && (worn == null || text != worn.Id)) { Tags.Clear(item); } } } private static LoadoutDef NewDef(Player player, string name) { return new LoadoutDef { Id = LoadoutDef.NewId(), Name = name, Owner = player.GetPlayerID() }; } private static void Capture(LoadoutDef def, List<ItemData> items) { def.Entries.Clear(); foreach (ItemData item2 in items) { LoadoutEntry item = new LoadoutEntry { Prefab = (((Object)(object)item2.m_dropPrefab != (Object)null) ? ((Object)item2.m_dropPrefab).name : ""), Quality = item2.m_quality, Variant = item2.m_variant, Equipped = (item2.m_equipped || IsHidden(item2)), HotbarX = ((item2.m_gridPos.y == 0) ? item2.m_gridPos.x : (-1)), Target = item2.m_stack, Stackable = (item2.m_shared.m_maxStackSize > 1) }; Tags.Set(item2, def.Id, def.Entries.Count); def.Entries.Add(item); } } private static bool IsHidden(ItemData item) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { if (item != ((Humanoid)localPlayer).m_hiddenLeftItem) { return item == ((Humanoid)localPlayer).m_hiddenRightItem; } return true; } return false; } private static void RemoveFromPlayer(Player player, List<ItemData> items) { if (items.Count == 0) { return; } Inventory inventory = ((Humanoid)player).GetInventory(); foreach (ItemData item in items) { if (inventory.m_inventory.Contains(item)) { if (((Humanoid)player).IsItemEquiped(item)) { ((Humanoid)player).UnequipItem(item, false); } if (item == ((Humanoid)player).m_hiddenLeftItem) { ((Humanoid)player).m_hiddenLeftItem = null; } if (item == ((Humanoid)player).m_hiddenRightItem) { ((Humanoid)player).m_hiddenRightItem = null; } item.m_equipped = false; inventory.m_inventory.Remove(item); } } inventory.Changed(false, false); } private static void Upsert(List<StoredLoadout> loadouts, LoadoutDef def, List<ItemData> items) { StoredLoadout storedLoadout = loadouts.FirstOrDefault((StoredLoadout l) => l.Def.Id == def.Id); if (storedLoadout == null) { loadouts.Add(storedLoadout = new StoredLoadout()); } storedLoadout.Def = def; storedLoadout.Items = items; storedLoadout.CheckedOut = false; } private static string UniqueName(Player player, BaseArea area, string name) { HashSet<string> hashSet = new HashSet<string>(from l in List(player, area) select l.Def.Name, StringComparer.CurrentCultureIgnoreCase); if (!hashSet.Contains(name)) { return name; } int num; for (num = 2; hashSet.Contains($"{name} {num}"); num++) { } return $"{name} {num}"; } private static void GiveOrDrop(Player player, List<ItemData> items) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) foreach (ItemData item in items) { Tags.Clear(item); if (!((Humanoid)player).GetInventory().AddItem(item)) { ItemDrop.DropItem(item, item.m_stack, ((Component)player).transform.position + Vector3.up, Quaternion.identity); } } } private static int MissingStackEntries(LoadoutDef def, List<ItemData> items) { if (!GearHeimPlugin.RefillFromChests.Value) { return 0; } HashSet<int> present = new HashSet<int>(items.Select(Tags.EntryOf)); return def.Entries.Where((LoadoutEntry e, int i) => e.Stackable && !present.Contains(i)).Count(); } private static void Restock(Player player, BaseArea area, LoadoutDef def, List<ItemData> items, List<string> missing, List<ItemData> created, bool trackTopUps) { int index; for (index = 0; index < def.Entries.Count; index++) { LoadoutEntry loadoutEntry = def.Entries[index]; List<ItemData> list = items.Where((ItemData i) => Tags.EntryOf(i) == index).ToList(); if (!loadoutEntry.Stackable) { if (list.Count == 0) { missing.Add(DisplayName(loadoutEntry.Prefab)); } continue; } int num = loadoutEntry.Target - list.Sum((ItemData i) => i.m_stack); if (num <= 0) { continue; } if (GearHeimPlugin.RefillFromChests.Value) { int worldLevel = ((list.Count > 0) ? list[0].m_worldLevel : (-1)); ItemData template; int num2 = ChestSupply.Take(player, area, loadoutEntry, worldLevel, num, out template); if (num2 > 0) { if (list.Count > 0) { ItemData obj = list[0]; obj.m_stack += num2; if (trackTopUps) { ItemData val = list[0].Clone(); val.m_stack = num2; created.Add(val); } } else { ItemData val2 = template.Clone(); val2.m_stack = num2; val2.m_equipped = false; Tags.Set(val2, def.Id, index); items.Add(val2); created.Add(val2); } num -= num2; } } if (num > 0) { missing.Add($"{num} {DisplayName(loadoutEntry.Prefab)}"); } } } private static string DisplayName(string prefab) { GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(prefab) : null); ItemDrop val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<ItemDrop>() : null); if (!((Object)(object)val2 != (Object)null)) { return prefab; } return Localization.instance.Localize(val2.m_itemData.m_shared.m_name); } private static void Report(Player player, LoadoutDef def, List<string> missing, string verb) { if (def != null && missing.Count != 0) { ((Character)player).Message((MessageType)1, "'" + def.Name + "' " + verb + " incomplete. Missing: " + string.Join(", ", missing), 0, (Sprite)null, false); } } private static bool PlanPlacement(Player player, LoadoutDef def, List<ItemData> incoming, List<ItemData> outgoing, int extraStacks, out Placement plan, out string why) { //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) plan = new Placement(); why = null; Inventory inventory = ((Humanoid)player).GetInventory(); HashSet<ItemData> leaving = new HashSet<ItemData>(outgoing); List<ItemData> source = inventory.m_inventory.Where((ItemData i) => !leaving.Contains(i)).ToList(); Dictionary<int, ItemData> hotbarClaims = new Dictionary<int, ItemData>(); List<ItemData> list = new List<ItemData>(); foreach (ItemData item in incoming) { int num = Tags.EntryOf(item); int num2 = ((num >= 0 && num < def.Entries.Count) ? def.Entries[num].HotbarX : (-1)); if (num2 >= 0 && num2 < inventory.GetWidth() && !hotbarClaims.ContainsKey(num2)) { hotbarClaims[num2] = item; } else { list.Add(item); } } List<ItemData> list2 = source.Where((ItemData i) => i.m_gridPos.y == 0 && hotbarClaims.ContainsKey(i.m_gridPos.x)).ToList(); List<Vector2i> list3 = FreeBagSlots(inventory, leaving); int num3 = list.Count + list2.Count + extraStacks; if (list3.Count < num3) { why = $"Not enough inventory space: free up {num3 - list3.Count} more slot(s)."; return false; } int num4 = 0; foreach (ItemData item2 in list2) { plan.Moves.Add((item2, list3[num4++])); } foreach (KeyValuePair<int, ItemData> item3 in hotbarClaims) { plan.Incoming.Add((item3.Value, new Vector2i(item3.Key, 0))); } foreach (ItemData item4 in list) { plan.Incoming.Add((item4, list3[num4++])); } return true; } private static List<Vector2i> FreeBagSlots(Inventory inventory, HashSet<ItemData> leaving) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) HashSet<Vector2i> hashSet = new HashSet<Vector2i>(from i in inventory.m_inventory where !leaving.Contains(i) select i.m_gridPos); List<Vector2i> list = new List<Vector2i>(); Vector2i item = default(Vector2i); for (int num = 1; num < inventory.GetHeight(); num++) { for (int num2 = 0; num2 < inventory.GetWidth(); num2++) { ((Vector2i)(ref item))..ctor(num2, num); if (!hashSet.Contains(item)) { list.Add(item); } } } return list; } private static void Apply(Player player, LoadoutDef def, Placement plan) { //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_002a: 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_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) Inventory inventory = ((Humanoid)player).GetInventory(); foreach (var move in plan.Moves) { ItemData item = move.item; Vector2i item2 = move.pos; item.m_gridPos = item2; } foreach (var item6 in plan.Incoming) { ItemData item3 = item6.item; Vector2i item4 = item6.pos; item3.m_equipped = false; item3.m_gridPos = item4; inventory.m_inventory.Add(item3); } inventory.Changed(false, false); foreach (var item7 in plan.Incoming) { ItemData item5 = item7.item; int num = Tags.EntryOf(item5); if (num >= 0 && num < def.Entries.Count && def.Entries[num].Equipped) { ((Humanoid)player).EquipItem(item5, true); } } } private static bool CanAct(Player player) { if ((Object)(object)player == (Object)null || ((Character)player).IsDead() || ((Character)player).IsTeleporting()) { return false; } if (((Character)player).InAttack() || ((Character)player).InDodge()) { Message(player, "Can't change loadouts while fighting."); return false; } if (((Character)player).IsSwimming()) { Message(player, "Can't change loadouts while swimming."); return false; } if ((Object)(object)InventoryGui.instance != (Object)null && InventoryGui.instance.m_dragItem != null) { Message(player, "Put down the item you're holding first."); return false; } return true; } private static bool RequireArea(Player player, BaseArea area) { if (area.IsValid) { return true; } Message(player, "You need to be in your base (near a workbench) to change loadouts."); return false; } internal static void Message(Player player, string text) { if ((Object)(object)player != (Object)null) { ((Character)player).Message((MessageType)2, text, 0, (Sprite)null, false); } } } [HarmonyPatch(typeof(Piece), "CanBeRemoved")] internal static class PieceCanBeRemovedPatch { private static void Postfix(Piece __instance, ref bool __result) { if (__result) { LoadoutChest component = ((Component)__instance).GetComponent<LoadoutChest>(); if ((Object)(object)component != (Object)null && component.HasStoredItems()) { __result = false; } } } } [HarmonyPatch(typeof(Player), "UseHotbarItem")] internal static class UseHotbarItemPatch { private static bool Prefix(int index) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: 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) KeyCode val = (KeyCode)(48 + index); ConfigEntry<KeyboardShortcut>[] quickKeys = GearHeimPlugin.QuickKeys; for (int i = 0; i < quickKeys.Length; i++) { KeyboardShortcut value = quickKeys[i].Value; if (((KeyboardShortcut)(ref value)).MainKey == val && ((KeyboardShortcut)(ref value)).Modifiers.Any() && ((KeyboardShortcut)(ref value)).Modifiers.All((Func<KeyCode, bool>)Input.GetKey)) { return false; } } return true; } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }