Decompiled source of Void Crew Fleet v0.3.0

VoidCrewFleet.dll

Decompiled 2 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using CG;
using CG.Client;
using CG.Client.Audio;
using CG.Client.Player.Interactions;
using CG.Client.Quests.Behaviours;
using CG.Client.Quests.SectorTwists;
using CG.Client.Ship;
using CG.Client.Ship.Hull;
using CG.Client.Ship.Interactions;
using CG.Client.Ship.Modules.Mediators;
using CG.Client.UserData;
using CG.Game;
using CG.Game.Player;
using CG.Game.Scenarios;
using CG.Game.Scenarios.Actions;
using CG.Game.SpaceObjects;
using CG.Game.SpaceObjects.Controllers;
using CG.GameLoopStateMachine;
using CG.GameLoopStateMachine.GameStates;
using CG.Input;
using CG.Network;
using CG.Objects;
using CG.Ship;
using CG.Ship.Hull;
using CG.Ship.Modules;
using CG.Ship.Object;
using CG.Ship.Repair;
using CG.Ship.Scanning;
using CG.Ship.Shield;
using CG.Ship.Status;
using CG.Ship.TargetLocking;
using CG.Ship.Tracking;
using CG.Space;
using CG.Space.Projectiles;
using CG.Utils;
using Client.Player.Interactions;
using Client.Utils;
using Code.Gameplay;
using ExitGames.Client.Photon;
using Extensions;
using FMOD.Studio;
using Gameplay.Atmosphere;
using Gameplay.Carryables;
using Gameplay.Chat;
using Gameplay.CompositeWeapons;
using Gameplay.Damage;
using Gameplay.Defects;
using Gameplay.Enhancements;
using Gameplay.Helm;
using Gameplay.Hub;
using Gameplay.MissionDifficulty;
using Gameplay.Power;
using Gameplay.Quests;
using Gameplay.Ship;
using Gameplay.Ship.VoidJump;
using Gameplay.SpacePlatforms;
using Gameplay.Utilities;
using HarmonyLib;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Opsive.UltimateCharacterController.Character;
using Opsive.UltimateCharacterController.Character.Abilities;
using Photon.Pun;
using Photon.Realtime;
using PlatformAbstractionLayer;
using ResourceAssets;
using RuntimeAssets;
using Steamworks;
using ToolClasses;
using UI;
using UI.Core;
using UI.Core.Audio;
using UI.LoadoutTerminal;
using UI.ObjectMarker;
using UI.PilotHUD;
using UI.Settings;
using UI.ShipLoadoutTerminal;
using Unity.Services.Vivox;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.UIElements;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Void Crew Fleet")]
[assembly: AssemblyDescription("BepInEx plugin for Void Crew: two player ships, up to 16 players, a two-ship mission and a PvP mode")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("CaptainChunck")]
[assembly: AssemblyProduct("VoidCrewFleet")]
[assembly: AssemblyCopyright("Copyright © CaptainChunck 2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("b7d3f2a9-4c1e-4f6b-8a25-3e9d0c7f1a64")]
[assembly: AssemblyFileVersion("0.3.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("0.3.0.0")]
namespace VoidCrewFleet;

internal static class ActionHint
{
	public const int PunchPriority = 0;

	public const int HackPriority = 10;

	private static readonly Dictionary<string, KeyValuePair<int, string>> Texts = new Dictionary<string, KeyValuePair<int, string>>();

	private static UIDocument _document;

	private static VisualElement _row;

	private static Label _key;

	private static Label _label;

	public static void Set(string source, int priority, string text)
	{
		if (string.IsNullOrEmpty(text))
		{
			if (!Texts.Remove(source))
			{
				return;
			}
		}
		else
		{
			if (Texts.TryGetValue(source, out var value) && value.Key == priority && value.Value == text)
			{
				return;
			}
			Texts[source] = new KeyValuePair<int, string>(priority, text);
		}
		Refresh();
	}

	private static void Refresh()
	{
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
		string text = null;
		int num = int.MinValue;
		foreach (KeyValuePair<int, string> value in Texts.Values)
		{
			if (value.Key > num)
			{
				num = value.Key;
				text = value.Value;
			}
		}
		if (text == null)
		{
			if (_row != null)
			{
				_row.style.display = StyleEnum<DisplayStyle>.op_Implicit((DisplayStyle)1);
			}
		}
		else if (Ensure())
		{
			int num2 = text.IndexOf("  ", StringComparison.Ordinal);
			string text2 = ((num2 > 0) ? text.Substring(0, num2).Trim() : null);
			((TextElement)_key).text = text2 ?? "";
			((VisualElement)_key).style.display = StyleEnum<DisplayStyle>.op_Implicit((DisplayStyle)(string.IsNullOrEmpty(text2) ? 1 : 0));
			((TextElement)_label).text = ((num2 > 0) ? text.Substring(num2).Trim() : text);
			_row.style.display = StyleEnum<DisplayStyle>.op_Implicit((DisplayStyle)0);
		}
	}

	private static bool Ensure()
	{
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Expected O, but got Unknown
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: 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_00c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00de: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_0108: Unknown result type (might be due to invalid IL or missing references)
		//IL_0119: 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_014b: Unknown result type (might be due to invalid IL or missing references)
		//IL_015f: Unknown result type (might be due to invalid IL or missing references)
		//IL_019b: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
		if (_row != null && _row.panel != null)
		{
			return true;
		}
		if ((Object)(object)_document == (Object)null)
		{
			_document = Ui.CreateOverlay("Void Crew Fleet action hint", 4000);
			if ((Object)(object)_document == (Object)null)
			{
				return false;
			}
		}
		VisualElement rootVisualElement = _document.rootVisualElement;
		if (rootVisualElement == null)
		{
			return false;
		}
		rootVisualElement.pickingMode = (PickingMode)1;
		_row = new VisualElement
		{
			pickingMode = (PickingMode)1
		};
		_row.style.position = StyleEnum<Position>.op_Implicit((Position)1);
		_row.style.left = StyleLength.op_Implicit(0f);
		_row.style.right = StyleLength.op_Implicit(0f);
		_row.style.top = StyleLength.op_Implicit(new Length(57f, (LengthUnit)1));
		_row.style.flexDirection = StyleEnum<FlexDirection>.op_Implicit((FlexDirection)2);
		_row.style.justifyContent = StyleEnum<Justify>.op_Implicit((Justify)1);
		_row.style.alignItems = StyleEnum<Align>.op_Implicit((Align)2);
		_key = Ui.HudLabel("", 17, Color.white);
		((VisualElement)_key).style.backgroundColor = StyleColor.op_Implicit(new Color(0f, 0f, 0f, 0.55f));
		Ui.Border((VisualElement)(object)_key, 2f, Color.white);
		Ui.Radius((VisualElement)(object)_key, 3f);
		Ui.Padding((VisualElement)(object)_key, 1f, 8f);
		((VisualElement)_key).style.marginRight = StyleLength.op_Implicit(10f);
		((VisualElement)_key).style.unityTextAlign = StyleEnum<TextAnchor>.op_Implicit((TextAnchor)4);
		_row.Add((VisualElement)(object)_key);
		_label = Ui.HudLabel("", 19, Color.white);
		_row.Add((VisualElement)(object)_label);
		_row.style.display = StyleEnum<DisplayStyle>.op_Implicit((DisplayStyle)1);
		rootVisualElement.Add(_row);
		return true;
	}
}
internal static class Aim
{
	private const float FreshSeconds = 0.3f;

	private static Vector3 _eye;

	private static Vector3 _forward;

	private static float _time = -1f;

	[GamePatch("PvP boarding rules", "CG.Client.Player.Interactions.RaycastHandler", "FindInteractable", PatchKind.Postfix)]
	private static void FindInteractablePostfix(Transform ___cameraTransform)
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)___cameraTransform == (Object)null))
		{
			_eye = ___cameraTransform.position;
			_forward = ___cameraTransform.forward;
			_time = Time.unscaledTime;
		}
	}

	public static bool Get(out Vector3 eye, out Vector3 forward)
	{
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Unknown result type (might be due to invalid IL or missing references)
		//IL_007a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: 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_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		if (_time >= 0f && Time.unscaledTime - _time < 0.3f)
		{
			eye = _eye;
			forward = _forward;
			return true;
		}
		Camera main = Camera.main;
		if ((Object)(object)main == (Object)null)
		{
			eye = Vector3.zero;
			forward = Vector3.forward;
			return false;
		}
		eye = ((Component)main).transform.position;
		forward = ((Component)main).transform.forward;
		return true;
	}
}
internal enum AutoTestMode
{
	Off,
	TwoShips,
	FleetPilgrimage,
	PvP
}
internal static class AutoTest
{
	private enum Step
	{
		WaitMenu,
		Hosting,
		WaitHub,
		Starting,
		WaitMission,
		Report,
		Jumping,
		Done
	}

	private static Step _step = Step.WaitMenu;

	private static float _stepStarted;

	private static float _lastReport;

	private static int _reports;

	private static int _shots;

	private static float _teamScreenSeen = -1f;

	private static bool _teamJoined;

	private static float Since => Time.unscaledTime - _stepStarted;

	private static void Go(Step step)
	{
		_step = step;
		_stepStarted = Time.unscaledTime;
		Log.Info("[autotest] " + step);
	}

	public static void Tick()
	{
		if (Settings.AutoTest == null || Settings.AutoTest.Value == AutoTestMode.Off || _step == Step.Done)
		{
			return;
		}
		try
		{
			Run();
		}
		catch (Exception e)
		{
			Log.Failure("[autotest] step " + _step, e);
		}
	}

	private static string StateName()
	{
		GameStateMachine instance = Singleton<GameStateMachine>.Instance;
		if (!((Object)(object)instance != (Object)null) || ((AbstractStateMachine<GameStateMachine>)(object)instance).CurrentState == null)
		{
			return "";
		}
		return ((object)((AbstractStateMachine<GameStateMachine>)(object)instance).CurrentState).GetType().Name;
	}

	private static void Run()
	{
		switch (_step)
		{
		case Step.WaitMenu:
			if (!(StateName() != "GSMainMenu") && PhotonNetwork.IsConnectedAndReady && !PhotonNetwork.InRoom && !(Since < 3f))
			{
				Host();
				Go(Step.Hosting);
			}
			break;
		case Step.Hosting:
			if (PhotonNetwork.InRoom && GameSessionManager.InHub && (Object)(object)HubQuestManager.Instance != (Object)null)
			{
				Go(Step.WaitHub);
			}
			else if (Since > 90f)
			{
				Fail("the hub never loaded");
			}
			break;
		case Step.WaitHub:
			if (!(Since < 8f))
			{
				StartMission();
				Go(Step.Starting);
			}
			break;
		case Step.Starting:
			if (!GameSessionManager.InHub && StateName() == "GSIngame" && (Object)(object)LocalPlayer.Instance != (Object)null)
			{
				Go(Step.WaitMission);
			}
			else if (PvpTeams.Choosing && PvpTeamScreen.Visible)
			{
				PickTeams();
			}
			else if (Since > 180f)
			{
				Fail("the mission never started");
			}
			break;
		case Step.WaitMission:
			if (!(Since < 10f))
			{
				Go(Step.Report);
			}
			break;
		case Step.Report:
			if (Time.unscaledTime - _lastReport < 5f)
			{
				break;
			}
			_lastReport = Time.unscaledTime;
			Report("mission");
			Screenshot("mission");
			if (FleetSession.IsPvP && _reports == 0)
			{
				StartHackTest();
			}
			if (++_reports >= (FleetSession.IsPvP ? 10 : 3))
			{
				if (Settings.AutoTestJump.Value && FleetSession.Mode == FleetMode.TwoShips)
				{
					StartJump();
				}
				else
				{
					Finish();
				}
			}
			break;
		case Step.Jumping:
			if (!(Time.unscaledTime - _lastReport < 3f))
			{
				_lastReport = Time.unscaledTime;
				Report("jump");
				if (_shots < 12)
				{
					Screenshot("jump");
				}
				if (Since > 75f)
				{
					Finish();
				}
			}
			break;
		}
	}

	private static void Host()
	{
		Log.Info("[autotest] Hosting a private test room.");
		PunSingleton<PhotonService>.I.CreateRoom(false, false).Then((Action)delegate
		{
			PAL.Matchmaking.CreateLobby(false);
		}).Then((Action)delegate
		{
			PunSingleton<PhotonService>.I.SetCurrentRoomPlayerLimit(1);
		})
			.Then((Action)delegate
			{
				PunSingleton<PhotonService>.I.SetCurrentRoomName("Fleet autotest");
			})
			.Then((Action)delegate
			{
				GameSessionManager.Instance.SetNextGameSession(GameSessionLoadPromise.LoadLobbyData());
				((AbstractStateMachine<GameStateMachine>)(object)Singleton<GameStateMachine>.Instance).ChangeState<GSLoadingGame>();
			})
			.Catch((Action<Exception>)delegate(Exception e)
			{
				Fail("hosting failed: " + e.Message);
			});
	}

	private static void StartMission()
	{
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		AutoTestMode value = Settings.AutoTest.Value;
		Log.Info("[autotest] Starting a mission: " + value.ToString() + ".");
		HubFleet.RequestTwoShips(on: true);
		switch (value)
		{
		case AutoTestMode.FleetPilgrimage:
			HubFleet.RequestVariant(HubVariant.FleetPilgrimage);
			break;
		case AutoTestMode.PvP:
			HubFleet.RequestVariant(HubVariant.FleetBattle);
			break;
		default:
			HubQuestManager.Instance.SelectQuest(((ResourceAssetRef)DataTable<QuestTable>.Instance.EndlessQuest).AssetGuid);
			break;
		}
		GUIDUnion val = Ship2Choice();
		if (!((GUIDUnion)(ref val)).IsNull)
		{
			HubFleet.RequestShipB(val);
		}
		((MonoBehaviour)FleetRuntime.Instance).StartCoroutine(StartSoon(val));
	}

	private static GUIDUnion Ship2Choice()
	{
		//IL_004c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_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)
		string text = ((Settings.AutoTestShip2.Value != null) ? Settings.AutoTestShip2.Value.Trim() : "");
		if (text.Length == 0)
		{
			return GUIDUnion.Empty();
		}
		try
		{
			return new GUIDUnion(text);
		}
		catch
		{
			Log.Warn("[autotest] AutoTestShip2 is not a loadout GUID: " + text);
			return GUIDUnion.Empty();
		}
	}

	private static IEnumerator StartSoon(GUIDUnion ship2)
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		yield return (object)new WaitForSeconds(1.5f);
		if (!((GUIDUnion)(ref ship2)).IsNull && HubFleet.ChosenShipB != ship2)
		{
			HubFleet.RequestShipB(ship2);
		}
		yield return (object)new WaitForSeconds(1.5f);
		if (!((GUIDUnion)(ref ship2)).IsNull && HubFleet.ChosenShipB != ship2)
		{
			Log.Warn("[autotest] Ship 2's loadout was not taken: " + ((GUIDUnion)(ref ship2)).AsHex() + ".");
		}
		HubQuestManager hub = HubQuestManager.Instance;
		if ((Object)(object)hub == (Object)null || (ResourceAssetRef)(object)hub.SelectedQuest == (ResourceAssetRef)null)
		{
			Fail("no mission is selected");
			yield break;
		}
		if (Settings.AutoTest.Value == AutoTestMode.PvP)
		{
			Log.Info("[autotest] Hub team screen showing: " + PvpTeamScreen.Visible + ", picking: " + PvpTeams.HubChoosing + ".");
			Screenshot("hub-teams");
			PvpTeams.Join(0);
			yield return (object)new WaitForSeconds(1.5f);
			PvpTeams.Confirm();
			yield return (object)new WaitForSeconds(1.5f);
			Log.Info("[autotest] Hub teams locked: " + PvpTeams.Locked + ", local team " + FleetShips.CrewSlot(FleetShips.LocalActor) + ", can edit ship 1 " + FleetApi.CanEditShip(FleetShips.LocalActor, 1) + ", ship 2 " + FleetApi.CanEditShip(FleetShips.LocalActor, 2) + ".");
		}
		Screenshot("hub");
		yield return (object)new WaitForSeconds(0.5f);
		Log.Info("[autotest] Planned: " + HubFleet.PlannedMode.ToString() + ", ship 2 = " + HubFleet.DescribeLoadout(HubFleet.ShipBDef) + ".");
		hub.StartQuest(hub.SelectedQuest, (SessionStartType)1, hub.QuestSeed, hub.ChallengeSeed);
	}

	private static void PickTeams()
	{
		if (_teamScreenSeen < 0f)
		{
			_teamScreenSeen = Time.unscaledTime;
			Log.Info("[autotest] The PvP team screen is showing; spawning is on hold until the teams are confirmed.");
			return;
		}
		float num = Time.unscaledTime - _teamScreenSeen;
		if (!_teamJoined && num > 3f)
		{
			Screenshot("teams-empty");
			PvpTeams.Join(0);
			_teamJoined = true;
		}
		else if (_teamJoined && num > 6f && PhotonNetwork.IsMasterClient)
		{
			Screenshot("teams-picked");
			Log.Info("[autotest] Confirming the teams (local player crew slot " + FleetShips.CrewSlot(FleetShips.LocalActor) + ").");
			PvpTeams.Confirm();
			_teamScreenSeen = float.MaxValue;
		}
	}

	private static void StartHackTest()
	{
		//IL_0028: 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_003e: 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_0058: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			LocalPlayer instance = LocalPlayer.Instance;
			if ((Object)(object)instance != (Object)null && (Object)(object)PrefabSpawnerSync.Instance != (Object)null && HackTerminal.Registered)
			{
				PrefabSpawnerSync.Instance.SpawnCloneStarObject(HackTerminal.Guid, ((Component)instance).transform.position + ((Component)instance).transform.forward * 1.2f + ((Component)instance).transform.up, Quaternion.identity);
				Log.Info("[autotest] Spawned a hacking terminal in front of the player.");
			}
			Log.Info("[autotest] Hack: " + PvpHack.DebugAccess(FleetShips.BySlot(1), 0, 30f) + ".");
			Log.Info("[autotest] Cockpits: ship 1 " + ((Object)(object)PvpHack.CockpitRoom(FleetShips.BySlot(0)) != (Object)null) + ", ship 2 " + ((Object)(object)PvpHack.CockpitRoom(FleetShips.BySlot(1)) != (Object)null) + ".");
		}
		catch (Exception e)
		{
			Log.Failure("[autotest] hack test", e);
		}
	}

	private static string DescribeTerminals()
	{
		int num = 0;
		CarryableObject[] array = Object.FindObjectsOfType<CarryableObject>();
		for (int i = 0; i < array.Length; i++)
		{
			if (HackTerminal.Is(array[i]))
			{
				num++;
			}
		}
		return num + " hacking terminal item(s) in the world";
	}

	private static void StartJump()
	{
		PlayerControlledShip val = FleetShips.BySlot(0);
		VoidJumpSystem val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponentInChildren<VoidJumpSystem>() : null);
		if ((Object)(object)val2 == (Object)null)
		{
			Fail("ship 1 has no void jump system");
			return;
		}
		Log.Info("[autotest] Making ship 1 jump (debug charge + travel); ship 2 should follow.");
		val2.DebugTransitionToRotatingState();
		Go(Step.Jumping);
	}

	private static void Finish()
	{
		Report("final");
		Screenshot("final");
		Log.Info("[autotest] DONE. Leave the game running to look around, or close it.");
		Go(Step.Done);
	}

	private static void Fail(string why)
	{
		Log.Error("[autotest] FAILED: " + why);
		Go(Step.Done);
	}

	public unsafe static void Report(string label)
	{
		//IL_0117: Unknown result type (might be due to invalid IL or missing references)
		//IL_011c: Unknown result type (might be due to invalid IL or missing references)
		//IL_03e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_03f1: Unknown result type (might be due to invalid IL or missing references)
		StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.AppendLine("[autotest] ---- report (" + label + ") ----");
		stringBuilder.AppendLine("  mode " + FleetSession.Mode.ToString() + ", plan " + ((FleetSession.Current != null) ? FleetSession.Current.ToString() : "none") + ", ships registered " + FleetShips.All.Count + ", active " + FleetShips.Active);
		foreach (PlayerControlledShip item in FleetShips.All)
		{
			VoidJumpSystem componentInChildren = ((Component)item).GetComponentInChildren<VoidJumpSystem>();
			CloneTubeModule module = item.GetModule<CloneTubeModule>();
			string[] obj = new string[16]
			{
				"  ",
				FleetShips.Describe(item),
				": view ",
				FleetShips.ViewId(item).ToString(),
				", pos ",
				null,
				null,
				null,
				null,
				null,
				null,
				null,
				null,
				null,
				null,
				null
			};
			Vector3 position = item.Platform.Position;
			obj[5] = ((object)(*(Vector3*)(&position))/*cast due to .constrained prefix*/).ToString();
			obj[6] = ", sector ";
			obj[7] = ((((OrbitObject)item).Sector != (GameSessionSector)null) ? ((OrbitObject)item).Sector.Id.ToString() : "none");
			obj[8] = ", jump ";
			obj[9] = (((Object)(object)componentInChildren != (Object)null && componentInChildren.ActiveState != null) ? ((object)componentInChildren.ActiveState).GetType().Name : "?");
			obj[10] = ", hp ";
			obj[11] = ((OrbitObject)item).HitPoints.ToString("0");
			obj[12] = ", clone tubes ";
			obj[13] = (((Object)(object)module != (Object)null) ? string.Join(",", module.CloneTubes.Select((CloneTube t) => t.Index.ToString()).ToArray()) : "none");
			obj[14] = ", crew ";
			obj[15] = FleetShips.CrewCount(FleetShips.Slot(item)).ToString();
			stringBuilder.AppendLine(string.Concat(obj));
		}
		if (FleetShips.Active)
		{
			stringBuilder.AppendLine("  resources: " + ShipResources.Describe() + (ShipResources.Active ? "" : " (per-ship resources off)"));
		}
		if (FleetSession.IsPvP)
		{
			PlayerControlledShip val = FleetShips.BySlot(0);
			PlayerControlledShip val2 = FleetShips.BySlot(1);
			stringBuilder.AppendLine("  PvP: teams locked " + PvpTeams.Locked + ", choosing " + PvpTeams.Choosing + ", team screen " + PvpTeamScreen.Visible + ", local team " + FleetShips.CrewSlot(FleetShips.LocalActor) + ", local player faction " + (((Object)(object)LocalPlayer.Instance != (Object)null) ? ((OrbitObject)LocalPlayer.Instance).faction.ToString() : "-"));
			if ((Object)(object)val != (Object)null && (Object)(object)val2 != (Object)null)
			{
				stringBuilder.AppendLine("  PvP: blue faction " + ((OrbitObject)val).faction + ", red faction " + ((OrbitObject)val2).faction + ", blue hostile to red " + ((SpaceCraft)val).IsHostile((OrbitObject)(object)val2) + ", red hostile to blue " + ((SpaceCraft)val2).IsHostile((OrbitObject)(object)val) + ", distance " + Vector3.Distance(((Component)val).transform.position, ((Component)val2).transform.position).ToString("0") + " m");
				stringBuilder.AppendLine("  PvP: red parts " + FactionCounts(val2) + "; blue parts " + FactionCounts(val));
				stringBuilder.AppendLine("  PvP arena: " + PvpArena.Describe());
				stringBuilder.AppendLine("  PvP turrets: ship 1 " + PvpTurrets.DescribeShip(val) + "; ship 2 " + PvpTurrets.DescribeShip(val2));
				stringBuilder.AppendLine("  PvP hack: BLUE door access to RED " + PvpHack.HasAccess(0, val2) + "; " + PvpBoarding.DescribeAccess(val2) + "; " + DescribeTerminals());
			}
		}
		PlayerControlledShip ship = (((Object)(object)ClientGame.Current != (Object)null) ? ClientGame.Current.PlayerShip : null);
		stringBuilder.AppendLine("  game's player ship = " + FleetShips.Describe(ship) + ", local crew ship = " + FleetShips.Describe(FleetShips.LocalShip) + ", aboard = " + FleetShips.Describe(FleetShips.AboardShip((Player)(object)LocalPlayer.Instance)));
		stringBuilder.AppendLine("  active sector " + ((GameSessionManager.ActiveSector != (GameSessionSector)null) ? GameSessionManager.ActiveSector.Id.ToString() : "none") + ", room players " + PhotonNetwork.PlayerList.Length + "/" + ((PhotonNetwork.CurrentRoom != null) ? PhotonNetwork.CurrentRoom.MaxPlayers : 0));
		Log.Info(stringBuilder.ToString());
	}

	private static string FactionCounts(PlayerControlledShip ship)
	{
		SortedDictionary<int, int> sortedDictionary = new SortedDictionary<int, int>();
		List<OrbitObject> list = new List<OrbitObject>(((Component)ship).GetComponentsInChildren<OrbitObject>(true));
		if ((Object)(object)ship.Hull != (Object)null)
		{
			list.AddRange(((Component)ship.Hull).GetComponentsInChildren<OrbitObject>(true));
		}
		foreach (OrbitObject item in list)
		{
			sortedDictionary.TryGetValue(item.faction, out var value);
			sortedDictionary[item.faction] = value + 1;
		}
		return string.Join(", ", sortedDictionary.Select((KeyValuePair<int, int> p) => "faction " + p.Key + " x" + p.Value).ToArray());
	}

	private static void Screenshot(string label)
	{
		try
		{
			string text = Path.Combine(Paths.BepInExRootPath, "fleet-autotest");
			Directory.CreateDirectory(text);
			int num = ++_shots;
			string text2 = Path.Combine(text, num.ToString("00") + "-" + label + ".png");
			ScreenCapture.CaptureScreenshot(text2);
			Log.Info("[autotest] screenshot " + text2);
		}
		catch (Exception e)
		{
			Log.Failure("[autotest] screenshot", e);
		}
	}
}
internal static class CharacterShips
{
	public const string Feature = "Two player ships";

