Decompiled source of BuildInSeatruckPlus v1.0.8

plugins/BuildInSeatruckPlus/BuildInSeatruckPlus.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Logging;
using BuildInSeatruckPlus.Buildables;
using BuildInSeatruckPlus.Patches;
using FMODUnity;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Nautilus.Assets;
using Nautilus.Assets.Gadgets;
using Nautilus.Assets.PrefabTemplates;
using Nautilus.Crafting;
using Nautilus.Handlers;
using Nautilus.Json;
using Nautilus.Options.Attributes;
using UWE;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("BuildInSeatruckPlus")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+814d0593c0c38c63b2bb09a75cd9d28c3a1442d9")]
[assembly: AssemblyProduct("BuildInSeatruckPlus")]
[assembly: AssemblyTitle("BuildInSeatruckPlus")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace BuildInSeatruckPlus
{
	[Menu("Build In Seatruck Plus")]
	public class Config : ConfigFile
	{
		[Keybind("Playback hotkey (in Seatruck / base)")]
		public KeyCode Hotkey = (KeyCode)114;

		[Slider("Long-press seconds", 0.1f, 2f, DefaultValue = 0.5f, Step = 0.05f, Format = "{0:F2}")]
		public float LongPressSeconds = 0.5f;

		[Toggle("Cheap recipe (1 Titanium) - restart required")]
		public bool CheapRecipe;

		[Toggle("Unlock buildables at start - restart required")]
		public bool UnlockBuildables;

		[Toggle("New jukeboxes start in shuffle mode")]
		public bool DefaultShuffle = true;

		[Toggle("Show 'Now playing' notifications")]
		public bool ShowTrackName = true;

		[Choice("Don't unload containers labeled this color (needs AutosortLockers)", new string[] { })]
		public UnloaderSkipColor UnloaderSkipColorChoice = UnloaderSkipColor.Red;
	}
	public enum UnloaderSkipColor
	{
		Off,
		Red,
		Yellow,
		Green,
		Blue,
		Magenta,
		White
	}
	internal class HotkeyController : MonoBehaviour
	{
		private float _downTime = -1f;

		private bool _longFired;

		private void Update()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			Config config = Plugin.Config;
			if (config == null || (Object)(object)Player.main == (Object)null)
			{
				return;
			}
			if (!PlayerInInterior())
			{
				_downTime = -1f;
				_longFired = false;
				return;
			}
			if (Input.GetKeyDown(config.Hotkey))
			{
				_downTime = Time.unscaledTime;
				_longFired = false;
			}
			if (_downTime >= 0f && !_longFired && Input.GetKey(config.Hotkey) && Time.unscaledTime - _downTime >= config.LongPressSeconds)
			{
				_longFired = true;
				TogglePlayStop();
			}
			if (Input.GetKeyUp(config.Hotkey))
			{
				if (_downTime >= 0f && !_longFired)
				{
					NextTrack();
				}
				_downTime = -1f;
				_longFired = false;
			}
		}

		private static bool PlayerInInterior()
		{
			if (!(Player.main.currentInterior is SeaTruckSegment))
			{
				return (Object)(object)Player.main.GetCurrentSub() != (Object)null;
			}
			return true;
		}

		private static JukeboxInstance ResolveInstance()
		{
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			IInteriorSpace currentInterior = Player.main.currentInterior;
			ISpeakerHost host = Speaker.GetHost((MonoBehaviour)(object)((currentInterior is MonoBehaviour) ? currentInterior : null));
			if (host == null && (Object)(object)Player.main.GetCurrentSub() != (Object)null)
			{
				host = Speaker.GetHost((MonoBehaviour)(object)Player.main.GetCurrentSub());
			}
			JukeboxInstance instance = Jukebox.instance;
			Vector3 val = default(Vector3);
			float num = default(float);
			float num2 = default(float);
			if ((Object)(object)instance != (Object)null && ((Behaviour)instance).isActiveAndEnabled && Jukebox.isStartingOrPlaying && Speaker.IsSameHost(Speaker.GetHost((MonoBehaviour)(object)instance), host) && instance.GetSoundPosition(ref val, ref num, ref num2))
			{
				return instance;
			}
			Vector3 position = ((Component)Player.main).transform.position;
			JukeboxInstance val2 = null;
			float num3 = float.MaxValue;
			bool flag = false;
			foreach (JukeboxInstance item in JukeboxInstance.all)
			{
				if (!((Object)(object)item == (Object)null) && ((Behaviour)item).isActiveAndEnabled && Speaker.IsSameHost(Speaker.GetHost((MonoBehaviour)(object)item), host))
				{
					bool soundPosition = item.GetSoundPosition(ref val, ref num2, ref num);
					val = ((Component)item).transform.position - position;
					float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
					if ((Object)(object)val2 == (Object)null || (soundPosition && !flag) || (soundPosition == flag && sqrMagnitude < num3))
					{
						val2 = item;
						num3 = sqrMagnitude;
						flag = soundPosition;
					}
				}
			}
			if (!((Object)(object)val2 != (Object)null))
			{
				return instance;
			}
			return val2;
		}

		private void TogglePlayStop()
		{
			JukeboxInstance val = ResolveInstance();
			if (!((Object)(object)val == (Object)null))
			{
				if (Jukebox.isStartingOrPlaying && (Object)(object)Jukebox.instance == (Object)(object)val)
				{
					Jukebox.Stop();
					return;
				}
				val.shuffle = Plugin.Config.DefaultShuffle;
				Jukebox.Play(val);
			}
		}

		private void NextTrack()
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			JukeboxInstance val = ResolveInstance();
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			string next = Jukebox.GetNext(val, true);
			if (string.IsNullOrEmpty(next))
			{
				return;
			}
			val.file = next;
			Jukebox.Play(val);
			if (Plugin.Config.ShowTrackName)
			{
				string label = Jukebox.GetInfo(next).label;
				if (!string.IsNullOrEmpty(label))
				{
					ErrorMessage.AddMessage("Now playing: " + label);
				}
			}
		}
	}
	[BepInPlugin("com.tristyn.buildinseatruckplus", "Build In Seatruck Plus", "1.0.8")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string GUID = "com.tristyn.buildinseatruckplus";

		public const string NAME = "Build In Seatruck Plus";

		public const string VERSION = "1.0.8";

		public static ManualLogSource Log { get; private set; }

		public static Config Config { get; private set; }

		private void Awake()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Config = OptionsPanelHandler.RegisterModOptions<Config>();
			MiniBuildables.Register();
			Harmony val = new Harmony("com.tristyn.buildinseatruckplus");
			val.PatchAll();
			((MonoBehaviour)this).StartCoroutine(AutosortCompat.TryPatchWhenReady(val));
			Log.LogInfo((object)"Build In Seatruck Plus 1.0.8 loaded.");
			((Component)this).gameObject.AddComponent<HotkeyController>();
		}
	}
	internal static class SeaTruckSegmentHelper
	{
		private static readonly int UseableLayer = LayerMask.NameToLayer("Useable");

		public static bool isPlayerInSeaTruckSegment()
		{
			if ((Object)(object)Player.main != (Object)null)
			{
				return Player.main.currentInterior is SeaTruckSegment;
			}
			return false;
		}

		public static SeaTruckSegment getCurrentSeaTruckSegment()
		{
			if (!((Object)(object)Player.main != (Object)null))
			{
				return null;
			}
			IInteriorSpace currentInterior = Player.main.currentInterior;
			return (SeaTruckSegment)(object)((currentInterior is SeaTruckSegment) ? currentInterior : null);
		}

		public static SeaTruckSegment getParentSeaTruckSegment(GameObject gameObject)
		{
			return gameObject.GetComponentInParent<SeaTruckSegment>();
		}

		public static SubRoot getCurrentSeaTruckSegmentSubRoot()
		{
			SeaTruckSegment currentSeaTruckSegment = getCurrentSeaTruckSegment();
			if (!((Object)(object)currentSeaTruckSegment == (Object)null))
			{
				return ((Component)currentSeaTruckSegment).gameObject.GetComponent<SubRoot>();
			}
			return null;
		}

		public static void NeutralizeCollidersForDocking(GameObject go)
		{
			Collider[] componentsInChildren = go.GetComponentsInChildren<Collider>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				((Component)componentsInChildren[i]).gameObject.layer = UseableLayer;
			}
		}

		public static void NeutralizeBuiltColliders(GameObject root)
		{
			if (!((Object)(object)root == (Object)null))
			{
				Constructable[] componentsInChildren = root.GetComponentsInChildren<Constructable>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					NeutralizeCollidersForDocking(((Component)componentsInChildren[i]).gameObject);
				}
			}
		}
	}
}
namespace BuildInSeatruckPlus.Patches
{
	internal static class AutosortCompat
	{
		private const string UnloaderTypeName = "AutosortLockers.AutosortUnloader";

