Decompiled source of StationPacks v0.3.0

plugins\StationPacks.dll

Decompiled 10 hours ago
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<TuningPanel>();
			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<PackBackTag>(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<StationExtension> __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 <give|phantoms|invariant|stations|buildstations|meshes> - StationPacks dev diagnostics";

		public override List<string> CommandOptionList()
		{
			return new List<string> { "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("<color=orange>StationPacks dev tools are off. Enable 'Enable dev tools' in the config to use these commands.</color>");
				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<string> list = new List<string>();
			foreach (PackDefinition item in PackDefinition.All)
			{
				if ((Object)(object)ObjectDB.instance.GetItemPrefab(item.PrefabName) == (Object)null)
				{
					Console.instance.Print("<color=red>" + item.PrefabName + " not in ObjectDB.</color>");
					continue;
				}
				((Humanoid)localPlayer).GetInventory().AddItem(item.PrefabName, 1, 1, 0, 0L, "", false);
				list.Add(item.DisplayName);
			}
			Console.instance.Print("<color=lime>Gave: " + string.Join(", ", list) + "</color>");
		}

		private static void Phantoms()
		{
			Console.instance.Print("<color=yellow>StationPacks phantoms</color>");
			foreach (PackDefinition item in PackDefinition.All)
			{
				string text = PhantomStationRegistry.StationNameFor(item.StationPrefab);
				string text2 = (((Object)(object)((text == null) ? null : PhantomStationRegistry.Get(text)) == (Object)null) ? "<color=red>MISSING</color>" : "<color=lime>ok</color>");
				Console.instance.Print(string.Format("  {0,-20} {1,-22} {2,-24} {3}", item.DisplayName, item.StationPrefab, text ?? "?", text2));
			}
		}

		private static void Invariant()
		{
			List<CraftingStation> allStations = CraftingStation.m_allStations;
			int num = allStations.Count(PhantomStationRegistry.IsPhantom);
			Console.instance.Print($"m_allStations.Count = {allStations.Count}");
			Console.instance.Print((num == 0) ? "<color=lime>OK: no phantom is registered. Station extensions cannot re-target onto a pack.</color>" : $"<color=red>LEAK: {num} phantom(s) in m_allStations. Real station levels are at risk.</color>");
		}

		private static void NearbyStations()
		{
			Player player = Player.m_localPlayer;
			if ((Object)(object)player == (Object)null)
			{
				return;
			}
			List<CraftingStation> 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("<color=yellow>Real stations within 30m</color>");
			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<string, int> dictionary = new Dictionary<string, int>();
			foreach (GameObject prefab in instance.m_prefabs)
			{
				Piece val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<Piece>() : 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<string, int> item in dictionary.OrderByDescending((KeyValuePair<string, int> 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 <prefabName> [all]");
				return;
			}
			GameObject prefab = PrefabManager.Instance.GetPrefab(args[1]);
			if ((Object)(object)prefab == (Object)null)
			{
				Console.instance.Print("<color=orange>No prefab named '" + args[1] + "'.</color>");
				return;
			}
			bool flag = args.Length > 2 && args[2].ToLowerInvariant() == "all";
			HashSet<string> hashSet = new HashSet<string>(PackVisual.PickedPartNames(prefab, null));
			Print("=== mesh parts of " + args[1] + " (" + (flag ? "all" : "used") + ") ===");
			int num = 0;
			int num2 = 0;
			Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(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<MeshFilter>();
					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<string, PackDefinition> ByItemName = new Dictionary<string, PackDefinition>();

		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<PackDefinition> All = new List<PackDefinition>
		{
			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<ItemDrop>().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<DamageModPair>();
			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<string, string> dictionary = new Dictionary<string, string> { { "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<Pick> 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>();
			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<MeshFilter>().sharedMesh = item.mesh;
				MeshRenderer obj = val3.AddComponent<MeshRenderer>();
				((Renderer)obj).sharedMaterials = ((IEnumerable<Material>)item.mats).Select((Func<Material, Material>)((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<SkinnedMeshRenderer>(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<string> PickedPartNames(GameObject donor, PackDefinition def)
		{
			return (from p in CollectPicks(donor, def)
				select ((Object)((Component)p.src).gameObject).name).ToList();
		}

		private static List<Pick> CollectPicks(GameObject donor, PackDefinition def)
		{
			List<Pick> list = Renderers(donor, def, requireActive: true);
			if (list.Count <= 0)
			{
				return Renderers(donor, def, requireActive: false);
			}
			return list;
		}

		private static List<Pick> Renderers(GameObject donor, PackDefinition def, bool requireActive)
		{
			HashSet<Renderer> hashSet = LodDrops(donor);
			List<Pick> list = new List<Pick>();
			Renderer[] componentsInChildren = donor.GetComponentsInChildren<Renderer>(!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<MeshFilter>();
						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<Renderer> LodDrops(GameObject donor)
		{
			HashSet<Renderer> hashSet = new HashSet<Renderer>();
			LODGroup[] componentsInChildren = donor.GetComponentsInChildren<LODGroup>(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<string, CraftingStation> ByStationName = new Dictionary<string, CraftingStation>();

		private static readonly Dictionary<string, string> PrefabToStationName = new Dictionary<string, string>();

		private static readonly HashSet<CraftingStation> Phantoms = new HashSet<CraftingStation>();

		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<CraftingStation>();
				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<CraftingStation>();
					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<StationExtension>();
			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<Transform> Instances()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return null;
			}
			return (from t in ((Component)localPlayer).GetComponentsInChildren<PackBackTag>(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<Transform> 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<GUILayoutOption>());
			}
		}

		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<Transform> list = Instances();
			if (list == null || list.Count == 0)
			{
				GUILayout.Label("Equip a pack to tune it.", Array.Empty<GUILayoutOption>());
				if (GUILayout.Button("Close", Array.Empty<GUILayoutOption>()))
				{
					_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<GUILayoutOption>());
			if (GUILayout.Button("Resync", Array.Empty<GUILayoutOption>()))
			{
				Seed();
			}
			if (GUILayout.Button("Copy bake line", Array.Empty<GUILayoutOption>()))
			{
				CopyBakeLine();
			}
			if (GUILayout.Button("Close", Array.Empty<GUILayoutOption>()))
			{
				_open = false;
			}
			GUILayout.EndHorizontal();
			GUILayout.Label(BakeLine(), Array.Empty<GUILayoutOption>());
			GUI.DragWindow();
		}

		private static float Slider(string label, float value, float min, float max, string fmt)
		{
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			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<GUILayoutOption>());
		}

		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("<color=lime>copied: " + text + "</color>");
			}
			Plugin.Log.LogInfo((object)("[tune] " + text));
		}
	}
}
namespace StationPacks.Config
{
	public enum SlotMode
	{
		Utility,
		Shoulder,
		AnyInventory
	}
	public static class SPConfig
	{
		public static ConfigEntry<SlotMode> Slot;

		public static ConfigEntry<bool> Verbose;

		public static ConfigEntry<bool> ShowChargeMessages;

		public static ConfigEntry<bool> ShowBackMesh;

		public static ConfigEntry<bool> HideCape;

		public static ConfigEntry<bool> DevTools;

		public static ConfigEntry<KeyboardShortcut> TuneKey;

		public static ConfigEntry<float> MaxDurability;

		public static ConfigEntry<float> DurabilityPerLevel;

		public static ConfigEntry<float> PlaceCost;

		public static ConfigEntry<float> RemoveCost;

		public static ConfigEntry<float> RepairCost;

		public static ConfigEntry<float> 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<SlotMode>("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<bool>("1 - General", "Verbose logging", false, "Log phantom-station construction and every grant. Noisy; for debugging only.");
			ShowChargeMessages = cfg.Bind<bool>("1 - General", "Show charge messages", true, "Show a top-left message with the pack's remaining charge as it drains.");
			ShowBackMesh = cfg.Bind<bool>("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<bool>("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<float>("2 - Balance", "Max charge", 100f, new ConfigDescription("Charge of a quality-1 pack. One point is spent per piece placed.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10000f), Array.Empty<object>()));
			DurabilityPerLevel = cfg.Bind<float>("2 - Balance", "Charge per upgrade level", 50f, new ConfigDescription("Extra charge for each quality level above 1.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10000f), Array.Empty<object>()));
			PlaceCost = cfg.Bind<float>("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<float>(0f, 100f), Array.Empty<object>()));
			RemoveCost = cfg.Bind<float>("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<float>(0f, 100f), Array.Empty<object>()));
			RepairCost = cfg.Bind<float>("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<float>(0f, 100f), Array.Empty<object>()));
			BuildRange = cfg.Bind<float>("2 - Balance", "Build range", 20f, new ConfigDescription("Radius the pack projects around you. Vanilla workbench is 20.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(4f, 64f), Array.Empty<object>()));
			DevTools = cfg.Bind<bool>("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<KeyboardShortcut>("9 - Dev", "Tuning panel key", new KeyboardShortcut((KeyCode)287, Array.Empty<KeyCode>()), "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)
		{
		}
	}
}