Decompiled source of SkyboatBomber v0.5.6

HowToFishFlyingBoat.BepInEx.dll

Decompiled 5 days ago
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Logging;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.SceneManagement;

[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace HowToFishFlyingBoat;

[BepInPlugin("chadi7bark.howtofish.flyingboat", "Skyboat Bomber", "0.5.4")]
[BepInProcess("How to Fish.exe")]
public sealed class FlyingBoatMod : BaseUnityPlugin
{
	private sealed class PendingBomb
	{
		public Component Explosive;

		public object PlayerWhoDropped;

		public float DetonateAt;
	}

	private const float RiseSpeed = 12f;

	private const float DescendSpeed = 9f;

	private const float VerticalAcceleration = 28f;

	private const float HoverAcceleration = 18f;

	private const float MaximumFlightSpeed = 50f;

	private const float EngineAcceleration = 15f;

	private const float BrakingAcceleration = 20f;

	private const float VelocityAlignment = 3.5f;

	private const float ThrottleIncreasePerSecond = 0.35f;

	private const float ThrottleDecreasePerSecond = 0.45f;

	private const float MouseFollowDegreesPerSecond = 85f;

	private const float MaximumAimPitchDegrees = 65f;

	private const float RollDegreesPerSecond = 115f;

	private const float RollAutoLevelDegreesPerSecond = 55f;

	private const float MouseSensitivity = 0.11f;

	private const float ThirdPersonDistance = 11f;

	private const float ThirdPersonHeight = 4f;

	private const float ThirdPersonPivotHeight = 1.5f;

	private const float CameraPitchDownDegrees = 8f;

	private const int CarpetBombCount = 10;

	private const float CarpetBombInterval = 0.14f;

	private const float CarpetBombCooldown = 3f;

	private const float CarpetBombFuseSeconds = 3.5f;

	private const float CarpetBombDropDistance = 2.2f;

	private const float CarpetBombSideSpread = 3.2f;

	private const float CarpetBombDownSpeed = 8f;

	private Type _boatType;

	private Component _activeBoat;

	private Rigidbody _physicsRig;

	private bool _flightEnabled;

	private bool _savedUseGravity;

	private float _savedDrag;

	private float _savedAngularDrag;

	private RigidbodyConstraints _savedConstraints;

	private float _nextTypeSearchTime;

	private float _nextMissingBoatMessageTime;

	private float _throttle;

	private float _manualRollAngle;

	private float _aimYaw;

	private float _aimPitch;

	private Vector3 _mouseAimDirection;

	private Camera _flightCamera;

	private Vector3 _savedCameraPosition;

	private Quaternion _savedCameraRotation;

	private bool _cameraStateSaved;

	private bool _cameraPreCullHooked;

	private Type _itemManagerType;

	private Type _explosiveType;

	private Type _serverType;

	private MethodInfo _spawnNewItemMethod;

	private MethodInfo _activateExplosiveMethod;

	private MethodInfo _setItemHolderMethod;

	private MethodInfo _handOverItemSimulationMethod;

	private Component _dynamitePrefab;

	private bool _bombBarrageActive;

	private int _bombsRemaining;

	private float _nextBombDropTime;

	private float _nextBombBarrageAllowedTime;

	private bool _loggedForcedSpawnThisBarrage;

	private readonly List<PendingBomb> _pendingBombs = new List<PendingBomb>();

	private void Awake()
	{
		PluginLog.Bind(((BaseUnityPlugin)this).Logger);
		ResolveBoatType();
		ResolveBombingSystems();
		PluginLog.Msg("Flying Boat v0.5.4 loaded.");
		PluginLog.Msg("F6 = flight + fixed third-person chase camera | mouse aim = point the bow | W/S = throttle | A/D = roll only | Space/Ctrl = rise/descend");
		PluginLog.Msg("LEFT CLICK = drop a 10-dynamite carpet-bomb barrage while flight is active.");
		PluginLog.Msg("Flight requires the local player to be the current boat driver and stops immediately when the driver seat is left.");
		PluginLog.Msg("Flying and carpet bombing are authoritative in solo games and for the host. The Item Spawner force-release route is embedded; no Item Spawner dependency is used.");
		LogBombingRouteStatus();
	}

	private void OnDestroy()
	{
		DisableFlight(null);
		_pendingBombs.Clear();
	}

	private void Update()
	{
		try
		{
			if (_boatType == null && Time.unscaledTime >= _nextTypeSearchTime)
			{
				_nextTypeSearchTime = Time.unscaledTime + 2f;
				ResolveBoatType();
			}
			if (Input.GetKeyDown((KeyCode)287))
			{
				if (_flightEnabled)
				{
					DisableFlight("Flight disabled. Gravity restored.");
				}
				else
				{
					TryEnableFlight();
				}
			}
			if (_flightEnabled && !IsActiveBoatStillValid())
			{
				DisableFlight("Flight disabled because you left the driver seat or changed boats.");
			}
			if (_flightEnabled)
			{
				UpdateMouseAim();
				if (Mouse.current != null && Mouse.current.leftButton.wasPressedThisFrame)
				{
					TryStartCarpetBombBarrage();
				}
				UpdateCarpetBombBarrage();
			}
			UpdatePendingBombs();
		}
		catch (Exception ex)
		{
			PluginLog.Error("Flying Boat update error: " + ex);
			DisableFlight("Flight disabled after an update error.");
		}
	}

	private void FixedUpdate()
	{
		if (!_flightEnabled || (Object)(object)_physicsRig == (Object)null)
		{
			return;
		}
		try
		{
			ApplyFlightPhysics();
		}
		catch (Exception ex)
		{
			PluginLog.Error("Flying Boat physics error: " + ex);
			DisableFlight("Flight disabled after a physics error.");
		}
	}

	private void LateUpdate()
	{
		if (!_flightEnabled)
		{
			return;
		}
		try
		{
			UpdateThirdPersonCamera();
		}
		catch (Exception ex)
		{
			PluginLog.Warning("Third-person camera update failed: " + ex.GetType().Name);
		}
	}

	private void TryEnableFlight()
	{
		//IL_0100: Unknown result type (might be due to invalid IL or missing references)
		//IL_0105: Unknown result type (might be due to invalid IL or missing references)
		//IL_0141: Unknown result type (might be due to invalid IL or missing references)
		//IL_0151: Unknown result type (might be due to invalid IL or missing references)
		if (_boatType == null)
		{
			ResolveBoatType();
			if (_boatType == null)
			{
				PluginLog.Warning("The game's Boat type is not loaded yet. Enter the playable world and try F6 again.");
				return;
			}
		}
		Component val = FindLocallyDrivenBoat();
		if ((Object)(object)val == (Object)null)
		{
			if (Time.unscaledTime >= _nextMissingBoatMessageTime)
			{
				_nextMissingBoatMessageTime = Time.unscaledTime + 1f;
				PluginLog.Warning("Flight was not enabled: you must be sitting in the driver seat, then press F6.");
			}
			return;
		}
		if (IsClientOnly(val))
		{
			PluginLog.Warning("Flight was not enabled: this first build requires solo play or the host. A client-only boat would be corrected by the server.");
			return;
		}
		object obj = ReadMember(val, "HiddenPhysicsRig");
		Rigidbody val2 = (Rigidbody)((obj is Rigidbody) ? obj : null);
		if ((Object)(object)val2 == (Object)null)
		{
			object obj2 = ReadMember(val, "<HiddenPhysicsRig>k__BackingField");
			val2 = (Rigidbody)((obj2 is Rigidbody) ? obj2 : null);
		}
		if ((Object)(object)val2 == (Object)null)
		{
			PluginLog.Warning("The current boat's HiddenPhysicsRig was not found.");
			return;
		}
		_activeBoat = val;
		_physicsRig = val2;
		_savedUseGravity = _physicsRig.useGravity;
		_savedDrag = _physicsRig.drag;
		_savedAngularDrag = _physicsRig.angularDrag;
		_savedConstraints = _physicsRig.constraints;
		_physicsRig.useGravity = false;
		_physicsRig.drag = 0.2f;
		_physicsRig.angularDrag = 2.5f;
		float num = Mathf.Max(0f, Vector3.Dot(_physicsRig.velocity, ((Component)_physicsRig).transform.forward));
		_throttle = Mathf.Clamp01(num / 50f);
		_manualRollAngle = 0f;
		_flightEnabled = true;
		BeginThirdPersonCamera();
		PluginLog.Msg("FLIGHT ENABLED: fixed third-person chase view active. Mouse aims the bow; W/S change throttle; A/D roll only.");
	}

	private void DisableFlight(string message)
	{
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_physicsRig != (Object)null)
		{
			try
			{
				_physicsRig.useGravity = _savedUseGravity;
				_physicsRig.drag = _savedDrag;
				_physicsRig.angularDrag = _savedAngularDrag;
				_physicsRig.constraints = _savedConstraints;
			}
			catch
			{
			}
		}
		bool flightEnabled = _flightEnabled;
		EndThirdPersonCamera();
		_flightEnabled = false;
		_activeBoat = null;
		_physicsRig = null;
		_throttle = 0f;
		_manualRollAngle = 0f;
		_bombBarrageActive = false;
		_bombsRemaining = 0;
		if (flightEnabled && !string.IsNullOrEmpty(message))
		{
			PluginLog.Msg(message);
		}
	}

	private void ApplyFlightPhysics()
	{
		//IL_0111: Unknown result type (might be due to invalid IL or missing references)
		//IL_0116: Unknown result type (might be due to invalid IL or missing references)
		//IL_0117: Unknown result type (might be due to invalid IL or missing references)
		//IL_0118: Unknown result type (might be due to invalid IL or missing references)
		//IL_011d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0122: Unknown result type (might be due to invalid IL or missing references)
		//IL_0129: Unknown result type (might be due to invalid IL or missing references)
		//IL_012e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0133: Unknown result type (might be due to invalid IL or missing references)
		//IL_0135: Unknown result type (might be due to invalid IL or missing references)
		//IL_0136: Unknown result type (might be due to invalid IL or missing references)
		//IL_0138: Unknown result type (might be due to invalid IL or missing references)
		//IL_013d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0145: Unknown result type (might be due to invalid IL or missing references)
		//IL_014a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0153: Unknown result type (might be due to invalid IL or missing references)
		//IL_0158: Unknown result type (might be due to invalid IL or missing references)
		//IL_0160: Unknown result type (might be due to invalid IL or missing references)
		//IL_0167: Unknown result type (might be due to invalid IL or missing references)
		//IL_0169: Unknown result type (might be due to invalid IL or missing references)
		//IL_016e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0173: Unknown result type (might be due to invalid IL or missing references)
		//IL_017b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0180: Unknown result type (might be due to invalid IL or missing references)
		//IL_0182: Unknown result type (might be due to invalid IL or missing references)
		//IL_0184: 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_01c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cb: 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_01d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fc: 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_02d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_02af: 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_02be: Unknown result type (might be due to invalid IL or missing references)
		float num = Mathf.Max(Time.fixedDeltaTime, 0.001f);
		if (Input.GetKey((KeyCode)119) || Input.GetKey((KeyCode)273))
		{
			_throttle = Mathf.Clamp01(_throttle + 0.35f * num);
		}
		if (Input.GetKey((KeyCode)115) || Input.GetKey((KeyCode)274))
		{
			_throttle = Mathf.Clamp01(_throttle - 0.45f * num);
		}
		float num2 = 0f;
		if (Input.GetKey((KeyCode)97) || Input.GetKey((KeyCode)276))
		{
			num2 -= 1f;
		}
		if (Input.GetKey((KeyCode)100) || Input.GetKey((KeyCode)275))
		{
			num2 += 1f;
		}
		if (Mathf.Abs(num2) > 0.01f)
		{
			_manualRollAngle -= num2 * 115f * num;
			_manualRollAngle = Mathf.Repeat(_manualRollAngle + 180f, 360f) - 180f;
		}
		else
		{
			_manualRollAngle = Mathf.MoveTowardsAngle(_manualRollAngle, 0f, 55f * num);
		}
		Vector3 mouseAimDirection = GetMouseAimDirection();
		Quaternion val = Quaternion.LookRotation(mouseAimDirection, Vector3.up);
		Quaternion val2 = Quaternion.AngleAxis(_manualRollAngle, Vector3.forward);
		Quaternion val3 = val * val2;
		Quaternion val4 = Quaternion.RotateTowards(_physicsRig.rotation, val3, 85f * num);
		_physicsRig.MoveRotation(val4);
		Vector3 val5 = val4 * Vector3.forward;
		Vector3 val6 = _physicsRig.velocity;
		float num3 = Vector3.Dot(val6, val5);
		float num4 = _throttle * 50f;
		float num5 = ((num4 >= num3) ? (15f * num) : (20f * num));
		float num6 = Mathf.MoveTowards(num3, num4, num5);
		Vector3 val7 = val6 - val5 * num3;
		val7 = Vector3.Lerp(val7, Vector3.zero, Mathf.Clamp01(3.5f * num));
		val6 = val5 * num6 + val7;
		float num7 = 0f;
		bool key = Input.GetKey((KeyCode)32);
		bool flag = Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)305);
		if (key && !flag)
		{
			num7 = 12f;
		}
		else if (flag && !key)
		{
			num7 = -9f;
		}
		if (key || flag)
		{
			float num8 = 28f * num;
			val6.y = Mathf.MoveTowards(val6.y, num7, num8);
		}
		else if (_throttle < 0.02f)
		{
			val6.y = Mathf.MoveTowards(val6.y, 0f, 18f * num);
		}
		if (((Vector3)(ref val6)).magnitude > 55f)
		{
			val6 = ((Vector3)(ref val6)).normalized * 55f;
		}
		_physicsRig.velocity = val6;
		_physicsRig.angularVelocity = Vector3.zero;
	}

	private Vector3 GetMouseAimDirection()
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_0104: Unknown result type (might be due to invalid IL or missing references)
		//IL_0107: Unknown result type (might be due to invalid IL or missing references)
		//IL_010c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0112: Unknown result type (might be due to invalid IL or missing references)
		//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_0120: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
		Vector3 val = _mouseAimDirection;
		if (((Vector3)(ref val)).sqrMagnitude < 0.001f)
		{
			val = (((Object)(object)_physicsRig != (Object)null) ? ((Component)_physicsRig).transform.forward : Vector3.forward);
		}
		if (((Vector3)(ref val)).sqrMagnitude < 0.001f)
		{
			val = Vector3.forward;
		}
		((Vector3)(ref val)).Normalize();
		float num = Mathf.Sin((float)Math.PI * 13f / 36f);
		float num2 = Mathf.Clamp(val.y, 0f - num, num);
		Vector3 val2 = default(Vector3);
		((Vector3)(ref val2))..ctor(val.x, 0f, val.z);
		if (((Vector3)(ref val2)).sqrMagnitude < 0.001f)
		{
			val2 = (Vector3)(((Object)(object)_physicsRig != (Object)null) ? new Vector3(((Component)_physicsRig).transform.forward.x, 0f, ((Component)_physicsRig).transform.forward.z) : Vector3.forward);
		}
		((Vector3)(ref val2)).Normalize();
		float num3 = Mathf.Sqrt(Mathf.Max(0f, 1f - num2 * num2));
		Vector3 val3 = val2 * num3 + Vector3.up * num2;
		return ((Vector3)(ref val3)).normalized;
	}

	private void BeginThirdPersonCamera()
	{
		//IL_003b: 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)
		HookCameraPreCull();
		if (!TryAcquireFlightCamera())
		{
			PluginLog.Warning("Flight enabled, but no active game camera was available for third-person view.");
			InitializeAimFromDirection(((Component)_physicsRig).transform.forward);
		}
		else
		{
			InitializeAimFromDirection(((Component)_physicsRig).transform.forward);
			UpdateThirdPersonCamera();
			PluginLog.Msg("Fixed third-person chase camera enabled.");
		}
	}

	private void EndThirdPersonCamera()
	{
		//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_0028: 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)
		UnhookCameraPreCull();
		if ((Object)(object)_flightCamera != (Object)null && _cameraStateSaved)
		{
			try
			{
				((Component)_flightCamera).transform.position = _savedCameraPosition;
				((Component)_flightCamera).transform.rotation = _savedCameraRotation;
			}
			catch
			{
			}
		}
		_flightCamera = null;
		_cameraStateSaved = false;
		_mouseAimDirection = Vector3.zero;
	}

	private void InitializeAimFromDirection(Vector3 direction)
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		if (((Vector3)(ref direction)).sqrMagnitude < 0.001f)
		{
			direction = Vector3.forward;
		}
		((Vector3)(ref direction)).Normalize();
		_aimYaw = Mathf.Atan2(direction.x, direction.z) * 57.29578f;
		_aimPitch = (0f - Mathf.Asin(Mathf.Clamp(direction.y, -1f, 1f))) * 57.29578f;
		_aimPitch = Mathf.Clamp(_aimPitch, -65f, 65f);
		RefreshAimDirection();
	}

	private void UpdateMouseAim()
	{
		//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_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		Vector2 val = Vector2.zero;
		try
		{
			if (Mouse.current != null)
			{
				val = ((InputControl<Vector2>)(object)((Pointer)Mouse.current).delta).ReadValue();
			}
		}
		catch
		{
		}
		_aimYaw += val.x * 0.11f;
		_aimPitch -= val.y * 0.11f;
		_aimPitch = Mathf.Clamp(_aimPitch, -65f, 65f);
		_aimYaw = Mathf.Repeat(_aimYaw + 180f, 360f) - 180f;
		RefreshAimDirection();
	}

	private void RefreshAimDirection()
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: 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_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		_mouseAimDirection = Quaternion.Euler(_aimPitch, _aimYaw, 0f) * Vector3.forward;
		if (((Vector3)(ref _mouseAimDirection)).sqrMagnitude < 0.001f)
		{
			_mouseAimDirection = Vector3.forward;
		}
		((Vector3)(ref _mouseAimDirection)).Normalize();
	}

	private void UpdateThirdPersonCamera()
	{
		if ((!((Object)(object)_flightCamera == (Object)null) || TryAcquireFlightCamera()) && !((Object)(object)_physicsRig == (Object)null))
		{
			ForceThirdPersonCameraTransform();
		}
	}

	private void ForceThirdPersonCameraTransform()
	{
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_0090: Unknown result type (might be due to invalid IL or missing references)
		//IL_0095: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_0100: Unknown result type (might be due to invalid IL or missing references)
		//IL_0111: 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_0082: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)_flightCamera == (Object)null) && !((Object)(object)_physicsRig == (Object)null))
		{
			Vector3 val = _physicsRig.rotation * Vector3.forward;
			val.y = 0f;
			if (((Vector3)(ref val)).sqrMagnitude < 0.001f)
			{
				((Vector3)(ref val))..ctor(_mouseAimDirection.x, 0f, _mouseAimDirection.z);
			}
			if (((Vector3)(ref val)).sqrMagnitude < 0.001f)
			{
				val = Vector3.forward;
			}
			((Vector3)(ref val)).Normalize();
			Vector3 val2 = _physicsRig.worldCenterOfMass + Vector3.up * 1.5f;
			Vector3 position = val2 - val * 11f + Vector3.up * 4f;
			Quaternion rotation = Quaternion.LookRotation(val, Vector3.up) * Quaternion.Euler(8f, 0f, 0f);
			((Component)_flightCamera).transform.position = position;
			((Component)_flightCamera).transform.rotation = rotation;
		}
	}

	private void HookCameraPreCull()
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Expected O, but got Unknown
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Expected O, but got Unknown
		if (!_cameraPreCullHooked)
		{
			Camera.onPreCull = (CameraCallback)Delegate.Combine((Delegate?)(object)Camera.onPreCull, (Delegate?)new CameraCallback(OnFlightCameraPreCull));
			_cameraPreCullHooked = true;
		}
	}

	private void UnhookCameraPreCull()
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Expected O, but got Unknown
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Expected O, but got Unknown
		if (_cameraPreCullHooked)
		{
			Camera.onPreCull = (CameraCallback)Delegate.Remove((Delegate?)(object)Camera.onPreCull, (Delegate?)new CameraCallback(OnFlightCameraPreCull));
			_cameraPreCullHooked = false;
		}
	}

	private void OnFlightCameraPreCull(Camera renderingCamera)
	{
		if (_flightEnabled && !((Object)(object)_physicsRig == (Object)null) && !((Object)(object)renderingCamera == (Object)null) && (!((Object)(object)_flightCamera == (Object)null) || TryAcquireFlightCamera()) && (Object)(object)renderingCamera == (Object)(object)_flightCamera)
		{
			ForceThirdPersonCameraTransform();
		}
	}

	private void TryStartCarpetBombBarrage()
	{
		if (_flightEnabled && !((Object)(object)_activeBoat == (Object)null) && !((Object)(object)_physicsRig == (Object)null) && !_bombBarrageActive && !(Time.unscaledTime < _nextBombBarrageAllowedTime) && IsLocalPlayerTheDriver(_activeBoat))
		{
			if (!ResolveBombingSystems() || !ResolveDynamitePrefab())
			{
				PluginLog.Warning("Carpet bombing is unavailable: the native Dynamite spawn systems were not found.");
				return;
			}
			_bombBarrageActive = true;
			_bombsRemaining = 10;
			_nextBombDropTime = Time.unscaledTime;
			_nextBombBarrageAllowedTime = Time.unscaledTime + 3f;
			_loggedForcedSpawnThisBarrage = false;
			PluginLog.Msg("CARPET BOMBING: force-spawning 10 dynamites 2.2 metres beneath the boat.");
		}
	}

	private void UpdateCarpetBombBarrage()
	{
		if (!_bombBarrageActive)
		{
			return;
		}
		if (!_flightEnabled || (Object)(object)_activeBoat == (Object)null || (Object)(object)_physicsRig == (Object)null || !IsLocalPlayerTheDriver(_activeBoat))
		{
			_bombBarrageActive = false;
			_bombsRemaining = 0;
		}
		else if (!(Time.unscaledTime < _nextBombDropTime))
		{
			DropOneCarpetBomb();
			_bombsRemaining--;
			if (_bombsRemaining <= 0)
			{
				_bombBarrageActive = false;
				PluginLog.Msg("Carpet-bomb barrage released.");
			}
			else
			{
				_nextBombDropTime = Time.unscaledTime + 0.14f;
			}
		}
	}

	private void DropOneCarpetBomb()
	{
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: 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_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_00d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00df: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0100: Unknown result type (might be due to invalid IL or missing references)
		//IL_011e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0129: Unknown result type (might be due to invalid IL or missing references)
		//IL_0188: Unknown result type (might be due to invalid IL or missing references)
		//IL_0196: 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_01e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_0203: Unknown result type (might be due to invalid IL or missing references)
		//IL_020f: 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)
		Component val = FindLiveRuntimeComponent(_itemManagerType, "Server(Clone)");
		if ((Object)(object)val == (Object)null || _spawnNewItemMethod == null || (Object)(object)_dynamitePrefab == (Object)null)
		{
			ResolveBombingSystems();
			ResolveDynamitePrefab();
			val = FindLiveRuntimeComponent(_itemManagerType, "Server(Clone)");
		}
		if ((Object)(object)val == (Object)null || _spawnNewItemMethod == null || (Object)(object)_dynamitePrefab == (Object)null)
		{
			PluginLog.Warning("A carpet bomb could not spawn because ItemManager was unavailable.");
			_bombBarrageActive = false;
			return;
		}
		Vector3 forward = ((Component)_physicsRig).transform.forward;
		Vector3 right = ((Component)_physicsRig).transform.right;
		float num = Random.Range(-3.2f, 3.2f);
		Vector3 val2 = _physicsRig.worldCenterOfMass - Vector3.up * 2.2f + right * num - forward * 0.75f;
		Quaternion rotation = Random.rotation;
		object obj;
		try
		{
			obj = _spawnNewItemMethod.Invoke(val, new object[3] { _dynamitePrefab, val2, rotation });
		}
		catch (Exception ex)
		{
			PluginLog.Warning("Native Dynamite spawn failed: " + ex.GetType().Name);
			return;
		}
		Component val3 = (Component)((obj is Component) ? obj : null);
		if ((Object)(object)val3 == (Object)null)
		{
			PluginLog.Warning("Native Dynamite spawn returned an object that was not an Item component.");
			return;
		}
		ForceReleaseBombToWorld(val3);
		val3.transform.position = val2;
		val3.transform.rotation = rotation;
		object obj2 = ReadMember(val3, "Rig");
		Rigidbody val4 = (Rigidbody)((obj2 is Rigidbody) ? obj2 : null);
		if ((Object)(object)val4 == (Object)null)
		{
			val4 = val3.GetComponent<Rigidbody>();
		}
		if ((Object)(object)val4 != (Object)null)
		{
			val4.velocity = _physicsRig.velocity + Vector3.down * 8f + right * Random.Range(-1.5f, 1.5f);
			val4.angularVelocity = Random.onUnitSphere * Random.Range(3f, 8f);
		}
		Component val5 = null;
		if (_explosiveType != null && _explosiveType.IsInstanceOfType(val3))
		{
			val5 = val3;
		}
		if ((Object)(object)val5 == (Object)null)
		{
			object obj3 = ReadMember(val3, "Explosive");
			val5 = (Component)((obj3 is Component) ? obj3 : null);
		}
		if ((Object)(object)val5 == (Object)null && _explosiveType != null)
		{
			val5 = val3.GetComponent(_explosiveType);
		}
		if ((Object)(object)val5 != (Object)null)
		{
			PendingBomb pendingBomb = new PendingBomb();
			pendingBomb.Explosive = val5;
			pendingBomb.PlayerWhoDropped = ReadMember(_activeBoat, "LocalPlayerOnBoat");
			pendingBomb.DetonateAt = Time.time + 3.5f;
			_pendingBombs.Add(pendingBomb);
		}
	}

	private void UpdatePendingBombs()
	{
		for (int num = _pendingBombs.Count - 1; num >= 0; num--)
		{
			PendingBomb pendingBomb = _pendingBombs[num];
			if (pendingBomb == null || (Object)(object)pendingBomb.Explosive == (Object)null)
			{
				_pendingBombs.RemoveAt(num);
			}
			else if (!(Time.time < pendingBomb.DetonateAt))
			{
				DetonateBomb(pendingBomb.Explosive, pendingBomb.PlayerWhoDropped);
				_pendingBombs.RemoveAt(num);
			}
		}
	}

	private void DetonateBomb(Component explosive, object playerWhoDropped)
	{
		if ((Object)(object)explosive == (Object)null)
		{
			return;
		}
		Component val = FindLiveRuntimeComponent(_serverType, "Server(Clone)");
		if ((Object)(object)val == (Object)null || _activateExplosiveMethod == null)
		{
			ResolveBombingSystems();
			val = FindLiveRuntimeComponent(_serverType, "Server(Clone)");
		}
		if ((Object)(object)val == (Object)null || _activateExplosiveMethod == null)
		{
			return;
		}
		uint num = ReadNetworkTick(val);
		try
		{
			_activateExplosiveMethod.Invoke(val, new object[5] { explosive, num, true, true, playerWhoDropped });
		}
		catch (Exception ex)
		{
			PluginLog.Warning("Dynamite detonation failed: " + ex.GetType().Name);
		}
	}

	private bool ResolveBombingSystems()
	{
		if (_itemManagerType == null)
		{
			_itemManagerType = FindRuntimeType("ItemManager");
		}
		if (_explosiveType == null)
		{
			_explosiveType = FindRuntimeType("Explosive");
		}
		if (_serverType == null)
		{
			_serverType = FindRuntimeType("Server");
		}
		if (_itemManagerType != null && _spawnNewItemMethod == null)
		{
			_spawnNewItemMethod = FindMethodRecursive(_itemManagerType, "SpawnNewItem", 3);
		}
		if (_serverType != null && _activateExplosiveMethod == null)
		{
			_activateExplosiveMethod = FindMethodRecursive(_serverType, "ActivateExplosive", 5);
		}
		if (_serverType != null && _setItemHolderMethod == null)
		{
			_setItemHolderMethod = FindMethodRecursive(_serverType, "SetItemHolder", 3);
		}
		if (_serverType != null && _handOverItemSimulationMethod == null)
		{
			_handOverItemSimulationMethod = FindMethodRecursive(_serverType, "HandOverItemSimulation", 1);
		}
		if (_itemManagerType != null && _explosiveType != null && _serverType != null && _spawnNewItemMethod != null && _activateExplosiveMethod != null && _setItemHolderMethod != null)
		{
			return _handOverItemSimulationMethod != null;
		}
		return false;
	}

	private void LogBombingRouteStatus()
	{
		PluginLog.Msg("FORCED-SPAWN ROUTE: SpawnNewItem=" + FoundText(_spawnNewItemMethod) + " | SetItemHolder=" + FoundText(_setItemHolderMethod) + " | HandOverItemSimulation=" + FoundText(_handOverItemSimulationMethod) + " | ActivateExplosive=" + FoundText(_activateExplosiveMethod));
	}

	private static string FoundText(MethodInfo method)
	{
		if (!(method == null))
		{
			return "FOUND";
		}
		return "NOT FOUND";
	}

	private void ForceReleaseBombToWorld(Component spawnedItem)
	{
		if ((Object)(object)spawnedItem == (Object)null)
		{
			return;
		}
		Component val = FindLiveRuntimeComponent(_serverType, "Server(Clone)");
		if ((Object)(object)val == (Object)null || _setItemHolderMethod == null || _handOverItemSimulationMethod == null)
		{
			ResolveBombingSystems();
			val = FindLiveRuntimeComponent(_serverType, "Server(Clone)");
		}
		if ((Object)(object)val == (Object)null || _setItemHolderMethod == null || _handOverItemSimulationMethod == null)
		{
			PluginLog.Warning("FORCED-SPAWN FAIL: the live Server release route was unavailable after SpawnNewItem.");
			return;
		}
		try
		{
			_setItemHolderMethod.Invoke(val, new object[3] { spawnedItem, null, null });
			_handOverItemSimulationMethod.Invoke(val, new object[1] { spawnedItem });
			if (!_loggedForcedSpawnThisBarrage)
			{
				_loggedForcedSpawnThisBarrage = true;
				PluginLog.Msg("FORCED-SPAWN PASS: Server.SetItemHolder(item, null, null) + Server.HandOverItemSimulation(item).");
			}
		}
		catch (TargetInvocationException ex)
		{
			Exception ex2 = ex.InnerException ?? ex;
			PluginLog.Warning("FORCED-SPAWN FAIL: " + ex2.GetType().Name + ": " + ex2.Message);
		}
		catch (Exception ex3)
		{
			PluginLog.Warning("FORCED-SPAWN FAIL: " + ex3.GetType().Name + ": " + ex3.Message);
		}
	}

	private static Component FindLiveRuntimeComponent(Type type, string preferredPathText)
	{
		//IL_0092: 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)
		if (type == null)
		{
			return null;
		}
		object obj = ReadStaticMember(type, "Instance");
		Component val = (Component)((obj is Component) ? obj : null);
		if ((Object)(object)val != (Object)null)
		{
			return val;
		}
		Object[] array;
		try
		{
			array = Resources.FindObjectsOfTypeAll(type);
		}
		catch
		{
			return null;
		}
		Component val2 = null;
		int num = int.MinValue;
		foreach (Object obj3 in array)
		{
			Component val3 = (Component)(object)((obj3 is Component) ? obj3 : null);
			if (!((Object)(object)val3 == (Object)null) && !((Object)(object)val3.gameObject == (Object)null))
			{
				int num2 = 0;
				if (val3.gameObject.activeInHierarchy)
				{
					num2 += 100;
				}
				Scene scene = val3.gameObject.scene;
				if (!string.IsNullOrEmpty(((Scene)(ref scene)).name))
				{
					num2 += 50;
				}
				string hierarchyPath = GetHierarchyPath(val3.transform);
				if (!string.IsNullOrEmpty(preferredPathText) && hierarchyPath.IndexOf(preferredPathText, StringComparison.OrdinalIgnoreCase) >= 0)
				{
					num2 += 500;
				}
				if (hierarchyPath.IndexOf("Backup", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					num2 -= 500;
				}
				if ((Object)(object)val2 == (Object)null || num2 > num)
				{
					val2 = val3;
					num = num2;
				}
			}
		}
		return val2;
	}

	private static string GetHierarchyPath(Transform transform)
	{
		if ((Object)(object)transform == (Object)null)
		{
			return string.Empty;
		}
		string text = ((Object)transform).name;
		Transform parent = transform.parent;
		while ((Object)(object)parent != (Object)null)
		{
			text = ((Object)parent).name + "/" + text;
			parent = parent.parent;
		}
		return text;
	}

	private bool ResolveDynamitePrefab()
	{
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_dynamitePrefab != (Object)null)
		{
			return true;
		}
		if (_explosiveType == null && !ResolveBombingSystems())
		{
			return false;
		}
		Object[] array;
		try
		{
			array = Resources.FindObjectsOfTypeAll(_explosiveType);
		}
		catch
		{
			return false;
		}
		Component dynamitePrefab = null;
		foreach (Object obj2 in array)
		{
			Component val = (Component)(object)((obj2 is Component) ? obj2 : null);
			if (!((Object)(object)val == (Object)null) && string.Equals(((Object)val.gameObject).name, "Dynamite", StringComparison.OrdinalIgnoreCase))
			{
				dynamitePrefab = val;
				Scene scene = val.gameObject.scene;
				if (string.IsNullOrEmpty(((Scene)(ref scene)).name))
				{
					_dynamitePrefab = val;
					return true;
				}
			}
		}
		_dynamitePrefab = dynamitePrefab;
		return (Object)(object)_dynamitePrefab != (Object)null;
	}

	private static uint ReadNetworkTick(Component server)
	{
		try
		{
			object target = ReadMember(server, "TimeManager");
			object obj = ReadMember(target, "Tick");
			if (obj != null)
			{
				return Convert.ToUInt32(obj);
			}
		}
		catch
		{
		}
		return 0u;
	}

	private bool IsActiveBoatStillValid()
	{
		if ((Object)(object)_activeBoat == (Object)null || (Object)(object)_physicsRig == (Object)null)
		{
			return false;
		}
		try
		{
			return _activeBoat.gameObject.activeInHierarchy && IsLocalPlayerTheDriver(_activeBoat);
		}
		catch
		{
			return false;
		}
	}

	private Component FindLocallyDrivenBoat()
	{
		//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)
		if (_boatType == null)
		{
			return null;
		}
		Object[] array;
		try
		{
			array = Resources.FindObjectsOfTypeAll(_boatType);
		}
		catch
		{
			return null;
		}
		foreach (Object obj2 in array)
		{
			Component val = (Component)(object)((obj2 is Component) ? obj2 : null);
			if ((Object)(object)val == (Object)null)
			{
				continue;
			}
			try
			{
				if (val.gameObject.activeInHierarchy)
				{
					Scene scene = val.gameObject.scene;
					if (!string.IsNullOrEmpty(((Scene)(ref scene)).name) && IsLocalPlayerTheDriver(val))
					{
						return val;
					}
				}
			}
			catch
			{
			}
		}
		return null;
	}

	private bool IsLocalPlayerTheDriver(Component boat)
	{
		if ((Object)(object)boat == (Object)null || _boatType == null)
		{
			return false;
		}
		if (!TryReadStaticBoolean(_boatType, "IsDrivingLocally", out var value) || !value)
		{
			return false;
		}
		object obj = ReadMember(boat, "LocalPlayerOnBoat");
		if (obj == null)
		{
			obj = ReadMember(boat, "<LocalPlayerOnBoat>k__BackingField");
		}
		object obj2 = ReadMember(boat, "Driver");
		if (obj == null || obj2 == null)
		{
			return false;
		}
		Object val = (Object)((obj is Object) ? obj : null);
		Object val2 = (Object)((obj2 is Object) ? obj2 : null);
		if (val != (Object)null && val2 != (Object)null)
		{
			return val == val2;
		}
		return object.ReferenceEquals(obj, obj2);
	}

	private bool TryAcquireFlightCamera()
	{
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: 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_0047: Unknown result type (might be due to invalid IL or missing references)
		Camera val = FindActiveGameCamera();
		if ((Object)(object)val == (Object)null)
		{
			return false;
		}
		_flightCamera = val;
		if (!_cameraStateSaved)
		{
			_savedCameraPosition = ((Component)_flightCamera).transform.position;
			_savedCameraRotation = ((Component)_flightCamera).transform.rotation;
			_cameraStateSaved = true;
		}
		return true;
	}

	private static Camera FindActiveGameCamera()
	{
		Camera main = Camera.main;
		if (IsUsableCamera(main))
		{
			return main;
		}
		Object[] array;
		try
		{
			array = Resources.FindObjectsOfTypeAll(typeof(Camera));
		}
		catch
		{
			return null;
		}
		Camera val = null;
		int num = int.MinValue;
		foreach (Object obj2 in array)
		{
			Camera val2 = (Camera)(object)((obj2 is Camera) ? obj2 : null);
			if (IsUsableCamera(val2))
			{
				int num2 = ScoreGameCamera(val2);
				if ((Object)(object)val == (Object)null || num2 > num)
				{
					val = val2;
					num = num2;
				}
			}
		}
		return val;
	}

	private static bool IsUsableCamera(Camera camera)
	{
		//IL_0026: 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)
		if ((Object)(object)camera == (Object)null)
		{
			return false;
		}
		try
		{
			int result;
			if (((Behaviour)camera).enabled && ((Component)camera).gameObject.activeInHierarchy)
			{
				Scene scene = ((Component)camera).gameObject.scene;
				if (!string.IsNullOrEmpty(((Scene)(ref scene)).name))
				{
					result = (((Object)(object)camera.targetTexture == (Object)null) ? 1 : 0);
					goto IL_0049;
				}
			}
			result = 0;
			goto IL_0049;
			IL_0049:
			return (byte)result != 0;
		}
		catch
		{
			return false;
		}
	}

	private static int ScoreGameCamera(Camera camera)
	{
		int num = 0;
		if (!camera.orthographic)
		{
			num += 50;
		}
		if ((Object)(object)((Component)camera).GetComponent<AudioListener>() != (Object)null)
		{
			num += 100;
		}
		string text = ((Object)((Component)camera).gameObject).name.ToLowerInvariant();
		if (text.IndexOf("player") >= 0)
		{
			num += 40;
		}
		if (text.IndexOf("main") >= 0)
		{
			num += 30;
		}
		if (text.IndexOf("game") >= 0)
		{
			num += 15;
		}
		if (text.IndexOf("ui") >= 0)
		{
			num -= 100;
		}
		if (text.IndexOf("menu") >= 0)
		{
			num -= 100;
		}
		if (text.IndexOf("endgame") >= 0)
		{
			num -= 100;
		}
		return num;
	}

	private static bool IsClientOnly(Component boat)
	{
		bool value;
		bool flag = TryReadBoolean(boat, "IsServerStarted", out value);
		bool value2;
		bool flag2 = TryReadBoolean(boat, "IsClientStarted", out value2);
		if (flag && flag2 && value2)
		{
			return !value;
		}
		return false;
	}

	private static Type FindRuntimeType(string fullName)
	{
		Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
		for (int i = 0; i < assemblies.Length; i++)
		{
			try
			{
				Type type = assemblies[i].GetType(fullName, throwOnError: false);
				if (type != null)
				{
					return type;
				}
			}
			catch
			{
			}
		}
		return null;
	}

	private static MethodInfo FindMethodRecursive(Type type, string name, int parameterCount)
	{
		Type type2 = type;
		while (type2 != null)
		{
			try
			{
				MethodInfo[] methods = type2.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (MethodInfo methodInfo in methods)
				{
					if (methodInfo.Name == name && methodInfo.GetParameters().Length == parameterCount)
					{
						return methodInfo;
					}
				}
			}
			catch
			{
			}
			type2 = type2.BaseType;
		}
		return null;
	}

	private void ResolveBoatType()
	{
		Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
		for (int i = 0; i < assemblies.Length; i++)
		{
			Type type = null;
			try
			{
				type = assemblies[i].GetType("Boat", throwOnError: false);
			}
			catch
			{
			}
			if (type != null && typeof(Component).IsAssignableFrom(type))
			{
				_boatType = type;
				PluginLog.Msg("Resolved the runtime Boat controller from " + assemblies[i].GetName().Name + ".");
				break;
			}
		}
	}

	private static object ReadMember(object target, string name)
	{
		if (target == null)
		{
			return null;
		}
		Type type = target.GetType();
		PropertyInfo propertyInfo = FindPropertyRecursive(type, name);
		if (propertyInfo != null && propertyInfo.GetIndexParameters().Length == 0)
		{
			try
			{
				return propertyInfo.GetValue(target, null);
			}
			catch
			{
			}
		}
		FieldInfo fieldInfo = FindFieldRecursive(type, name);
		if (fieldInfo != null)
		{
			try
			{
				return fieldInfo.GetValue(target);
			}
			catch
			{
			}
		}
		return null;
	}

	private static object ReadStaticMember(Type type, string name)
	{
		if (type == null)
		{
			return null;
		}
		PropertyInfo propertyInfo = FindPropertyRecursive(type, name);
		if (propertyInfo != null && propertyInfo.GetIndexParameters().Length == 0)
		{
			try
			{
				return propertyInfo.GetValue(null, null);
			}
			catch
			{
			}
		}
		FieldInfo fieldInfo = FindFieldRecursive(type, name);
		if (fieldInfo != null && fieldInfo.IsStatic)
		{
			try
			{
				return fieldInfo.GetValue(null);
			}
			catch
			{
			}
		}
		return null;
	}

	private static bool TryReadBoolean(object target, string name, out bool value)
	{
		value = false;
		object obj = ReadMember(target, name);
		if (obj is bool)
		{
			value = (bool)obj;
			return true;
		}
		return false;
	}

	private static bool TryReadStaticBoolean(Type type, string name, out bool value)
	{
		value = false;
		PropertyInfo propertyInfo = FindPropertyRecursive(type, name);
		if (propertyInfo != null)
		{
			try
			{
				object value2 = propertyInfo.GetValue(null, null);
				if (value2 is bool)
				{
					value = (bool)value2;
					return true;
				}
			}
			catch
			{
			}
		}
		FieldInfo fieldInfo = FindFieldRecursive(type, name);
		if (fieldInfo != null && fieldInfo.IsStatic)
		{
			try
			{
				object value3 = fieldInfo.GetValue(null);
				if (value3 is bool)
				{
					value = (bool)value3;
					return true;
				}
			}
			catch
			{
			}
		}
		return false;
	}

	private static FieldInfo FindFieldRecursive(Type type, string name)
	{
		Type type2 = type;
		while (type2 != null)
		{
			try
			{
				FieldInfo field = type2.GetField(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null)
				{
					return field;
				}
			}
			catch
			{
			}
			type2 = type2.BaseType;
		}
		return null;
	}

	private static PropertyInfo FindPropertyRecursive(Type type, string name)
	{
		Type type2 = type;
		while (type2 != null)
		{
			try
			{
				PropertyInfo property = type2.GetProperty(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (property != null)
				{
					return property;
				}
			}
			catch
			{
			}
			type2 = type2.BaseType;
		}
		return null;
	}
}
internal static class PluginLog
{
	private static ManualLogSource _source;

	internal static void Bind(ManualLogSource source)
	{
		_source = source;
	}

	internal static void Msg(object value)
	{
		if (_source != null)
		{
			_source.LogInfo(value);
		}
	}

	internal static void Warning(object value)
	{
		if (_source != null)
		{
			_source.LogWarning(value);
		}
	}

	internal static void Error(object value)
	{
		if (_source != null)
		{
			_source.LogError(value);
		}
	}
}