Decompiled source of PowerfulOar v1.0.3

BepInEx/plugins/PowerfulOar/PowerfulOar.dll

Decompiled 28 minutes ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.SceneManagement;
using cakeslice;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("PowerfulOar")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.3.0")]
[assembly: AssemblyInformationalVersion("1.0.3")]
[assembly: AssemblyProduct("PowerfulOar")]
[assembly: AssemblyTitle("PowerfulOar")]
[assembly: AssemblyVersion("1.0.3.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace PowerfulOar
{
	internal static class BoneIslandBfoPlacement
	{
		private const string BoneIslandSceneName = "island 36 ()";

		private const float SafeSpawnDistance = 500f;

		private static readonly Vector3 LocalPosition = new Vector3(232.5f, 17.88f, 431.6406f);

		private static readonly Quaternion LocalRotation = Quaternion.Euler(-0.415f, 116.637f, 81.422f);

		private static readonly HashSet<int> PendingScenes = new HashSet<int>();

		private static bool initialized;

		internal static void Initialize()
		{
			if (!initialized)
			{
				initialized = true;
				SceneManager.sceneLoaded += OnSceneLoaded;
				QueueLoadedBoneIslandScenes();
			}
		}

		internal static void Shutdown()
		{
			if (initialized)
			{
				SceneManager.sceneLoaded -= OnSceneLoaded;
				PendingScenes.Clear();
				initialized = false;
			}
		}

		internal static void OnPrefabsReady()
		{
			QueueLoadedBoneIslandScenes();
		}

		private static void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			QueueScene(scene);
		}

		private static void QueueLoadedBoneIslandScenes()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < SceneManager.sceneCount; i++)
			{
				QueueScene(SceneManager.GetSceneAt(i));
			}
		}

		private static void QueueScene(Scene scene)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			PowerfulOarPlugin instance = PowerfulOarPlugin.Instance;
			if (!((Object)(object)instance == (Object)null) && ((Scene)(ref scene)).IsValid() && ((Scene)(ref scene)).isLoaded && !(((Scene)(ref scene)).name != "island 36 ()") && PendingScenes.Add(((Scene)(ref scene)).handle))
			{
				((MonoBehaviour)instance).StartCoroutine(PlaceWhenReady(scene));
			}
		}

		private static IEnumerator PlaceWhenReady(Scene scene)
		{
			//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)
			int sceneHandle = ((Scene)(ref scene)).handle;
			Transform scenery = null;
			while ((Object)(object)PowerfulOarPlugin.Instance != (Object)null && ((Scene)(ref scene)).IsValid() && ((Scene)(ref scene)).isLoaded)
			{
				if ((Object)(object)scenery == (Object)null)
				{
					scenery = FindSceneryRoot(scene);
				}
				PrefabsDirectory instance = PrefabsDirectory.instance;
				Camera main = Camera.main;
				Vector3 val = (((Object)(object)scenery != (Object)null) ? scenery.TransformPoint(LocalPosition) : Vector3.zero);
				if (GameState.playing && !GameState.currentlyLoading && (Object)(object)scenery != (Object)null && (Object)(object)main != (Object)null && Vector3.Distance(((Component)main).transform.position, val) <= 500f && (Object)(object)instance != (Object)null && instance.directory != null && instance.directory.Length > 666 && (Object)(object)instance.directory[666] != (Object)null)
				{
					if (ScaledOarFactory.ValidateRuntimeCache(instance))
					{
						TryPlace(instance, scenery);
					}
					PendingScenes.Remove(sceneHandle);
					yield break;
				}
				yield return null;
			}
			PendingScenes.Remove(sceneHandle);
		}

		private static void TryPlace(PrefabsDirectory directory, Transform scenery)
		{
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = directory.directory[666];
			if (HasExistingRuntimeBfo(val))
			{
				ManualLogSource logSource = PowerfulOarPlugin.LogSource;
				if (logSource != null)
				{
					logSource.LogInfo((object)"Skipped Bone Island BFO display: an existing collected or display BFO 5000 is already loaded.");
				}
				return;
			}
			GameObject val2 = Object.Instantiate<GameObject>(val);
			ShipItem component = val2.GetComponent<ShipItem>();
			if ((Object)(object)component == (Object)null)
			{
				ManualLogSource logSource2 = PowerfulOarPlugin.LogSource;
				if (logSource2 != null)
				{
					logSource2.LogError((object)"Could not place Bone Island BFO 5000: cloned ShipItem missing.");
				}
				val2.SetActive(false);
				return;
			}
			((Object)val2).name = "BFO 5000 (Bone Island)";
			val2.transform.SetParent(scenery, false);
			val2.transform.localPosition = LocalPosition;
			val2.transform.localRotation = LocalRotation;
			component.sold = true;
			Good component2 = val2.GetComponent<Good>();
			if ((Object)(object)component2 != (Object)null)
			{
				component2.RegisterAsMissionless();
			}
			ItemRigidbody itemRigidbody = component.GetItemRigidbody();
			if ((Object)(object)itemRigidbody != (Object)null)
			{
				itemRigidbody.debugForceKinematic = true;
				Rigidbody component3 = ((Component)itemRigidbody).GetComponent<Rigidbody>();
				if ((Object)(object)component3 != (Object)null)
				{
					component3.isKinematic = true;
					component3.useGravity = false;
					component3.velocity = Vector3.zero;
					component3.angularVelocity = Vector3.zero;
				}
			}
			BoneIslandBfoDisplay boneIslandBfoDisplay = val2.GetComponent<BoneIslandBfoDisplay>();
			if ((Object)(object)boneIslandBfoDisplay == (Object)null)
			{
				boneIslandBfoDisplay = val2.AddComponent<BoneIslandBfoDisplay>();
			}
			boneIslandBfoDisplay.Initialize(component);
			ManualLogSource logSource3 = PowerfulOarPlugin.LogSource;
			if (logSource3 != null)
			{
				logSource3.LogInfo((object)("Placed one fixed BFO 5000 at the configured Bone Island _scenery-local pose. It will enter normal item/save control when picked up. " + $"Camera was within {500f:0} m of the placement."));
			}
		}

		private static bool HasExistingRuntimeBfo(GameObject registeredPrefab)
		{
			SaveablePrefab[] array = Resources.FindObjectsOfTypeAll<SaveablePrefab>();
			foreach (SaveablePrefab val in array)
			{
				if ((Object)(object)val != (Object)null && val.prefabIndex == 666 && (Object)(object)((Component)val).gameObject != (Object)(object)registeredPrefab)
				{
					return true;
				}
			}
			return false;
		}

		private static Transform FindSceneryRoot(Scene scene)
		{
			GameObject[] rootGameObjects = ((Scene)(ref scene)).GetRootGameObjects();
			foreach (GameObject val in rootGameObjects)
			{
				if (((Object)val).name == "_scenery")
				{
					return val.transform;
				}
			}
			return null;
		}
	}
	internal sealed class BoneIslandBfoDisplay : MonoBehaviour
	{
		private ShipItem item;

		private ItemRigidbody itemBody;

		private SaveablePrefab saveable;

		internal void Initialize(ShipItem newItem)
		{
			item = newItem;
			itemBody = (((Object)(object)item != (Object)null) ? item.GetItemRigidbody() : null);
			saveable = (((Object)(object)item != (Object)null) ? ((Component)item).GetComponent<SaveablePrefab>() : null);
		}

		private void Update()
		{
			if ((Object)(object)item == (Object)null || !Object.op_Implicit((Object)(object)((PickupableItem)item).held))
			{
				return;
			}
			SaveablePrefab obj = saveable;
			if (obj != null)
			{
				obj.RegisterToSave();
			}
			if ((Object)(object)itemBody != (Object)null)
			{
				itemBody.debugForceKinematic = false;
				Rigidbody component = ((Component)itemBody).GetComponent<Rigidbody>();
				if ((Object)(object)component != (Object)null)
				{
					component.useGravity = true;
				}
			}
			if ((Object)(object)FloatingOriginManager.instance != (Object)null)
			{
				((Component)this).transform.SetParent(((Component)FloatingOriginManager.instance).transform, true);
			}
			((Behaviour)this).enabled = false;
			ManualLogSource logSource = PowerfulOarPlugin.LogSource;
			if (logSource != null)
			{
				logSource.LogInfo((object)"Released the Bone Island BFO 5000 to normal held-item physics and saving.");
			}
		}
	}
	internal static class RadRefinementCompatibility
	{
		internal const string PluginGuid = "com.raddude.radrefinements";

		private const string ConfigsTypeName = "RadRefinements.Configs";

		private const string OarPatchTypeName = "RadRefinements.Patches.OarPatches+ShipItemOarPatches";

		private static ConfigEntry<float> rowingNeedsReduction;

		private static ConfigEntry<bool> continualRow;

		private static bool needsReductionEnabled;

		private static bool continualRowAvailable;

		internal static bool NeedsReductionEnabled => needsReductionEnabled;

		internal static bool ContinualRowAvailable => continualRowAvailable;

		internal static float NeedsCostMultiplier
		{
			get
			{
				if (!needsReductionEnabled || rowingNeedsReduction == null)
				{
					return 1f;
				}
				return 1f - Mathf.Clamp01(rowingNeedsReduction.Value);
			}
		}

		internal static bool ContinualRowEnabled
		{
			get
			{
				if (continualRowAvailable && continualRow != null)
				{
					return continualRow.Value;
				}
				return false;
			}
		}

		internal static void Initialize(Harmony harmony)
		{
			Type type = AccessTools.TypeByName("RadRefinements.Configs");
			Type type2 = AccessTools.TypeByName("RadRefinements.Patches.OarPatches+ShipItemOarPatches");
			if (type == null || type2 == null)
			{
				return;
			}
			rowingNeedsReduction = AccessTools.Field(type, "rowingNeedsMult")?.GetValue(null) as ConfigEntry<float>;
			continualRow = AccessTools.Field(type, "continualRow")?.GetValue(null) as ConfigEntry<bool>;
			MethodBase methodBase = AccessTools.DeclaredMethod(typeof(ShipItemOar), "ExtraLateUpdate", (Type[])null, (Type[])null);
			MethodBase target = AccessTools.DeclaredMethod(typeof(ShipItemOar), "OnAltHeld", (Type[])null, (Type[])null);
			MethodInfo methodInfo = AccessTools.Method(type2, "ReduceNeedsPrefix", (Type[])null, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(type2, "ReduceNeedsPostfix", (Type[])null, (Type[])null);
			MethodInfo patchMethod = AccessTools.Method(type2, "ContinualRow", (Type[])null, (Type[])null);
			continualRowAvailable = continualRow != null && ContainsPatch(target, patchMethod);
			if (harmony == null || rowingNeedsReduction == null || !ContainsPatch(methodBase, methodInfo) || !ContainsPatch(methodBase, methodInfo2))
			{
				ManualLogSource logSource = PowerfulOarPlugin.LogSource;
				if (logSource != null)
				{
					logSource.LogWarning((object)"RadRefinement was detected, but its rowing-needs patches could not be safely replaced. Its slider will not alter PowerfulOar needs costs.");
				}
				return;
			}
			try
			{
				harmony.Unpatch(methodBase, methodInfo);
				harmony.Unpatch(methodBase, methodInfo2);
				needsReductionEnabled = !ContainsPatch(methodBase, methodInfo) && !ContainsPatch(methodBase, methodInfo2);
				if (needsReductionEnabled)
				{
					ManualLogSource logSource2 = PowerfulOarPlugin.LogSource;
					if (logSource2 != null)
					{
						logSource2.LogInfo((object)"RadRefinement rowing-needs compatibility enabled: its reduction slider now scales PowerfulOar baselines.");
					}
				}
				else
				{
					ManualLogSource logSource3 = PowerfulOarPlugin.LogSource;
					if (logSource3 != null)
					{
						logSource3.LogError((object)"RadRefinement rowing-needs patches remained installed; slider compatibility was disabled.");
					}
				}
			}
			catch (Exception ex)
			{
				needsReductionEnabled = false;
				ManualLogSource logSource4 = PowerfulOarPlugin.LogSource;
				if (logSource4 != null)
				{
					logSource4.LogError((object)("Could not install RadRefinement rowing-needs compatibility: " + ex));
				}
			}
			if (continualRowAvailable)
			{
				ManualLogSource logSource5 = PowerfulOarPlugin.LogSource;
				if (logSource5 != null)
				{
					logSource5.LogInfo((object)"RadRefinement continual-row force compatibility enabled.");
				}
			}
		}

		private static bool ContainsPatch(MethodBase target, MethodInfo patchMethod)
		{
			if (target == null || patchMethod == null)
			{
				return false;
			}
			Patches patchInfo = Harmony.GetPatchInfo(target);
			if (patchInfo == null)
			{
				return false;
			}
			if (!ContainsPatch(patchInfo.Prefixes, patchMethod) && !ContainsPatch(patchInfo.Postfixes, patchMethod) && !ContainsPatch(patchInfo.Transpilers, patchMethod))
			{
				return ContainsPatch(patchInfo.Finalizers, patchMethod);
			}
			return true;
		}

		private static bool ContainsPatch(IEnumerable<Patch> patches, MethodInfo patchMethod)
		{
			foreach (Patch patch in patches)
			{
				if (patch.PatchMethod == patchMethod)
				{
					return true;
				}
			}
			return false;
		}
	}
	internal static class HookHangMoreCompatibility
	{
		internal const string PluginGuid = "com.raddude.hookshangmore";

		private const string AttachableItemTypeName = "HooksHangMore.AttachableItem";

		internal static bool IsExcluded(ShipItem item)
		{
			int prefabIndex = OarStats.GetPrefabIndex(item);
			if (prefabIndex != 169)
			{
				return prefabIndex == 666;
			}
			return true;
		}

		internal static void Exclude(ShipItem item)
		{
			if (!IsExcluded(item))
			{
				return;
			}
			HangableItem component = ((Component)item).GetComponent<HangableItem>();
			if ((Object)(object)component != (Object)null && ((Behaviour)component).enabled)
			{
				component.DisconnectJoint();
				((Behaviour)component).enabled = false;
				ManualLogSource logSource = PowerfulOarPlugin.LogSource;
				if (logSource != null)
				{
					logSource.LogInfo((object)("Disabled vanilla hook hanging for " + item.name + "."));
				}
			}
			Type type = AccessTools.TypeByName("HooksHangMore.AttachableItem");
			Component val = ((type != null) ? ((Component)item).GetComponent(type) : null);
			if (!((Object)(object)val == (Object)null))
			{
				Behaviour val2 = (Behaviour)(object)((val is Behaviour) ? val : null);
				if ((Object)(object)val2 != (Object)null)
				{
					val2.enabled = false;
				}
				Object.Destroy((Object)(object)val);
				ManualLogSource logSource2 = PowerfulOarPlugin.LogSource;
				if (logSource2 != null)
				{
					logSource2.LogInfo((object)("Removed HooksHangMore attachment support from " + item.name + "."));
				}
			}
		}
	}
	[BepInPlugin("DogEggz.PowerfulOar", "PowerfulOar", "1.0.3")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class PowerfulOarPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "DogEggz.PowerfulOar";

		public const string PluginName = "PowerfulOar";

		public const string PluginVersion = "1.0.3";

		internal const string GoPointerInputLoopMethod = "LateUpdate";

		private Harmony harmony;

		internal static PowerfulOarPlugin Instance { get; private set; }

		internal static ManualLogSource LogSource { get; private set; }

		private void Awake()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			Instance = this;
			LogSource = ((BaseUnityPlugin)this).Logger;
			harmony = new Harmony("DogEggz.PowerfulOar");
			RadRefinementCompatibility.Initialize(harmony);
			bool flag = ApplyPatchClass(typeof(OarStatsPatch), typeof(ShipItemOar), "OnAltHeld");
			bool flag2 = ApplyPatchClass(typeof(OarLateUpdatePatch), typeof(ShipItemOar), "ExtraLateUpdate");
			bool flag3 = ApplyPatchClass(typeof(ScaledOarPrefabRegistrationPatch), typeof(PrefabsDirectory), "Start");
			bool flag4 = ApplyPatchClass(typeof(ScaledOarOutlineEffectPatch), typeof(OutlineEffect), "OnEnable");
			bool flag5 = ApplyPatchClass(typeof(ReverseOarInputPatch), typeof(GoPointer), "LateUpdate");
			bool flag6 = ApplyPatchClass(typeof(ScaledOarNailingPatch), typeof(ShipItemHammer), "CanNail", new Type[1] { typeof(ShipItem) });
			bool flag7 = ApplyPatchClass(typeof(BigOarVendorPatch), typeof(ShopItemSpawner), "Start");
			bool flag8 = ApplyPatchClass(typeof(BigOarVendorSpawnPatch), typeof(ShopItemSpawner), "SpawnItem");
			bool flag9 = ApplyPatchClass(typeof(HookHangMoreExclusionPatch), typeof(ShipItem), "Awake");
			BoneIslandBfoPlacement.Initialize();
			((BaseUnityPlugin)this).Logger.LogInfo((object)("PowerfulOar 1.0.3 loaded. Fixed per-oar stats and needs costs enabled. Hold Q to row opposite vanilla. Bone Island BFO placement and upright Big Oar vendor displays enabled. " + $"Patches: stats={flag}, late update={flag2}, " + $"prefab={flag3}, outline wake fix={flag4}, " + $"reverse input={flag5}, nailing={flag6}, " + $"vendors={flag7}, vendor displays={flag8}, " + $"HookHangMore exclusion={flag9}, " + $"RadRefinement needs={RadRefinementCompatibility.NeedsReductionEnabled}, " + $"continual row={RadRefinementCompatibility.ContinualRowAvailable}."));
		}

		private bool ApplyPatchClass(Type patchType, Type targetType, string targetMethodName, Type[] argumentTypes = null)
		{
			if (AccessTools.DeclaredMethod(targetType, targetMethodName, argumentTypes ?? Type.EmptyTypes, (Type[])null) == null)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Skipped " + patchType.Name + ": target method " + targetType.FullName + "." + targetMethodName + " was not found."));
				return false;
			}
			try
			{
				harmony.PatchAll(patchType);
				return true;
			}
			catch (Exception arg)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Failed to apply " + patchType.Name + " to " + $"{targetType.FullName}.{targetMethodName}: {arg}"));
				return false;
			}
		}

		private void OnDestroy()
		{
			BoneIslandBfoPlacement.Shutdown();
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
				LogSource = null;
			}
		}
	}
	internal static class PowerfulOarInput
	{
		internal static bool ReverseRowHeld
		{
			get
			{
				if (GameState.playing && !GameState.inCursorMenu && !GameState.wasInSettingsMenu)
				{
					return Input.GetKey((KeyCode)113);
				}
				return false;
			}
		}
	}
	[HarmonyPatch(typeof(GoPointer), "LateUpdate")]
	internal static class ReverseOarInputPatch
	{
		[HarmonyPostfix]
		private static void Postfix(GoPointer __instance)
		{
			if (!PowerfulOarInput.ReverseRowHeld)
			{
				return;
			}
			PickupableItem heldItem = __instance.GetHeldItem();
			ShipItemOar val = (ShipItemOar)(object)((heldItem is ShipItemOar) ? heldItem : null);
			if (!((Object)(object)val == (Object)null) && !GameInput.GetKey((InputName)9))
			{
				if (Input.GetKeyDown((KeyCode)113))
				{
					((GoPointerButton)val).OnAltActivate();
				}
				((GoPointerButton)val).OnAltHeld();
			}
		}
	}
	[HarmonyPatch(typeof(ShipItemOar), "OnAltHeld")]
	internal static class OarStatsPatch
	{
		private struct RowCallState
		{
			internal float ProgressBefore;

			internal bool Reverse;
		}

		[HarmonyPrefix]
		private static bool Prefix(ShipItemOar __instance, ref bool ___isHoldingButton, bool ___isOverWater, ref bool ___isRowing, ref float ___rowProgress, out RowCallState __state)
		{
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: 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_00b6: 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_00c6: 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)
			__state = new RowCallState
			{
				ProgressBefore = ___rowProgress,
				Reverse = PowerfulOarInput.ReverseRowHeld
			};
			OarStats.Apply(__instance);
			if (!__state.Reverse)
			{
				return true;
			}
			___isHoldingButton = true;
			if (Object.op_Implicit((Object)(object)((PickupableItem)__instance).held) && ___isOverWater && Object.op_Implicit((Object)(object)GameState.currentBoat))
			{
				if (___rowProgress <= 1f)
				{
					___isRowing = true;
					___rowProgress += Time.deltaTime;
					Rigidbody component = ((Component)GameState.currentBoat.parent).GetComponent<Rigidbody>();
					float maxBoatSpeed = __instance.maxBoatSpeed;
					Vector3 velocity = component.velocity;
					float num = Mathf.InverseLerp(maxBoatSpeed, 0f, ((Vector3)(ref velocity)).magnitude);
					component.AddForceAtPosition(__instance.waterPos.forward * __instance.rowForce * Time.deltaTime * num, __instance.waterPos.position);
				}
				else
				{
					___isRowing = false;
				}
			}
			return false;
		}

		[HarmonyPostfix]
		[HarmonyAfter(new string[] { "com.raddude.radrefinements" })]
		private static void Postfix(ShipItemOar __instance, bool ___isOverWater, RowCallState __state)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: 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)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: 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_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: 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_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			if (RadRefinementCompatibility.ContinualRowEnabled && Object.op_Implicit((Object)(object)((PickupableItem)__instance).held) && ___isOverWater && Object.op_Implicit((Object)(object)GameState.currentBoat) && !(__state.ProgressBefore > 1f) && !(__state.ProgressBefore + Time.deltaTime > 1f))
			{
				Rigidbody component = ((Component)GameState.currentBoat.parent).GetComponent<Rigidbody>();
				Vector3 val = __instance.waterPos.forward * (0f - __instance.rowForce) * Time.deltaTime;
				component.AddForceAtPosition(-val, __instance.waterPos.position);
				float maxBoatSpeed = __instance.maxBoatSpeed;
				Vector3 velocity = component.velocity;
				float num = Mathf.InverseLerp(maxBoatSpeed, 0f, ((Vector3)(ref velocity)).magnitude);
				float num2 = (__state.Reverse ? 1f : (-1f));
				component.AddForceAtPosition(__instance.waterPos.forward * __instance.rowForce * Time.deltaTime * num * num2, __instance.waterPos.position);
			}
		}
	}
	[HarmonyPatch(typeof(ShipItemOar), "ExtraLateUpdate")]
	internal static class OarLateUpdatePatch
	{
		private const float VanillaWaterCost = 0.4f;

		private const float VanillaFoodCost = 0.6f;

		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Expected O, but got Unknown
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			FieldInfo needsField = AccessTools.Field(typeof(PlayerNeeds), "water");
			FieldInfo needsField2 = AccessTools.Field(typeof(PlayerNeeds), "food");
			FieldInfo rowProgressField = AccessTools.Field(typeof(ShipItemOar), "rowProgress");
			List<int> list2 = FindNeedCostConstants(list, needsField, 0.4f);
			List<int> list3 = FindNeedCostConstants(list, needsField2, 0.6f);
			if (list2.Count == 1 && list3.Count == 1)
			{
				MethodInfo selector = AccessTools.Method(typeof(OarLateUpdatePatch), "SelectWaterCost", (Type[])null, (Type[])null);
				MethodInfo selector2 = AccessTools.Method(typeof(OarLateUpdatePatch), "SelectFoodCost", (Type[])null, (Type[])null);
				ReplaceNeedCostConstant(list, list3[0], selector2);
				ReplaceNeedCostConstant(list, list2[0], selector);
				ManualLogSource logSource = PowerfulOarPlugin.LogSource;
				if (logSource != null)
				{
					logSource.LogInfo((object)"Patched per-oar rowing water and food costs: Original=0.1/s, Big Oar=0.2/s, BFO 5000=1/s.");
				}
			}
			else
			{
				ManualLogSource logSource2 = PowerfulOarPlugin.LogSource;
				if (logSource2 != null)
				{
					logSource2.LogError((object)("Could not safely patch rowing needs costs: " + $"water matches={list2.Count}, food matches={list3.Count}. " + "Vanilla needs costs were left unchanged."));
				}
			}
			List<int> list4 = FindStrokeProgressLoads(list, rowProgressField);
			if (list4.Count == 1)
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(OarLateUpdatePatch), "SelectStrokeProgress", (Type[])null, (Type[])null);
				list.Insert(list4[0] + 1, new CodeInstruction(OpCodes.Call, (object)methodInfo));
				ManualLogSource logSource3 = PowerfulOarPlugin.LogSource;
				if (logSource3 != null)
				{
					logSource3.LogInfo((object)"Patched reverse oar stroke animation for the Q key.");
				}
			}
			else
			{
				ManualLogSource logSource4 = PowerfulOarPlugin.LogSource;
				if (logSource4 != null)
				{
					logSource4.LogError((object)("Could not safely patch reverse oar stroke animation: " + $"matches={list4.Count}. Reverse thrust remains available on Q."));
				}
			}
			return list;
		}

		private static float SelectStrokeProgress(float progress)
		{
			if (!PowerfulOarInput.ReverseRowHeld)
			{
				return progress;
			}
			return 1f - progress;
		}

		private static float SelectWaterCost(ShipItemOar oar)
		{
			return OarStats.GetWaterCostPerSecond(oar);
		}

		private static float SelectFoodCost(ShipItemOar oar)
		{
			return OarStats.GetFoodCostPerSecond(oar);
		}

		private static void ReplaceNeedCostConstant(IList<CodeInstruction> codes, int constantIndex, MethodInfo selector)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			CodeInstruction obj = codes[constantIndex];
			obj.opcode = OpCodes.Ldarg_0;
			obj.operand = null;
			codes.Insert(constantIndex + 1, new CodeInstruction(OpCodes.Call, (object)selector));
		}

		private static List<int> FindNeedCostConstants(IList<CodeInstruction> codes, FieldInfo needsField, float expectedConstant)
		{
			List<int> list = new List<int>();
			for (int i = 0; i <= codes.Count - 6; i++)
			{
				if (!(codes[i].opcode != OpCodes.Ldsfld) && object.Equals(codes[i].operand, needsField) && !(codes[i + 2].opcode != OpCodes.Ldc_R4) && codes[i + 2].operand is float num && Mathf.Approximately(num, expectedConstant) && !(codes[i + 3].opcode != OpCodes.Mul) && !(codes[i + 4].opcode != OpCodes.Sub) && !(codes[i + 5].opcode != OpCodes.Stsfld) && object.Equals(codes[i + 5].operand, needsField))
				{
					list.Add(i + 2);
				}
			}
			return list;
		}

		private static List<int> FindStrokeProgressLoads(IList<CodeInstruction> codes, FieldInfo rowProgressField)
		{
			List<int> list = new List<int>();
			for (int i = 0; i <= codes.Count - 6; i++)
			{
				if (LoadsFloat(codes[i], -1f) && LoadsFloat(codes[i + 1], 2f) && !(codes[i + 2].opcode != OpCodes.Ldarg_0) && !(codes[i + 3].opcode != OpCodes.Ldfld) && object.Equals(codes[i + 3].operand, rowProgressField) && !(codes[i + 4].opcode != OpCodes.Mul) && !(codes[i + 5].opcode != OpCodes.Add))
				{
					list.Add(i + 3);
				}
			}
			return list;
		}

		private static bool LoadsFloat(CodeInstruction instruction, float expected)
		{
			if (instruction.opcode == OpCodes.Ldc_R4 && instruction.operand is float num)
			{
				return Mathf.Approximately(num, expected);
			}
			return false;
		}
	}
	internal static class OarStats
	{
		internal const float OriginalForce = 35000f;

		internal const float OriginalMaxBoatSpeed = 2.06f;

		internal const float OriginalNeedsCostPerSecond = 0.1f;

		internal const float BigForce = 76500f;

		internal const float BigMaxBoatSpeed = 2.57f;

		internal const float BigNeedsCostPerSecond = 0.2f;

		internal const float Bfo5000Force = 510000f;

		internal const float Bfo5000MaxBoatSpeed = 10.29f;

		internal const float Bfo5000NeedsCostPerSecond = 1f;

		internal static bool Apply(ShipItemOar oar)
		{
			switch (GetPrefabIndex((ShipItem)(object)oar))
			{
			case 168:
				oar.rowForce = 35000f;
				oar.maxBoatSpeed = 2.06f;
				return true;
			case 169:
				oar.rowForce = 76500f;
				oar.maxBoatSpeed = 2.57f;
				return true;
			case 666:
				oar.rowForce = 510000f;
				oar.maxBoatSpeed = 10.29f;
				return true;
			default:
				return false;
			}
		}

		internal static float GetWaterCostPerSecond(ShipItemOar oar)
		{
			return GetNeedsCostPerSecond(oar, 0.4f) * RadRefinementCompatibility.NeedsCostMultiplier;
		}

		internal static float GetFoodCostPerSecond(ShipItemOar oar)
		{
			return GetNeedsCostPerSecond(oar, 0.6f) * RadRefinementCompatibility.NeedsCostMultiplier;
		}

		private static float GetNeedsCostPerSecond(ShipItemOar oar, float fallback)
		{
			return GetPrefabIndex((ShipItem)(object)oar) switch
			{
				168 => 0.1f, 
				169 => 0.2f, 
				666 => 1f, 
				_ => fallback, 
			};
		}

		internal static int GetPrefabIndex(ShipItem item)
		{
			SaveablePrefab val = (((Object)(object)item != (Object)null) ? ((Component)item).GetComponent<SaveablePrefab>() : null);
			if (!((Object)(object)val != (Object)null))
			{
				return -1;
			}
			return val.prefabIndex;
		}
	}
	internal sealed class ScaledOarDefinition
	{
		internal int PrefabIndex { get; }

		internal string ItemName { get; }

		internal float Scale { get; }

		internal float WaterPosDistance { get; }

		internal float WaterPosHeight { get; }

		internal float RowDipHeight { get; }

		internal float MassMultiplier { get; }

		internal int ValueMultiplier { get; }

		internal GameObject Prefab { get; set; }

		internal bool CacheValidationLogged { get; set; }

		internal ScaledOarDefinition(int prefabIndex, string itemName, float scale, float waterPosDistance, float waterPosHeight, float rowDipHeight, float massMultiplier, int valueMultiplier)
		{
			PrefabIndex = prefabIndex;
			ItemName = itemName;
			Scale = scale;
			WaterPosDistance = waterPosDistance;
			WaterPosHeight = waterPosHeight;
			RowDipHeight = rowDipHeight;
			MassMultiplier = massMultiplier;
			ValueMultiplier = valueMultiplier;
		}
	}
	internal static class ScaledOarFactory
	{
		internal const int VanillaOarPrefabIndex = 168;

		internal const int BigOarPrefabIndex = 169;

		internal const int Bfo5000PrefabIndex = 666;

		private static readonly ScaledOarDefinition[] Definitions = new ScaledOarDefinition[2]
		{
			new ScaledOarDefinition(169, "Big Oar", 2f, 1.5f, 2.8f, 1f, 8f, 4),
			new ScaledOarDefinition(666, "BFO 5000", 5f, 3.75f, 7f, 2.5f, 125f, 10)
		};

		internal static bool EnsureRegistered(PrefabsDirectory directory)
		{
			if ((Object)(object)directory == (Object)null || directory.directory == null)
			{
				ManualLogSource logSource = PowerfulOarPlugin.LogSource;
				if (logSource != null)
				{
					logSource.LogError((object)"Could not register scaled oars: PrefabsDirectory is unavailable.");
				}
				return false;
			}
			if (directory.directory.Length <= 168 || (Object)(object)directory.directory[168] == (Object)null)
			{
				ManualLogSource logSource2 = PowerfulOarPlugin.LogSource;
				if (logSource2 != null)
				{
					logSource2.LogError((object)("Could not register scaled oars: vanilla oar prefab " + $"{168} was not found."));
				}
				return false;
			}
			ShipItemOar component = directory.directory[168].GetComponent<ShipItemOar>();
			if ((Object)(object)component == (Object)null)
			{
				ManualLogSource logSource3 = PowerfulOarPlugin.LogSource;
				if (logSource3 != null)
				{
					logSource3.LogError((object)"Could not register scaled oars: prefab 168 is not a ShipItemOar.");
				}
				return false;
			}
			OarStats.Apply(component);
			EnsureDirectoryCapacity(directory);
			bool flag = true;
			ScaledOarDefinition[] definitions = Definitions;
			foreach (ScaledOarDefinition definition in definitions)
			{
				flag &= EnsureRegistered(directory, definition, component);
			}
			return flag;
		}

		internal static bool ValidateRuntimeCache(PrefabsDirectory directory)
		{
			if (!EnsureRegistered(directory))
			{
				return false;
			}
			EnsureDirectoryCapacity(directory);
			EnsureShipItemCacheCapacity(directory);
			bool result = true;
			ScaledOarDefinition[] definitions = Definitions;
			foreach (ScaledOarDefinition scaledOarDefinition in definitions)
			{
				GameObject val = directory.directory[scaledOarDefinition.PrefabIndex];
				ShipItem val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<ShipItem>() : null);
				SaveablePrefab val3 = (((Object)(object)val != (Object)null) ? val.GetComponent<SaveablePrefab>() : null);
				ScaledOarController scaledOarController = (((Object)(object)val != (Object)null) ? val.GetComponent<ScaledOarController>() : null);
				if ((Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null || (Object)(object)scaledOarController == (Object)null || val3.prefabIndex != scaledOarDefinition.PrefabIndex || scaledOarController.PrefabIndex != scaledOarDefinition.PrefabIndex)
				{
					ManualLogSource logSource = PowerfulOarPlugin.LogSource;
					if (logSource != null)
					{
						logSource.LogError((object)(scaledOarDefinition.ItemName + " registration failed validation: directory entry is missing ShipItem, ScaledOarController, or the expected prefab index."));
					}
					result = false;
					continue;
				}
				directory.shipItems[scaledOarDefinition.PrefabIndex] = val2;
				if (!scaledOarDefinition.CacheValidationLogged)
				{
					scaledOarDefinition.CacheValidationLogged = true;
					ManualLogSource logSource2 = PowerfulOarPlugin.LogSource;
					if (logSource2 != null)
					{
						logSource2.LogInfo((object)("Validated " + scaledOarDefinition.ItemName + " prefab and item cache at index " + $"{scaledOarDefinition.PrefabIndex}."));
					}
				}
			}
			return result;
		}

		private static bool EnsureRegistered(PrefabsDirectory directory, ScaledOarDefinition definition, ShipItemOar vanillaOar)
		{
			GameObject val = directory.directory[definition.PrefabIndex];
			if ((Object)(object)val != (Object)null)
			{
				ScaledOarController scaledOarController = val.GetComponent<ScaledOarController>();
				if ((Object)(object)val == (Object)(object)definition.Prefab || ((Object)(object)scaledOarController != (Object)null && scaledOarController.PrefabIndex == definition.PrefabIndex))
				{
					ShipItemOar component = val.GetComponent<ShipItemOar>();
					if ((Object)(object)component == (Object)null)
					{
						ManualLogSource logSource = PowerfulOarPlugin.LogSource;
						if (logSource != null)
						{
							logSource.LogError((object)("Could not configure " + definition.ItemName + ": ShipItemOar is missing."));
						}
						return false;
					}
					if ((Object)(object)scaledOarController == (Object)null)
					{
						scaledOarController = val.AddComponent<ScaledOarController>();
					}
					ConfigureScaledOar(val, component, vanillaOar, definition);
					definition.Prefab = val;
					scaledOarController.Initialize(definition.PrefabIndex, definition.Scale);
					return true;
				}
				ManualLogSource logSource2 = PowerfulOarPlugin.LogSource;
				if (logSource2 != null)
				{
					logSource2.LogError((object)("Could not register " + definition.ItemName + ": prefab index " + $"{definition.PrefabIndex} is already occupied by '{((Object)val).name}'."));
				}
				return false;
			}
			if ((Object)(object)definition.Prefab != (Object)null)
			{
				ShipItemOar component2 = definition.Prefab.GetComponent<ShipItemOar>();
				ScaledOarController component3 = definition.Prefab.GetComponent<ScaledOarController>();
				if ((Object)(object)component2 == (Object)null || (Object)(object)component3 == (Object)null)
				{
					ManualLogSource logSource3 = PowerfulOarPlugin.LogSource;
					if (logSource3 != null)
					{
						logSource3.LogError((object)("Could not restore " + definition.ItemName + ": cached components are missing."));
					}
					return false;
				}
				ConfigureScaledOar(definition.Prefab, component2, vanillaOar, definition);
				component3.Initialize(definition.PrefabIndex, definition.Scale);
				directory.directory[definition.PrefabIndex] = definition.Prefab;
				return true;
			}
			GameObject val2 = null;
			try
			{
				val2 = Object.Instantiate<GameObject>(directory.directory[168]);
				SaveablePrefab component4 = val2.GetComponent<SaveablePrefab>();
				ShipItemOar component5 = val2.GetComponent<ShipItemOar>();
				if ((Object)(object)component4 == (Object)null || (Object)(object)component5 == (Object)null)
				{
					ManualLogSource logSource4 = PowerfulOarPlugin.LogSource;
					if (logSource4 != null)
					{
						logSource4.LogError((object)("Could not register " + definition.ItemName + ": the cloned vanilla prefab is missing SaveablePrefab or ShipItemOar."));
					}
					Object.Destroy((Object)(object)val2);
					return false;
				}
				ConfigureScaledOar(val2, component5, vanillaOar, definition);
				ScaledOarController scaledOarController2 = val2.GetComponent<ScaledOarController>();
				if ((Object)(object)scaledOarController2 == (Object)null)
				{
					scaledOarController2 = val2.AddComponent<ScaledOarController>();
				}
				scaledOarController2.Initialize(definition.PrefabIndex, definition.Scale);
				directory.directory[definition.PrefabIndex] = val2;
				definition.Prefab = val2;
				ManualLogSource logSource5 = PowerfulOarPlugin.LogSource;
				if (logSource5 != null)
				{
					logSource5.LogInfo((object)("Registered " + definition.ItemName + " at prefab index " + $"{definition.PrefabIndex}. Scale={definition.Scale:0.0}x, " + $"mass={((ShipItem)component5).mass:0.0}, value={((ShipItem)component5).value}, " + $"water distance={definition.WaterPosDistance:0.00}, " + $"water height={definition.WaterPosHeight:0.00}, " + $"dip={definition.RowDipHeight:0.00}, big=false."));
				}
				return true;
			}
			catch (Exception arg)
			{
				if ((Object)(object)val2 != (Object)null)
				{
					Object.Destroy((Object)(object)val2);
				}
				ManualLogSource logSource6 = PowerfulOarPlugin.LogSource;
				if (logSource6 != null)
				{
					logSource6.LogError((object)$"Could not register {definition.ItemName}: {arg}");
				}
				return false;
			}
		}

		private static void ConfigureScaledOar(GameObject prefab, ShipItemOar oar, ShipItemOar vanillaOar, ScaledOarDefinition definition)
		{
			//IL_0037: 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)
			SaveablePrefab component = prefab.GetComponent<SaveablePrefab>();
			if ((Object)(object)component == (Object)null)
			{
				throw new InvalidOperationException(definition.ItemName + " is missing SaveablePrefab.");
			}
			((Object)prefab).name = definition.ItemName;
			prefab.transform.localScale = Vector3.one * definition.Scale;
			Object.DontDestroyOnLoad((Object)(object)prefab);
			component.prefabIndex = definition.PrefabIndex;
			((ShipItem)oar).name = definition.ItemName;
			((PickupableItem)oar).big = false;
			((ShipItem)oar).wallAttachment = false;
			((ShipItem)oar).mass = ((ShipItem)vanillaOar).mass * definition.MassMultiplier;
			((ShipItem)oar).value = ((ShipItem)vanillaOar).value * definition.ValueMultiplier;
			oar.waterPosDistance = definition.WaterPosDistance;
			oar.waterPosHeight = definition.WaterPosHeight;
			oar.rowDipHeight = definition.RowDipHeight;
			OarStats.Apply(oar);
			HookHangMoreCompatibility.Exclude((ShipItem)(object)oar);
		}

		private static void EnsureDirectoryCapacity(PrefabsDirectory directory)
		{
			if (directory.directory.Length <= 666)
			{
				Array.Resize(ref directory.directory, 667);
			}
		}

		private static void EnsureShipItemCacheCapacity(PrefabsDirectory directory)
		{
			if (directory.shipItems == null)
			{
				directory.shipItems = (ShipItem[])(object)new ShipItem[directory.directory.Length];
				for (int i = 0; i < directory.directory.Length; i++)
				{
					GameObject val = directory.directory[i];
					if ((Object)(object)val != (Object)null)
					{
						directory.shipItems[i] = val.GetComponent<ShipItem>();
					}
				}
			}
			else if (directory.shipItems.Length < directory.directory.Length)
			{
				Array.Resize(ref directory.shipItems, directory.directory.Length);
			}
		}
	}
	[DefaultExecutionOrder(10000)]
	internal sealed class ScaledOarController : MonoBehaviour
	{
		private static readonly HashSet<ScaledOarController> ActiveControllers = new HashSet<ScaledOarController>();

		private static readonly FieldInfo CollidedCollidersField = AccessTools.Field(typeof(PickupableItemCollisionChecker), "collidedCols");

		private static readonly FieldInfo CurrentDecolDistanceField = AccessTools.Field(typeof(PickupableItemCollisionChecker), "currentDecolDistance");

		[SerializeField]
		private int prefabIndex;

		[SerializeField]
		private float targetScale = 1f;

		private ShipItemOar item;

		private ItemRigidbody itemRigidbody;

		private Outline outline;

		private bool wasInSleepOrLoadTransition;

		internal int PrefabIndex => prefabIndex;

		internal void Initialize(int newPrefabIndex, float newTargetScale)
		{
			prefabIndex = newPrefabIndex;
			targetScale = newTargetScale;
			item = ((Component)this).GetComponent<ShipItemOar>();
			ApplyScale(((Component)this).transform);
			HookHangMoreCompatibility.Exclude((ShipItem)(object)item);
		}

		internal static void SuppressTransitionOutlines()
		{
			foreach (ScaledOarController activeController in ActiveControllers)
			{
				if ((Object)(object)activeController != (Object)null)
				{
					activeController.SuppressStaleOutline();
				}
			}
		}

		private void Awake()
		{
			item = ((Component)this).GetComponent<ShipItemOar>();
			HookHangMoreCompatibility.Exclude((ShipItem)(object)item);
		}

		private void OnEnable()
		{
			ActiveControllers.Add(this);
		}

		private void OnDisable()
		{
			ActiveControllers.Remove(this);
		}

		private void OnDestroy()
		{
			ActiveControllers.Remove(this);
		}

		private void LateUpdate()
		{
			if ((Object)(object)item == (Object)null)
			{
				item = ((Component)this).GetComponent<ShipItemOar>();
				if ((Object)(object)item == (Object)null)
				{
					return;
				}
			}
			if ((Object)(object)itemRigidbody == (Object)null)
			{
				itemRigidbody = ((ShipItem)item).itemRigidbodyC;
			}
			if ((Object)(object)itemRigidbody == (Object)null || (Object)(object)itemRigidbody.GetCurrentInventorySlot() == (Object)null)
			{
				ApplyScale(((Component)this).transform);
				if ((Object)(object)itemRigidbody != (Object)null)
				{
					ApplyScale(((Component)itemRigidbody).transform);
				}
			}
			bool flag = GameState.sleeping || GameState.recovering || GameState.currentlyLoading || GameState.justWokeUp;
			if (flag)
			{
				if (!GameState.sleeping && !GameState.currentlyLoading)
				{
					ReconcileCollisionState();
				}
				SuppressStaleOutline();
			}
			else if (wasInSleepOrLoadTransition)
			{
				ReconcileCollisionState();
				SuppressStaleOutline();
			}
			wasInSleepOrLoadTransition = flag;
		}

		private void ApplyScale(Transform target)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//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_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_0020: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = Vector3.one * targetScale;
			if (target.localScale != val)
			{
				target.localScale = val;
			}
		}

		private void SuppressStaleOutline()
		{
			if ((Object)(object)item == (Object)null)
			{
				item = ((Component)this).GetComponent<ShipItemOar>();
			}
			if ((Object)(object)item != (Object)null)
			{
				((GoPointerButton)item).enableRedOutline = false;
			}
			if ((Object)(object)outline == (Object)null)
			{
				outline = ((Component)this).GetComponent<Outline>();
			}
			if ((Object)(object)outline != (Object)null)
			{
				((Behaviour)outline).enabled = false;
			}
		}

		private void ReconcileCollisionState()
		{
			//IL_010c: 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_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			PickupableItemCollisionChecker val = ((PickupableItem)(item?)).colChecker;
			if ((Object)(object)val == (Object)null || CollidedCollidersField == null || CurrentDecolDistanceField == null)
			{
				return;
			}
			List<Collider> list = CollidedCollidersField.GetValue(val) as List<Collider>;
			Collider component = ((Component)val).GetComponent<Collider>();
			int num = 0;
			float num2 = 0f;
			if (Object.op_Implicit((Object)(object)((PickupableItem)item).held) && ((ShipItem)item).GetCurrentInventorySlot() < 0 && (Object)(object)component != (Object)null && component.enabled && list != null)
			{
				Vector3 val2 = default(Vector3);
				float num3 = default(float);
				foreach (Collider item in list)
				{
					if (!((Object)(object)item == (Object)null) && item.enabled && ((Component)item).gameObject.activeInHierarchy && !item.isTrigger && !((Object)(object)((Component)item).gameObject == (Object)(object)((Component)this.item).gameObject) && !((Component)item).CompareTag("Boat") && Physics.ComputePenetration(component, ((Component)component).transform.position, ((Component)component).transform.rotation, item, ((Component)item).transform.position, ((Component)item).transform.rotation, ref val2, ref num3) && num3 > 0f)
					{
						num++;
						num2 = Mathf.Max(num2, num3);
					}
				}
			}
			val.collisions = num;
			CurrentDecolDistanceField.SetValue(val, num2);
			val.allowObstructedDropping = num2 < 0.06f;
			((GoPointerButton)this.item).enableRedOutline = false;
		}
	}
	[HarmonyPatch(typeof(PrefabsDirectory), "Start")]
	internal static class ScaledOarPrefabRegistrationPatch
	{
		[HarmonyPrefix]
		[HarmonyPriority(0)]
		private static void Prefix(PrefabsDirectory __instance)
		{
			ScaledOarFactory.EnsureRegistered(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPriority(0)]
		private static void Postfix(PrefabsDirectory __instance)
		{
			ScaledOarFactory.ValidateRuntimeCache(__instance);
			BoneIslandBfoPlacement.OnPrefabsReady();
		}
	}
	[HarmonyPatch(typeof(OutlineEffect), "OnEnable")]
	internal static class ScaledOarOutlineEffectPatch
	{
		[HarmonyPostfix]
		[HarmonyPriority(0)]
		private static void Postfix()
		{
			ScaledOarController.SuppressTransitionOutlines();
		}
	}
	[HarmonyPatch(typeof(ShipItemHammer), "CanNail")]
	internal static class ScaledOarNailingPatch
	{
		[HarmonyPostfix]
		private static void Postfix(ShipItem item, ref bool __result)
		{
			if (HookHangMoreCompatibility.IsExcluded(item))
			{
				__result = item.sold;
			}
		}
	}
	[HarmonyPatch(typeof(ShipItem), "Awake")]
	[HarmonyAfter(new string[] { "com.raddude.hookshangmore" })]
	internal static class HookHangMoreExclusionPatch
	{
		[HarmonyPostfix]
		[HarmonyPriority(0)]
		private static void Postfix(ShipItem __instance)
		{
			HookHangMoreCompatibility.Exclude(__instance);
		}
	}
	[HarmonyPatch(typeof(ShopItemSpawner), "Start")]
	internal static class BigOarVendorPatch
	{
		private sealed class VendorPlacement
		{
			internal readonly string SpawnerName;

			internal readonly Vector3 LocalPosition;

			internal readonly Vector3 LocalEuler;

			internal VendorPlacement(string spawnerName, Vector3 localPosition, Vector3 localEuler)
			{
				//IL_000e: 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)
				//IL_0015: 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)
				SpawnerName = spawnerName;
				LocalPosition = localPosition;
				LocalEuler = localEuler;
			}
		}

		private static readonly Dictionary<string, VendorPlacement> TargetPlacements = new Dictionary<string, VendorPlacement>
		{
			{
				"island 9 E Dragon Cliffs",
				new VendorPlacement("shop item spawner (236)", new Vector3(0.198f, 1.5f, -0.049f), new Vector3(0.625f, -176.864f, 0.7f))
			},
			{
				"island 1 A Gold Rock",
				new VendorPlacement("shop item (224)", new Vector3(0.145f, 1.467f, -0.004f), new Vector3(0f, -12.273f, 0f))
			},
			{
				"island 15 M (Fort)",
				new VendorPlacement("shop item (284)", new Vector3(0.287f, 1.46f, -0.251f), new Vector3(-2.876f, -2.876f, -1.02f))
			}
		};

		[HarmonyPrefix]
		[HarmonyPriority(0)]
		private static void Prefix(ShopItemSpawner __instance)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: 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)
			Scene scene = ((Component)__instance).gameObject.scene;
			if (!((Scene)(ref scene)).IsValid() || !TargetPlacements.TryGetValue(((Scene)(ref scene)).name, out var value) || ((Object)((Component)__instance).gameObject).name != value.SpawnerName)
			{
				return;
			}
			PrefabsDirectory instance = PrefabsDirectory.instance;
			if ((Object)(object)instance == (Object)null || !ScaledOarFactory.ValidateRuntimeCache(instance))
			{
				ManualLogSource logSource = PowerfulOarPlugin.LogSource;
				if (logSource != null)
				{
					logSource.LogError((object)("Could not add Big Oar to vendor in " + ((Scene)(ref scene)).name + ": prefab directory unavailable."));
				}
				return;
			}
			int prefabIndex = GetPrefabIndex(__instance.itemPrefab);
			switch (prefabIndex)
			{
			case 169:
				break;
			default:
			{
				ManualLogSource logSource3 = PowerfulOarPlugin.LogSource;
				if (logSource3 != null)
				{
					logSource3.LogWarning((object)("Configured Big Oar vendor slot '" + value.SpawnerName + "' in " + ((Scene)(ref scene)).name + " does not contain vanilla oar prefab " + $"{168}; found {prefabIndex}."));
				}
				break;
			}
			case 168:
			{
				__instance.itemPrefab = instance.directory[169];
				BigOarVendorDisplaySpawner bigOarVendorDisplaySpawner = ((Component)__instance).GetComponent<BigOarVendorDisplaySpawner>();
				if ((Object)(object)bigOarVendorDisplaySpawner == (Object)null)
				{
					bigOarVendorDisplaySpawner = ((Component)__instance).gameObject.AddComponent<BigOarVendorDisplaySpawner>();
				}
				bigOarVendorDisplaySpawner.Initialize(((Scene)(ref scene)).name, value.LocalPosition, value.LocalEuler);
				ManualLogSource logSource2 = PowerfulOarPlugin.LogSource;
				if (logSource2 != null)
				{
					logSource2.LogInfo((object)("Replaced one vanilla-oar vendor slot with Big Oar in " + ((Scene)(ref scene)).name + " at '" + value.SpawnerName + "' using its configured local pose."));
				}
				break;
			}
			}
		}

		private static int GetPrefabIndex(GameObject prefab)
		{
			SaveablePrefab val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<SaveablePrefab>() : null);
			if (!((Object)(object)val != (Object)null))
			{
				return -1;
			}
			return val.prefabIndex;
		}
	}
	[HarmonyPatch(typeof(ShopItemSpawner), "SpawnItem")]
	internal static class BigOarVendorSpawnPatch
	{
		[HarmonyPostfix]
		[HarmonyPriority(0)]
		private static void Postfix(ShopItemSpawner __instance, ShipItem ___item)
		{
			BigOarVendorDisplaySpawner component = ((Component)__instance).GetComponent<BigOarVendorDisplaySpawner>();
			if ((Object)(object)component != (Object)null && OarStats.GetPrefabIndex(___item) == 169)
			{
				component.ConfigureSpawnedItem(___item);
			}
		}
	}
	internal sealed class BigOarVendorDisplaySpawner : MonoBehaviour
	{
		private string sceneName;

		private Vector3 localPosition;

		private Quaternion localRotation;

		internal void Initialize(string newSceneName, Vector3 newLocalPosition, Vector3 newLocalEuler)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: 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)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			sceneName = newSceneName;
			localPosition = newLocalPosition;
			localRotation = Quaternion.Euler(newLocalEuler);
		}

		internal void ConfigureSpawnedItem(ShipItem item)
		{
			//IL_0029: 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 (!((Object)(object)item == (Object)null))
			{
				BigOarVendorDisplayItem bigOarVendorDisplayItem = ((Component)item).GetComponent<BigOarVendorDisplayItem>();
				if ((Object)(object)bigOarVendorDisplayItem == (Object)null)
				{
					bigOarVendorDisplayItem = ((Component)item).gameObject.AddComponent<BigOarVendorDisplayItem>();
				}
				bigOarVendorDisplayItem.Initialize(item, localPosition, localRotation, 2f);
				ManualLogSource logSource = PowerfulOarPlugin.LogSource;
				if (logSource != null)
				{
					logSource.LogInfo((object)("Positioned Big Oar vendor display in " + sceneName + " at the configured spawner-local pose."));
				}
			}
		}
	}
	[DefaultExecutionOrder(10001)]
	internal sealed class BigOarVendorDisplayItem : MonoBehaviour
	{
		private ShipItem item;

		private Vector3 localPosition;

		private Quaternion localRotation;

		private float targetWorldScale;

		internal void Initialize(ShipItem newItem, Vector3 newLocalPosition, Quaternion newLocalRotation, float newTargetWorldScale)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: 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)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			item = newItem;
			localPosition = newLocalPosition;
			localRotation = newLocalRotation;
			targetWorldScale = newTargetWorldScale;
			ApplyPlacement();
		}

		private void LateUpdate()
		{
			if ((Object)(object)item == (Object)null || item.sold || Object.op_Implicit((Object)(object)((PickupableItem)item).held))
			{
				((Behaviour)this).enabled = false;
			}
			else
			{
				ApplyPlacement();
			}
		}

		private void ApplyPlacement()
		{
			//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_0024: 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_003c: 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)
			//IL_0058: 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)
			Transform parent = ((Component)this).transform.parent;
			if (!((Object)(object)parent == (Object)null))
			{
				Vector3 lossyScale = parent.lossyScale;
				((Component)this).transform.localScale = new Vector3(SafeLocalScale(lossyScale.x), SafeLocalScale(lossyScale.y), SafeLocalScale(lossyScale.z));
				((Component)this).transform.localPosition = localPosition;
				((Component)this).transform.localRotation = localRotation;
			}
		}

		private float SafeLocalScale(float parentScale)
		{
			if (!(Mathf.Abs(parentScale) > 0.0001f))
			{
				return targetWorldScale;
			}
			return targetWorldScale / Mathf.Abs(parentScale);
		}
	}
}