		private const string MethodName = "AccumulateUnloadTargets";

		private static bool done;

		internal static IEnumerator TryPatchWhenReady(Harmony harmony)
		{
			for (int attempt = 0; attempt < 10; attempt++)
			{
				if (done)
				{
					break;
				}
				if (TryPatch(harmony))
				{
					break;
				}
				yield return (object)new WaitForSeconds(1f);
			}
		}

		private static bool TryPatch(Harmony harmony)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Expected O, but got Unknown
			if (done)
			{
				return true;
			}
			try
			{
				Type type = AccessTools.TypeByName("AutosortLockers.AutosortUnloader");
				if (type == null)
				{
					return false;
				}
				MethodInfo methodInfo = AccessTools.Method(type, "AccumulateUnloadTargets", (Type[])null, (Type[])null);
				if (methodInfo == null)
				{
					Plugin.Log.LogInfo((object)"AutosortLockers present but AccumulateUnloadTargets not found; planter-protection patch skipped.");
					done = true;
					return true;
				}
				HarmonyMethod val = new HarmonyMethod(typeof(AutosortCompat), "AccumulateUnloadTargets_Postfix", (Type[])null);
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				done = true;
				Plugin.Log.LogInfo((object)"AutosortLockers detected — unloader patched to leave Seatruck planters alone.");
				return true;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("AutosortLockers planter-protection patch failed (harmless): " + ex.Message));
				done = true;
				return true;
			}
		}

		private static void AccumulateUnloadTargets_Postfix(object __instance)
		{
			try
			{
				List<ItemsContainer> value = Traverse.Create(__instance).Field("containerTargets").GetValue<List<ItemsContainer>>();
				if (value == null || value.Count == 0)
				{
					return;
				}
				Planter[] planters = Object.FindObjectsOfType<Planter>();
				if (planters.Length != 0)
				{
					value.RemoveAll((ItemsContainer ct) => ct != null && planters.Any((Planter p) => (Object)(object)p != (Object)null && (Object)(object)p.storageContainer != (Object)null && p.storageContainer.container == ct));
				}
				RemoveColorMarkedContainers(value);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("AutosortLockers protection postfix error (harmless): " + ex.Message));
			}
		}

		private static void RemoveColorMarkedContainers(List<ItemsContainer> list)
		{
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			if (list == null || list.Count == 0)
			{
				return;
			}
			UnloaderSkipColor unloaderSkipColor = ((Plugin.Config != null) ? Plugin.Config.UnloaderSkipColorChoice : UnloaderSkipColor.Off);
			if (unloaderSkipColor == UnloaderSkipColor.Off)
			{
				return;
			}
			ColoredLabel[] array = Object.FindObjectsOfType<ColoredLabel>();
			if (array.Length == 0)
			{
				return;
			}
			HashSet<ItemsContainer> protectedContainers = new HashSet<ItemsContainer>();
			ColoredLabel[] array2 = array;
			foreach (ColoredLabel val in array2)
			{
				if ((Object)(object)val == (Object)null || (Object)(object)val.signInput == (Object)null)
				{
					continue;
				}
				Color[] colors = val.signInput.colors;
				int colorIndex = val.signInput.colorIndex;
				if (colors != null && colorIndex >= 0 && colorIndex < colors.Length && Classify(colors[colorIndex]) == unloaderSkipColor)
				{
					StorageContainer val2 = ResolveContainer(val);
					if ((Object)(object)val2 != (Object)null && val2.container != null)
					{
						protectedContainers.Add(val2.container);
					}
				}
			}
			if (protectedContainers.Count > 0)
			{
				list.RemoveAll((ItemsContainer ct) => ct != null && protectedContainers.Contains(ct));
			}
		}

		private static StorageContainer ResolveContainer(ColoredLabel cl)
		{
			//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)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			StorageContainer componentInParent = GetComponentExtensions.GetComponentInParent<StorageContainer>((Component)(object)cl, true);
			if ((Object)(object)componentInParent != (Object)null)
			{
				return componentInParent;
			}
			Vector3 position = ((Component)cl).transform.position;
			Transform parent = ((Component)cl).transform.parent;
			int num = 0;
			while (num < 4 && (Object)(object)parent != (Object)null)
			{
				StorageContainer val = NearestContainer(parent, position);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
				num++;
				parent = parent.parent;
			}
			return null;
		}

		private static StorageContainer NearestContainer(Transform scope, Vector3 lp)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			StorageContainer result = null;
			float num = float.MaxValue;
			StorageContainer[] componentsInChildren = ((Component)scope).GetComponentsInChildren<StorageContainer>(true);
			foreach (StorageContainer val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && val.container != null)
				{
					Vector3 val2 = ((Component)val).transform.position - lp;
					float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
					if (sqrMagnitude < num)
					{
						num = sqrMagnitude;
						result = val;
					}
				}
			}
			return result;
		}

		private static UnloaderSkipColor Classify(Color c)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			float num = default(float);
			float num2 = default(float);
			float num3 = default(float);
			Color.RGBToHSV(c, ref num, ref num2, ref num3);
			if (num3 < 0.15f)
			{
				return UnloaderSkipColor.Off;
			}
			if (num2 < 0.25f)
			{
				return UnloaderSkipColor.White;
			}
			float num4 = num * 360f;
			if (num4 < 20f || num4 >= 330f)
			{
				return UnloaderSkipColor.Red;
			}
			if (num4 < 70f)
			{
				return UnloaderSkipColor.Yellow;
			}
			if (num4 < 170f)
			{
				return UnloaderSkipColor.Green;
			}
			if (num4 < 260f)
			{
				return UnloaderSkipColor.Blue;
			}
			return UnloaderSkipColor.Magenta;
		}
	}
	[HarmonyPatch(typeof(Builder), "CheckAsSubModule")]
	internal static class Builder_CheckAsSubModule_Patch
	{
		private static bool Prefix(out Collider hitCollider, ref bool __result)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			hitCollider = null;
			if ((Object)(object)SeaTruckSegmentHelper.getCurrentSeaTruckSegment() == (Object)null)
			{
				return true;
			}
			Builder.placementTarget = null;
			Transform aimTransform = Builder.GetAimTransform();
			RaycastHit val = default(RaycastHit);
			if (!Physics.Raycast(aimTransform.position, aimTransform.forward, ref val, Builder.placeMaxDistance, ((LayerMask)(ref Builder.placeLayerMask)).value, (QueryTriggerInteraction)1))
			{
				__result = false;
				return false;
			}
			if (!Constructable.CheckFlags(Builder.allowedInBase, Builder.allowedInSub, Builder.allowedOutside, Builder.allowedUnderwater, ((RaycastHit)(ref val)).point))
			{
				__result = false;
				return false;
			}
			hitCollider = ((RaycastHit)(ref val)).collider;
			Builder.placementTarget = ((Component)hitCollider).gameObject;
			Builder.SetPlaceOnSurface(val, ref Builder.placePosition, ref Builder.placeRotation);
			__result = true;
			return false;
		}
	}
	[HarmonyPatch(typeof(Builder), "TryPlace")]
	internal static class Builder_TryPlace_Patch
	{
		private static bool Prefix(ref bool __result)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			SeaTruckSegment currentSeaTruckSegment = SeaTruckSegmentHelper.getCurrentSeaTruckSegment();
			if ((Object)(object)currentSeaTruckSegment == (Object)null)
			{
				return true;
			}
			if ((Object)(object)Builder.prefab == (Object)null || !Builder.canPlace)
			{
				RuntimeManager.PlayOneShot("event:/bz/ui/item_error", default(Vector3));
				__result = false;
				return false;
			}
			RuntimeManager.PlayOneShot("event:/tools/builder/place", Builder.ghostModel.transform.position);
			GameObject obj = Object.Instantiate<GameObject>(Builder.prefab);
			SeaTruckSegment val = (((Object)(object)Builder.placementTarget != (Object)null) ? SeaTruckSegmentHelper.getParentSeaTruckSegment(Builder.placementTarget) : null);
			SeaTruckSegment val2 = (((Object)(object)val != (Object)null) ? val : currentSeaTruckSegment);
			obj.transform.parent = ((Component)val2).transform;
			obj.transform.position = Builder.placePosition;
			obj.transform.rotation = Builder.placeRotation;
			Constructable componentInParent = obj.GetComponentInParent<Constructable>();
			componentInParent.SetState(false, true);
			if ((Object)(object)Builder.ghostModel != (Object)null)
			{
				Object.Destroy((Object)(object)Builder.ghostModel);
			}
			componentInParent.SetIsInside(true);
			SkyEnvironmentChanged.Send(obj, (Component)(object)val2);
			SeaTruckSegmentHelper.NeutralizeCollidersForDocking(obj);
			Builder.ghostModel = null;
			Builder.prefab = null;
			Builder.canPlace = false;
			__result = true;
			return false;
		}
	}
	[HarmonyPatch(typeof(Builder), "CheckTag")]
	internal static class Builder_CheckTag_Patch
	{
		private static bool Prefix(Collider c, ref bool __result)
		{
			if ((Object)(object)c != (Object)null && (Object)(object)((Component)c).GetComponentInParent<MoonpoolExpansionManager>() != (Object)null)
			{
				__result = true;
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(CanvasLink), "SetCanvasesEnabled")]
	internal static class CanvasLink_SetCanvasesEnabled_Patch
	{
		private static readonly FieldInfo Field = AccessTools.Field(typeof(CanvasLink), "canvases");

		private static bool Prefix(CanvasLink __instance, bool enabled)
		{
			return CanvasLinkToggle.Run(Field, __instance, enabled);
		}
	}
	[HarmonyPatch(typeof(CanvasLink), "SetRectMasksEnabled")]
	internal static class CanvasLink_SetRectMasksEnabled_Patch
	{
		private static readonly FieldInfo Field = AccessTools.Field(typeof(CanvasLink), "rectMasks");

		private static bool Prefix(CanvasLink __instance, bool enabled)
		{
			return CanvasLinkToggle.Run(Field, __instance, enabled);
		}
	}
	internal static class CanvasLinkToggle
	{
		public static bool Run(FieldInfo field, CanvasLink instance, bool enabled)
		{
			if (field.GetValue(instance) is Behaviour[] array)
			{
				Behaviour[] array2 = array;
				foreach (Behaviour val in array2)
				{
					if ((Object)(object)val != (Object)null)
					{
						val.enabled = enabled;
					}
				}
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(Constructable), "CheckFlags")]
	internal static class Constructable_CheckFlags_Patch
	{
		private static bool Prefix(ref bool __result)
		{
			if ((Object)(object)SeaTruckSegmentHelper.getCurrentSeaTruckSegment() == (Object)null)
			{
				return true;
			}
			__result = true;
			return false;
		}
	}
	internal static class DockedAudio
	{
		internal static readonly List<MoonpoolExpansionManager> Moonpools = new List<MoonpoolExpansionManager>();
	}
	[HarmonyPatch(typeof(MoonpoolExpansionManager), "Start")]
	internal static class MoonpoolExpansionManager_Start_Patch
	{
		private static void Postfix(MoonpoolExpansionManager __instance)
		{
			if (!DockedAudio.Moonpools.Contains(__instance))
			{
				DockedAudio.Moonpools.Add(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(Speaker), "GetSpeakers")]
	internal static class Speaker_GetSpeakers_Patch
	{
		private static bool _bridging;

		private static readonly List<Speaker> _other = new List<Speaker>();

		private static void Postfix(ISpeakerHost host, Vector3 position, float radius, List<Speaker> results)
		{
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			if (_bridging || host == null)
			{
				return;
			}
			_bridging = true;
			try
			{
				for (int num = DockedAudio.Moonpools.Count - 1; num >= 0; num--)
				{
					MoonpoolExpansionManager val = DockedAudio.Moonpools[num];
					if ((Object)(object)val == (Object)null)
					{
						DockedAudio.Moonpools.RemoveAt(num);
						continue;
					}
					SeaTruckSegment dockedHead = val.GetDockedHead();
					SeaTruckSegment dockedTail = val.GetDockedTail();
					if ((Object)(object)dockedHead == (Object)null && (Object)(object)dockedTail == (Object)null)
					{
						continue;
					}
					BaseRoot baseRoot = val.baseRoot;
					int num2;
					if (host is BaseRoot)
					{
						num2 = (((object)host == baseRoot) ? 1 : 0);
						if (num2 != 0)
						{
							goto IL_00b5;
						}
					}
					else
					{
						num2 = 0;
					}
					if (!(host is SeaTruckSegment))
					{
						goto IL_00b5;
					}
					int num3 = ((((Object)(object)dockedTail != (Object)null && Speaker.IsSameHost(host, (ISpeakerHost)(object)dockedTail)) || ((Object)(object)dockedHead != (Object)null && Speaker.IsSameHost(host, (ISpeakerHost)(object)dockedHead))) ? 1 : 0);
					goto IL_00b6;
					IL_00b6:
					bool flag = (byte)num3 != 0;
					if (num2 != 0)
					{
						Append((ISpeakerHost)(object)dockedTail, position, radius, results);
						Append((ISpeakerHost)(object)dockedHead, position, radius, results);
					}
					else if (flag)
					{
						Append((ISpeakerHost)(object)baseRoot, position, radius, results);
					}
					continue;
					IL_00b5:
					num3 = 0;
					goto IL_00b6;
				}
			}
			finally
			{
				_bridging = false;
			}
		}

		private static void Append(ISpeakerHost other, Vector3 position, float radius, List<Speaker> results)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if (other == null)
			{
				return;
			}
			_other.Clear();
			Speaker.GetSpeakers(other, position, radius, _other);
			for (int i = 0; i < _other.Count; i++)
			{
				Speaker val = _other[i];
				if ((Object)(object)val != (Object)null && !results.Contains(val))
				{
					results.Add(val);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Speaker), "IsSameHost")]
	internal static class Speaker_IsSameHost_Patch
	{
		private static bool _reentry;

		private static void Postfix(ISpeakerHost a, ISpeakerHost b, ref bool __result)
		{
			if (__result || _reentry || a == null || b == null)
			{
				return;
			}
			_reentry = true;
			try
			{
				for (int num = DockedAudio.Moonpools.Count - 1; num >= 0; num--)
				{
					MoonpoolExpansionManager val = DockedAudio.Moonpools[num];
					if ((Object)(object)val == (Object)null)
					{
						DockedAudio.Moonpools.RemoveAt(num);
					}
					else
					{
						SeaTruckSegment dockedHead = val.GetDockedHead();
						SeaTruckSegment dockedTail = val.GetDockedTail();
						if ((!((Object)(object)dockedHead == (Object)null) || !((Object)(object)dockedTail == (Object)null)) && InGroup(a, val, dockedHead, dockedTail) && InGroup(b, val, dockedHead, dockedTail))
						{
							__result = true;
							break;
						}
					}
				}
			}
			finally
			{
				_reentry = false;
			}
		}

		private static bool InGroup(ISpeakerHost h, MoonpoolExpansionManager mp, SeaTruckSegment head, SeaTruckSegment tail)
		{
			if (h is BaseRoot && (object)h == mp.baseRoot)
			{
				return true;
			}
			if ((Object)(object)head != (Object)null && Speaker.IsSameHost(h, (ISpeakerHost)(object)head))
			{
				return true;
			}
			if ((Object)(object)tail != (Object)null && Speaker.IsSameHost(h, (ISpeakerHost)(object)tail))
			{
				return true;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(SeaTruckMotor), "StartPiloting")]
	internal static class SeaTruckMotor_StartPiloting_Patch
	{
		private static void Postfix(SeaTruckMotor __instance)
		{
			if ((Object)(object)__instance != (Object)null && (Object)(object)__instance.truckSegment != (Object)null)
			{
				SeaTruckSegmentHelper.NeutralizeBuiltColliders(((Component)__instance.truckSegment).gameObject);
			}
		}
	}
	[HarmonyPatch(typeof(MoonpoolExpansionManager), "StartUndocking")]
	internal static class MoonpoolExpansionManager_StartUndocking_Patch
	{
		private static void Postfix(MoonpoolExpansionManager __instance)
		{
			SeaTruckSegment dockedHead = __instance.GetDockedHead();
			if ((Object)(object)dockedHead != (Object)null)
			{
				SeaTruckSegmentHelper.NeutralizeBuiltColliders(((Component)dockedHead).gameObject);
			}
			SeaTruckSegment dockedTail = __instance.GetDockedTail();
			if ((Object)(object)dockedTail != (Object)null)
			{
				SeaTruckSegmentHelper.NeutralizeBuiltColliders(((Component)dockedTail).gameObject);
			}
		}
	}
	[HarmonyPatch(typeof(JukeboxInstance), "ConsumePower")]
	internal static class JukeboxInstance_ConsumePower_Patch
	{
		private static void Prefix(JukeboxInstance __instance)
		{
			if (!((Object)(object)__instance._powerRelay != (Object)null))
			{
				PowerRelay componentInParent = ((Component)__instance).GetComponentInParent<PowerRelay>();
				if ((Object)(object)componentInParent != (Object)null)
				{
					__instance._powerRelay = componentInParent;
					Plugin.Log.LogInfo((object)("Re-resolved missing PowerRelay for " + ((Object)__instance).name + " -> " + ((Object)componentInParent).name + " (load-timing fix)."));
				}
			}
		}
	}
	internal static class JukeboxSync
	{
		internal static bool InDisable;

		private static int _frame = -1;

		private static readonly Dictionary<JukeboxInstance, bool> _cache = new Dictionary<JukeboxInstance, bool>();

		internal static bool IsMirror(JukeboxInstance ji)
		{
			if (Time.frameCount != _frame)
			{
				_frame = Time.frameCount;
				_cache.Clear();
			}
			if (_cache.TryGetValue(ji, out var value))
			{
				return value;
			}
			bool flag = Compute(ji);
			_cache[ji] = flag;
			return flag;
		}

		private static bool Compute(JukeboxInstance ji)
		{
			JukeboxInstance instance = Jukebox.instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance == (Object)(object)ji)
			{
				return false;
			}
			if (!Jukebox.isStartingOrPlaying)
			{
				return false;
			}
			return Speaker.IsSameHost(Speaker.GetHost((MonoBehaviour)(object)ji), Speaker.GetHost((MonoBehaviour)(object)instance));
		}
	}
	[HarmonyPatch(/*Could not decode attribute arguments.*/)]
	internal static class JukeboxInstance_isControlling_Patch
	{
		private static void Postfix(JukeboxInstance __instance, ref bool __result)
		{
			if (!__result && !JukeboxSync.InDisable && JukeboxSync.IsMirror(__instance))
			{
				__result = true;
			}
		}
	}
	[HarmonyPatch(typeof(JukeboxInstance), "UpdatePower")]
	internal static class JukeboxInstance_UpdatePower_Patch
	{
		private static bool Prefix(JukeboxInstance __instance)
		{
			return !JukeboxSync.IsMirror(__instance);
		}
	}
	[HarmonyPatch(typeof(JukeboxInstance), "OnDisable")]
	internal static class JukeboxInstance_OnDisable_Patch
	{
		private static void Prefix()
		{
			JukeboxSync.InDisable = true;
		}

		private static void Finalizer()
		{
			JukeboxSync.InDisable = false;
		}
	}
	[HarmonyPatch(typeof(JukeboxInstance), "UpdateUI")]
	internal static class JukeboxInstance_UpdateUI_Patch
	{
		private static void Prefix(JukeboxInstance __instance)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			if (!JukeboxSync.IsMirror(__instance))
			{
				return;
			}
			JukeboxInstance instance = Jukebox.instance;
			if (!((Object)(object)instance == (Object)null))
			{
				if (__instance.file != instance.file)
				{
					__instance.file = instance.file;
				}
				if (__instance.repeat != instance.repeat)
				{
					__instance.repeat = instance.repeat;
					__instance.imageRepeat.sprite = __instance.spritesRepeat[instance.repeat];
				}
				if (__instance.shuffle != instance.shuffle)
				{
					__instance.shuffle = instance.shuffle;
					__instance.imageShuffle.sprite = (instance.shuffle ? __instance.spriteShuffleOn : __instance.spriteShuffleOff);
				}
			}
		}
	}
	internal static class PlanterDiagnostics
	{
		private const string Tag = "[PlantDiag]";

		internal static bool IsSeatruckPlanter(Planter p)
		{
			if ((Object)(object)p != (Object)null)
			{
				return (Object)(object)((Component)p).GetComponentInParent<SeaTruckSegment>() != (Object)null;
			}
			return false;
		}

		internal static string PlanterId(Planter p)
		{
			UniqueIdentifier val = ((Component)p).GetComponent<UniqueIdentifier>() ?? ((Component)p).GetComponentInParent<UniqueIdentifier>();
			if (!((Object)(object)val != (Object)null))
			{
				return "<no-uid>";
			}
			return val.Id;
		}

		internal static void Dump(Planter p, string phase)
		{
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)p == (Object)null)
				{
					return;
				}
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.Append("[PlantDiag]").Append(' ').Append(phase)
					.Append(" planter=")
					.Append(PlanterId(p));
				SeaTruckSegment componentInParent = ((Component)p).GetComponentInParent<SeaTruckSegment>();
				stringBuilder.Append(" seg=").Append(((Object)(object)componentInParent != (Object)null) ? ((Object)componentInParent).name : "<none>");
				int value = (((Object)(object)p.grownPlantsRoot != (Object)null) ? p.grownPlantsRoot.childCount : (-1));
				stringBuilder.Append(" grownModels=").Append(value);
				Transform val = (((Object)(object)p.storageContainer != (Object)null && (Object)(object)p.storageContainer.storageRoot != (Object)null) ? ((Component)p.storageContainer.storageRoot).transform : null);
				int value2 = (((Object)(object)val != (Object)null) ? val.childCount : (-1));
				stringBuilder.Append(" storedItems=").Append(value2);
				Plugin.Log.LogInfo((object)stringBuilder.ToString());
				if (!((Object)(object)val != (Object)null))
				{
					return;
				}
				for (int i = 0; i < val.childCount; i++)
				{
					Transform child = val.GetChild(i);
					StringBuilder stringBuilder2 = new StringBuilder();
					stringBuilder2.Append("[PlantDiag]").Append("   item[").Append(i)
						.Append("] ")
						.Append(((Object)child).name);
					Pickupable component = ((Component)child).GetComponent<Pickupable>();
					stringBuilder2.Append(" tech=").Append(((Object)(object)component != (Object)null) ? ((object)component.GetTechType()/*cast due to .constrained prefix*/).ToString() : "<no-pickupable>");
					Plantable component2 = ((Component)child).GetComponent<Plantable>();
					if ((Object)(object)component2 != (Object)null)
					{
						stringBuilder2.Append(" slot=").Append(component2.planterSlotId).Append(" age=")
							.Append(component2.plantAge.ToString("0.000"));
					}
					UniqueIdentifier component3 = ((Component)child).GetComponent<UniqueIdentifier>();
					stringBuilder2.Append(" uid=").Append(((Object)(object)component3 != (Object)null) ? component3.Id : "<none>").Append(" active=")
						.Append(((Component)child).gameObject.activeSelf);
					Plugin.Log.LogInfo((object)stringBuilder2.ToString());
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[PlantDiag] dump failed: " + ex.Message));
			}
		}

		internal static IEnumerator DumpDelayed(Planter p, string phase, float seconds)
		{
			yield return (object)new WaitForSeconds(seconds);
			Dump(p, phase);
		}
	}
	[HarmonyPatch(typeof(Planter), "OnProtoSerializeObjectTree")]
	internal static class Planter_OnProtoSerializeObjectTree_Diag
	{
		private static void Postfix(Planter __instance)
		{
			if (PlanterDiagnostics.IsSeatruckPlanter(__instance))
			{
				PlanterDiagnostics.Dump(__instance, "SAVE");
			}
		}
	}
	[HarmonyPatch(typeof(Planter), "OnProtoDeserializeObjectTree")]
	internal static class Planter_OnProtoDeserializeObjectTree_Diag
	{
		private static void Postfix(Planter __instance)
		{
			if (PlanterDiagnostics.IsSeatruckPlanter(__instance))
			{
				PlanterDiagnostics.Dump(__instance, "LOAD-start");
				CoroutineHost.StartCoroutine(PlanterDiagnostics.DumpDelayed(__instance, "LOAD+5s", 5f));
			}
		}
	}
	[HarmonyPatch(typeof(Planter), "ReplaceItem")]
	internal static class Planter_ReplaceItem_Diag
	{
		private static void Postfix(Planter __instance, Plantable seed, Plantable plant, bool __result)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			if (!PlanterDiagnostics.IsSeatruckPlanter(__instance))
			{
				return;
			}
			try
			{
				string arg = (((Object)(object)seed != (Object)null && (Object)(object)seed.pickupable != (Object)null) ? ((object)seed.pickupable.GetTechType()/*cast due to .constrained prefix*/).ToString() : "<null>");
				string arg2 = (((Object)(object)plant != (Object)null && (Object)(object)plant.pickupable != (Object)null) ? ((object)plant.pickupable.GetTechType()/*cast due to .constrained prefix*/).ToString() : "<null>");
				Plugin.Log.LogInfo((object)("[PlantDiag] REPLACE (seed->plant) planter=" + PlanterDiagnostics.PlanterId(__instance) + " " + $"seed={arg} plant={arg2} result={__result}"));
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(Planter), "SetupRenderers")]
	internal static class Planter_SetupRenderers_Patch
	{
		private static void Postfix(Planter __instance, GameObject gameObject)
		{
			if (!((Object)(object)__instance == (Object)null) && !((Object)(object)gameObject == (Object)null) && !((Object)(object)((Component)__instance).GetComponentInParent<SeaTruckSegment>() == (Object)null))
			{
				SeaTruckSegmentHelper.NeutralizeCollidersForDocking(gameObject);
			}
		}
	}
	[HarmonyPatch(typeof(PowerConsumer), "IsPowered")]
	internal static class PowerConsumer_IsPowered_Patch
	{
		private static bool Prefix(PowerConsumer __instance, ref bool __result)
		{
			SeaTruckSegment parentSeaTruckSegment = SeaTruckSegmentHelper.getParentSeaTruckSegment(((Component)__instance).gameObject);
			if ((Object)(object)parentSeaTruckSegment == (Object)null)
			{
				return true;
			}
			__result = ((IInteriorSpace)parentSeaTruckSegment).CanBreathe();
			return false;
		}
	}
	[HarmonyPatch(typeof(SeaTruckSegment), "CanEnter")]
	internal static class SeaTruckSegment_CanEnter_Patch
	{
		private static bool Prefix(ref bool __result)
		{
			__result = true;
			return false;
		}
	}
}
namespace BuildInSeatruckPlus.Buildables
{
	internal static class MiniBuildables
	{
		public static TechType MiniJukebox { get; private set; }