	private static readonly Collider[] Hits = (Collider[])(object)new Collider[16];

	[GamePatch("Two player ships", "CharacterAtmosphericDataTracker", "CheckForInertiaZones", PatchKind.Prefix)]
	private static bool InertiaZonePrefix(CharacterAtmosphericDataTracker __instance, Vector3? overridePosition, int ___gravityZoneMask, ref bool __result)
	{
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: 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_00c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
		if (!FleetShips.Active)
		{
			return true;
		}
		try
		{
			Vector3 val = (Vector3)(((??)overridePosition) ?? ((Component)__instance.CollectionPoint).transform.position);
			int num = Physics.OverlapSphereNonAlloc(val, __instance.InInertiaZone ? 1f : 0.01f, Hits, ___gravityZoneMask);
			if (num == 0)
			{
				__result = false;
				return false;
			}
			MovingSpacePlatform val2 = null;
			float num2 = float.MaxValue;
			for (int i = 0; i < num; i++)
			{
				Collider val3 = Hits[i];
				if ((Object)(object)val3 == (Object)null)
				{
					continue;
				}
				MovingPlatformInertiaZone componentInParent = ((Component)val3).GetComponentInParent<MovingPlatformInertiaZone>();
				MovingSpacePlatform val4 = (((Object)(object)componentInParent != (Object)null && (Object)(object)componentInParent.ConnectedPlatform != (Object)null) ? componentInParent.ConnectedPlatform : ((Component)val3).GetComponentInParent<MovingSpacePlatform>());
				if (!((Object)(object)val4 == (Object)null))
				{
					Vector3 val5 = val3.ClosestPoint(val) - val;
					float sqrMagnitude = ((Vector3)(ref val5)).sqrMagnitude;
					if (sqrMagnitude < num2)
					{
						num2 = sqrMagnitude;
						val2 = val4;
					}
				}
			}
			if ((Object)(object)val2 == (Object)null)
			{
				PlayerControlledShip viewShip = FleetShips.ViewShip;
				if ((Object)(object)viewShip == (Object)null)
				{
					return true;
				}
				val2 = viewShip.Platform;
			}
			__instance.InInertiaZone = true;
			__instance.ConnectedSpacePlatform = (SpacePlatform)(object)val2;
			__result = true;
			return false;
		}
		catch (Exception e)
		{
			Log.Failure("Finding which ship's inertia zone a player is in", e);
			return true;
		}
	}

	[GamePatch("Two player ships", "CG.Game.Player.LocalPlayer", "IsOnPlayerShip", PatchKind.Prefix)]
	private static bool OnPlayerShipPrefix(LocalPlayer __instance, ref bool __result)
	{
		if (!FleetShips.Active)
		{
			return true;
		}
		try
		{
			PlayerControlledShip val = (((Object)(object)((Player)__instance).ZonedPlatform != (Object)null) ? ((Component)((Player)__instance).ZonedPlatform).GetComponent<PlayerControlledShip>() : null);
			__result = (Object)(object)val != (Object)null && !((Player)__instance).Locomotion.AtmosphereTracker.InInertiaZone;
			return false;
		}
		catch (Exception e)
		{
			Log.Failure("Checking whether the local player is aboard a ship", e);
			return true;
		}
	}
}
internal static class CloneTubes
{
	private sealed class ShipTubes
	{
		public PlayerControlledShip Ship;

		public int ShipView;

		public CloneTubeModule Module;

		public List<CloneTube> Tubes;
	}

	public const string Feature = "Two player ships";

	private static readonly List<ShipTubes> Registered = new List<ShipTubes>();

	private static CloneTubeModule _disabling;

	private static Player _spawning;

	public static Func<bool> HoldSpawns;

	[GamePatch("Two player ships", "CloneTubeHealing", "OnEnter", PatchKind.Finalizer)]
	private static Exception HealingEnterFinalizer(Exception __exception, CloneTube cloneTube)
	{
		if (!(__exception is NullReferenceException) || (Object)(object)cloneTube == (Object)null)
		{
			return __exception;
		}
		try
		{
			if ((Object)(object)cloneTube.GetOccupant() != (Object)null)
			{
				return __exception;
			}
		}
		catch
		{
			return __exception;
		}
		Log.WarnOnce("tube occupant", "A clone tube's occupant hadn't loaded yet on this client; skipped its healing set-up.");
		return null;
	}

	[GamePatch("Two player ships", "CG.Game.Player.SpawnSystem", "RegisterCloneTubes", PatchKind.Prefix)]
	private static bool RegisterPrefix(List<CloneTube> cts, ref List<CloneTube> ___clonetubes)
	{
		try
		{
			if (cts == null || cts.Count == 0 || (Object)(object)cts[0] == (Object)null)
			{
				return true;
			}
			CloneTubeModule module = ((Component)cts[0]).GetComponentInParent<CloneTubeModule>();
			PlayerControlledShip ship = FleetShips.OwnerOf((Component)(object)cts[0]);
			Registered.RemoveAll((ShipTubes r) => (Object)(object)r.Module == (Object)null || ((Object)(object)module != (Object)null && (Object)(object)r.Module == (Object)(object)module) || r.Tubes == cts);
			Registered.Add(new ShipTubes
			{
				Ship = ship,
				ShipView = FleetShips.ViewId(ship),
				Module = module,
				Tubes = new List<CloneTube>(cts)
			});
			___clonetubes = Rebuild();
			return false;
		}
		catch (Exception e)
		{
			Log.Failure("Registering a ship's clone tubes", e);
			return true;
		}
	}

	[GamePatch("Two player ships", "CG.Ship.Modules.CloneTubeModule", "OnDisable", PatchKind.Prefix)]
	private static void ModuleDisablePrefix(CloneTubeModule __instance)
	{
		_disabling = __instance;
	}

	[GamePatch("Two player ships", "CG.Ship.Modules.CloneTubeModule", "OnDisable", PatchKind.Finalizer)]
	private static void ModuleDisableFinalizer()
	{
		_disabling = null;
	}

	[GamePatch("Two player ships", "CG.Game.Player.SpawnSystem", "ClearCloneTubes", PatchKind.Prefix)]
	private static bool ClearPrefix(ref List<CloneTube> ___clonetubes)
	{
		try
		{
			if ((Object)(object)_disabling != (Object)null)
			{
				CloneTubeModule module = _disabling;
				Registered.RemoveAll((ShipTubes r) => (Object)(object)r.Module == (Object)null || (Object)(object)r.Module == (Object)(object)module);
			}
			else
			{
				Registered.Clear();
			}
			___clonetubes = Rebuild();
			return false;
		}
		catch (Exception e)
		{
			Log.Failure("Removing a ship's clone tubes", e);
			return true;
		}
	}

	private static List<CloneTube> Rebuild()
	{
		List<CloneTube> list = new List<CloneTube>();
		foreach (ShipTubes item in Registered.OrderBy((ShipTubes r) => r.ShipView))
		{
			foreach (CloneTube tube in item.Tubes)
			{
				if (!((Object)(object)tube == (Object)null))
				{
					tube.Index = list.Count;
					list.Add(tube);
				}
			}
		}
		return list;
	}

	private static List<CloneTube> TubesOf(PlayerControlledShip ship)
	{
		List<CloneTube> list = new List<CloneTube>();
		foreach (ShipTubes item in Registered)
		{
			if ((Object)(object)item.Ship == (Object)(object)ship)
			{
				list.AddRange(item.Tubes.Where((CloneTube t) => (Object)(object)t != (Object)null));
			}
		}
		return list;
	}

	private static PlayerControlledShip SpawnShipFor(Player player)
	{
		if (player == null)
		{
			return null;
		}
		PlayerControlledShip val = FleetShips.ShipOfActor(player.ActorNumber);
		if ((Object)(object)val != (Object)null && !val.StartedDeath)
		{
			return val;
		}
		if (FleetSession.IsPvP)
		{
			return null;
		}
		foreach (PlayerControlledShip item in FleetShips.All)
		{
			if ((Object)(object)item != (Object)null && !item.StartedDeath)
			{
				return item;
			}
		}
		return null;
	}

	[GamePatch("Two player ships", "CG.Game.Player.SpawnSystem", "TrySpawnPlayer", PatchKind.Prefix)]
	private static void TrySpawnPrefix(Player player)
	{
		_spawning = player;
		ShipRedirect.BeginOverride(FleetShips.Active ? SpawnShipFor(player) : null);
	}

	[GamePatch("Two player ships", "CG.Game.Player.SpawnSystem", "TrySpawnPlayer", PatchKind.Finalizer)]
	private static void TrySpawnFinalizer()
	{
		ShipRedirect.EndOverride();
		_spawning = null;
	}

	[GamePatch("Two player ships", "CG.Game.Player.SpawnSystem", "CheckSpawningFromQueue", PatchKind.Prefix)]
	private static void QueuePrefix(Queue<Player> ___playersQueuedToSpawn)
	{
		_spawning = null;
		try
		{
			if (___playersQueuedToSpawn != null && ___playersQueuedToSpawn.Count > 0)
			{
				if (FleetShips.Active && ___playersQueuedToSpawn.Count > 1 && (HoldSpawns == null || !HoldSpawns()))
				{
					FrontLoad(___playersQueuedToSpawn);
				}
				_spawning = ___playersQueuedToSpawn.Peek();
			}
		}
		catch (Exception e)
		{
			Log.Failure("Reading the spawn queue", e);
		}
		ShipRedirect.BeginOverride((FleetShips.Active && _spawning != null) ? SpawnShipFor(_spawning) : null);
	}

	private static void FrontLoad(Queue<Player> queue)
	{
		Player[] array = queue.ToArray();
		int num = Array.FindIndex(array, delegate(Player player)
		{
			PlayerControlledShip val = SpawnShipFor(player);
			return (Object)(object)val != (Object)null && TubesOf(val).Any((CloneTube t) => t.IsAvailable());
		});
		if (num <= 0)
		{
			return;
		}
		queue.Clear();
		queue.Enqueue(array[num]);
		for (int num2 = 0; num2 < array.Length; num2++)
		{
			if (num2 != num)
			{
				queue.Enqueue(array[num2]);
			}
		}
	}

	[GamePatch("Two player ships", "CG.Game.Player.SpawnSystem", "CheckSpawningFromQueue", PatchKind.Finalizer)]
	private static void QueueFinalizer()
	{
		ShipRedirect.EndOverride();
		_spawning = null;
	}

	[GamePatch("Two player ships", "CG.Game.Player.SpawnSystem", "GetNextFreeCloneTube", PatchKind.Prefix)]
	private static bool NextFreeTubePrefix(ref CloneTube __result)
	{
		try
		{
			if (HoldSpawns != null && PhotonNetwork.IsMasterClient && HoldSpawns())
			{
				__result = null;
				return false;
			}
			if (!FleetShips.Active || _spawning == null)
			{
				return true;
			}
			PlayerControlledShip val = SpawnShipFor(_spawning);
			__result = (((Object)(object)val == (Object)null) ? null : ((IEnumerable<CloneTube>)TubesOf(val)).FirstOrDefault((Func<CloneTube, bool>)((CloneTube t) => t.IsAvailable())));
			return false;
		}
		catch (Exception e)
		{
			Log.Failure("Choosing a clone tube", e);
			return true;
		}
	}

