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 PendingScenes = new HashSet(); 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(val); ShipItem component = val2.GetComponent(); 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(); 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(); if ((Object)(object)component3 != (Object)null) { component3.isKinematic = true; component3.useGravity = false; component3.velocity = Vector3.zero; component3.angularVelocity = Vector3.zero; } } BoneIslandBfoDisplay boneIslandBfoDisplay = val2.GetComponent(); if ((Object)(object)boneIslandBfoDisplay == (Object)null) { boneIslandBfoDisplay = val2.AddComponent(); } 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(); 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() : 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(); 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 rowingNeedsReduction; private static ConfigEntry 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; continualRow = AccessTools.Field(type, "continualRow")?.GetValue(null) as ConfigEntry; 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 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(); 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(); 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(); 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 Transpiler(IEnumerable instructions) { //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Expected O, but got Unknown List list = new List(instructions); FieldInfo needsField = AccessTools.Field(typeof(PlayerNeeds), "water"); FieldInfo needsField2 = AccessTools.Field(typeof(PlayerNeeds), "food"); FieldInfo rowProgressField = AccessTools.Field(typeof(ShipItemOar), "rowProgress"); List list2 = FindNeedCostConstants(list, needsField, 0.4f); List 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 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 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 FindNeedCostConstants(IList codes, FieldInfo needsField, float expectedConstant) { List list = new List(); 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 FindStrokeProgressLoads(IList codes, FieldInfo rowProgressField) { List list = new List(); 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() : 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(); 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() : null); SaveablePrefab val3 = (((Object)(object)val != (Object)null) ? val.GetComponent() : null); ScaledOarController scaledOarController = (((Object)(object)val != (Object)null) ? val.GetComponent() : 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(); if ((Object)(object)val == (Object)(object)definition.Prefab || ((Object)(object)scaledOarController != (Object)null && scaledOarController.PrefabIndex == definition.PrefabIndex)) { ShipItemOar component = val.GetComponent(); 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(); } 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(); ScaledOarController component3 = definition.Prefab.GetComponent(); 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(directory.directory[168]); SaveablePrefab component4 = val2.GetComponent(); ShipItemOar component5 = val2.GetComponent(); 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(); if ((Object)(object)scaledOarController2 == (Object)null) { scaledOarController2 = val2.AddComponent(); } 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(); 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(); } } } 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 ActiveControllers = new HashSet(); 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(); 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(); 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(); 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(); } if ((Object)(object)item != (Object)null) { ((GoPointerButton)item).enableRedOutline = false; } if ((Object)(object)outline == (Object)null) { outline = ((Component)this).GetComponent(); } 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 list = CollidedCollidersField.GetValue(val) as List; Collider component = ((Component)val).GetComponent(); 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 TargetPlacements = new Dictionary { { "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(); if ((Object)(object)bigOarVendorDisplaySpawner == (Object)null) { bigOarVendorDisplaySpawner = ((Component)__instance).gameObject.AddComponent(); } 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() : 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(); 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(); if ((Object)(object)bigOarVendorDisplayItem == (Object)null) { bigOarVendorDisplayItem = ((Component)item).gameObject.AddComponent(); } 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); } } }