		public static TechType MiniSpeaker { get; private set; }

		public static void Register()
		{
			//IL_0019: 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)
			MiniJukebox = Make("MiniJukebox", "Mini Jukebox", "A compact jukebox that fits inside a Seatruck.", (TechType)1564, 0.25f);
			MiniSpeaker = Make("MiniSpeaker", "Mini Speaker", "A compact speaker for tight interiors.", (TechType)1566, 0.5f);
		}

		private static TechType Make(string classId, string friendly, string description, TechType cloneOf, float scale)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			//IL_0040: 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_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Expected O, but got Unknown
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Expected O, but got Unknown
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Expected O, but got Unknown
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Expected O, but got Unknown
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			PrefabInfo val = PrefabInfo.WithTechType(classId, friendly, description, "English", false, (Assembly)null);
			PrefabInfo val2 = ((PrefabInfo)(ref val)).WithIcon(SpriteManager.Get(cloneOf));
			CustomPrefab val3 = new CustomPrefab(val2);
			CloneTemplate val4 = new CloneTemplate(val2, cloneOf);
			val4.ModifyPrefab = (Action<GameObject>)Delegate.Combine(val4.ModifyPrefab, (Action<GameObject>)delegate(GameObject go)
			{
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_0012: Unknown result type (might be due to invalid IL or missing references)
				//IL_0030: 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_003f: Unknown result type (might be due to invalid IL or missing references)
				Transform transform = go.transform;
				transform.localScale *= scale;
				ConstructableBounds[] componentsInChildren = go.GetComponentsInChildren<ConstructableBounds>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					componentsInChildren[i].bounds.extents = Vector3.one * 0.02f;
				}
				Plugin.Log.LogInfo((object)$"{classId}: scaled to {scale} with liberal bounds.");
			});
			val3.SetGameObject((PrefabTemplate)(object)val4);
			RecipeData val5 = (RecipeData)((!Plugin.Config.CheapRecipe) ? (((object)CraftDataHandler.GetRecipeData(cloneOf)) ?? ((object)new RecipeData((Ingredient[])(object)new Ingredient[1]
			{
				new Ingredient((TechType)16, 1)
			}))) : ((object)new RecipeData((Ingredient[])(object)new Ingredient[1]
			{
				new Ingredient((TechType)16, 1)
			})));
			GadgetExtensions.SetRecipe((ICustomPrefab)(object)val3, val5);
			TechGroup val6 = default(TechGroup);
			TechCategory val7 = default(TechCategory);
			int num = default(int);
			if (CraftData.GetBuilderIndex(cloneOf, ref val6, ref val7, ref num))
			{
				GadgetExtensions.SetPdaGroupCategory((ICustomPrefab)(object)val3, val6, val7);
			}
			if (!Plugin.Config.UnlockBuildables)
			{
				GadgetExtensions.SetUnlock((ICustomPrefab)(object)val3, (TechType)1564, 1);
			}
			val3.Register();
			return ((PrefabInfo)(ref val2)).TechType;
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}