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.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using PerformanceTweaks.Configuration;
using PerformanceTweaks.Patches;
using PerformanceTweaks.Runtime;
using UnityEngine;
using cakeslice;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("PerformanceTweaks")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Keevi")]
[assembly: AssemblyProduct("PerformanceTweaks")]
[assembly: AssemblyCopyright("Copyright © 2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("5406f2ba-bc59-485d-91b1-3c59b7af05fb")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace PerformanceTweaks
{
[BepInPlugin("com.keevi.performancetweaks", "Performance Tweaks", "1.0.0")]
public class Plugin : BaseUnityPlugin
{
public const string PLUGIN_GUID = "com.keevi.performancetweaks";
public const string PLUGIN_NAME = "Performance Tweaks";
public const string PLUGIN_VERSION = "1.0.0";
internal static ManualLogSource Log { get; private set; }
private void Awake()
{
Log = ((BaseUnityPlugin)this).Logger;
try
{
ModConfig.Bind(((BaseUnityPlugin)this).Config);
LogSettings();
ApplyHarmonyPatches();
ApplySettingChangesImmediately();
((Component)this).gameObject.AddComponent<FrameUpdater>();
}
catch (Exception arg)
{
Log.LogError((object)string.Format("{0} failed to load and will not activate: {1}", "Performance Tweaks", arg));
return;
}
Log.LogInfo((object)string.Format("{0} v{1} loaded.", "Performance Tweaks", "1.0.0"));
}
private void LogSettings()
{
Log.LogInfo((object)"Configuration:");
foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item in ((BaseUnityPlugin)this).Config)
{
Log.LogInfo((object)$" {item.Key.Key}: {item.Value.BoxedValue}");
}
}
private static void ApplyHarmonyPatches()
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
Harmony val = new Harmony("com.keevi.performancetweaks");
val.PatchAll(Assembly.GetExecutingAssembly());
foreach (MethodBase patchedMethod in val.GetPatchedMethods())
{
Log.LogInfo((object)$"Patched {patchedMethod.DeclaringType}.{patchedMethod.Name}");
}
}
private static void ApplySettingChangesImmediately()
{
ModConfig.SkipUnchangedRopes.SettingChanged += delegate
{
RopeLod.RebuildAll();
};
ModConfig.SimplifyDistantRopes.SettingChanged += delegate
{
RopeLod.RebuildAll();
};
ModConfig.DirtCameraOnDemand.SettingChanged += delegate
{
DirtCameraSwitch.Apply(MasterPainter.instance);
};
ModConfig.OutlineCamerasOnDemand.SettingChanged += delegate
{
OutlineEffectPatch.Forget();
};
}
}
}
namespace PerformanceTweaks.Runtime
{
internal static class BoatMotion
{
private sealed class BoatState
{
public readonly Transform Boat;
public float StepTime = float.NegativeInfinity;
public bool IsStill;
private Vector3 position;
private Quaternion rotation;
public BoatState(Transform boat)
{
Boat = boat;
}
public void Measure(float stepTime)
{
//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_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_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_004d: Unknown result type (might be due to invalid IL or missing references)
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_0055: Unknown result type (might be due to invalid IL or missing references)
Vector3 newPosition = Boat.position;
Quaternion newRotation = Boat.rotation;
IsStill = stepTime - StepTime < 1.5f * Time.fixedDeltaTime && MovementMillimetres(newPosition, newRotation) < 5f;
StepTime = stepTime;
position = newPosition;
rotation = newRotation;
}
private float MovementMillimetres(Vector3 newPosition, Quaternion newRotation)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
float num = Vector3.Distance(newPosition, position);
float num2 = Quaternion.Angle(newRotation, rotation) * ((float)Math.PI / 180f) * 20f;
return (num + num2) * 1000f;
}
}
private const float ReachMetres = 20f;
private const float StillMillimetres = 5f;
private const float MillimetresPerMetre = 1000f;
private const float MaxStepGap = 1.5f;
private const float ForgetAfterSeconds = 1f;
private static readonly List<BoatState> States = new List<BoatState>();
private static BoatState lastState;
public static bool IsStill(Transform boat)
{
float fixedTime = Time.fixedTime;
if (lastState == null || lastState.Boat != boat)
{
lastState = StateOf(boat, fixedTime);
}
if (lastState.StepTime != fixedTime)
{
lastState.Measure(fixedTime);
}
return lastState.IsStill;
}
private static BoatState StateOf(Transform boat, float stepTime)
{
foreach (BoatState state in States)
{
if (state.Boat == boat)
{
return state;
}
}
ForgetStaleStates(stepTime);
BoatState boatState = new BoatState(boat);
States.Add(boatState);
return boatState;
}
private static void ForgetStaleStates(float stepTime)
{
for (int num = States.Count - 1; num >= 0; num--)
{
if (stepTime - States[num].StepTime > 1f)
{
States.RemoveAt(num);
}
}
}
}
internal static class DirtCameraSwitch
{
private const int FramesRenderedPerClean = 2;
private static int renderUntilFrame = -1;
public static void Apply(MasterPainter painter)
{
if (!((Object)(object)painter == (Object)null))
{
Camera component = ((Component)painter).GetComponent<Camera>();
bool flag = !ModConfig.DirtCameraOnDemand.Value || Time.frameCount <= renderUntilFrame;
if ((Object)(object)component != (Object)null && ((Behaviour)component).enabled != flag)
{
((Behaviour)component).enabled = flag;
}
}
}
public static void RenderForClean(MasterPainter painter)
{
renderUntilFrame = Time.frameCount + 2 - 1;
Apply(painter);
((MonoBehaviour)painter).StartCoroutine(ApplyAfterClean(painter));
}
private static IEnumerator ApplyAfterClean(MasterPainter painter)
{
while (Time.frameCount <= renderUntilFrame)
{
yield return null;
}
Apply(painter);
}
}
internal sealed class FrameUpdater : MonoBehaviour
{
private void Update()
{
HiddenRopePauser.Update();
ShopItemFreezer.Update();
}
}
internal static class HiddenRopePauser
{
private sealed class PausableRope
{
public readonly RopeEffect Rope;
public int HiddenFrames;
public PausableRope(RopeEffect rope)
{
Rope = rope;
}
}
private const int RefreshInterval = 20;
private const int PruneEveryRegistrations = 256;
private static readonly FieldRef<RopeEffect, ClothRope> ClothOf = AccessTools.FieldRefAccess<RopeEffect, ClothRope>("clothRope");
private static readonly FieldRef<RopeEffect, bool> IsOutOfRange = AccessTools.FieldRefAccess<RopeEffect, bool>("outOfRange");
private static readonly Predicate<PausableRope> IsDestroyed = (PausableRope entry) => (Object)(object)entry.Rope == (Object)null;
private static readonly List<PausableRope> ropes = new List<PausableRope>();
private static bool hasPausedRopes;
public static void Register(RopeEffect rope)
{
ropes.Add(new PausableRope(rope));
if (ropes.Count % 256 == 0)
{
ropes.RemoveAll(IsDestroyed);
}
}
public static void Update()
{
bool value = ModConfig.PauseHiddenRopes.Value;
if (!value && !hasPausedRopes)
{
return;
}
hasPausedRopes = false;
for (int num = ropes.Count - 1; num >= 0; num--)
{
PausableRope pausableRope = ropes[num];
if ((Object)(object)pausableRope.Rope == (Object)null)
{
ropes.RemoveAt(num);
}
else
{
bool flag = !value || NeedsUpdate(pausableRope);
if (((Behaviour)pausableRope.Rope).enabled != flag)
{
((Behaviour)pausableRope.Rope).enabled = flag;
}
if (!flag)
{
hasPausedRopes = true;
}
}
}
}
private static bool NeedsUpdate(PausableRope entry)
{
RopeEffect rope = entry.Rope;
if ((Object)(object)rope.attachment == (Object)null || IsOutOfRange.Invoke(rope) || !IsHidden3DRope(rope))
{
entry.HiddenFrames = 0;
return true;
}
entry.HiddenFrames++;
return entry.HiddenFrames % 20 == 0;
}
private static bool IsHidden3DRope(RopeEffect rope)
{
ClothRope val = ClothOf.Invoke(rope);
if ((Object)(object)val != (Object)null && (Object)(object)val.skinned != (Object)null && ((Component)val).gameObject.activeSelf)
{
return !((Renderer)val.skinned).isVisible;
}
return false;
}
}
internal static class ItemPlacement
{
public static bool TryPlace(Transform twin, ShipItem item)
{
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Unknown result type (might be due to invalid IL or missing references)
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_0058: Unknown result type (might be due to invalid IL or missing references)
//IL_0063: 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_0081: Unknown result type (might be due to invalid IL or missing references)
//IL_006d: Unknown result type (might be due to invalid IL or missing references)
if (!RedundantWriteGuard.IsSkipping)
{
return false;
}
Transform currentActualBoat = item.currentActualBoat;
if (currentActualBoat == null || !BoatMotion.IsStill(currentActualBoat))
{
return false;
}
Transform currentWalkCol = item.currentWalkCol;
Vector3 position = currentActualBoat.TransformPoint(currentWalkCol.InverseTransformPoint(twin.position));
Quaternion rotation = currentActualBoat.rotation * (Quaternion.Inverse(currentWalkCol.rotation) * twin.rotation);
Transform transform = ((Component)item).transform;
if (RedundantWriteGuard.IsSamePosition(transform, position) && RedundantWriteGuard.IsSameRotation(transform, rotation))
{
return true;
}
transform.position = position;
transform.rotation = rotation;
return true;
}
}
internal static class RedundantWriteGuard
{
private const float PositionTolerance = 0.001f;
private const float RotationToleranceDegrees = 0.1f;
private static readonly float MinRotationDot = Mathf.Cos(0.0008726646f);
public static bool IsSkipping => ModConfig.SkipRedundantItemUpdates.Value;
public static void SetPosition(Transform transform, Vector3 position)
{
//IL_0012: 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)
if (!IsSkipping || !IsSamePosition(transform, position))
{
transform.position = position;
}
}
public static void SetRotation(Transform transform, Quaternion rotation)
{
//IL_0012: 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)
if (!IsSkipping || !IsSameRotation(transform, rotation))
{
transform.rotation = rotation;
}
}
public static void SetLocalScale(Transform transform, Vector3 scale)
{
//IL_0017: 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)
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
if (!IsSkipping || !(transform.localScale == scale))
{
transform.localScale = scale;
}
}
public static void SetIsTrigger(Collider collider, bool isTrigger)
{
if (!IsSkipping || collider.isTrigger != isTrigger)
{
collider.isTrigger = isTrigger;
}
}
public static void SetEnabled(Collider collider, bool enabled)
{
if (!IsSkipping || collider.enabled != enabled)
{
collider.enabled = enabled;
}
}
public static bool IsSamePosition(Transform transform, Vector3 position)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
Vector3 val = transform.position - position;
return ((Vector3)(ref val)).sqrMagnitude < 1.0000001E-06f;
}
public static bool IsSameRotation(Transform transform, Quaternion rotation)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
return Mathf.Abs(Quaternion.Dot(transform.rotation, rotation)) >= MinRotationDot;
}
}
internal static class RopeLod
{
private sealed class RopeState
{
public readonly ClothRope Cloth;
public readonly PickupableBoatMooringRope MooringLine;
public RopeShapeKey Key;
public Quaternion RopeEndRotation;
public Quaternion AttachmentRotation;
public bool NeedsRebuild = true;
public bool IsFlat;
public RopeState(ClothRope cloth, PickupableBoatMooringRope mooringLine)
{
Cloth = cloth;
MooringLine = mooringLine;
}
public void Remember(RopeEffect rope, RopeShapeKey key)
{
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
Key = key;
RopeEndRotation = ((Component)rope).transform.localRotation;
AttachmentRotation = rope.attachment.localRotation;
NeedsRebuild = false;
}
}
private const float MinRangeCheckInterval = 5f;
private const float MaxRangeCheckInterval = 8f;
private const float FlatRopeDeadZone = 1f;
private static readonly Action<RopeEffect> UpdateAttachments = RopeMethod("UpdateAttachments");
private static readonly Action<RopeEffect> ApplyLimits = RopeMethod("ApplyLimits");
private static readonly Action<RopeEffect> UpdateTension = RopeMethod("UpdateTension");
private static readonly Action<RopeEffect> DisplayRope = RopeMethod("DisplayRope");
private static readonly Action<RopeEffect> CheckDistance = RopeMethod("CheckDistance");
private static readonly Dictionary<RopeEffect, RopeState> states = new Dictionary<RopeEffect, RopeState>();
private static int cameraFrame = -1;
private static Vector3 cameraPosition;
private static bool IsAnySettingOn
{
get
{
if (!ModConfig.SkipUnchangedRopes.Value)
{
return ModConfig.SimplifyDistantRopes.Value != DistantRopeSimplification.Off;
}
return true;
}
}
public static bool TryUpdate(RopeEffect rope, LineRenderer line, ClothRope cloth, ref float rangeCheckTimer, ref bool isOutOfRange)
{
if (!IsAnySettingOn || !Settings.clothRopes || (Object)(object)cloth == (Object)null || (Object)(object)rope.attachment == (Object)null || GameState.shipyardUpdatingOrder || (Object)(object)Refs.observerMirror == (Object)null)
{
return false;
}
RunRangeCheck(rope, ref rangeCheckTimer);
RopeState state = StateOf(rope, cloth);
if (isOutOfRange)
{
Hide(line, cloth, state);
}
else if (WantsFlatRope(rope, state))
{
DrawFlat(rope, line, cloth, state);
}
else
{
Draw3D(rope, line, cloth, state);
}
return true;
}
public static void RebuildAll()
{
foreach (RopeState value in states.Values)
{
value.NeedsRebuild = true;
}
}
public static void Forget(RopeEffect rope)
{
states.Remove(rope);
}
private static Action<RopeEffect> RopeMethod(string name)
{
return AccessTools.MethodDelegate<Action<RopeEffect>>(AccessTools.Method(typeof(RopeEffect), name, (Type[])null, (Type[])null), (object)null, true);
}
private static void RunRangeCheck(RopeEffect rope, ref float rangeCheckTimer)
{
if (rangeCheckTimer <= 0f)
{
CheckDistance(rope);
rangeCheckTimer = Random.Range(5f, 8f);
}
rangeCheckTimer -= Time.deltaTime;
}
private static RopeState StateOf(RopeEffect rope, ClothRope cloth)
{
if (!states.TryGetValue(rope, out var value) || (Object)(object)value.Cloth != (Object)(object)cloth)
{
value = new RopeState(cloth, ((Component)rope).GetComponent<PickupableBoatMooringRope>());
states[rope] = value;
}
return value;
}
private static void Hide(LineRenderer line, ClothRope cloth, RopeState state)
{
if (((Renderer)line).enabled)
{
((Renderer)line).enabled = false;
}
if (((Component)cloth).gameObject.activeSelf)
{
((Component)cloth).gameObject.SetActive(false);
}
state.NeedsRebuild = true;
}
private static bool WantsFlatRope(RopeEffect rope, RopeState state)
{
float num = FlatRopeDistance(ModConfig.SimplifyDistantRopes.Value);
if (state.IsFlat)
{
num -= 1f;
}
state.IsFlat = DistanceFromViewer(rope) > num;
return state.IsFlat;
}
private static float FlatRopeDistance(DistantRopeSimplification simplification)
{
return simplification switch
{
DistantRopeSimplification.Quality => 50f,
DistantRopeSimplification.Default => 30f,
DistantRopeSimplification.Performance => 15f,
_ => float.PositiveInfinity,
};
}
private static float DistanceFromViewer(RopeEffect rope)
{
//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_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_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: 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_003d: Unknown result type (might be due to invalid IL or missing references)
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
Vector3 position = ((Component)rope).transform.position;
Vector3 val = rope.attachment.position - position;
Vector3 val2 = ViewerPosition();
float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
float num = ((sqrMagnitude > 0f) ? Mathf.Clamp01(Vector3.Dot(val2 - position, val) / sqrMagnitude) : 0f);
return Vector3.Distance(val2, position + val * num);
}
private static Vector3 ViewerPosition()
{
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_0063: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
if (ModConfig.RopeDistanceMeasuredFrom.Value == RopeDistanceOrigin.Player)
{
return ((Component)Refs.observerMirror).transform.position;
}
if (cameraFrame != Time.frameCount)
{
Camera main = Camera.main;
cameraPosition = (((Object)(object)main != (Object)null) ? ((Component)main).transform.position : ((Component)Refs.observerMirror).transform.position);
cameraFrame = Time.frameCount;
}
return cameraPosition;
}
private static void DrawFlat(RopeEffect rope, LineRenderer line, ClothRope cloth, RopeState state)
{
if (!((Renderer)line).enabled)
{
((Renderer)line).enabled = true;
}
if (((Component)cloth).gameObject.activeSelf)
{
((Component)cloth).gameObject.SetActive(false);
}
RunGameRopeSteps(rope);
state.NeedsRebuild = true;
}
private static void Draw3D(RopeEffect rope, LineRenderer line, ClothRope cloth, RopeState state)
{
//IL_0096: Unknown result type (might be due to invalid IL or missing references)
if (((Renderer)line).enabled)
{
((Renderer)line).enabled = false;
}
if (!((Component)cloth).gameObject.activeSelf)
{
((Component)cloth).gameObject.SetActive(true);
state.NeedsRebuild = true;
}
bool value = ModConfig.SkipUnchangedRopes.Value;
bool flag = value && IsStowed(state.MooringLine);
RopeShapeKey key = (value ? RopeShapeKey.Capture(rope, flag) : default(RopeShapeKey));
if (value && !state.NeedsRebuild && key.Matches(state.Key))
{
KeepEndRotations(rope, state);
return;
}
if (flag)
{
UprightRope.Build(rope, ((Component)state.MooringLine.GetBoatRigidbody()).transform.up);
}
else
{
RunGameRopeSteps(rope);
}
cloth.UpdateRope();
state.Remember(rope, key);
}
private static bool IsStowed(PickupableBoatMooringRope line)
{
if ((Object)(object)line != (Object)null && !Object.op_Implicit((Object)(object)((PickupableItem)line).held) && !line.IsMoored())
{
return line.IsAtInitialPos();
}
return false;
}
private static void RunGameRopeSteps(RopeEffect rope)
{
UpdateAttachments(rope);
ApplyLimits(rope);
UpdateTension(rope);
DisplayRope(rope);
}
private static void KeepEndRotations(RopeEffect rope, RopeState state)
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
if (((Component)rope).transform.localRotation != state.RopeEndRotation)
{
((Component)rope).transform.localRotation = state.RopeEndRotation;
}
if (rope.attachment.localRotation != state.AttachmentRotation)
{
rope.attachment.localRotation = state.AttachmentRotation;
}
}
}
internal struct RopeShapeKey
{
private const float PositionTolerance = 0.001f;
private const float SagSwingTolerance = 0.005f;
private const float LengthTolerance = 0.0001f;
private const float MaxTiltTolerance = 0.08726646f;
private const float GameCurveRateFactor = 0.75f;
private const float BezierMidpointShare = 0.75f;
private const float MaxHalfSagAngleDegrees = 90f;
private Vector3 ropeEnd;
private Vector3 attachmentEnd;
private Vector3 worldUp;
private float sag;
private bool isStowedLine;
private bool ropeEndIsHigher;
private float currentLength;
private float totalLength;
private float width;
private float sailArea;
public static RopeShapeKey Capture(RopeEffect rope, bool isStowedLine)
{
//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_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: 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_0037: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_0055: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
//IL_0073: 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_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: Unknown result type (might be due to invalid IL or missing references)
//IL_0085: Unknown result type (might be due to invalid IL or missing references)
//IL_0086: Unknown result type (might be due to invalid IL or missing references)
//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
Transform parent = ((Component)rope).transform.parent;
Vector3 position = ((Component)rope).transform.position;
Vector3 position2 = rope.attachment.position;
return new RopeShapeKey
{
ropeEnd = (((Object)(object)parent != (Object)null) ? parent.InverseTransformPoint(position) : position),
attachmentEnd = (((Object)(object)parent != (Object)null) ? parent.InverseTransformPoint(position2) : position2),
worldUp = (((Object)(object)parent != (Object)null) ? parent.InverseTransformDirection(Vector3.up) : Vector3.up),
sag = EstimateSag(rope, Vector3.Distance(position, position2)),
isStowedLine = isStowedLine,
ropeEndIsHigher = (position.y >= position2.y),
currentLength = rope.currentRopeLength,
totalLength = rope.totalRopeLength,
width = rope.ropeWidth,
sailArea = rope.attachedSailArea
};
}
public bool Matches(RopeShapeKey other)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
if (IsNear(ropeEnd, other.ropeEnd) && IsNear(attachmentEnd, other.attachmentEnd) && isStowedLine == other.isStowedLine && (isStowedLine || (ropeEndIsHigher == other.ropeEndIsHigher && IsTiltNear(other))) && Mathf.Abs(currentLength - other.currentLength) < 0.0001f && Mathf.Abs(totalLength - other.totalLength) < 0.0001f && Mathf.Abs(width - other.width) < 0.0001f)
{
return Mathf.Abs(sailArea - other.sailArea) < 0.0001f;
}
return false;
}
private bool IsTiltNear(RopeShapeKey other)
{
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
float num = Mathf.Cos(TiltTolerance(Mathf.Max(sag, other.sag)));
return Vector3.Dot(((Vector3)(ref worldUp)).normalized, ((Vector3)(ref other.worldUp)).normalized) > num;
}
private static float EstimateSag(RopeEffect rope, float span)
{
float num = 1f - rope.totalRopeLength;
float num2 = num * Mathf.Clamp01(rope.currentRopeLength) * 0.75f;
float num3 = Mathf.Clamp(num * 90f, -90f, 90f);
return Mathf.Abs(0.75f * span * num2 * Mathf.Sin(num3 * ((float)Math.PI / 180f)));
}
private static float TiltTolerance(float sag)
{
if (!(sag * 0.08726646f > 0.005f))
{
return 0.08726646f;
}
return 0.005f / sag;
}
private static bool IsNear(Vector3 point, Vector3 other)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
Vector3 val = point - other;
return ((Vector3)(ref val)).sqrMagnitude < 1.0000001E-06f;
}
}
internal static class ShopItemFreezer
{
private sealed class FreezableItem
{
public readonly ShipItem Item;
public int IdleFrames;
public float LastHeldTime = float.NegativeInfinity;
private readonly List<Behaviour> switchedOff = new List<Behaviour>();
private bool? mayFreeze;
public bool IsFrozen { get; private set; }
public bool MayFreeze
{
get
{
if (!mayFreeze.HasValue)
{
mayFreeze = !HasKeepUpdatingMarker(Item);
}
return mayFreeze.Value;
}
}
public FreezableItem(ShipItem item)
{
Item = item;
}
public void Freeze()
{
SwitchOff((Behaviour)(object)Item);
SwitchOff((Behaviour)(object)Item.itemRigidbodyC);
SwitchOff((Behaviour)(object)((PickupableItem)Item).colChecker);
SwitchOff((Behaviour)(object)((Component)Item).GetComponent<FoodState>());
SwitchOff((Behaviour)(object)((Component)Item).GetComponent<CookableFood>());
IsFrozen = true;
}
public void Thaw()
{
foreach (Behaviour item in switchedOff)
{
if ((Object)(object)item != (Object)null)
{
item.enabled = true;
}
}
switchedOff.Clear();
IdleFrames = 0;
IsFrozen = false;
}
private void SwitchOff(Behaviour behaviour)
{
if (!((Object)(object)behaviour == (Object)null) && behaviour.enabled)
{
behaviour.enabled = false;
switchedOff.Add(behaviour);
}
}
}
private const string KeepUpdatingMarker = "KeepUpdatingInShop";
private const int IdleFramesBeforeFreezing = 10;
private const float IdleSecondsAfterHolding = 1f;
private static readonly FieldRef<GoPointerButton, bool> IsClicked = AccessTools.FieldRefAccess<GoPointerButton, bool>("isClicked");
private static readonly FieldRef<GoPointerButton, GoPointer> StickyClickedBy = AccessTools.FieldRefAccess<GoPointerButton, GoPointer>("stickyClickedBy");
private static readonly FieldRef<GoPointerButton, float> FlashOutlineTimer = AccessTools.FieldRefAccess<GoPointerButton, float>("flashOutlineTimer");
private static readonly FieldRef<GoPointerButton, Outline> OutlineOf = AccessTools.FieldRefAccess<GoPointerButton, Outline>("outline");
private static readonly FieldRef<ShipItemLight, bool> IsLightOn = AccessTools.FieldRefAccess<ShipItemLight, bool>("on");
private static readonly List<FreezableItem> items = new List<FreezableItem>();
private static readonly Dictionary<ShipItem, FreezableItem> itemsByShipItem = new Dictionary<ShipItem, FreezableItem>();
private static bool hasFrozenItems;
public static void Register(ShipItem item)
{
if (!((Object)(object)item == (Object)null) && !itemsByShipItem.ContainsKey(item))
{
FreezableItem freezableItem = new FreezableItem(item);
items.Add(freezableItem);
itemsByShipItem[item] = freezableItem;
}
}
public static void Update()
{
bool value = ModConfig.FreezeIdleShopItems.Value;
if (!value && !hasFrozenItems)
{
return;
}
hasFrozenItems = false;
for (int num = items.Count - 1; num >= 0; num--)
{
FreezableItem freezableItem = items[num];
if ((Object)(object)freezableItem.Item == (Object)null)
{
items.RemoveAt(num);
itemsByShipItem.Remove(freezableItem.Item);
}
else
{
UpdateEntry(freezableItem, value);
hasFrozenItems |= freezableItem.IsFrozen;
}
}
}
public static void Thaw(GoPointerButton button)
{
ShipItem val = (ShipItem)(object)((button is ShipItem) ? button : null);
if (val != null && itemsByShipItem.TryGetValue(val, out var value) && value.IsFrozen)
{
value.Thaw();
}
}
private static void UpdateEntry(FreezableItem entry, bool isFreezing)
{
if (Object.op_Implicit((Object)(object)((PickupableItem)entry.Item).held))
{
entry.LastHeldTime = Time.time;
}
if (!isFreezing || !IsIdle(entry))
{
if (entry.IsFrozen)
{
entry.Thaw();
}
entry.IdleFrames = 0;
}
else if (!entry.IsFrozen && ++entry.IdleFrames >= 10)
{
entry.Freeze();
}
}
private static bool IsIdle(FreezableItem entry)
{
ShipItem item = entry.Item;
if (item.sold || Object.op_Implicit((Object)(object)((PickupableItem)item).held) || Time.time - entry.LastHeldTime < 1f)
{
return false;
}
if (((GoPointerButton)item).IsLookedAt() || IsClicked.Invoke((GoPointerButton)(object)item) || (Object)(object)StickyClickedBy.Invoke((GoPointerButton)(object)item) != (Object)null)
{
return false;
}
if (FlashOutlineTimer.Invoke((GoPointerButton)(object)item) > 0f || ((GoPointerButton)item).enableRedOutline)
{
return false;
}
Outline val = OutlineOf.Invoke((GoPointerButton)(object)item);
if (((Object)(object)val == (Object)null || !((Behaviour)val).enabled) && entry.MayFreeze)
{
return !AnimatesWhileIdle(item);
}
return false;
}
private static bool AnimatesWhileIdle(ShipItem item)
{
if (!(item is ShipItemClock) && !(item is ShipItemTotem))
{
ShipItemLight val = (ShipItemLight)(object)((item is ShipItemLight) ? item : null);
if (val != null)
{
return IsLightOn.Invoke(val);
}
return false;
}
return true;
}
private static bool HasKeepUpdatingMarker(ShipItem item)
{
MonoBehaviour[] componentsInChildren = ((Component)item).GetComponentsInChildren<MonoBehaviour>(true);
foreach (MonoBehaviour val in componentsInChildren)
{
if ((Object)(object)val != (Object)null && ((object)val).GetType().Name == "KeepUpdatingInShop")
{
return true;
}
}
return false;
}
}
internal static class UnmovedCrateContents
{
private struct CratePose
{
private Transform parent;
private Vector3 localPosition;
private Quaternion localRotation;
private int contentsHash;
public static bool TryCapture(CrateInventory crate, out CratePose pose)
{
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
Transform transform = ((Component)crate).transform;
pose = new CratePose
{
parent = transform.parent,
localPosition = transform.localPosition,
localRotation = transform.localRotation,
contentsHash = crate.containedItems.Count
};
foreach (ShipItem containedItem in crate.containedItems)
{
if ((Object)(object)containedItem == (Object)null || (Object)(object)((Component)containedItem).transform.parent != (Object)(object)pose.parent)
{
return false;
}
pose.contentsHash = pose.contentsHash * 31 + ((Object)containedItem).GetInstanceID();
}
return true;
}
public bool Matches(CratePose other)
{
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)parent == (Object)(object)other.parent && contentsHash == other.contentsHash)
{
Vector3 val = localPosition - other.localPosition;
if (((Vector3)(ref val)).sqrMagnitude < 9.999999E-09f)
{
return Mathf.Abs(Quaternion.Dot(localRotation, other.localRotation)) >= 0.9999999f;
}
}
return false;
}
}
private const float PositionTolerance = 0.0001f;
private const float MinRotationDot = 0.9999999f;
private const int PruneEveryChecks = 4096;
private static readonly Dictionary<CrateInventory, CratePose> lastPoseByCrate = new Dictionary<CrateInventory, CratePose>();
private static readonly List<CrateInventory> destroyedCrates = new List<CrateInventory>();
private static int checksSincePrune;
public static bool CanSkip(CrateInventory crate)
{
if (!ModConfig.SkipUnmovedCrateContents.Value)
{
return false;
}
PruneDestroyedCratesNowAndThen();
if (IsOpenInUi(crate) || !CratePose.TryCapture(crate, out var pose))
{
lastPoseByCrate.Remove(crate);
return false;
}
CratePose value;
bool result = lastPoseByCrate.TryGetValue(crate, out value) && value.Matches(pose);
lastPoseByCrate[crate] = pose;
return result;
}
private static void PruneDestroyedCratesNowAndThen()
{
if (++checksSincePrune < 4096)
{
return;
}
checksSincePrune = 0;
foreach (CrateInventory key in lastPoseByCrate.Keys)
{
if ((Object)(object)key == (Object)null)
{
destroyedCrates.Add(key);
}
}
foreach (CrateInventory destroyedCrate in destroyedCrates)
{
lastPoseByCrate.Remove(destroyedCrate);
}
destroyedCrates.Clear();
}
private static bool IsOpenInUi(CrateInventory crate)
{
CrateInventoryUI instance = CrateInventoryUI.instance;
if ((Object)(object)instance != (Object)null && instance.showingUI)
{
return (Object)(object)instance.currentCrate == (Object)(object)crate;
}
return false;
}
}
internal static class UprightRope
{
private const float CurveRateFactor = 0.75f;
private const float MaxSagDegrees = 180f;
private const float UprightDegrees = 90f;
private static readonly FieldRef<RopeEffect, Transform> AttachmentOne = AccessTools.FieldRefAccess<RopeEffect, Transform>("attachmentOne");
private static readonly FieldRef<RopeEffect, Transform> AttachmentTwo = AccessTools.FieldRefAccess<RopeEffect, Transform>("attachmentTwo");
private static readonly Action<RopeEffect> ApplyLimits = RopeMethod("ApplyLimits");
private static readonly Action<RopeEffect> DisplayRope = RopeMethod("DisplayRope");
public static void Build(RopeEffect rope, Vector3 up)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
AssignEnds(rope, up);
ApplyLimits(rope);
ApplyTension(rope, up);
DisplayRope(rope);
}
private static Action<RopeEffect> RopeMethod(string name)
{
return AccessTools.MethodDelegate<Action<RopeEffect>>(AccessTools.Method(typeof(RopeEffect), name, (Type[])null, (Type[])null), (object)null, true);
}
private static void AssignEnds(RopeEffect rope, Vector3 up)
{
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
Transform transform = ((Component)rope).transform;
Transform attachment = rope.attachment;
bool flag = !rope.sheet && !rope.jibSheet && Vector3.Dot(transform.position - attachment.position, up) >= 0f;
AttachmentOne.Invoke(rope) = (flag ? transform : attachment);
AttachmentTwo.Invoke(rope) = (flag ? attachment : transform);
}
private static void ApplyTension(RopeEffect rope, Vector3 up)
{
//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_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_0080: Unknown result type (might be due to invalid IL or missing references)
//IL_0087: Unknown result type (might be due to invalid IL or missing references)
//IL_0093: Unknown result type (might be due to invalid IL or missing references)
//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
Transform val = AttachmentOne.Invoke(rope);
Transform val2 = AttachmentTwo.Invoke(rope);
val.LookAt(val2, up);
val2.LookAt(val, up);
float num = 1f - rope.totalRopeLength;
rope.curveRate = num * rope.currentRopeLength * 0.75f;
float num2 = (90f - Vector3.Angle(val2.forward, up)) / 90f;
float num3 = num * 180f;
val.Rotate(Vector3.right * (0.5f - 0.5f * num2) * num3, (Space)1);
val2.Rotate(Vector3.right * (0.5f + 0.5f * num2) * num3, (Space)1);
}
}
}
namespace PerformanceTweaks.Patches
{
[HarmonyPatch(typeof(CrateInventory), "LateUpdate")]
internal static class CrateContentsPatch
{
private static bool Prefix(CrateInventory __instance)
{
return !UnmovedCrateContents.CanSkip(__instance);
}
}
[HarmonyPatch(typeof(FoodState), "Update")]
internal static class FoodDescriptionPatch
{
private const int RefreshIntervalFrames = 15;
private static readonly MethodInfo UpdateLookTextMethod = AccessTools.Method(typeof(FoodState), "UpdateLookText", (Type[])null, (Type[])null);
private static readonly Action<FoodState> UpdateLookText = AccessTools.MethodDelegate<Action<FoodState>>(UpdateLookTextMethod, (object)null, true);
private static readonly FieldRef<FoodState, ShipItemFood> FoodOf = AccessTools.FieldRefAccess<FoodState, ShipItemFood>("food");
public static void RefreshIfNeeded(FoodState state)
{
if (!ModConfig.FoodDescriptionsOnDemand.Value || IsShown(FoodOf.Invoke(state)) || IsOnTurn(state))
{
UpdateLookText(state);
}
}
private static bool IsShown(ShipItemFood food)
{
if (!((Object)(object)food == (Object)null) && !((GoPointerButton)food).IsLookedAt())
{
return Object.op_Implicit((Object)(object)((PickupableItem)food).held);
}
return true;
}
private static bool IsOnTurn(FoodState state)
{
int num = ((Object)state).GetInstanceID() & 0x7FFFFFFF;
return (Time.frameCount + num) % 15 == 0;
}
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
List<CodeInstruction> list = new List<CodeInstruction>(instructions);
MethodInfo operand = AccessTools.Method(typeof(FoodDescriptionPatch), "RefreshIfNeeded", (Type[])null, (Type[])null);
int num = 0;
foreach (CodeInstruction item in list)
{
if (CodeInstructionExtensions.Calls(item, UpdateLookTextMethod))
{
item.operand = operand;
num++;
}
}
if (num == 0)
{
Plugin.Log.LogWarning((object)"Found no description refresh to route in FoodState.Update.");
}
return list;
}
}
[HarmonyPatch(typeof(ItemRigidbody), "MoveItemToWalkColRigidbody")]
internal static class ItemPlacementPatch
{
private static bool Prefix(ItemRigidbody __instance, ShipItem ___item)
{
return !ItemPlacement.TryPlace(((Component)__instance).transform, ___item);
}
}
[HarmonyPatch(typeof(MasterPainter), "Awake")]
internal static class MasterPainterAwakePatch
{
private static void Postfix(MasterPainter __instance)
{
DirtCameraSwitch.Apply(__instance);
}
}
[HarmonyPatch(typeof(MasterPainter), "DoApplyRenderTex")]
internal static class MasterPainterFullCleanPatch
{
private static void Prefix(MasterPainter __instance)
{
DirtCameraSwitch.RenderForClean(__instance);
}
}
[HarmonyPatch(typeof(OutlineEffect), "OnPreRender")]
internal static class OutlineEffectPatch
{
private static readonly FieldRef<LinkedSet<Outline>, LinkedList<Outline>> OutlineList = AccessTools.FieldRefAccess<LinkedSet<Outline>, LinkedList<Outline>>("list");
private static readonly HashSet<OutlineEffect> clearedWhileIdle = new HashSet<OutlineEffect>();
public static void Forget()
{
clearedWhileIdle.Clear();
}
private static bool Prefix(OutlineEffect __instance, LinkedSet<Outline> ___outlines)
{
if (!ModConfig.OutlineCamerasOnDemand.Value || ___outlines == null || OutlineList.Invoke(___outlines).Count > 0)
{
clearedWhileIdle.Remove(__instance);
return true;
}
return clearedWhileIdle.Add(__instance);
}
}
[HarmonyPatch]
internal static class RedundantItemWritesPatch
{
private static readonly Dictionary<MethodInfo, MethodInfo> GuardBySetter = new Dictionary<MethodInfo, MethodInfo>
{
{
Setter(typeof(Transform), "position"),
Guard("SetPosition")
},
{
Setter(typeof(Transform), "rotation"),
Guard("SetRotation")
},
{
Setter(typeof(Transform), "localScale"),
Guard("SetLocalScale")
},
{
Setter(typeof(Collider), "isTrigger"),
Guard("SetIsTrigger")
},
{
Setter(typeof(Collider), "enabled"),
Guard("SetEnabled")
}
};
private static IEnumerable<MethodBase> TargetMethods()
{
yield return AccessTools.Method(typeof(ItemRigidbody), "FixedUpdate", (Type[])null, (Type[])null);
yield return AccessTools.Method(typeof(ItemRigidbody), "LateUpdate", (Type[])null, (Type[])null);
yield return AccessTools.Method(typeof(ItemRigidbody), "ToggleCollider", (Type[])null, (Type[])null);
yield return AccessTools.Method(typeof(ItemRigidbody), "SetSubcollidersTriggers", (Type[])null, (Type[])null);
yield return AccessTools.Method(typeof(ItemRigidbody), "MoveRigidbodyToWalkCol", (Type[])null, (Type[])null);
yield return AccessTools.Method(typeof(CrateInventory), "LateUpdate", (Type[])null, (Type[])null);
}
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase original)
{
List<CodeInstruction> list = new List<CodeInstruction>(instructions);
int num = 0;
foreach (CodeInstruction item in list)
{
if (item.operand is MethodInfo key && GuardBySetter.TryGetValue(key, out var value))
{
item.opcode = OpCodes.Call;
item.operand = value;
num++;
}
}
if (num == 0)
{
Plugin.Log.LogWarning((object)$"Found no writes to guard in {original.DeclaringType}.{original.Name}.");
}
return list;
}
private static MethodInfo Setter(Type type, string property)
{
return AccessTools.PropertySetter(type, property);
}
private static MethodInfo Guard(string method)
{
return AccessTools.Method(typeof(RedundantWriteGuard), method, (Type[])null, (Type[])null);
}
}
[HarmonyPatch(typeof(RopeEffect), "LateUpdate")]
internal static class RopeEffectUpdatePatch
{
private static bool Prefix(RopeEffect __instance, LineRenderer ___lineRenderer, ClothRope ___clothRope, ref float ___distanceCheckTimer, ref bool ___outOfRange)
{
return !RopeLod.TryUpdate(__instance, ___lineRenderer, ___clothRope, ref ___distanceCheckTimer, ref ___outOfRange);
}
}
[HarmonyPatch(typeof(RopeEffect), "Start")]
internal static class RopeEffectStartPatch
{
private static void Postfix(RopeEffect __instance)
{
HiddenRopePauser.Register(__instance);
}
}
[HarmonyPatch(typeof(RopeEffect), "OnDestroy")]
internal static class RopeEffectDestroyPatch
{
private static void Postfix(RopeEffect __instance)
{
RopeLod.Forget(__instance);
}
}
[HarmonyPatch]
internal static class SailShadowRaycastPatch
{
private static MethodBase TargetMethod()
{
return AccessTools.EnumeratorMoveNext((MethodBase)AccessTools.Method(typeof(SailShadowCol), "CheckShadow", (Type[])null, (Type[])null));
}
private static void Prefix(out bool __state)
{
__state = ModConfig.SkipSyncForSailWindShadows.Value && Physics.autoSyncTransforms;
if (__state)
{
Physics.autoSyncTransforms = false;
}
}
private static void Finalizer(bool __state)
{
if (__state)
{
Physics.autoSyncTransforms = true;
}
}
}
[HarmonyPatch(typeof(ShopItemSpawner), "SpawnItem")]
internal static class ShopItemSpawnPatch
{
private static void Postfix(ShipItem ___item)
{
ShopItemFreezer.Register(___item);
}
}
[HarmonyPatch(typeof(GoPointerButton), "Look")]
internal static class ShopItemLookPatch
{
private static void Postfix(GoPointerButton __instance)
{
ShopItemFreezer.Thaw(__instance);
}
}
}
namespace PerformanceTweaks.Configuration
{
public enum DistantRopeSimplification
{
Off,
Quality,
Default,
Performance
}
internal static class ModConfig
{
private const string ItemsSection = "Items";
private const string BoatsSection = "Boats";
private const string RenderingSection = "Rendering";
public static ConfigEntry<bool> SkipRedundantItemUpdates { get; private set; }
public static ConfigEntry<bool> SkipUnmovedCrateContents { get; private set; }
public static ConfigEntry<bool> FreezeIdleShopItems { get; private set; }
public static ConfigEntry<bool> FoodDescriptionsOnDemand { get; private set; }
public static ConfigEntry<bool> SkipUnchangedRopes { get; private set; }
public static ConfigEntry<DistantRopeSimplification> SimplifyDistantRopes { get; private set; }
public static ConfigEntry<RopeDistanceOrigin> RopeDistanceMeasuredFrom { get; private set; }
public static ConfigEntry<bool> PauseHiddenRopes { get; private set; }
public static ConfigEntry<bool> SkipSyncForSailWindShadows { get; private set; }
public static ConfigEntry<bool> DirtCameraOnDemand { get; private set; }
public static ConfigEntry<bool> OutlineCamerasOnDemand { get; private set; }
public static void Bind(ConfigFile config)
{
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Expected O, but got Unknown
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: Expected O, but got Unknown
//IL_0063: Unknown result type (might be due to invalid IL or missing references)
//IL_006d: Expected O, but got Unknown
//IL_0089: Unknown result type (might be due to invalid IL or missing references)
//IL_0093: Expected O, but got Unknown
//IL_00af: Unknown result type (might be due to invalid IL or missing references)
//IL_00b9: Expected O, but got Unknown
//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
//IL_00df: Expected O, but got Unknown
//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
//IL_0105: Expected O, but got Unknown
//IL_0121: Unknown result type (might be due to invalid IL or missing references)
//IL_012b: Expected O, but got Unknown
//IL_0147: Unknown result type (might be due to invalid IL or missing references)
//IL_0151: Expected O, but got Unknown
//IL_016d: Unknown result type (might be due to invalid IL or missing references)
//IL_0177: Expected O, but got Unknown
//IL_0193: Unknown result type (might be due to invalid IL or missing references)
//IL_019d: Expected O, but got Unknown
SkipRedundantItemUpdates = config.Bind<bool>("Items", "Skip redundant item updates", true, new ConfigDescription("Skips item and crate updates that would change nothing.", (AcceptableValueBase)null, Array.Empty<object>()));
SkipUnmovedCrateContents = config.Bind<bool>("Items", "Skip unmoved crate contents", true, new ConfigDescription("Puts the items inside a crate back into place only after the crate has moved or its contents changed.", (AcceptableValueBase)null, Array.Empty<object>()));
FreezeIdleShopItems = config.Bind<bool>("Items", "Freeze idle shop items", true, new ConfigDescription("Pauses the updates of shop goods while nobody holds or looks at them.", (AcceptableValueBase)null, Array.Empty<object>()));
FoodDescriptionsOnDemand = config.Bind<bool>("Items", "Food descriptions on demand", true, new ConfigDescription("Updates a food's description only while you look at it or hold it.", (AcceptableValueBase)null, Array.Empty<object>()));
SkipUnchangedRopes = config.Bind<bool>("Boats", "Skip unchanged ropes", true, new ConfigDescription("Rebuilds a 3D rope only when it has moved on its boat.", (AcceptableValueBase)null, Array.Empty<object>()));
SimplifyDistantRopes = config.Bind<DistantRopeSimplification>("Boats", "Simplify distant ropes", DistantRopeSimplification.Default, new ConfigDescription("Draws distant ropes as the game's flat ropes instead of 3D ropes.", (AcceptableValueBase)null, Array.Empty<object>()));
RopeDistanceMeasuredFrom = config.Bind<RopeDistanceOrigin>("Boats", "Rope distance measured from", RopeDistanceOrigin.Camera, new ConfigDescription("Where the distance for Simplify distant ropes is measured from: the camera or your character.", (AcceptableValueBase)null, Array.Empty<object>()));
PauseHiddenRopes = config.Bind<bool>("Boats", "Pause hidden ropes", true, new ConfigDescription("Updates ropes you can't see only a few times a second.", (AcceptableValueBase)null, Array.Empty<object>()));
SkipSyncForSailWindShadows = config.Bind<bool>("Boats", "Skip sync for sail wind shadows", true, new ConfigDescription("Checks the wind shadow between sails against positions from the last physics step.", (AcceptableValueBase)null, Array.Empty<object>()));
DirtCameraOnDemand = config.Bind<bool>("Rendering", "Dirt camera on demand", true, new ConfigDescription("Turns the hidden dirt camera on only when it is really needed.", (AcceptableValueBase)null, Array.Empty<object>()));
OutlineCamerasOnDemand = config.Bind<bool>("Rendering", "Outline cameras on demand", true, new ConfigDescription("Renders the highlight outline cameras only while something is highlighted.", (AcceptableValueBase)null, Array.Empty<object>()));
}
}
public enum RopeDistanceOrigin
{
Camera,
Player
}
}