	[GamePatch("Two player ships", "CG.Game.Player.SpawnSystem", "SpawnPlayer", PatchKind.Prefix)]
	private static void SpawnPlayerPrefix(CloneTube tube)
	{
		ShipRedirect.BeginOverride((FleetShips.Active && (Object)(object)tube != (Object)null) ? FleetShips.OwnerOf((Component)(object)tube) : null);
	}

	[GamePatch("Two player ships", "CG.Game.Player.SpawnSystem", "SpawnPlayer", PatchKind.Finalizer)]
	private static void SpawnPlayerFinalizer()
	{
		ShipRedirect.EndOverride();
	}

	[GamePatch("Two player ships", "CG.Game.Player.SpawnSystem", "RespawnPlayer", PatchKind.Prefix)]
	private static bool RespawnPrefix(int clonetubeIndex, List<CloneTube> ___clonetubes)
	{
		if (___clonetubes != null && clonetubeIndex >= 0 && clonetubeIndex < ___clonetubes.Count)
		{
			return true;
		}
		Log.Warn("The host sent clone tube " + clonetubeIndex + " but this client knows " + (___clonetubes?.Count ?? 0) + " tubes; asking to spawn again.");
		if ((Object)(object)SpawnSystem.Instance != (Object)null)
		{
			SpawnSystem.Instance.RequestSpawn();
		}
		return false;
	}
}
internal static class CustomizerLink
{
	public const string PluginGuid = "com.captainchunck.voidcrew.shipcustomizer";

	private const string ApiTypeName = "VoidCrewShipCustomizer.ShipCustomizerApi";

	private const int ApiVersion = 1;

	private static bool _looked;

	private static bool _installed;

	private static MethodInfo _getDef;

	private static MethodInfo _getStandIn;

	private static MethodInfo _setTerminalShip;

	private static MethodInfo _checkShip2;

	private static MethodInfo _setShip2;

	private static MethodInfo _buildShip2;

	private static MethodInfo _getShip2Alloys;

	private static MethodInfo _getRuleOptions;

	public static bool Installed
	{
		get
		{
			Look();
			return _installed;
		}
	}

	public static bool Linked
	{
		get
		{
			Look();
			return _getDef != null;
		}
	}

	public static bool HasRules
	{
		get
		{
			if (Linked)
			{
				return _getRuleOptions != null;
			}
			return false;
		}
	}

	private static void Look()
	{
		if (_looked || !FleetRuntime.GameReady)
		{
			return;
		}
		_looked = true;
		try
		{
			if (!Chainloader.PluginInfos.TryGetValue("com.captainchunck.voidcrew.shipcustomizer", out var value) || value == null)
			{
				Log.Verbose("Ship Customizer is not installed.");
				return;
			}
			_installed = true;
			Type type = FindApi(value);
			FieldInfo fieldInfo = ((type != null) ? type.GetField("ApiVersion", BindingFlags.Static | BindingFlags.Public) : null);
			if (fieldInfo == null || (int)fieldInfo.GetValue(null) < 1)
			{
				Log.Info("Ship Customizer is installed without its API for a second ship: ship 2 can be a copy of ship 1 (CUSTOM included), but can't have a CUSTOM loadout of its own until the Customizer is updated.");
				return;
			}
			MethodInfo method = type.GetMethod("GetDef", new Type[1] { typeof(GUIDUnion) });
			_getStandIn = type.GetMethod("GetStandIn", new Type[1] { typeof(GUIDUnion) });
			_setTerminalShip = type.GetMethod("SetTerminalShip", new Type[1] { typeof(int) });
			_checkShip2 = type.GetMethod("CheckShip2", new Type[2]
			{
				typeof(GUIDUnion),
				typeof(int)
			});
			_setShip2 = type.GetMethod("SetShip2", new Type[1] { typeof(GUIDUnion) });
			_buildShip2 = type.GetMethod("BuildShip2", new Type[1] { typeof(GUIDUnion) });
			_getShip2Alloys = type.GetMethod("GetShip2Alloys", new Type[1] { typeof(GUIDUnion) });
			_getRuleOptions = type.GetMethod("GetRuleOptions", Type.EmptyTypes);
			if (method == null || _getStandIn == null || _setTerminalShip == null || _checkShip2 == null || _setShip2 == null || _buildShip2 == null)
			{
				Log.Warn("Ship Customizer's API is missing members, so ship 2 can't use CUSTOM of its own.");
				return;
			}
			_getDef = method;
			EventInfo eventInfo = type.GetEvent("Ship2CustomCancelled", BindingFlags.Static | BindingFlags.Public);
			if (eventInfo != null)
			{
				eventInfo.AddEventHandler(null, new Action(HubFleet.Ship2CustomCancelled));
			}
			Log.Info("Ship Customizer found: ship 2 can use its own CUSTOM loadout.");
		}
		catch (Exception e)
		{
			_getDef = null;
			Log.Failure("Linking to Ship Customizer", e);
		}
	}

	private static Type FindApi(PluginInfo info)
	{
		if (info.Instance != null)
		{
			Type type = ((object)info.Instance).GetType().Assembly.GetType("VoidCrewShipCustomizer.ShipCustomizerApi", throwOnError: false);
			if (type != null)
			{
				return type;
			}
		}
		Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
		foreach (Assembly assembly in assemblies)
		{
			Type type2;
			try
			{
				type2 = assembly.GetType("VoidCrewShipCustomizer.ShipCustomizerApi", throwOnError: false);
			}
			catch
			{
				continue;
			}
			if (type2 != null)
			{
				return type2;
			}
		}
		return null;
	}

	public static ShipLoadoutDataDef GetDef(GUIDUnion loadout)
	{
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		if (!((GUIDUnion)(ref loadout)).IsNull)
		{
			object obj = Call(() => _getDef, loadout);
			return (ShipLoadoutDataDef)((obj is ShipLoadoutDataDef) ? obj : null);
		}
		return null;
	}

	public static bool IsCustom(GUIDUnion loadout)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		return GetDef(loadout) != null;
	}

	public static ShipLoadoutDataDef GetStandIn(GUIDUnion loadout)
	{
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		object obj = Call(() => _getStandIn, loadout);
		return (ShipLoadoutDataDef)((obj is ShipLoadoutDataDef) ? obj : null);
	}

	public static void SetTerminalShip(int ship)
	{
		Call(() => _setTerminalShip, ship);
	}

	public static string CheckShip2(GUIDUnion loadout, int actor)
	{
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		if (!Linked)
		{
			return "Ship Customizer is not available.";
		}
		try
		{
			return _checkShip2.Invoke(null, new object[2] { loadout, actor }) as string;
		}
		catch (Exception e)
		{
			Log.Failure("Calling Ship Customizer (CheckShip2)", e);
			return "CUSTOM could not be checked (see the BepInEx log).";
		}
	}

	public static void SetShip2(GUIDUnion loadout)
	{
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		Call(() => _setShip2, loadout);
	}

	public static ShipLoadout BuildShip2(GUIDUnion loadout)
	{
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		object obj = Call(() => _buildShip2, loadout);
		return (ShipLoadout)((obj is ShipLoadout) ? obj : null);
	}

	public static int GetShip2Alloys(GUIDUnion loadout)
	{
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		object obj = Call(() => _getShip2Alloys, loadout);
		if (!(obj is int))
		{
			return -1;
		}
		return (int)obj;
	}

	public static string[] GetRuleOptions()
	{
		return (Call(() => _getRuleOptions) as string[]) ?? new string[0];
	}

	private static object Call(Func<MethodInfo> member, params object[] args)
	{
		if (!Linked)
		{
			return null;
		}
		MethodInfo methodInfo = member();
		if (methodInfo == null)
		{
			return null;
		}
		try
		{
			return methodInfo.Invoke(null, args);
		}
		catch (Exception e)
		{
			Log.Failure("Calling Ship Customizer (" + methodInfo.Name + ")", e);
			return null;
		}
	}
}
internal static class Features
{
	public static readonly string[] All = new string[24]
	{
		"16-player rooms", "Modded-session rules", "Progression pause", "Fleet session data", "Two ships in the hub", "Two-ship loadout terminal", "Fleet missions on the galaxy map", "Two player ships", "Ships kept apart", "Pings and ship markers per ship",
		"Per-ship resources", "Ship voice and sounds per ship", "Helm and outside camera per ship", "Two ships jump together", "Fleet Pilgrimage enemies", "PvP ship combat", "PvP match result", "PvP boarding rules", "PvP panel sabotage", "PvP enemy markers",
		"PvP proximity voice", "PvP turrets shoot enemy players", "PvP hacking terminal", "PvP arena"
	};

	public static void Listen()
	{
		Notice.Listen();
		HubFleet.Listen();
		PvpTeams.Listen();
		PvpMatch.Listen();
		PvpSabotage.Listen();
		PvpPunch.Listen();
		PvpTurrets.Listen();
		PvpHack.Listen();
		FleetRuntime.Frame += PvpPunch.Frame;
		FleetRuntime.Frame += PvpTurrets.Frame;
		FleetRuntime.Frame += PvpHack.Frame;
		FleetRuntime.Frame += PvpVoice.Frame;
		FleetRuntime.Frame += ShipResources.Frame;
		ShipDeath.ShipLost += ShipResources.OnShipLost;
		CloneTubes.HoldSpawns = () => PvpTeams.Choosing;
		FleetRuntime.Slow += HackTerminal.EnsureRegistered;
		FleetRuntime.Slow += HubFleet.Poll;
		FleetRuntime.Slow += ShipSpawn.KeepCrewsUpToDate;
		FleetRuntime.Slow += PvpTeamScreen.Tick;
		FleetRuntime.Slow += PvpCombat.KeepFactions;
		FleetRuntime.Slow += PvpCombat.KeepHostility;
		FleetRuntime.Slow += PvpMatch.Tick;
		FleetRuntime.Slow += PvpSabotage.Apply;
		FleetRuntime.Slow += PvpHack.Tick;
		FleetRuntime.Slow += PvpArena.Tick;
		FleetRuntime.Slow += PvpMarkers.Tick;
		FleetRuntime.Slow += ShipMarkers.Tick;
		FleetRuntime.Slow += HelmIsolation.Tick;
		FleetRuntime.Slow += FleetApi.Tick;
		FleetRuntime.Slow += AutoTest.Tick;
	}
}
public static class FleetApi
{
	public const int ApiVersion = 1;

	private static readonly Color Blue = new Color(0.24f, 0.55f, 1f, 1f);

	private static readonly Color Red = new Color(1f, 0.33f, 0.27f, 1f);

	private static string _signature;

	private static string _rulesSignature;

	public static bool ShipRulesActive
	{
		get
		{
			try
			{
				return IsTeamMatch && ShipRules.Current.Restricts;
			}
			catch
			{
				return false;
			}
		}
	}

	public static int FabricatorMaxLevel
	{
		get
		{
			try
			{
				return ShipRulesActive ? (ShipRules.Current.HighestTier - 1) : 2;
			}
			catch
			{
				return 2;
			}
		}
	}

	public static int MaxStartAlloys
	{
		get
		{
			try
			{
				return ShipRulesActive ? ShipRules.Current.MaxAlloys : int.MaxValue;
			}
			catch
			{
				return int.MaxValue;
			}
		}
	}

	public static bool ReadsShip2Alloys => true;

	public static bool IsTeamMatch
	{
		get
		{
			try
			{
				if (FleetSession.IsPvP)
				{
					return true;
				}
				return GameSessionManager.InHub && HubFleet.HostHasFleet && HubFleet.Variant == HubVariant.FleetBattle;
			}
			catch
			{
				return false;
			}
		}
	}

	public static event Action TeamsChanged;

	public static event Action ShipRulesChanged;

	public static bool IsTierAllowed(int tier)
	{
		try
		{
			return !ShipRulesActive || ShipRules.Current.TierAllowed(tier);
		}
		catch
		{
			return true;
		}
	}

	public static bool IsCategoryAllowed(string category)
	{
		try
		{
			return !ShipRulesActive || ShipRules.Current.CategoryAllowed(category);
		}
		catch
		{
			return true;
		}
	}

	public static bool IsItemAllowed(string code)
	{
		try
		{
			return !ShipRulesActive || ShipRules.Current.ItemAllowed(code);
		}
		catch
		{
			return true;
		}
	}

	public static int TeamOf(int actorNumber)
	{
		try
		{
			return IsTeamMatch ? FleetShips.CrewSlot(actorNumber) : (-1);
		}
		catch
		{
			return -1;
		}
	}

	public static int TeamOfShip(int ship)
	{
		if (!IsTeamMatch || (ship != 1 && ship != 2))
		{
			return -1;
		}
		return ship - 1;
	}

	public static bool CanEditShip(int actorNumber, int ship)
	{
		if (!IsTeamMatch)
		{
			return true;
		}
		int num = TeamOf(actorNumber);
		if (num >= 0)
		{
			return num == TeamOfShip(ship);
		}
		return false;
	}

	public static Color ShipColor(int ship)
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		return (Color)(TeamOfShip(ship) switch
		{
			1 => Red, 
			0 => Blue, 
			_ => Color.clear, 
		});
	}

	internal static Color TeamColor(int team)
	{
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		return (Color)(team switch
		{
			1 => Red, 
			0 => Blue, 
			_ => Color.clear, 
		});
	}

	internal static void Tick()
	{
		string text;
		try
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append(IsTeamMatch ? '1' : '0').Append(PvpTeams.Locked ? 'L' : '-');
			if (IsTeamMatch && PhotonNetwork.InRoom)
			{
				Player[] playerList = PhotonNetwork.PlayerList;
				foreach (Player val in playerList)
				{
					stringBuilder.Append(val.ActorNumber).Append(':').Append(FleetShips.CrewSlot(val.ActorNumber))
						.Append(',');
				}
			}
			text = stringBuilder.ToString();
		}
		catch
		{
			return;
		}
		if (text != _signature)
		{
			_signature = text;
			Raise(FleetApi.TeamsChanged, "the teams changed");
		}
		string text2;
		try
		{
			text2 = (ShipRulesActive ? "1" : "0") + ShipRules.CurrentJson;
		}
		catch
		{
			return;
		}
		if (!(text2 == _rulesSignature))
		{
			_rulesSignature = text2;
			Raise(FleetApi.ShipRulesChanged, "the ship rules changed");
		}
	}

	private static void Raise(Action handlers, string what)
	{
		if (handlers == null)
		{
			return;
		}
		Delegate[] invocationList = handlers.GetInvocationList();
		foreach (Delegate obj in invocationList)
		{
			try
			{
				((Action)obj)();
			}
			catch (Exception e)
			{
				Log.Failure("Telling another plugin that " + what, e);
			}
		}
	}
}
internal static class FleetDifficulty
{
	public const string Feature = "Fleet Pilgrimage enemies";

	private static bool Scaling
	{
		get
		{
			FleetPlan current = FleetSession.Current;
			if (current != null && current.ScaleEnemies)
			{
				return PhotonNetwork.IsMasterClient;
			}
			return false;
		}
	}

	private static float Multiplier
	{
		get
		{
			if (Settings.EnemyMultiplier == null)
			{
				return 1.6f;
			}
			return Settings.EnemyMultiplier.Value;
		}
	}

	[GamePatch("Fleet Pilgrimage enemies", "Gameplay.MissionDifficulty.DifficultyState", "GetSpawnGroupAmountMultiplier", PatchKind.Postfix)]
	private static void GroupSizePostfix(ref float __result)
	{
		if (Scaling)
		{
			__result *= Multiplier;
		}
	}

	[GamePatch("Fleet Pilgrimage enemies", "Gameplay.NPC.AI.Spawner", "SpawnUnitEntry", PatchKind.Prefix)]
	private static void SpawnPrefix(float ___currentIntensity, out float __state)
	{
		__state = ___currentIntensity;
	}

	[GamePatch("Fleet Pilgrimage enemies", "Gameplay.NPC.AI.Spawner", "SpawnUnitEntry", PatchKind.Postfix)]
	private static void SpawnPostfix(ref float ___currentIntensity, float __state)
	{
		if (Scaling)
		{
			___currentIntensity = __state + (___currentIntensity - __state) / Multiplier;
		}
	}

	[GamePatch("Fleet Pilgrimage enemies", "Gameplay.NPC.AI.Spawner", "TrackedUnitDestroyed", PatchKind.Prefix)]
	private static void DestroyedPrefix(float ___currentIntensity, out float __state)
	{
		__state = ___currentIntensity;
	}

	[GamePatch("Fleet Pilgrimage enemies", "Gameplay.NPC.AI.Spawner", "TrackedUnitDestroyed", PatchKind.Postfix)]
	private static void DestroyedPostfix(ref float ___currentIntensity, float __state)
	{
		if (Scaling)
		{
			___currentIntensity = __state + (___currentIntensity - __state) / Multiplier;
		}
	}
}
internal sealed class FleetRuntime : MonoBehaviour
{
	private const float PollSeconds = 0.25f;

	private float _nextPoll;

	public static FleetRuntime Instance { get; private set; }

	public static bool GameReady { get; private set; }

	public static event Action Frame;

	public static event Action Slow;

	private void Awake()
	{
		Instance = this;
	}

	private void Update()
	{
		if (!GameReady)
		{
			if (!CheckReady())
			{
				return;
			}
			GameReady = true;
			Net.StartListening();
			Log.Info("The game has loaded; Void Crew Fleet is active.");
		}
		Run(FleetRuntime.Frame, "per-frame");
		if (!(Time.unscaledTime < _nextPoll))
		{
			_nextPoll = Time.unscaledTime + 0.25f;
			Run(FleetRuntime.Slow, "periodic");
		}
	}

	private static bool CheckReady()
	{
		try
		{
			GameStateMachine instance = Singleton<GameStateMachine>.Instance;
			if ((Object)(object)instance == (Object)null || ((AbstractStateMachine<GameStateMachine>)(object)instance).CurrentState == null)
			{
				return false;
			}
			return ((object)((AbstractStateMachine<GameStateMachine>)(object)instance).CurrentState).GetType().Name != "GSLoading";
		}
		catch
		{
			return false;
		}
	}

	private static void Run(Action work, string what)
	{
		if (work == null)
		{
			return;
		}
		Delegate[] invocationList = work.GetInvocationList();
		foreach (Delegate obj in invocationList)
		{
			try
			{
				((Action)obj)();
			}
			catch (Exception e)
			{
				Log.Failure("Running " + what + " work (" + obj.Method.DeclaringType.Name + "." + obj.Method.Name + ")", e);
			}
		}
	}
}
internal enum FleetMode : byte
{
	OneShip,
	TwoShips,
	PvP
}
internal sealed class FleetPlan
{
	public const int Protocol = 2;

	public FleetMode Mode;

	public bool ScaleEnemies;

	public GUIDUnion ShipB;

	public string ShipBName;

	public GUIDUnion ShipBHomunculus;

	public ShipLoadout ShipBLoadout;

	public int ShipBAlloys = -2;

	public int HackCost = 10;

	public string Arena = "auto";

	public JObject ToJson()
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: 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_005d: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: Expected O, but got Unknown
		return new JObject
		{
			["protocol"] = JToken.op_Implicit(2),
			["mode"] = JToken.op_Implicit((int)Mode),
			["scale"] = JToken.op_Implicit(ScaleEnemies),
			["shipB"] = JToken.op_Implicit(((GUIDUnion)(ref ShipB)).AsHex()),
			["shipBName"] = JToken.op_Implicit(ShipBName ?? ""),
			["shipBHomunculus"] = JToken.op_Implicit(((GUIDUnion)(ref ShipBHomunculus)).AsHex()),
			["hackCost"] = JToken.op_Implicit(HackCost),
			["arena"] = JToken.op_Implicit(Arena ?? "auto")
		};
	}

	public static FleetPlan FromJson(JObject json)
	{
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_0058: Unknown result type (might be due to invalid IL or missing references)
		//IL_009b: 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)
		FleetPlan fleetPlan = new FleetPlan();
		JToken val = default(JToken);
		if (json.TryGetValue("mode", ref val))
		{
			fleetPlan.Mode = (FleetMode)Extensions.Value<int>((IEnumerable<JToken>)val);
		}
		if (json.TryGetValue("scale", ref val))
		{
			fleetPlan.ScaleEnemies = Extensions.Value<bool>((IEnumerable<JToken>)val);
		}
		if (json.TryGetValue("shipB", ref val))
		{
			fleetPlan.ShipB = new GUIDUnion(Extensions.Value<string>((IEnumerable<JToken>)val));
		}
		if (json.TryGetValue("shipBName", ref val))
		{
			fleetPlan.ShipBName = Extensions.Value<string>((IEnumerable<JToken>)val);
		}
		if (json.TryGetValue("shipBHomunculus", ref val) && !string.IsNullOrEmpty(Extensions.Value<string>((IEnumerable<JToken>)val)))
		{
			fleetPlan.ShipBHomunculus = new GUIDUnion(Extensions.Value<string>((IEnumerable<JToken>)val));
		}
		if (json.TryGetValue("hackCost", ref val))
		{
			fleetPlan.HackCost = Extensions.Value<int>((IEnumerable<JToken>)val);
		}
		if (json.TryGetValue("arena", ref val))
		{
			fleetPlan.Arena = Extensions.Value<string>((IEnumerable<JToken>)val);
		}
		return fleetPlan;
	}

	public override string ToString()
	{
		if (Mode != FleetMode.OneShip)
		{
			if (Mode != FleetMode.PvP)
			{
				return "two ships" + (ScaleEnemies ? ", Fleet Pilgrimage enemy scaling" : "");
			}
			return "PvP, two ships";
		}
		return "one ship";
	}
}
internal static class FleetSession
{
	public const string Feature = "Fleet session data";

	private const string JsonKey = "vcf";

	private static readonly ConditionalWeakTable<GameSession, FleetPlan> Plans = new ConditionalWeakTable<GameSession, FleetPlan>();

	private static GameSession _cachedSession;

	private static FleetPlan _cachedPlan;

	public static FleetPlan Current
	{
		get
		{
			GameSession activeSession;
			try
			{
				activeSession = GameSessionManager.ActiveSession;
			}
			catch
			{
				return null;
			}
			if (activeSession == null)
			{
				return null;
			}
			if (activeSession != _cachedSession)
			{
				_cachedPlan = (Plans.TryGetValue(activeSession, out var value) ? value : null);
				_cachedSession = activeSession;
			}
			return _cachedPlan;
		}
	}

	public static FleetMode Mode => Current?.Mode ?? FleetMode.OneShip;

	public static bool IsPvP => Mode == FleetMode.PvP;

	public static int ShipCount
	{
		get
		{
			if (Mode != FleetMode.OneShip)
			{
				return 2;
			}
			return 1;
		}
	}

	public static void Attach(GameSession session, FleetPlan plan)
	{
		if (session != null)
		{
			Plans.Remove(session);
			if (plan != null)
			{
				Plans.Add(session, plan);
			}
			_cachedSession = null;
		}
	}

	public static int DifficultyPlayerCount(int roomPlayers)
	{
		if (ShipCount < 2)
		{
			return roomPlayers;
		}
		return Mathf.Max(1, Mathf.CeilToInt((float)roomPlayers / 2f));
	}

	[GamePatch("Fleet session data", "GameSession", "AsJObject", PatchKind.Postfix)]
	private static void AsJObjectPostfix(GameSession __instance, JObject __result)
	{
		try
		{
			if (__result != null && Plans.TryGetValue(__instance, out var value))
			{
				__result["vcf"] = (JToken)(object)value.ToJson();
			}
		}
		catch (Exception e)
		{
			Log.Failure("Adding the fleet plan to the session data", e);
		}
	}

	[GamePatch("Fleet session data", "GameSession", "FromJObject", PatchKind.Postfix)]
	private static void FromJObjectPostfix(JObject jObj, GameSession __result)
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Invalid comparison between Unknown and I4
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Expected O, but got Unknown
		try
		{
			JToken val = default(JToken);
			if (__result != null && jObj != null && jObj.TryGetValue("vcf", ref val) && (int)val.Type == 1)
			{
				FleetPlan fleetPlan = FleetPlan.FromJson((JObject)val);
				Attach(__result, fleetPlan);
				Log.Info("This mission is a fleet mission: " + fleetPlan?.ToString() + ".");
			}
		}
		catch (Exception e)
		{
			Log.Failure("Reading the fleet plan from the session data", e);
		}
	}
}
internal static class FleetShips
{
	public const string Feature = "Two player ships";

	private const string KeyShips = "VCF_Ships";

	private const string KeyCrew = "VCF_Crew";

	private static readonly List<PlayerControlledShip> Registered = new List<PlayerControlledShip>();

	private static readonly Dictionary<int, PlayerControlledShip> OwnerCache = new Dictionary<int, PlayerControlledShip>();

	private static int[] _hostCrew;

	private static readonly Dictionary<int, PlayerControlledShip> Assigned = new Dictionary<int, PlayerControlledShip>();

	public static bool Active
	{
		get
		{
			Prune();
			return Registered.Count > 1;
		}
	}

