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.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using StationPacks.Compat; using StationPacks.Config; using StationPacks.Core; using UnityEngine; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("assembly_guiutils")] [assembly: IgnoresAccessChecksTo("assembly_utils")] [assembly: IgnoresAccessChecksTo("assembly_valheim")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("StationPacks")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Wearable crafting stations for building in the field.")] [assembly: AssemblyFileVersion("0.3.0.0")] [assembly: AssemblyInformationalVersion("0.3.0+42a8634a570e5675f3bf6cdaa8b2729f5009a226")] [assembly: AssemblyProduct("StationPacks")] [assembly: AssemblyTitle("StationPacks")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.3.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 StationPacks { [BepInPlugin("LosGoobers.StationPacks", "StationPacks", "0.3.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] internal sealed class Plugin : BaseUnityPlugin { public const string Guid = "LosGoobers.StationPacks"; public const string Name = "StationPacks"; public const string Version = "0.3.0"; internal static ManualLogSource Log; private Harmony _harmony; private void Awake() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; SPConfig.Bind(((BaseUnityPlugin)this).Config); _harmony = new Harmony("LosGoobers.StationPacks"); _harmony.PatchAll(); PrefabManager.OnVanillaPrefabsAvailable += OnVanillaPrefabsAvailable; ZNetSceneReady.Subscribe(PhantomStationRegistry.Build); DebugCommands.Register(); ((Component)this).gameObject.AddComponent(); Log.LogInfo((object)"StationPacks 0.3.0 loaded."); } private void OnVanillaPrefabsAvailable() { PrefabManager.OnVanillaPrefabsAvailable -= OnVanillaPrefabsAvailable; PackRegistry.Register(); AdventureBackpacksCompat.ReportOnce(); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } [HarmonyPatch(typeof(ZNetScene), "Awake")] internal static class ZNetSceneReady { private static Action _callback; public static void Subscribe(Action callback) { _callback = callback; } [HarmonyPostfix] private static void Postfix() { _callback?.Invoke(); } } } namespace StationPacks.Patches { [HarmonyPatch(typeof(VisEquipment), "AttachArmor")] internal static class BackBonePatch { private static bool _loggedBone; [HarmonyPostfix] private static void Bind(VisEquipment __instance) { //IL_007d: 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_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) if (!SPConfig.ShowBackMesh.Value) { return; } SkinnedMeshRenderer bodyModel = __instance.m_bodyModel; if ((Object)(object)bodyModel == (Object)null) { return; } PackBackTag[] componentsInChildren = ((Component)__instance).GetComponentsInChildren(true); if (componentsInChildren.Length == 0) { return; } Transform val = FindSpineBone(bodyModel); if ((Object)(object)val == (Object)null) { return; } PackBackTag[] array = componentsInChildren; foreach (PackBackTag packBackTag in array) { if (!packBackTag.Bound) { packBackTag.Source = ((Component)packBackTag).transform.parent; ((Component)packBackTag).transform.SetParent(val, false); ((Component)packBackTag).transform.localScale = Vector3.one * packBackTag.TargetScale; ((Component)packBackTag).transform.localPosition = packBackTag.TargetOffset; ((Component)packBackTag).transform.localRotation = Quaternion.Euler(packBackTag.TargetEuler); packBackTag.Bound = true; } } } private static Transform FindSpineBone(SkinnedMeshRenderer bodyModel) { Transform[] bones = bodyModel.bones; if (bones == null || bones.Length == 0) { return bodyModel.rootBone; } Transform val = null; Transform[] array = bones; foreach (Transform val2 in array) { if (!((Object)(object)val2 == (Object)null)) { string text = ((Object)val2).name.ToLowerInvariant(); if ((text.Contains("spine") || text.Contains("chest") || text.Contains("back")) && ((Object)(object)val == (Object)null || CompareDepth(val2, val) > 0)) { val = val2; } } } if ((Object)(object)val != (Object)null && !_loggedBone) { _loggedBone = true; Plugin.Log.LogInfo((object)("Back mesh bound to spine bone '" + ((Object)val).name + "'.")); } return val ?? bodyModel.rootBone; } private static int CompareDepth(Transform a, Transform b) { int num = TrailingNumber(((Object)a).name); int num2 = TrailingNumber(((Object)b).name); if (num != num2) { return num - num2; } return Depth(a) - Depth(b); } private static int TrailingNumber(string name) { int num = name.Length; while (num > 0 && char.IsDigit(name[num - 1])) { num--; } if (num >= name.Length || !int.TryParse(name.Substring(num), out var result)) { return 0; } return result; } private static int Depth(Transform t) { int num = 0; while ((Object)(object)t.parent != (Object)null) { num++; t = t.parent; } return num; } } [HarmonyPatch] internal static class BuildPatches { [HarmonyPostfix] [HarmonyPatch(typeof(Player), "PlacePiece")] private static void OnPlacePiece(Player __instance, Piece piece) { PackCharge.SpendFor(__instance, piece, SPConfig.PlaceCost.Value); } [HarmonyPrefix] [HarmonyPatch(typeof(Player), "RemovePiece")] private static void BeforeRemovePiece(Player __instance, out Piece __state) { __state = null; Piece hoveringPiece = __instance.m_hoveringPiece; if ((Object)(object)hoveringPiece != (Object)null) { __state = hoveringPiece; } } [HarmonyPostfix] [HarmonyPatch(typeof(Player), "RemovePiece")] private static void AfterRemovePiece(Player __instance, bool __result, Piece __state) { if (__result && !((Object)(object)__state == (Object)null)) { PackCharge.SpendFor(__instance, __state, SPConfig.RemoveCost.Value); } } [HarmonyPostfix] [HarmonyPatch(typeof(Player), "Repair")] private static void OnRepair(Player __instance, Piece repairPiece) { PackCharge.SpendFor(__instance, repairPiece, SPConfig.RepairCost.Value); } } [HarmonyPatch] internal static class CraftingStationPatches { private const float MaxGrantDistance = 64f; [HarmonyPostfix] [HarmonyPatch(typeof(CraftingStation), "HaveBuildStationInRange")] private static void GrantFromPack(string name, Vector3 point, ref CraftingStation __result) { //IL_0035: 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_0071: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__result != (Object)null) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsDedicated()) || Vector3.Distance(point, ((Component)localPlayer).transform.position) > 64f) { return; } ItemData val = EquippedPackResolver.TryGetPack(localPlayer, name); if (val == null) { return; } CraftingStation val2 = PhantomStationRegistry.Get(name); if (!((Object)(object)val2 == (Object)null)) { ((Component)val2).transform.position = point; PackCharge.NoteGrant(name); __result = val2; if (SPConfig.Verbose.Value) { Plugin.Log.LogInfo((object)$"granted '{name}' from {val.m_shared.m_name} ({val.m_durability:0.#} left)"); } } } [HarmonyPrefix] [HarmonyPatch(typeof(CraftingStation), "GetLevel")] private static bool GetLevel(CraftingStation __instance, ref int __result) { if (!PhantomStationRegistry.IsPhantom(__instance)) { return true; } __result = 1; return false; } [HarmonyPrefix] [HarmonyPatch(typeof(CraftingStation), "GetStationBuildRange")] private static bool GetStationBuildRange(CraftingStation __instance, ref float __result) { if (!PhantomStationRegistry.IsPhantom(__instance)) { return true; } __result = SPConfig.BuildRange.Value; return false; } [HarmonyPrefix] [HarmonyPatch(typeof(CraftingStation), "CheckUsable")] private static bool CheckUsable(CraftingStation __instance, ref bool __result) { if (!PhantomStationRegistry.IsPhantom(__instance)) { return true; } __result = true; return false; } [HarmonyPrefix] [HarmonyPatch(typeof(CraftingStation), "InUseDistance")] private static bool InUseDistance(CraftingStation __instance, ref bool __result) { if (!PhantomStationRegistry.IsPhantom(__instance)) { return true; } __result = true; return false; } [HarmonyPrefix] [HarmonyPatch(typeof(CraftingStation), "ShowAreaMarker")] private static bool ShowAreaMarker(CraftingStation __instance) { return !PhantomStationRegistry.IsPhantom(__instance); } [HarmonyPrefix] [HarmonyPatch(typeof(CraftingStation), "HideMarker")] private static bool HideMarker(CraftingStation __instance) { return !PhantomStationRegistry.IsPhantom(__instance); } [HarmonyPrefix] [HarmonyPatch(typeof(CraftingStation), "GetExtensions")] private static bool GetExtensions(CraftingStation __instance, ref List __result) { if (!PhantomStationRegistry.IsPhantom(__instance)) { return true; } __result = __instance.m_attachedExtensions; return false; } } } namespace StationPacks.Core { internal sealed class DebugCommands : ConsoleCommand { public override string Name => "stationpacks"; public override string Help => "stationpacks - StationPacks dev diagnostics"; public override List CommandOptionList() { return new List { "give", "phantoms", "invariant", "stations", "buildstations", "meshes" }; } public static void Register() { CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new DebugCommands()); } public override void Run(string[] args) { if (!SPConfig.DevTools.Value) { Console.instance.Print("StationPacks dev tools are off. Enable 'Enable dev tools' in the config to use these commands."); return; } switch ((args.Length != 0) ? args[0].ToLowerInvariant() : "phantoms") { case "give": Give(); break; case "phantoms": Phantoms(); break; case "invariant": Invariant(); break; case "stations": NearbyStations(); break; case "buildstations": ListBuildStations(); break; case "meshes": ListMeshes(args); break; default: Console.instance.Print(((ConsoleCommand)this).Help); break; } } private static void Give() { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } List list = new List(); foreach (PackDefinition item in PackDefinition.All) { if ((Object)(object)ObjectDB.instance.GetItemPrefab(item.PrefabName) == (Object)null) { Console.instance.Print("" + item.PrefabName + " not in ObjectDB."); continue; } ((Humanoid)localPlayer).GetInventory().AddItem(item.PrefabName, 1, 1, 0, 0L, "", false); list.Add(item.DisplayName); } Console.instance.Print("Gave: " + string.Join(", ", list) + ""); } private static void Phantoms() { Console.instance.Print("StationPacks phantoms"); foreach (PackDefinition item in PackDefinition.All) { string text = PhantomStationRegistry.StationNameFor(item.StationPrefab); string text2 = (((Object)(object)((text == null) ? null : PhantomStationRegistry.Get(text)) == (Object)null) ? "MISSING" : "ok"); Console.instance.Print(string.Format(" {0,-20} {1,-22} {2,-24} {3}", item.DisplayName, item.StationPrefab, text ?? "?", text2)); } } private static void Invariant() { List allStations = CraftingStation.m_allStations; int num = allStations.Count(PhantomStationRegistry.IsPhantom); Console.instance.Print($"m_allStations.Count = {allStations.Count}"); Console.instance.Print((num == 0) ? "OK: no phantom is registered. Station extensions cannot re-target onto a pack." : $"LEAK: {num} phantom(s) in m_allStations. Real station levels are at risk."); } private static void NearbyStations() { Player player = Player.m_localPlayer; if ((Object)(object)player == (Object)null) { return; } List list = CraftingStation.m_allStations.Where((CraftingStation s) => (Object)(object)s != (Object)null && Vector3.Distance(((Component)s).transform.position, ((Component)player).transform.position) < 30f).ToList(); if (list.Count == 0) { Console.instance.Print("No real crafting stations within 30m."); return; } Console.instance.Print("Real stations within 30m"); foreach (CraftingStation item in list) { Console.instance.Print($" {item.m_name,-24} level={item.GetLevel(true)} extensions={item.GetExtensions().Count}"); } } private static void ListBuildStations() { ZNetScene instance = ZNetScene.instance; if ((Object)(object)instance == (Object)null) { Print("ZNetScene not ready."); return; } Dictionary dictionary = new Dictionary(); foreach (GameObject prefab in instance.m_prefabs) { Piece val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent() : null); CraftingStation val2 = (((Object)(object)val != (Object)null) ? val.m_craftingStation : null); if (!((Object)(object)val2 == (Object)null) && !string.IsNullOrEmpty(val2.m_name)) { dictionary.TryGetValue(val2.m_name, out var value); dictionary[val2.m_name] = value + 1; } } Print("=== stations that gate building (piece count) ==="); foreach (KeyValuePair item in dictionary.OrderByDescending((KeyValuePair k) => k.Value)) { Print($" {item.Key,-28} {item.Value} piece(s)"); } Print((dictionary.Count == 0) ? " (none found)" : $" {dictionary.Count} station(s) gate building."); } private static void ListMeshes(string[] args) { //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) if (args.Length < 2) { Print("Usage: stationpacks meshes [all]"); return; } GameObject prefab = PrefabManager.Instance.GetPrefab(args[1]); if ((Object)(object)prefab == (Object)null) { Console.instance.Print("No prefab named '" + args[1] + "'."); return; } bool flag = args.Length > 2 && args[2].ToLowerInvariant() == "all"; HashSet hashSet = new HashSet(PackVisual.PickedPartNames(prefab, null)); Print("=== mesh parts of " + args[1] + " (" + (flag ? "all" : "used") + ") ==="); int num = 0; int num2 = 0; Renderer[] componentsInChildren = prefab.GetComponentsInChildren(true); foreach (Renderer val in componentsInChildren) { if (!(val is MeshRenderer) && !(val is SkinnedMeshRenderer)) { continue; } SkinnedMeshRenderer val2 = (SkinnedMeshRenderer)(object)((val is SkinnedMeshRenderer) ? val : null); object obj; if (val2 == null) { MeshFilter component = ((Component)val).GetComponent(); obj = ((component != null) ? component.sharedMesh : null); } else { obj = val2.sharedMesh; } Mesh val3 = (Mesh)obj; if (!((Object)(object)val3 == (Object)null)) { bool flag2 = hashSet.Contains(((Object)((Component)val).gameObject).name); if (!flag2 && !flag) { num2++; continue; } Bounds bounds = val3.bounds; Vector3 size = ((Bounds)(ref bounds)).size; string text = ((val is SkinnedMeshRenderer) ? "skin" : "mesh"); string text2 = (flag2 ? "USED " : (((Object)((Component)val).gameObject).name.ToLowerInvariant().Contains("destruction") ? "destr" : "off ")); Print($" [{text2}][{text}] {((Object)((Component)val).gameObject).name,-28} {size.x:0.##} x {size.y:0.##} x {size.z:0.##}"); num++; } } Print($" {num} shown" + ((num2 > 0) ? $", {num2} hidden (add 'all')." : ".")); } private static void Print(string line) { if ((Object)(object)Console.instance != (Object)null) { Console.instance.Print(line); } Plugin.Log.LogInfo((object)("[cmd] " + line)); } } public static class EquippedPackResolver { private static readonly Dictionary ByItemName = new Dictionary(); public static void Register(PackDefinition def) { ByItemName[def.NameToken] = def; } public static PackDefinition DefinitionOf(ItemData item) { if (item == null || !ByItemName.TryGetValue(item.m_shared.m_name, out var value)) { return null; } return value; } public static ItemData TryGetPack(Player player, string stationName) { if ((Object)(object)player == (Object)null || string.IsNullOrEmpty(stationName)) { return null; } switch (SPConfig.Slot.Value) { case SlotMode.AnyInventory: { Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory == null) { return null; } foreach (ItemData allItem in inventory.GetAllItems()) { if (Matches(allItem, stationName)) { return allItem; } } return null; } case SlotMode.Shoulder: if (!Matches(((Humanoid)player).m_shoulderItem, stationName)) { return null; } return ((Humanoid)player).m_shoulderItem; default: if (!Matches(((Humanoid)player).m_utilityItem, stationName)) { return null; } return ((Humanoid)player).m_utilityItem; } } private static bool Matches(ItemData item, string stationName) { PackDefinition packDefinition = DefinitionOf(item); if (packDefinition == null) { return false; } if (item.m_durability <= 0f) { return false; } return PhantomStationRegistry.StationNameFor(packDefinition.StationPrefab) == stationName; } } internal sealed class PackBackTag : MonoBehaviour { public bool Bound; public Transform Source; public float TargetScale = 0.16f; public Vector3 TargetOffset = Vector3.zero; public Vector3 TargetEuler = Vector3.zero; private void LateUpdate() { if (Bound && (Object)(object)Source == (Object)null) { Object.Destroy((Object)(object)((Component)this).gameObject); } } } public static class PackCharge { private static string _grantedStation; private static int _grantedFrame = -1; public static void NoteGrant(string stationName) { _grantedStation = stationName; _grantedFrame = Time.frameCount; } private static bool GrantedThisFrame(string stationName) { if (_grantedFrame == Time.frameCount) { return _grantedStation == stationName; } return false; } public static bool SpendFor(Player player, Piece piece, float cost) { if ((Object)(object)player == (Object)null || (Object)(object)piece == (Object)null || cost <= 0f) { return false; } if ((Object)(object)piece.m_craftingStation == (Object)null) { return false; } string name = piece.m_craftingStation.m_name; if (!GrantedThisFrame(name)) { return false; } ItemData val = EquippedPackResolver.TryGetPack(player, name); if (val == null) { return false; } float durability = val.m_durability; val.m_durability = Mathf.Max(0f, durability - cost); if (val.m_durability <= 0f && durability > 0f) { ((Character)player).Message((MessageType)2, "$sp_pack_depleted", 0, (Sprite)null); } else if (SPConfig.ShowChargeMessages.Value) { ((Character)player).Message((MessageType)1, Localization.instance.Localize(val.m_shared.m_name) + " " + $"{Mathf.CeilToInt(val.m_durability)}/{Mathf.CeilToInt(val.GetMaxDurability())}", 0, (Sprite)null); } return true; } } public sealed class PackDefinition { public string PrefabName; public string ClonedCape; public string StationPrefab; public string CraftedAt; public int MinStationLevel; public string RepairedAt; public string DisplayName; public string Description; public float Weight; public float MovementModifier; public RequirementConfig[] Requirements; public string BackMeshDonor; public float BackScale = 0.0032f; public Vector3 BackOffset = new Vector3(0f, -0.0007f, -0.0001f); public Vector3 BackEuler = new Vector3(55f, 160f, -6.3f); public string Tag; public string[] BackIncludeParts; public string[] BackExcludeParts; public static readonly List All = new List { new PackDefinition { PrefabName = "SP_PackWorkbench", Tag = "workbench", ClonedCape = "CapeDeerHide", StationPrefab = CraftingStations.Workbench, CraftedAt = CraftingStations.Workbench, MinStationLevel = 1, RepairedAt = CraftingStations.Workbench, DisplayName = "Workbench Pack", Description = "A carpenter's bench lashed to a hide frame. Heavy, awkward, and it means you never have to plant another bench mid-build.", Weight = 8f, MovementModifier = -0.03f, Requirements = (RequirementConfig[])(object)new RequirementConfig[3] { new RequirementConfig("Wood", 20, 10, true), new RequirementConfig("LeatherScraps", 8, 4, true), new RequirementConfig("Flint", 6, 3, true) } }, new PackDefinition { PrefabName = "SP_PackStonecutter", Tag = "stonecutter", ClonedCape = "CapeTrollHide", StationPrefab = CraftingStations.Stonecutter, CraftedAt = CraftingStations.Forge, MinStationLevel = 1, RepairedAt = CraftingStations.Stonecutter, DisplayName = "Stonecutter Pack", Description = "Chisels, saws and a dust-caked apron. The stone will not cut itself, but at least now it will cut where you are standing.", Weight = 14f, MovementModifier = -0.06f, Requirements = (RequirementConfig[])(object)new RequirementConfig[3] { new RequirementConfig("Wood", 10, 5, true), new RequirementConfig("Iron", 8, 4, true), new RequirementConfig("Stone", 20, 10, true) } }, new PackDefinition { PrefabName = "SP_PackForge", Tag = "forge", ClonedCape = "CapeWolf", StationPrefab = CraftingStations.Forge, CraftedAt = CraftingStations.Forge, MinStationLevel = 2, RepairedAt = CraftingStations.Forge, DisplayName = "Forge Pack", Description = "A field anvil and a bellows you will regret carrying uphill.", Weight = 16f, MovementModifier = -0.07f, BackScale = 0.0032f, BackOffset = new Vector3(0f, -0.0001f, -0.0001f), BackEuler = new Vector3(55f, 160f, -6.3f), Requirements = (RequirementConfig[])(object)new RequirementConfig[3] { new RequirementConfig("Bronze", 8, 4, true), new RequirementConfig("DeerHide", 6, 3, true), new RequirementConfig("Wood", 10, 5, true) } }, new PackDefinition { PrefabName = "SP_PackArtisan", Tag = "artisan", ClonedCape = "CapeLinen", StationPrefab = CraftingStations.ArtisanTable, CraftedAt = CraftingStations.ArtisanTable, MinStationLevel = 1, RepairedAt = CraftingStations.ArtisanTable, DisplayName = "Artisan Pack", Description = "Fine tools, rolled in oilcloth. For work that does not forgive a shaking hand.", Weight = 12f, MovementModifier = -0.05f, BackScale = 0.0032f, BackOffset = new Vector3(0f, -0.0011f, -0.0001f), BackEuler = new Vector3(55f, 160f, -6.3f), Requirements = (RequirementConfig[])(object)new RequirementConfig[3] { new RequirementConfig("Iron", 8, 4, true), new RequirementConfig("Silver", 4, 2, true), new RequirementConfig("WolfPelt", 6, 3, true) } }, new PackDefinition { PrefabName = "SP_PackBlackForge", Tag = "blackforge", ClonedCape = "CapeFeather", StationPrefab = CraftingStations.BlackForge, CraftedAt = CraftingStations.BlackForge, MinStationLevel = 1, RepairedAt = CraftingStations.BlackForge, DisplayName = "Black Forge Pack", Description = "Black metal, still warm. It hums against your spine as you walk.", Weight = 20f, MovementModifier = -0.08f, BackScale = 0.0032f, BackOffset = new Vector3(0.0002f, 0.001f, 0.0001f), BackEuler = new Vector3(-78.7f, -11.3f, 1.2f), Requirements = (RequirementConfig[])(object)new RequirementConfig[2] { new RequirementConfig("BlackMetal", 12, 6, true), new RequirementConfig("YggdrasilWood", 8, 4, true) } }, new PackDefinition { PrefabName = "SP_PackGaldr", Tag = "galdr", ClonedCape = "CapeLox", StationPrefab = CraftingStations.GaldrTable, CraftedAt = CraftingStations.GaldrTable, MinStationLevel = 1, RepairedAt = CraftingStations.GaldrTable, DisplayName = "Galdr Pack", Description = "Runes stitched into the lining. Carrying it feels like being watched.", Weight = 10f, MovementModifier = -0.04f, BackScale = 0.0032f, BackOffset = new Vector3(0.0008f, 0.001f, -0.0016f), BackEuler = new Vector3(-78.7f, -11.3f, 1.2f), Requirements = (RequirementConfig[])(object)new RequirementConfig[3] { new RequirementConfig("Eitr", 20, 10, true), new RequirementConfig("YggdrasilWood", 8, 4, true), new RequirementConfig("LinenThread", 10, 5, true) } } }; public string IconResource => "StationPacks.Assets.icon_" + Tag + ".png"; public string EffectiveBackMeshDonor { get { if (!string.IsNullOrEmpty(BackMeshDonor)) { return BackMeshDonor; } return StationPrefab; } } public string NameToken => "$sp_" + PrefabName.ToLowerInvariant(); public string DescToken => NameToken + "_desc"; } public static class PackRegistry { public static void Register() { //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_0141: 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_0152: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Expected O, but got Unknown //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Expected O, but got Unknown foreach (PackDefinition item in PackDefinition.All) { GameObject val = PrefabManager.Instance.CreateClonedPrefab(item.PrefabName, item.ClonedCape); if ((Object)(object)val == (Object)null) { Plugin.Log.LogError((object)("Could not clone '" + item.ClonedCape + "' for " + item.PrefabName + "; skipping.")); continue; } SharedData shared = val.GetComponent().m_itemData.m_shared; shared.m_name = item.NameToken; shared.m_description = item.DescToken; shared.m_itemType = (ItemType)18; shared.m_weight = item.Weight; shared.m_movementModifier = item.MovementModifier; shared.m_useDurability = true; shared.m_canBeReparied = true; shared.m_maxDurability = SPConfig.MaxDurability.Value; shared.m_durabilityPerLevel = SPConfig.DurabilityPerLevel.Value; shared.m_durabilityDrain = 0f; shared.m_useDurabilityDrain = 0f; StripInheritedPerks(shared, item); shared.m_maxQuality = 3; Sprite val2 = LoadIcon(item); if ((Object)(object)val2 != (Object)null) { shared.m_icons = (Sprite[])(object)new Sprite[1] { val2 }; } PackVisual.Apply(val, item); ItemConfig val3 = new ItemConfig { Name = item.NameToken, Description = item.DescToken, CraftingStation = item.CraftedAt, MinStationLevel = item.MinStationLevel, RepairStation = item.RepairedAt, Requirements = item.Requirements }; ItemManager.Instance.AddItem(new CustomItem(val, true, val3)); EquippedPackResolver.Register(item); Plugin.Log.LogInfo((object)("Registered " + item.DisplayName + " (clone of " + item.ClonedCape + ").")); } AddLocalization(); } private static void StripInheritedPerks(SharedData shared, PackDefinition def) { shared.m_armor = 0f; shared.m_armorPerLevel = 0f; shared.m_damageModifiers = new List(); shared.m_equipStatusEffect = null; shared.m_setStatusEffect = null; shared.m_setName = string.Empty; shared.m_setSize = 0; shared.m_eitrRegenModifier = 0f; shared.m_heatResistanceModifier = 0f; shared.m_jumpStaminaModifier = 0f; shared.m_attackStaminaModifier = 0f; shared.m_blockStaminaModifier = 0f; shared.m_dodgeStaminaModifier = 0f; shared.m_swimStaminaModifier = 0f; shared.m_sneakStaminaModifier = 0f; shared.m_runStaminaModifier = 0f; shared.m_homeItemsStaminaModifier = 0f; shared.m_weight = def.Weight; shared.m_movementModifier = def.MovementModifier; } private static Sprite LoadIcon(PackDefinition def) { //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) try { using Stream stream = typeof(PackRegistry).Assembly.GetManifestResourceStream(def.IconResource); if (stream == null) { Plugin.Log.LogWarning((object)(def.DisplayName + ": icon resource '" + def.IconResource + "' not found.")); return null; } byte[] array = new byte[stream.Length]; stream.Read(array, 0, array.Length); Texture2D val = AssetUtils.LoadImage(array); if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)(def.DisplayName + ": failed to decode icon PNG.")); return null; } ((Texture)val).filterMode = (FilterMode)1; return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f)); } catch (Exception ex) { Plugin.Log.LogWarning((object)(def.DisplayName + ": icon load threw " + ex.GetType().Name + ": " + ex.Message)); return null; } } private static void AddLocalization() { Dictionary dictionary = new Dictionary { { "sp_pack_depleted", "Your pack is spent. Repair it at the station it replaces." } }; foreach (PackDefinition item in PackDefinition.All) { dictionary[item.NameToken.TrimStart(new char[1] { '$' })] = item.DisplayName; dictionary[item.DescToken.TrimStart(new char[1] { '$' })] = item.Description; } CustomLocalization localization = LocalizationManager.Instance.GetLocalization(); string text = "English"; localization.AddTranslation(ref text, dictionary); } } public static class PackVisual { private struct Pick { public Mesh mesh; public Material[] mats; public Transform src; } private const string BackNode = "SP_BackMesh"; public static void Apply(GameObject packPrefab, PackDefinition def) { //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Expected O, but got Unknown //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_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0160: 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_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) if (!SPConfig.ShowBackMesh.Value) { return; } Transform val = FindAttachSkin(packPrefab); if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)(def.DisplayName + ": no attach_skin node on the cloned cape; back mesh skipped (pack still works, just looks like the cape).")); return; } GameObject prefab = PrefabManager.Instance.GetPrefab(def.EffectiveBackMeshDonor); if ((Object)(object)prefab == (Object)null) { Plugin.Log.LogWarning((object)(def.DisplayName + ": donor prefab '" + def.EffectiveBackMeshDonor + "' not found; back mesh skipped.")); return; } List list = CollectPicks(prefab, def); if (list.Count == 0) { Plugin.Log.LogWarning((object)(def.DisplayName + ": donor '" + def.EffectiveBackMeshDonor + "' has no mesh to borrow; back mesh skipped.")); return; } GameObject val2 = new GameObject("SP_BackMesh"); PackBackTag packBackTag = val2.AddComponent(); packBackTag.TargetScale = def.BackScale; packBackTag.TargetOffset = def.BackOffset; packBackTag.TargetEuler = def.BackEuler; val2.transform.SetParent(((Component)val).transform, false); Transform transform = prefab.transform; foreach (Pick item in list) { GameObject val3 = new GameObject(((Object)((Component)item.src).gameObject).name); val3.transform.SetParent(val2.transform, false); val3.transform.localPosition = transform.InverseTransformPoint(item.src.position); val3.transform.localRotation = Quaternion.Inverse(transform.rotation) * item.src.rotation; val3.transform.localScale = item.src.lossyScale; val3.AddComponent().sharedMesh = item.mesh; MeshRenderer obj = val3.AddComponent(); ((Renderer)obj).sharedMaterials = ((IEnumerable)item.mats).Select((Func)((Material m) => ((Object)(object)m != (Object)null) ? new Material(m) : ((Material)null))).ToArray(); ((Renderer)obj).shadowCastingMode = (ShadowCastingMode)1; } int count = list.Count; if (SPConfig.HideCape.Value) { SkinnedMeshRenderer[] componentsInChildren = ((Component)val).GetComponentsInChildren(true); for (int num = 0; num < componentsInChildren.Length; num++) { ((Renderer)componentsInChildren[num]).enabled = false; } } Plugin.Log.LogInfo((object)($"{def.DisplayName}: mounted {count} mesh part(s) from " + "'" + def.EffectiveBackMeshDonor + "'.")); } public static List PickedPartNames(GameObject donor, PackDefinition def) { return (from p in CollectPicks(donor, def) select ((Object)((Component)p.src).gameObject).name).ToList(); } private static List CollectPicks(GameObject donor, PackDefinition def) { List list = Renderers(donor, def, requireActive: true); if (list.Count <= 0) { return Renderers(donor, def, requireActive: false); } return list; } private static List Renderers(GameObject donor, PackDefinition def, bool requireActive) { HashSet hashSet = LodDrops(donor); List list = new List(); Renderer[] componentsInChildren = donor.GetComponentsInChildren(!requireActive); foreach (Renderer val in componentsInChildren) { if ((val is MeshRenderer || val is SkinnedMeshRenderer) && (!requireActive || val.enabled) && !hashSet.Contains(val) && !IsDestruction(((Component)val).transform, donor.transform) && KeepPart(((Object)((Component)val).gameObject).name, def)) { SkinnedMeshRenderer val2 = (SkinnedMeshRenderer)(object)((val is SkinnedMeshRenderer) ? val : null); object obj; if (val2 == null) { MeshFilter component = ((Component)val).GetComponent(); obj = ((component != null) ? component.sharedMesh : null); } else { obj = val2.sharedMesh; } Mesh val3 = (Mesh)obj; if (!((Object)(object)val3 == (Object)null)) { list.Add(new Pick { mesh = val3, mats = val.sharedMaterials, src = ((Component)val).transform }); } } } return list; } private static bool IsDestruction(Transform t, Transform stopAt) { Transform val = t; while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)stopAt.parent) { if (((Object)val).name.ToLowerInvariant().Contains("destruction")) { return true; } val = val.parent; } return false; } private static HashSet LodDrops(GameObject donor) { HashSet hashSet = new HashSet(); LODGroup[] componentsInChildren = donor.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { LOD[] lODs = componentsInChildren[i].GetLODs(); for (int j = 1; j < lODs.Length; j++) { Renderer[] renderers = lODs[j].renderers; foreach (Renderer val in renderers) { if ((Object)(object)val != (Object)null) { hashSet.Add(val); } } } } return hashSet; } private static bool KeepPart(string partName, PackDefinition def) { if (def == null) { return true; } string name = partName.ToLowerInvariant(); if (def.BackExcludeParts != null && def.BackExcludeParts.Any((string x) => name.Contains(x.ToLowerInvariant()))) { return false; } if (def.BackIncludeParts != null && def.BackIncludeParts.Length != 0) { return def.BackIncludeParts.Any((string x) => name.Contains(x.ToLowerInvariant())); } return true; } private static Transform FindAttachSkin(GameObject prefab) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown foreach (Transform item in prefab.transform) { Transform val = item; string name = ((Object)((Component)val).gameObject).name; if (name.StartsWith("attach_") && name.Substring("attach_".Length).StartsWith("skin")) { return val; } } return null; } } public static class PhantomStationRegistry { private static readonly Dictionary ByStationName = new Dictionary(); private static readonly Dictionary PrefabToStationName = new Dictionary(); private static readonly HashSet Phantoms = new HashSet(); private static GameObject _holder; public static bool IsPhantom(CraftingStation station) { if ((Object)(object)station != (Object)null) { return Phantoms.Contains(station); } return false; } public static string StationNameFor(string stationPrefab) { if (!PrefabToStationName.TryGetValue(stationPrefab, out var value)) { return null; } return value; } public static CraftingStation Get(string stationName) { if (!ByStationName.TryGetValue(stationName, out var value) || !((Object)(object)value != (Object)null)) { return null; } return value; } public static void Build() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) ZNetScene instance = ZNetScene.instance; if ((Object)(object)instance == (Object)null) { Plugin.Log.LogWarning((object)"ZNetScene not ready; phantom stations not built."); return; } int count = CraftingStation.m_allStations.Count; Clear(); _holder = new GameObject("StationPacks_Phantoms"); _holder.SetActive(false); Object.DontDestroyOnLoad((Object)(object)_holder); foreach (GameObject prefab in instance.m_prefabs) { if ((Object)(object)prefab == (Object)null) { continue; } CraftingStation component = prefab.GetComponent(); if (!((Object)(object)component == (Object)null) && !string.IsNullOrEmpty(component.m_name) && !ByStationName.ContainsKey(component.m_name)) { GameObject val = new GameObject("SP_Phantom_" + ((Object)prefab).name); val.transform.SetParent(_holder.transform, false); CraftingStation val2 = val.AddComponent(); CopyFrom(component, val2); ByStationName[val2.m_name] = val2; PrefabToStationName[((Object)prefab).name] = val2.m_name; Phantoms.Add(val2); if (SPConfig.Verbose.Value) { Plugin.Log.LogInfo((object)(" phantom: " + ((Object)prefab).name + " -> m_name '" + val2.m_name + "'")); } } } int count2 = CraftingStation.m_allStations.Count; if (count2 != count) { Plugin.Log.LogError((object)($"INVARIANT VIOLATED: m_allStations changed {count} -> {count2} while building phantoms. " + "A phantom registered itself; station extensions may re-target onto it. Disabling grants.")); Clear(); } else { Plugin.Log.LogInfo((object)$"Built {ByStationName.Count} phantom stations; m_allStations unchanged at {count2}."); ValidatePackDefinitions(); } } private static void ValidatePackDefinitions() { foreach (PackDefinition item in PackDefinition.All) { if (!PrefabToStationName.ContainsKey(item.StationPrefab)) { Plugin.Log.LogError((object)(item.DisplayName + " points at station prefab '" + item.StationPrefab + "', which no loaded prefab provides. This pack will never grant anything. Did the game rename it?")); } } } private static void CopyFrom(CraftingStation src, CraftingStation dst) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Expected O, but got Unknown //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Expected O, but got Unknown dst.m_name = src.m_name; dst.m_icon = src.m_icon; dst.m_craftingSkill = src.m_craftingSkill; dst.m_useDistance = src.m_useDistance; dst.m_useAnimation = src.m_useAnimation; dst.m_rangeBuild = SPConfig.BuildRange.Value; dst.m_buildRange = SPConfig.BuildRange.Value; dst.m_extraRangePerLevel = 0f; dst.m_craftRequireRoof = false; dst.m_craftRequireFire = false; dst.m_discoverRange = 0f; dst.m_attachedExtensions = new List(); dst.m_craftItemEffects = new EffectList(); dst.m_craftItemDoneEffects = new EffectList(); dst.m_repairItemDoneEffects = new EffectList(); dst.m_areaMarker = null; dst.m_areaMarkerCircle = null; dst.m_inUseObject = null; dst.m_haveFireObject = null; dst.m_roofCheckPoint = null; dst.m_connectionPoint = null; dst.m_effectAreaCollider = null; dst.m_nview = null; } private static void Clear() { ByStationName.Clear(); PrefabToStationName.Clear(); Phantoms.Clear(); if ((Object)(object)_holder != (Object)null) { Object.Destroy((Object)(object)_holder); } _holder = null; } } internal sealed class TuningPanel : MonoBehaviour { private bool _open; private bool _seeded; private Rect _win = new Rect(20f, 60f, 320f, 430f); private float _scale = 0.002f; private Vector3 _pos; private Vector3 _rot; private void Update() { //IL_0019: 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) if (!SPConfig.DevTools.Value) { _open = false; return; } KeyboardShortcut value = SPConfig.TuneKey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { _open = !_open; if (_open) { Seed(); } } } private List Instances() { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return null; } return (from t in ((Component)localPlayer).GetComponentsInChildren(true) select ((Component)t).transform).ToList(); } private void Seed() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0035: 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_0041: 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) List list = Instances(); if (list == null || list.Count == 0) { _seeded = false; return; } Transform val = list[0]; _scale = val.localScale.x; _pos = val.localPosition; _rot = val.localEulerAngles; if (_rot.x > 180f) { _rot.x -= 360f; } if (_rot.y > 180f) { _rot.y -= 360f; } if (_rot.z > 180f) { _rot.z -= 360f; } _seeded = true; } private void OnGUI() { //IL_001c: 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_003c: Expected O, but got Unknown //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) if (_open && SPConfig.DevTools.Value) { _win = GUILayout.Window(23164, _win, new WindowFunction(DrawWindow), "StationPacks - back mesh", Array.Empty()); } } private void DrawWindow(int id) { //IL_01b1: 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_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) List list = Instances(); if (list == null || list.Count == 0) { GUILayout.Label("Equip a pack to tune it.", Array.Empty()); if (GUILayout.Button("Close", Array.Empty())) { _open = false; } GUI.DragWindow(); return; } if (!_seeded) { Seed(); } _scale = Slider("Scale", _scale, 0.0005f, 0.02f, "0.####"); GUILayout.Space(4f); _pos.x = Slider("Pos X (left/right)", _pos.x, -0.03f, 0.03f, "0.####"); _pos.y = Slider("Pos Y (up back)", _pos.y, -0.03f, 0.03f, "0.####"); _pos.z = Slider("Pos Z (from spine)", _pos.z, -0.03f, 0.03f, "0.####"); GUILayout.Space(4f); _rot.x = Slider("Pitch", _rot.x, -180f, 180f, "0.#"); _rot.y = Slider("Yaw", _rot.y, -180f, 180f, "0.#"); _rot.z = Slider("Roll", _rot.z, -180f, 180f, "0.#"); foreach (Transform item in list) { item.localScale = Vector3.one * _scale; item.localPosition = _pos; item.localRotation = Quaternion.Euler(_rot); } GUILayout.Space(8f); GUILayout.BeginHorizontal(Array.Empty()); if (GUILayout.Button("Resync", Array.Empty())) { Seed(); } if (GUILayout.Button("Copy bake line", Array.Empty())) { CopyBakeLine(); } if (GUILayout.Button("Close", Array.Empty())) { _open = false; } GUILayout.EndHorizontal(); GUILayout.Label(BakeLine(), Array.Empty()); GUI.DragWindow(); } private static float Slider(string label, float value, float min, float max, string fmt) { GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label(label, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(140f) }); GUILayout.Label(value.ToString(fmt), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) }); GUILayout.EndHorizontal(); return GUILayout.HorizontalSlider(value, min, max, Array.Empty()); } private string BakeLine() { return $"BackScale={_scale:0.####} BackOffset=({_pos.x:0.####},{_pos.y:0.####},{_pos.z:0.####}) " + $"BackEuler=({_rot.x:0.#},{_rot.y:0.#},{_rot.z:0.#})"; } private void CopyBakeLine() { string text = (GUIUtility.systemCopyBuffer = BakeLine()); if ((Object)(object)Console.instance != (Object)null) { Console.instance.Print("copied: " + text + ""); } Plugin.Log.LogInfo((object)("[tune] " + text)); } } } namespace StationPacks.Config { public enum SlotMode { Utility, Shoulder, AnyInventory } public static class SPConfig { public static ConfigEntry Slot; public static ConfigEntry Verbose; public static ConfigEntry ShowChargeMessages; public static ConfigEntry ShowBackMesh; public static ConfigEntry HideCape; public static ConfigEntry DevTools; public static ConfigEntry TuneKey; public static ConfigEntry MaxDurability; public static ConfigEntry DurabilityPerLevel; public static ConfigEntry PlaceCost; public static ConfigEntry RemoveCost; public static ConfigEntry RepairCost; public static ConfigEntry BuildRange; public static void Bind(ConfigFile cfg) { //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Expected O, but got Unknown //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Expected O, but got Unknown //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Expected O, but got Unknown //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Expected O, but got Unknown //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Expected O, but got Unknown //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Expected O, but got Unknown //IL_0207: Unknown result type (might be due to invalid IL or missing references) Slot = cfg.Bind("1 - General", "Slot mode", SlotMode.Utility, "Where a station pack must sit to work.\nUtility: the vanilla utility slot (shared with the Megingjord belt and Wishbone). One pack at a time, and your cape slot stays free for survival capes.\nShoulder: the vanilla cape slot - you give up your cape instead of your belt.\nAnyInventory: just carry it anywhere. No opportunity cost; effectively easy mode."); Verbose = cfg.Bind("1 - General", "Verbose logging", false, "Log phantom-station construction and every grant. Noisy; for debugging only."); ShowChargeMessages = cfg.Bind("1 - General", "Show charge messages", true, "Show a top-left message with the pack's remaining charge as it drains."); ShowBackMesh = cfg.Bind("3 - Appearance", "Show station on back", true, "Mount a shrunk copy of the emulated station on your back, so each pack looks distinct.\nTurn off to keep the plain cape look."); HideCape = cfg.Bind("3 - Appearance", "Hide the cape", true, "Hide the cape's own cloth so only the backpack shows. Off keeps the cape draping behind\nthe pack. Only matters when 'Show station on back' is on."); MaxDurability = cfg.Bind("2 - Balance", "Max charge", 100f, new ConfigDescription("Charge of a quality-1 pack. One point is spent per piece placed.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 10000f), Array.Empty())); DurabilityPerLevel = cfg.Bind("2 - Balance", "Charge per upgrade level", 50f, new ConfigDescription("Extra charge for each quality level above 1.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 10000f), Array.Empty())); PlaceCost = cfg.Bind("2 - Balance", "Charge per placement", 1f, new ConfigDescription("Charge spent when the pack is what allowed a piece to be placed.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); RemoveCost = cfg.Bind("2 - Balance", "Charge per deconstruct", 0.5f, new ConfigDescription("Charge spent when the pack is what allowed a piece to be removed.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); RepairCost = cfg.Bind("2 - Balance", "Charge per repair", 0.5f, new ConfigDescription("Charge spent when the pack is what allowed a piece to be repaired.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); BuildRange = cfg.Bind("2 - Balance", "Build range", 20f, new ConfigDescription("Radius the pack projects around you. Vanilla workbench is 20.", (AcceptableValueBase)(object)new AcceptableValueRange(4f, 64f), Array.Empty())); DevTools = cfg.Bind("9 - Dev", "Enable dev tools", false, "Enables the in-game dev tooling: the 'stationpacks' console commands (give, meshes, back, phantoms, invariant, ...) and the back-mesh tuning panel. Off for normal play."); TuneKey = cfg.Bind("9 - Dev", "Tuning panel key", new KeyboardShortcut((KeyCode)287, Array.Empty()), "Opens the live slider panel for positioning the pack on your back. Only works when 'Enable dev tools' is on."); } } } namespace StationPacks.Compat { public static class AdventureBackpacksCompat { private const string Guid = "vapok.mods.adventurebackpacks"; public static bool Installed => Chainloader.PluginInfos.ContainsKey("vapok.mods.adventurebackpacks"); public static void ReportOnce() { if (Installed) { if (SPConfig.Slot.Value == SlotMode.Shoulder) { Plugin.Log.LogInfo((object)"AdventureBackpacks detected, and StationPacks 'Slot mode' is set to Shoulder - both want the cape slot, so you can wear one or the other. Switch Slot mode to Utility (the default) to wear a backpack and a station pack together."); } else { Plugin.Log.LogInfo((object)"AdventureBackpacks detected. Station packs use the utility slot, so the two coexist - backpack on your back, station pack on your belt."); } } } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }