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);
}
}
}