	public static IList<PlayerControlledShip> All
	{
		get
		{
			Prune();
			return Registered;
		}
	}

	public static int LocalActor
	{
		get
		{
			if (PhotonNetwork.LocalPlayer == null)
			{
				return -1;
			}
			return PhotonNetwork.LocalPlayer.ActorNumber;
		}
	}

	public static PlayerControlledShip LocalShip => ShipOfActor(LocalActor);

	public static PlayerControlledShip ViewShip
	{
		get
		{
			PlayerControlledShip val;
			try
			{
				val = AboardShip((Player)(object)LocalPlayer.Instance);
			}
			catch
			{
				val = null;
			}
			if ((Object)(object)val != (Object)null && !FleetSession.IsPvP)
			{
				return val;
			}
			PlayerControlledShip localShip = LocalShip;
			if ((Object)(object)localShip != (Object)null)
			{
				return localShip;
			}
			localShip = val;
			if ((Object)(object)localShip != (Object)null)
			{
				return localShip;
			}
			localShip = BySlot(0);
			if ((Object)(object)localShip != (Object)null)
			{
				return localShip;
			}
			Prune();
			if (Registered.Count <= 0)
			{
				return null;
			}
			return Registered[0];
		}
	}

	private static void Prune()
	{
		for (int num = Registered.Count - 1; num >= 0; num--)
		{
			if ((Object)(object)Registered[num] == (Object)null)
			{
				Registered.RemoveAt(num);
			}
		}
	}

	public static void Register(PlayerControlledShip ship)
	{
		if (!((Object)(object)ship == (Object)null) && !Registered.Contains(ship))
		{
			Registered.Add(ship);
			OwnerCache.Clear();
			if (Registered.Count > 1)
			{
				Log.Info("Player ship " + Registered.Count + " is in the game (view " + ViewId(ship) + ").");
			}
		}
	}

	public static void Unregister(PlayerControlledShip ship)
	{
		bool num = Registered.Count > 1;
		Registered.Remove(ship);
		OwnerCache.Clear();
		Prune();
		if (!num || Registered.Count != 1)
		{
			return;
		}
		try
		{
			if ((Object)(object)ClientGame.Current != (Object)null)
			{
				ClientGame.Current.PlayerShip = Registered[0];
			}
			Log.Info("Only " + Describe(Registered[0]) + " is left; it is everyone's ship now.");
		}
		catch (Exception e)
		{
			Log.Failure("Making the remaining ship everyone's ship", e);
		}
	}

	public static int ViewId(PlayerControlledShip ship)
	{
		try
		{
			return ((Object)(object)ship != (Object)null && (Object)(object)((MonoBehaviourPun)ship).photonView != (Object)null) ? ((MonoBehaviourPun)ship).photonView.ViewID : 0;
		}
		catch
		{
			return 0;
		}
	}

	private static int[] PublishedShips()
	{
		if (!PhotonNetwork.InRoom || PhotonNetwork.CurrentRoom == null || !((Dictionary<object, object>)(object)((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties).TryGetValue((object)"VCF_Ships", out object value))
		{
			return null;
		}
		return value as int[];
	}

	public static void PublishShips(PlayerControlledShip shipA, PlayerControlledShip shipB)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Expected O, but got Unknown
		if (PhotonNetwork.IsMasterClient && PhotonNetwork.CurrentRoom != null)
		{
			Room currentRoom = PhotonNetwork.CurrentRoom;
			Hashtable val = new Hashtable();
			((Dictionary<object, object>)(object)val).Add((object)"VCF_Ships", (object)new int[2]
			{
				ViewId(shipA),
				ViewId(shipB)
			});
			currentRoom.SetCustomProperties(val, (Hashtable)null, (WebFlags)null);
		}
	}

	public static void ClearRoom()
	{
		//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_002b: Expected O, but got Unknown
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Expected O, but got Unknown
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_0043: Expected O, but got Unknown
		//IL_004a: Expected O, but got Unknown
		_hostCrew = null;
		if (PhotonNetwork.IsMasterClient && PhotonNetwork.CurrentRoom != null)
		{
			Room currentRoom = PhotonNetwork.CurrentRoom;
			Hashtable val = new Hashtable();
			((Dictionary<object, object>)val).Add((object)"VCF_Ships", (object)null);
			((Dictionary<object, object>)val).Add((object)"VCF_Crew", (object)null);
			((Dictionary<object, object>)val).Add((object)"VCF_ResStart", (object)null);
			currentRoom.SetCustomProperties(val, (Hashtable)null, (WebFlags)null);
		}
	}

	public static int Slot(PlayerControlledShip ship)
	{
		if ((Object)(object)ship == (Object)null)
		{
			return -1;
		}
		int num = ViewId(ship);
		int[] array = PublishedShips();
		if (array != null)
		{
			int num2 = Array.IndexOf(array, num);
			if (num2 >= 0)
			{
				return num2;
			}
		}
		Prune();
		int num3 = 0;
		foreach (PlayerControlledShip item in Registered)
		{
			if ((Object)(object)item != (Object)(object)ship && ViewId(item) < num)
			{
				num3++;
			}
		}
		return num3;
	}

	public static PlayerControlledShip BySlot(int slot)
	{
		Prune();
		foreach (PlayerControlledShip item in Registered)
		{
			if (Slot(item) == slot)
			{
				return item;
			}
		}
		return null;
	}

	private static int[] Crew()
	{
		if (_hostCrew != null && PhotonNetwork.IsMasterClient)
		{
			return _hostCrew;
		}
		if (!PhotonNetwork.InRoom || PhotonNetwork.CurrentRoom == null || !((Dictionary<object, object>)(object)((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties).TryGetValue((object)"VCF_Crew", out object value))
		{
			return null;
		}
		return value as int[];
	}

	public static int CrewSlot(int actor)
	{
		int[] array = Crew();
		if (array == null)
		{
			return -1;
		}
		for (int i = 0; i + 1 < array.Length; i += 2)
		{
			if (array[i] == actor)
			{
				return array[i + 1];
			}
		}
		return -1;
	}

	public static Dictionary<int, int> CrewMap()
	{
		Dictionary<int, int> dictionary = new Dictionary<int, int>();
		int[] array = Crew();
		if (array == null)
		{
			return dictionary;
		}
		for (int i = 0; i + 1 < array.Length; i += 2)
		{
			dictionary[array[i]] = array[i + 1];
		}
		return dictionary;
	}

	public static void PublishCrew(Dictionary<int, int> map)
	{
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Unknown result type (might be due to invalid IL or missing references)
		//IL_0081: Expected O, but got Unknown
		//IL_0088: Expected O, but got Unknown
		if (!PhotonNetwork.IsMasterClient || PhotonNetwork.CurrentRoom == null)
		{
			return;
		}
		int[] array = new int[map.Count * 2];
		int num = 0;
		foreach (KeyValuePair<int, int> item in map)
		{
			array[num++] = item.Key;
			array[num++] = item.Value;
		}
		_hostCrew = array;
		Room currentRoom = PhotonNetwork.CurrentRoom;
		Hashtable val = new Hashtable();
		((Dictionary<object, object>)val).Add((object)"VCF_Crew", (object)array);
		currentRoom.SetCustomProperties(val, (Hashtable)null, (WebFlags)null);
	}

	public static int CrewCount(int slot)
	{
		int num = 0;
		foreach (KeyValuePair<int, int> item in CrewMap())
		{
			if (item.Value == slot)
			{
				num++;
			}
		}
		return num;
	}

	public static PlayerControlledShip ShipOfActor(int actor)
	{
		int num = CrewSlot(actor);
		if (num < 0)
		{
			return null;
		}
		return BySlot(num);
	}

	public static PlayerControlledShip AboardShip(Player player)
	{
		if ((Object)(object)player == (Object)null)
		{
			return null;
		}
		try
		{
			SpacePlatform val = (((Object)(object)player.ZonedPlatform != (Object)null) ? player.ZonedPlatform : player.Platform);
			return ((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<PlayerControlledShip>() : null;
		}
		catch
		{
			return null;
		}
	}

	public static void AssignOwner(Component component, PlayerControlledShip ship)
	{
		if (!((Object)(object)component == (Object)null))
		{
			if ((Object)(object)ship == (Object)null)
			{
				Assigned.Remove(((Object)component).GetInstanceID());
			}
			else
			{
				Assigned[((Object)component).GetInstanceID()] = ship;
			}
		}
	}

	public static PlayerControlledShip AssignedOwner(Component component)
	{
		if (!((Object)(object)component != (Object)null) || !Assigned.TryGetValue(((Object)component).GetInstanceID(), out var value) || !((Object)(object)value != (Object)null))
		{
			return null;
		}
		return value;
	}

	public static PlayerControlledShip OwnerOf(Component component)
	{
		if ((Object)(object)component == (Object)null)
		{
			return null;
		}
		int instanceID;
		try
		{
			instanceID = ((Object)component).GetInstanceID();
		}
		catch
		{
			return null;
		}
		if (Assigned.TryGetValue(instanceID, out var value) && (Object)(object)value != (Object)null)
		{
			return value;
		}
		if (OwnerCache.TryGetValue(instanceID, out value) && (Object)(object)value != (Object)null)
		{
			return value;
		}
		PlayerControlledShip val = component.GetComponentInParent<PlayerControlledShip>();
		if ((Object)(object)val == (Object)null)
		{
			OrbitObject val2 = (OrbitObject)(object)((component is OrbitObject) ? component : null);
			if ((Object)(object)val2 != (Object)null)
			{
				OrbitObject rootSpatialParent = val2.GetRootSpatialParent();
				val = (PlayerControlledShip)(object)((rootSpatialParent is PlayerControlledShip) ? rootSpatialParent : null);
			}
		}
		if ((Object)(object)val == (Object)null)
		{
			ShipHull componentInParent = component.GetComponentInParent<ShipHull>();
			if ((Object)(object)componentInParent != (Object)null)
			{
				val = componentInParent.Ship;
			}
		}
		if ((Object)(object)val == (Object)null)
		{
			CarryableObject val3 = (CarryableObject)(object)((component is CarryableObject) ? component : null);
			if ((Object)(object)val3 != (Object)null && (Object)(object)val3.ParentPlatform != (Object)null)
			{
				val = ((Component)val3.ParentPlatform).GetComponent<PlayerControlledShip>();
			}
		}
		if ((Object)(object)val != (Object)null && !(component is CarryableObject))
		{
			OwnerCache[instanceID] = val;
		}
		return val;
	}

	public static PlayerControlledShip InteriorAt(Vector3 point)
	{
		//IL_0043: 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_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		Prune();
		Vector3 val3 = default(Vector3);
		foreach (PlayerControlledShip item in Registered)
		{
			try
			{
				ShipHull hull = item.Hull;
				RoomCollection val = (((Object)(object)hull != (Object)null) ? hull.RoomCollection : null);
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				Bounds bounds = val.Bounds;
				((Bounds)(ref bounds)).Expand(1f);
				if (!((Bounds)(ref bounds)).Contains(((Component)val).transform.InverseTransformPoint(point)))
				{
					continue;
				}
				Room[] rooms = val.Rooms;
				foreach (Room val2 in rooms)
				{
					if ((Object)(object)val2 != (Object)null && !val2.InSpace && val.RoomSphereIntersect(val2, point, 0.25f, ref val3))
					{
						return item;
					}
				}
			}
			catch
			{
			}
		}
		return null;
	}

	public static string Describe(PlayerControlledShip ship)
	{
		return Slot(ship) switch
		{
			1 => "ship 2", 
			0 => "ship 1", 
			_ => "a ship", 
		};
	}

	public static Player CharacterOf(int actor)
	{
		ClientGame current = ClientGame.Current;
		if ((Object)(object)current == (Object)null || current.Players == null)
		{
			return null;
		}
		foreach (Player player in current.Players)
		{
			if (!((Object)(object)player == (Object)null))
			{
				PhotonView photonView = ((MonoBehaviourPun)player).photonView;
				if ((Object)(object)photonView != (Object)null && (photonView.OwnerActorNr == actor || photonView.CreatorActorNr == actor))
				{
					return player;
				}
			}
		}
		return null;
	}
}
internal static class GalaxyMapModes
{
	public const string Feature = "Fleet missions on the galaxy map";

	private const int FleetPilgrimageType = 100;

	private const int FleetBattleType = 101;

	private static readonly MethodInfo AddEntry = GameMember.Method(typeof(GalaxyMapUIController), "AddGamemodeEntry");

	private static readonly MethodInfo UpdateStyles = GameMember.Method(typeof(GalaxyMapUIController), "UpdateStyles");

	private static readonly MethodInfo UpdateIncludedMutators = GameMember.Method(typeof(GalaxyMapUIController), "UpdateIncludedMutators");

	private static readonly MethodInfo CheckSelected = GameMember.Method(typeof(GalaxyMapUIController), "CheckSelectedGamemode");

	private static readonly FieldInfo ShownField = GameMember.Field(typeof(GalaxyMapUIController), "_shownGameModeEntry");

	private static readonly FieldInfo ActivatedField = GameMember.Field(typeof(GalaxyMapUIController), "_activatedGameModeEntry");

	private static readonly FieldInfo BannerField = GameMember.Field(typeof(GalaxyMapUIController), "_banner");

	private static readonly FieldInfo MutatorMenuField = GameMember.Field(typeof(GalaxyMapUIController), "_mutatorsSelectionMenu");

	private static readonly FieldInfo EntryOnShown = GameMember.Field("GalaxyMapUIController+GameModeEntry", "OnShown");

	private static readonly FieldInfo EntryOnActivate = GameMember.Field("GalaxyMapUIController+GameModeEntry", "OnActivate");

	private static readonly FieldInfo EntryKind = GameMember.Field("GalaxyMapUIController+GameModeEntry", "GamemodeType");

	private static GalaxyMapUIController _controller;

	private static object _fleetEntry;

	private static object _battleEntry;

	private static ContextInfo _fleetInfo;

	private static ContextInfo _battleInfo;

	private static bool _subscribed;

	[GamePatch("Fleet missions on the galaxy map", "GalaxyMapUIController", "UpdateAvailableGamemodes", PatchKind.Postfix)]
	private static void AvailableModesPostfix(GalaxyMapUIController __instance)
	{
		try
		{
			if (!(AddEntry == null) && !(EntryOnShown == null) && !(EntryOnActivate == null))
			{
				_controller = __instance;
				MakeInfos();
				_fleetEntry = AddEntry.Invoke(__instance, new object[2]
				{
					(object)(GamemodeType)100,
					_fleetInfo
				});
				_battleEntry = AddEntry.Invoke(__instance, new object[2]
				{
					(object)(GamemodeType)101,
					_battleInfo
				});
				Wire(__instance, _fleetEntry, HubVariant.FleetPilgrimage);
				Wire(__instance, _battleEntry, HubVariant.FleetBattle);
				if (!_subscribed)
				{
					HubFleet.Changed += Recheck;
					_subscribed = true;
				}
			}
		}
		catch (Exception e)
		{
			Log.Failure("Adding the fleet missions to the galaxy map", e);
		}
	}

	private static void MakeInfos()
	{
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_fleetInfo != (Object)null && (Object)(object)_battleInfo != (Object)null)
		{
			return;
		}
		Sprite val = null;
		try
		{
			QuestAssetDef assetDefById = ((ResourceAssetContainer<QuestAssetContainer, QuestAsset, QuestAssetDef>)(object)ResourceAssetContainer<QuestAssetContainer, QuestAsset, QuestAssetDef>.Instance).GetAssetDefById(((ResourceAssetRef)DataTable<QuestTable>.Instance.EndlessQuest).AssetGuid, true);
			if (assetDefById != null && assetDefById.ContextInfo != null)
			{
				val = assetDefById.ContextInfo.Icon;
			}
		}
		catch (Exception e)
		{
			Log.Failure("Reading the Pilgrimage's picture", e);
		}
		_fleetInfo = ContextInfo.Create(val, "FLEET PILGRIMAGE", "The Pilgrimage for <b>two ships</b>. Enemies come in greater numbers and every sector holds more objectives, so the two crews can split up and work on different objectives at the same time. Up to 16 players, shared evenly between the ships.\n<i>Fleet missions give no XP or rewards (Void Crew's modding rules).</i>");
		_battleInfo = ContextInfo.Create(val, "FLEET BATTLE", "<b>PvP</b>: two crews, one ship each, starting on opposite sides of an asteroid field full of objectives that pay out alloys for upgrades and ammo. Pick your team before the match; the host balances and confirms the teams. Board through open airlocks, or hack one with a hacking terminal from the fabricator to open the enemy's doors for five minutes. Sabotage enemy systems at their enhancement panels, and destroy the enemy ship to win.\n<i>No XP or rewards (Void Crew's modding rules).</i>");
		((Object)_fleetInfo).hideFlags = (HideFlags)32;
		((Object)_battleInfo).hideFlags = (HideFlags)32;
	}

	private static void Wire(GalaxyMapUIController controller, object entry, HubVariant variant)
	{
		EntryOnShown.SetValue(entry, (Action)delegate
		{
			Shown(controller, entry);
		});
		EntryOnActivate.SetValue(entry, (Action)delegate
		{
			Activate(variant);
		});
	}

	private static void Shown(GalaxyMapUIController controller, object entry)
	{
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			QuestAsset asset = ((ResourceAssetRef<QuestAssetContainer, QuestAsset, QuestAssetDef>)(object)DataTable<QuestTable>.Instance.EndlessQuest).Asset;
			ShownField.SetValue(controller, entry);
			UpdateStyles.Invoke(controller, null);
			UpdateIncludedMutators.Invoke(controller, new object[1] { asset.ForcedMutators });
			VisualElement val = (VisualElement)((BannerField != null) ? /*isinst with value type is only supported in some contexts*/: null);
			if (val != null)
			{
				val.style.backgroundImage = new StyleBackground(DataTable<QuestTable>.Instance.EndlessMoodImage);
			}
			MutatorsSelectionMenu val2 = (MutatorsSelectionMenu)((MutatorMenuField != null) ? /*isinst with value type is only supported in some contexts*/: null);
			if (val2 != null)
			{
				val2.OnShownQuestChangedInGalaxyMap(asset);
			}
		}
		catch (Exception e)
		{
			Log.Failure("Showing a fleet mission on the galaxy map", e);
		}
	}

	private static void Activate(HubVariant variant)
	{
		if (!HubFleet.HostHasFleet)
		{
			Notice.Show("The host of this room doesn't run Void Crew Fleet, so fleet missions aren't available here.");
		}
		else
		{
			HubFleet.RequestVariant(variant);
		}
	}

	[GamePatch("Fleet missions on the galaxy map", "GalaxyMapUIController", "CheckSelectedGamemode", PatchKind.Postfix)]
	private static void CheckSelectedPostfix(GalaxyMapUIController __instance, bool switchToActivated)
	{
		//IL_0023: 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)
		try
		{
			HubQuestManager instance = HubQuestManager.Instance;
			if ((Object)(object)instance == (Object)null || (ResourceAssetRef)(object)instance.SelectedQuest == (ResourceAssetRef)null || ((ResourceAssetRef)instance.SelectedQuest).AssetGuid != ((ResourceAssetRef)DataTable<QuestTable>.Instance.EndlessQuest).AssetGuid)
			{
				return;
			}
			object obj = ((HubFleet.Variant == HubVariant.FleetPilgrimage) ? _fleetEntry : ((HubFleet.Variant == HubVariant.FleetBattle) ? _battleEntry : null));
			if (obj != null && !(ActivatedField == null))
			{
				ActivatedField.SetValue(__instance, obj);
				if (switchToActivated)
				{
					ShownField.SetValue(__instance, obj);
				}
				UpdateStyles.Invoke(__instance, null);
			}
		}
		catch (Exception e)
		{
			Log.Failure("Marking the chosen fleet mission on the galaxy map", e);
		}
	}

	private static void Recheck()
	{
		if ((Object)(object)_controller == (Object)null || CheckSelected == null)
		{
			return;
		}
		try
		{
			CheckSelected.Invoke(_controller, new object[1] { false });
		}
		catch (Exception e)
		{
			Log.Failure("Refreshing the galaxy map", e);
		}
	}

	[GamePatch("Fleet missions on the galaxy map", "GalaxyMapUIController+GameModeEntry", "GetQuestType", PatchKind.Postfix)]
	private static void QuestTypePostfix(object __instance, ref string __result)
	{
		if (!(EntryKind == null) && __instance != null)
		{
			switch (Convert.ToInt32(EntryKind.GetValue(__instance)))
			{
			case 100:
				__result = "PILGRIMAGE · 2 SHIPS";
				break;
			case 101:
				__result = "PVP · 2 SHIPS";
				break;
			}
		}
	}
}
internal static class GameMember
{
	public static Type Type(string typeName)
	{
		Type type = AccessTools.TypeByName(typeName);
		if (type == null)
		{
			Log.WarnOnce("type " + typeName, "Game type " + typeName + " was not found; the game may have changed.");
		}
		return type;
	}

	public static FieldInfo Field(string typeName, string fieldName)
	{
		Type type = Type(typeName);
		if (type == null)
		{
			return null;
		}
		FieldInfo fieldInfo = AccessTools.Field(type, fieldName);
		if (fieldInfo == null)
		{
			Log.WarnOnce("field " + typeName + "." + fieldName, "Game field " + typeName + "." + fieldName + " was not found; the game may have changed.");
		}
		return fieldInfo;
	}

	public static MethodInfo Method(string typeName, string methodName)
	{
		Type type = Type(typeName);
		if (type == null)
		{
			return null;
		}
		MethodInfo methodInfo = AccessTools.Method(type, methodName, (Type[])null, (Type[])null);
		if (methodInfo == null)
		{
			Log.WarnOnce("method " + typeName + "." + methodName, "Game method " + typeName + "." + methodName + " was not found; the game may have changed.");
		}
		return methodInfo;
	}

	public static PropertyInfo Property(string typeName, string propertyName)
	{
		Type type = Type(typeName);
		if (type == null)
		{
			return null;
		}
		PropertyInfo propertyInfo = AccessTools.Property(type, propertyName);
		if (propertyInfo == null)
		{
			Log.WarnOnce("property " + typeName + "." + propertyName, "Game property " + typeName + "." + propertyName + " was not found; the game may have changed.");
		}
		return propertyInfo;
	}

	public static FieldInfo Field(Type type, string fieldName)
	{
		FieldInfo fieldInfo = AccessTools.Field(type, fieldName);
		if (fieldInfo == null)
		{
			Log.WarnOnce("field " + type.FullName + "." + fieldName, "Game field " + type.FullName + "." + fieldName + " was not found; the game may have changed.");
		}
		return fieldInfo;
	}

	public static MethodInfo Method(Type type, string methodName)
	{
		MethodInfo methodInfo = AccessTools.Method(type, methodName, (Type[])null, (Type[])null);
		if (methodInfo == null)
		{
			Log.WarnOnce("method " + type.FullName + "." + methodName, "Game method " + type.FullName + "." + methodName + " was not found; the game may have changed.");
		}
		return methodInfo;
	}

	public static PropertyInfo Property(Type type, string propertyName)
	{
		PropertyInfo propertyInfo = AccessTools.Property(type, propertyName);
		if (propertyInfo == null)
		{
			Log.WarnOnce("property " + type.FullName + "." + propertyName, "Game property " + type.FullName + "." + propertyName + " was not found; the game may have changed.");
		}
		return propertyInfo;
	}

	public static T Read<T>(FieldInfo field, object instance, T fallback)
	{
		if (field == null)
		{
			return fallback;
		}
		try
		{
			object value = field.GetValue(instance);
			return (value is T) ? ((T)value) : fallback;
		}
		catch
		{
			return fallback;
		}
	}
}
internal static class HackTerminal
{
	public const string Feature = "PvP hacking terminal";

	public const int DefaultCost = 10;

	public static readonly GUIDUnion Guid = new GUIDUnion("f1ee7c0de5f1ee7c0de5f1ee7c0de5b2");

	private static readonly GUIDUnion ModelGuid = new GUIDUnion("d2427729f742ec04d98aa89b0575e9e0");

	private const string Header = "AIRLOCK HACKING TERMINAL";

	private const string Body = "PvP: plug it into the control panel outside an enemy airlock (hold Fire on the panel). After a one-minute hack, your whole team can open that ship's doors for five minutes, except its cockpit. Their crew can pull it out while it hacks.";

	private static readonly MethodInfo AddPrintableMethod = GameMember.Method(typeof(CraftData), "AddCraftableAsPrintable");

	private static readonly MethodInfo SetupCategoriesMethod = GameMember.Method(typeof(CraftData), "SetupCategories");

	private static GameObject _template;

	private static int _cost = -1;

	private static bool _attempted;

	public static bool Registered { get; private set; }

	public static CarryableObject LocalHeld
	{
		get
		{
			LocalPlayer instance = LocalPlayer.Instance;
			CarryableObject val = (((Object)(object)instance != (Object)null && (Object)(object)((Player)instance).Carrier != (Object)null) ? ((Player)instance).Payload : null);
			if (!Is(val))
			{
				return null;
			}
			return val;
		}
	}

	private static CloneStarObjectContainer Objects => ResourceAssetContainer<CloneStarObjectContainer, AbstractCloneStarObject, CloneStarObjectDef>.Instance;

	public static bool Is(CarryableObject carryable)
	{
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)carryable != (Object)null)
		{
			return ((AbstractCloneStarObject)carryable).assetGuid == Guid;
		}
		return false;
	}

	public static void EnsureRegistered()
	{
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c9: 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_00ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_010b: 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_0139: Unknown result type (might be due to invalid IL or missing references)
		//IL_0150: 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_0167: Unknown result type (might be due to invalid IL or missing references)
		//IL_016c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0174: Unknown result type (might be due to invalid IL or missing references)
		//IL_017e: Unknown result type (might be due to invalid IL or missing references)
		//IL_019c: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
		if (_attempted || !FleetRuntime.GameReady)
		{
			return;
		}
		_attempted = true;
		if (!Patcher.IsReady("PvP hacking terminal"))
		{
			return;
		}
		try
		{
			if (((ResourceAssetContainer<CloneStarObjectContainer, AbstractCloneStarObject, CloneStarObjectDef>)(object)Objects).HasItem(Guid))
			{
				Registered = true;
				return;
			}
			CarryableObject val = ((ResourceAssetDef<CarryableObject>)(object)((ResourceAssetContainer<CarryableContainer, CarryableObject, CarryableDef>)(object)ResourceAssetContainer<CarryableContainer, CarryableObject, CarryableDef>.Instance).GetAssetDefById(ModelGuid, false))?.Asset;
			if ((Object)(object)val == (Object)null)
			{
				Log.Warn("Hacking terminal: the game's Data Shard wasn't found, so there is no hacking terminal.");
				return;
			}
			GameObject gameObject = ((Component)val).gameObject;
			bool activeSelf = gameObject.activeSelf;
			if (activeSelf)
			{
				gameObject.SetActive(false);
			}
			try
			{
				_template = Object.Instantiate<GameObject>(gameObject);
			}
			finally
			{
				if (activeSelf)
				{
					gameObject.SetActive(true);
				}
			}
			Object.DontDestroyOnLoad((Object)(object)_template);
			((Object)_template).name = "VCF_HackTerminal";
			((AbstractCloneStarObject)_template.GetComponent<CarryableObject>()).ContainerGuid = Guid;
			if (!RuntimeAssetsRegister.Instance.HasAsset(Guid))
			{
				RuntimeAssetsRegister.Instance.RegisterAsset(Guid, (Object)(object)_template, (SessionModificationEffect)0, (RuntimeAssetInfo)null);
			}
			IResourceAssetContextInfo context = Objects.GetContext(ModelGuid);
			RuntimeAssetConverter.RegisterCarryableToContainers(Guid, "AIRLOCK HACKING TERMINAL", "PvP: plug it into the control panel outside an enemy airlock (hold Fire on the panel). After a one-minute hack, your whole team can open that ship's doors for five minutes, except its cockpit. Their crew can pull it out while it hacks.", (context != null) ? context.Icon : null);
			SetCost(10);
			((PurchasableResourceAssetDef<CarryableObject>)(object)((ResourceAssetContainer<CarryableContainer, CarryableObject, CarryableDef>)(object)ResourceAssetContainer<CarryableContainer, CarryableObject, CarryableDef>.Instance).GetAssetDefById(Guid, true)).SetPurchaseCategory((PurchasableItemSubCategory)34);
			UnlockItemDef assetDefById = ((ResourceAssetContainer<UnlockContainer, Object, UnlockItemDef>)(object)ResourceAssetContainer<UnlockContainer, Object, UnlockItemDef>.Instance).GetAssetDefById(Guid, true);
			assetDefById.UnlockOptions = new UnlockOptions
			{
				UnlockCriteria = (UnlockCriteriaType)3
			};
			assetDefById.rarity = (RarityType)3;
			IResourceAssetContextInfo context2 = Objects.GetContext(Guid);
			ContextInfo val2 = (ContextInfo)(object)((context2 is ContextInfo) ? context2 : null);
			if ((Object)(object)val2 != (Object)null)
			{
				((Object)val2).hideFlags = (HideFlags)(((Object)val2).hideFlags | 0x20);
			}
			Registered = true;
			Log.Info("The Airlock Hacking Terminal is ready (PvP fabricators offer it).");
			Describe();
		}
		catch (Exception e)
		{
			Log.Failure("Adding the hacking terminal item", e);
		}
	}

	private static void SetCost(int cost)
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_002d: 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_0043: 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)
		if (cost != _cost)
		{
			((ResourceAssetContainer<CraftingDataContainer, Object, CraftableItemDef>)(object)ResourceAssetContainer<CraftingDataContainer, Object, CraftableItemDef>.Instance).GetAssetDefById(Guid, true).SetCraftingRules(new CraftingRules
			{
				CraftingMethod = (CraftMethod)2,
				Creation = new ResourceCurrency((ResourceType)2, cost),
				CanBeRecycled = false,
				Recycle = new ResourceCurrency((ResourceType)2, 0)
			});
			_cost = cost;
		}
	}

	private static void Describe()
	{
		try
		{
			Component[] componentsInChildren = _template.GetComponentsInChildren<Component>(true);
			List<string> list = new List<string>();
			Component[] array = componentsInChildren;
			foreach (Component val in array)
			{
				if ((Object)(object)val != (Object)null)
				{
					list.Add(((Object)val.gameObject).name + ":" + ((object)val).GetType().Name);
				}
			}
			Log.Verbose("Hacking terminal model: " + string.Join(", ", list.ToArray()));
		}
		catch
		{
		}
	}

	[GamePatch("PvP hacking terminal", "FabricatorData", ".ctor", PatchKind.Postfix)]
	private static void FabricatorDataPostfix(FabricatorData __instance)
	{
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		if (!Registered || !FleetSession.IsPvP || __instance == null || __instance.CraftingData == null)
		{
			return;
		}
		try
		{
			FleetPlan current = FleetSession.Current;
			SetCost((current != null) ? Mathf.Clamp(current.HackCost, 1, 60) : 10);
			CraftData craftingData = __instance.CraftingData;
			if (!craftingData.Craftables.ContainsKey(Guid))
			{
				craftingData.TryAddItem(Guid);
			}
			if (!craftingData.Craftables.TryGetValue(Guid, out var value))
			{
				value = AddDirectly(craftingData);
			}
			if (value != null)
			{
				value.SharedSessionUnlocked = false;
				value.IsUnlocked = true;
				Log.InfoOnce("hack shop", "PvP fabricators offer the Airlock Hacking Terminal for " + value.CraftingRules.Creation.Amount + " alloys.");
			}
		}
		catch (Exception e)
		{
			Log.Failure("Adding the hacking terminal to a fabricator", e);
		}
	}

	private static PurchasableItem AddDirectly(CraftData shop)
	{
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		if (AddPrintableMethod == null || SetupCategoriesMethod == null)
		{
			return null;
		}
		CraftableItemDef assetDefById = ((ResourceAssetContainer<CraftingDataContainer, Object, CraftableItemDef>)(object)ResourceAssetContainer<CraftingDataContainer, Object, CraftableItemDef>.Instance).GetAssetDefById(Guid, false);
		if (assetDefById == null)
		{
			return null;
		}
		object[] parameters = new object[3] { assetDefById, -1, false };
		object? obj = AddPrintableMethod.Invoke(shop, parameters);
		object? result = ((obj is PurchasableItem) ? obj : null);
		SetupCategoriesMethod.Invoke(shop, null);
		if (shop.OnShopUpdated != null)
		{
			shop.OnShopUpdated();
		}
		return (PurchasableItem)result;
	}

	[GamePatch("PvP hacking terminal", "CG.Ship.Hull.CarryablesSocket", "DoesAccept", PatchKind.Postfix)]
	private static void DoesAcceptPostfix(CarryablesSocket __instance, CarryableObject carryable, ref bool __result)
	{
		if (__result && Is(carryable) && (Object)(object)((Component)__instance).GetComponentInParent<CarryablesShelf>() == (Object)null)
		{
			__result = false;
		}
	}

	[GamePatch("PvP hacking terminal", "CG.Ship.Object.InteractiveCarryableItemCopier", "GetGuidOfCopyableCarryable", PatchKind.Postfix)]
	private static void CopyPostfix(CarryableObject targetCarryable, ref GUIDUnion __result)
	{
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		if (Is(targetCarryable))
		{
			__result = GUIDUnion.Empty();
		}
	}

	public static void Consume(CarryableObject charge)
	{
		if (!((Object)(object)charge == (Object)null) && !((Object)(object)((MonoBehaviourPun)charge).photonView == (Object)null) && ((MonoBehaviourPun)charge).photonView.IsMine)
		{
			if (charge.Carrier != null)
			{
				charge.Carrier.TryReleaseCarryable().Then((Action)((OrbitObject)charge).Kill);
			}
			else
			{
				((OrbitObject)charge).Kill();
			}
		}
	}

	public static void Destroy(CarryableObject charge)
	{
		if (!((Object)(object)charge == (Object)null) && !((Object)(object)((MonoBehaviourPun)charge).photonView == (Object)null))
		{
			if (((MonoBehaviourPun)charge).photonView.IsMine)
			{
				ObjectFactory.DestroyCloneStarObject((AbstractCloneStarObject)(object)charge);
			}
			else
			{
				((AbstractCloneStarObject)charge).Destroy();
			}
		}
	}

	public static GameObject BuildModel()
	{
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Expected O, but got Unknown
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Expected O, but got Unknown
		//IL_0195: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c8: Expected O, but got Unknown
		//IL_0105: Unknown result type (might be due to invalid IL or missing references)
		//IL_010a: Unknown result type (might be due to invalid IL or missing references)
		//IL_011c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0121: Unknown result type (might be due to invalid IL or missing references)
		//IL_012d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0132: Unknown result type (might be due to invalid IL or missing references)
		//IL_014a: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_026f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0274: Unknown result type (might be due to invalid IL or missing references)
		//IL_0276: Unknown result type (might be due to invalid IL or missing references)
		//IL_027d: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01da: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0202: Unknown result type (might be due to invalid IL or missing references)
		//IL_0207: Unknown result type (might be due to invalid IL or missing references)
		//IL_020c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0211: Unknown result type (might be due to invalid IL or missing references)
		//IL_0296: Unknown result type (might be due to invalid IL or missing references)
		//IL_029d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0286: Unknown result type (might be due to invalid IL or missing references)
		//IL_028d: Unknown result type (might be due to invalid IL or missing references)
		//IL_022c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0217: Unknown result type (might be due to invalid IL or missing references)
		//IL_0219: Unknown result type (might be due to invalid IL or missing references)
		//IL_021e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0223: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_02bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_02bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_02da: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_02eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f0: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_02fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_0307: Unknown result type (might be due to invalid IL or missing references)
		//IL_030c: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = new GameObject("VCF_HackTerminalModel");
		if ((Object)(object)_template == (Object)null)
		{
			return val;
		}
		GameObject val2 = new GameObject("Pivot");
		val2.transform.SetParent(val.transform, false);
		Transform transform = _template.transform;
		List<GameObject> list = new List<GameObject>();
		Renderer[] componentsInChildren = _template.GetComponentsInChildren<Renderer>(true);
		foreach (Renderer val3 in componentsInChildren)
		{
			Mesh val4 = null;
			SkinnedMeshRenderer val5 = (SkinnedMeshRenderer)(object)((val3 is SkinnedMeshRenderer) ? val3 : null);
			if ((Object)(object)val5 != (Object)null)
			{
				val4 = val5.sharedMesh;
			}
			else if (val3 is MeshRenderer)
			{
				MeshFilter component = ((Component)val3).GetComponent<MeshFilter>();
				val4 = (((Object)(object)component != (Object)null) ? component.sharedMesh : null);
			}
			if (!((Object)(object)val4 == (Object)null))
			{
				GameObject val6 = new GameObject(((Object)val3).name);
				val6.layer = ((Component)val3).gameObject.layer;
				val6.transform.SetParent(val2.transform, false);
				list.Add(val6);
				val6.transform.localPosition = transform.InverseTransformPoint(((Component)val3).transform.position);
				val6.transform.loc