Decompiled source of GuakRogueWaves v2.0.1

Eden.RogueWaves.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;

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

[BepInPlugin("eden.valheim.roguewaves", "Guak Rogue Waves", "2.0.1")]
public class RogueWavesPlugin : BaseUnityPlugin
{
	private sealed class RogueWave
	{
		public readonly long Id;

		public readonly double StartTime;

		public readonly Vector3 Origin;

		public readonly Vector3 Direction;

		public readonly float Height;

		public readonly float Duration;

		public readonly float Length;

		public readonly float Width;

		public readonly float Speed;

		public readonly bool IsGiga;

		public readonly float CullRadius;

		public float DepthScale;

		public bool IsLocal;

		public float NextRebroadcastAt;

		private readonly Vector3 right;

		private readonly float sigma;

		private readonly float profileNorm;

		private readonly float cullRadiusSqr;

		public RogueWave(long id, double startTime, Vector3 origin, Vector3 direction, float height, float duration, float length, float width, float speed, bool isGiga)
		{
			//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)
			//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_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)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			Id = id;
			StartTime = startTime;
			Origin = origin;
			Direction = ((Vector3)(ref direction)).normalized;
			Vector3 val = Vector3.Cross(Vector3.up, Direction);
			right = ((Vector3)(ref val)).normalized;
			Height = height;
			Duration = duration;
			Length = Mathf.Max(20f, length);
			Width = Mathf.Max(40f, width);
			Speed = speed;
			IsGiga = isGiga;
			DepthScale = 1f;
			sigma = Length * 0.25f;
			float num = 0.0001f;
			for (int i = 0; i <= 240; i++)
			{
				float x = (-8f + (float)i * (1f / 15f)) * sigma;
				float num2 = Profile(x);
				if (num2 > num)
				{
					num = num2;
				}
			}
			profileNorm = 1f / num;
			CullRadius = Speed * Duration * 0.5f + 9f * sigma + 3f * Width;
			cullRadiusSqr = CullRadius * CullRadius;
		}

		private float Profile(float x)
		{
			float num = sigma;
			float num2 = (IsGiga ? 0.6f : 0.3f);
			float num3 = (IsGiga ? 0.16f : 0.07f);
			float num4 = 0.4f * Gauss(x - 1.9f * num, 2.6f * num);
			float num5 = -0.1f * Gauss(x - 0.85f * num, 0.5f * num);
			float num6 = num2 * Gauss(x - 0.28f * num, 0.3f * num);
			float num7 = Gauss(x, num);
			float num8 = 0.45f * Gauss(x + 1.5f * num, 2.4f * num);
			float num9 = (0f - num3) * Gauss(x + 1.1f * num, 0.9f * num);
			return num4 + num5 + num6 + num7 + num8 + num9;
		}

		private static float Gauss(float x, float sigma)
		{
			float num = x / sigma;
			return Mathf.Exp(-0.5f * num * num);
		}

		public bool IsExpired(double time)
		{
			double num = time - StartTime;
			if (!(num < -5.0))
			{
				return num > (double)Duration + 6.0;
			}
			return true;
		}

		public Vector3 GetCrestCenter(double time)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Clamp((float)(time - StartTime), 0f, Duration);
			float num2 = (0f - Speed) * Duration * 0.5f + Speed * num;
			return Origin + Direction * num2;
		}

		public float GetHeight(Vector3 worldPos, double time)
		{
			//IL_0021: 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_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_004f: 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_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			float num = (float)(time - StartTime);
			if (num < 0f || num > Duration)
			{
				return 0f;
			}
			Vector3 val = worldPos - Origin;
			val.y = 0f;
			if (((Vector3)(ref val)).sqrMagnitude > cullRadiusSqr)
			{
				return 0f;
			}
			float num2 = Vector3.Dot(val, Direction);
			float x = Vector3.Dot(val, right);
			float num3 = (0f - Speed) * Duration * 0.5f + Speed * num;
			float num4 = num2 - num3;
			if (Mathf.Abs(num4) > 9f * sigma)
			{
				return 0f;
			}
			float num5 = Gauss(x, Width);
			float num6 = Mathf.Clamp01(num / (IsGiga ? 12f : 8f));
			float num7 = Mathf.Clamp01((Duration - num) / (IsGiga ? 12f : 9f));
			return Height * DepthScale * Profile(num4) * profileNorm * num5 * num6 * num7;
		}

		public float GetInfluence(Vector3 worldPos, double time)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if (Height < 0.01f)
			{
				return 0f;
			}
			return Mathf.Clamp01(GetHeight(worldPos, time) / (Height * Mathf.Max(0.05f, DepthScale)));
		}

		public float GetCrestCloseness(Vector3 worldPos, double time)
		{
			//IL_0021: 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_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_003a: 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_0049: Unknown result type (might be due to invalid IL or missing references)
			float num = (float)(time - StartTime);
			if (num < 0f || num > Duration)
			{
				return 0f;
			}
			Vector3 val = worldPos - Origin;
			val.y = 0f;
			float num2 = Vector3.Dot(val, Direction);
			float x = Vector3.Dot(val, right);
			float num3 = (0f - Speed) * Duration * 0.5f + Speed * num;
			float x2 = num2 - num3;
			float num4 = Mathf.Clamp01(num / 12f) * Mathf.Clamp01((Duration - num) / 12f);
			return Gauss(x2, 0.9f * sigma) * Gauss(x, Width) * num4 * DepthScale;
		}
	}

	public const string ModGuid = "eden.valheim.roguewaves";

	public const string ModName = "Guak Rogue Waves";

	public const string ModVersion = "2.0.1";

	private const string RpcName = "GuakRogueWaves_Wave_v2";

	private const int RpcVersion = 2;

	private const float FeetToMeters = 0.3048f;

	private const float DefaultSeaLevel = 30f;

	private const int MaxActiveWaves = 8;

	private const int MaxRememberedIds = 64;

	private static ConfigEntry<bool> cfgEnabled;

	private static ConfigEntry<bool> cfgSyncWaves;

	private static ConfigEntry<bool> cfgChatWarning;

	private static ConfigEntry<bool> cfgScreenShake;

	private static ConfigEntry<float> cfgNormalMinHeightFeet;

	private static ConfigEntry<float> cfgNormalMaxHeightFeet;

	private static ConfigEntry<float> cfgNormalCrestLength;

	private static ConfigEntry<float> cfgNormalCrestWidth;

	private static ConfigEntry<float> cfgNormalMinSpeed;

	private static ConfigEntry<float> cfgNormalMaxSpeed;

	private static ConfigEntry<float> cfgNormalMinSpawnDist;

	private static ConfigEntry<float> cfgNormalMaxSpawnDist;

	private static ConfigEntry<float> cfgNormalDuration;

	private static ConfigEntry<bool> cfgAllowFullWavesEverywhere;

	private static ConfigEntry<float> cfgShallowDepthMeters;

	private static ConfigEntry<float> cfgShoreSpectacleDistanceFeet;

	private static ConfigEntry<float> cfgCalmMinSeconds;

	private static ConfigEntry<float> cfgCalmMaxSeconds;

	private static ConfigEntry<float> cfgBadMinSeconds;

	private static ConfigEntry<float> cfgBadMaxSeconds;

	private static ConfigEntry<float> cfgStormMinSeconds;

	private static ConfigEntry<float> cfgStormMaxSeconds;

	private static ConfigEntry<float> cfgStormFrequencyMult;

	private static ConfigEntry<bool> cfgBoatStabilizer;

	private static ConfigEntry<float> cfgBoatStability;

	private static ConfigEntry<bool> cfgAllowNearVerticalPitch;

	private static ConfigEntry<bool> cfgGigaEnabled;

	private static ConfigEntry<float> cfgGigaMinHeightFeet;

	private static ConfigEntry<float> cfgGigaMaxHeightFeet;

	private static ConfigEntry<float> cfgGigaChancePercent;

	private static ConfigEntry<float> cfgGigaMinAttemptSeconds;

	private static ConfigEntry<float> cfgGigaMaxAttemptSeconds;

	private static ConfigEntry<bool> cfgGigaRequiresThunderstorm;

	private static ConfigEntry<bool> cfgGigaRequiresOcean;

	private static ConfigEntry<float> cfgGigaOceanRadius;

	private static ConfigEntry<float> cfgGigaCrestLength;

	private static ConfigEntry<float> cfgGigaCrestWidth;

	private static ConfigEntry<float> cfgGigaMinSpeed;

	private static ConfigEntry<float> cfgGigaMaxSpeed;

	private static ConfigEntry<float> cfgGigaMinSpawnDist;

	private static ConfigEntry<float> cfgGigaMaxSpawnDist;

	private static ConfigEntry<float> cfgGigaDuration;

	private static ConfigEntry<bool> cfgGigaDamageEnabled;

	private static ConfigEntry<float> cfgGigaDamagePercentPerSecond;

	private static ConfigEntry<float> cfgLongshipReferenceHealth;

	private static ConfigEntry<float> cfgStormWindChaosMult;

	private static ConfigEntry<float> cfgThunderWeightMult;

	private static readonly Random rng = new Random();

	private static readonly List<RogueWave> waves = new List<RogueWave>();

	private static readonly Queue<long> recentIdQueue = new Queue<long>();

	private static readonly HashSet<long> recentIds = new HashSet<long>();

	private static readonly Dictionary<int, float> gigaDamageAccum = new Dictionary<int, float>();

	private static ManualLogSource log;

	private static FieldInfo shipBodyField;

	private static ZRoutedRpc registeredRpc;

	private static EnvMan weightPatchedEnvMan;

	private static float nextWaveTime;

	private static float nextGigaAttemptTime;

	private static float nextDepthRefreshTime;

	private static float nextShakeTime;

	private static int lastWeatherTier = -1;

	private static bool shipPatchApplied;

	private static bool wavePatchApplied;

	private static bool windPatchApplied;

	private Harmony harmony;

	private static double frameNetTime;

	private static int frameNetFrame = -1;

	private void Awake()
	{
		//IL_069a: Unknown result type (might be due to invalid IL or missing references)
		//IL_06a4: Expected O, but got Unknown
		log = ((BaseUnityPlugin)this).Logger;
		cfgEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable rogue ocean waves.");
		cfgChatWarning = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ChatWarning", true, "Show a center-screen warning when a rogue wave starts.");
		cfgScreenShake = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ScreenShake", true, "Shake the camera while a rogue wave is passing under the local player.");
		cfgSyncWaves = ((BaseUnityPlugin)this).Config.Bind<bool>("Multiplayer", "SyncWaves", true, "Share waves with other modded players (both sending AND receiving). Off = fully local waves; other players will not see the water that moves your boat.");
		cfgNormalMinHeightFeet = ((BaseUnityPlugin)this).Config.Bind<float>("Normal Waves", "NormalMinHeightFeet", 15f, "Minimum peak height of a normal rogue wave, in feet (15 ft = 4.6 m). Height is the TRUE peak after profile normalization.");
		cfgNormalMaxHeightFeet = ((BaseUnityPlugin)this).Config.Bind<float>("Normal Waves", "NormalMaxHeightFeet", 45f, "Maximum peak height of a normal rogue wave, in feet (45 ft = 13.7 m).");
		cfgNormalCrestLength = ((BaseUnityPlugin)this).Config.Bind<float>("Normal Waves", "CrestLengthMeters", 190f, "Approximate full front-to-back size of the main crest. Each wave randomizes 75%-135% of this.");
		cfgNormalCrestWidth = ((BaseUnityPlugin)this).Config.Bind<float>("Normal Waves", "CrestWidthMeters", 520f, "Base side-to-side spread. Each wave randomizes 75%-135% of this.");
		cfgNormalMinSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Normal Waves", "MinTravelSpeedMetersPerSecond", 8f, "Minimum travel speed of a normal wave.");
		cfgNormalMaxSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Normal Waves", "MaxTravelSpeedMetersPerSecond", 14f, "Maximum travel speed of a normal wave.");
		cfgNormalMinSpawnDist = ((BaseUnityPlugin)this).Config.Bind<float>("Normal Waves", "MinSpawnDistanceMeters", 140f, "Minimum distance from the player at which the crest starts.");
		cfgNormalMaxSpawnDist = ((BaseUnityPlugin)this).Config.Bind<float>("Normal Waves", "MaxSpawnDistanceMeters", 240f, "Maximum distance from the player at which the crest starts.");
		cfgNormalDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Normal Waves", "DurationSeconds", 58f, "How long a normal wave lives while it travels through.");
		cfgAllowFullWavesEverywhere = ((BaseUnityPlugin)this).Config.Bind<bool>("Normal Waves", "AllowFullWavesEverywhere", false, "If false, waves shrink in shallow water and outside the Ocean biome so coastal sailing stays gentler.");
		cfgShallowDepthMeters = ((BaseUnityPlugin)this).Config.Bind<float>("Normal Waves", "ShallowWaterDepthMeters", 14f, "Water depth at which waves reach full size when AllowFullWavesEverywhere is false.");
		cfgShoreSpectacleDistanceFeet = ((BaseUnityPlugin)this).Config.Bind<float>("Normal Waves", "ShoreSpectacleDistanceFeet", 100f, "Normal waves are allowed while the local player is on/near ocean or large water within this distance. Far inland, waves stop.");
		cfgCalmMinSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Timing", "NormalWeatherMinSecondsBetweenWaves", 120f, "Calm/clear weather: minimum seconds between local wave events.");
		cfgCalmMaxSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Timing", "NormalWeatherMaxSecondsBetweenWaves", 300f, "Calm/clear weather: maximum seconds between local wave events.");
		cfgBadMinSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Timing", "BadWeatherMinSecondsBetweenWaves", 90f, "Rainy/windy weather: minimum seconds between local wave events.");
		cfgBadMaxSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Timing", "BadWeatherMaxSecondsBetweenWaves", 210f, "Rainy/windy weather: maximum seconds between local wave events.");
		cfgStormMinSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Timing", "ThunderstormMinSecondsBetweenWaves", 45f, "Thunderstorm: minimum seconds between local wave events.");
		cfgStormMaxSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Timing", "ThunderstormMaxSecondsBetweenWaves", 120f, "Thunderstorm: maximum seconds between local wave events.");
		cfgStormFrequencyMult = ((BaseUnityPlugin)this).Config.Bind<float>("Timing", "StormNormalWaveFrequencyMultiplier", 1f, "Extra frequency multiplier applied on top of the thunderstorm timing range. 2 = twice as often. Leave 1 to use the range as-is.");
		cfgBoatStabilizer = ((BaseUnityPlugin)this).Config.Bind<bool>("Boat Physics", "NormalWaveBoatStabilizer", true, "Dampen violent roll/spin during NORMAL waves so they are scary but controllable. Giga waves ignore this.");
		cfgBoatStability = ((BaseUnityPlugin)this).Config.Bind<float>("Boat Physics", "NormalWaveBoatStability", 0.72f, "0..1. How strongly normal waves are kept from capsizing boats. Roll and spin are damped; pitch is left mostly free.");
		cfgAllowNearVerticalPitch = ((BaseUnityPlugin)this).Config.Bind<bool>("Boat Physics", "AllowNearVerticalPitch", true, "If true, pitch is barely damped so the bow can point at the sky while climbing. If false, pitch is also moderated.");
		cfgGigaEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Giga Wave", "Enabled", true, "Enable rare, genuinely dangerous giga waves.");
		cfgGigaMinHeightFeet = ((BaseUnityPlugin)this).Config.Bind<float>("Giga Wave", "GigaMinHeightFeet", 50f, "Minimum giga wave peak height in feet (50 ft = 15.2 m).");
		cfgGigaMaxHeightFeet = ((BaseUnityPlugin)this).Config.Bind<float>("Giga Wave", "GigaMaxHeightFeet", 80f, "Maximum giga wave peak height in feet (80 ft = 24.4 m).");
		cfgGigaChancePercent = ((BaseUnityPlugin)this).Config.Bind<float>("Giga Wave", "GigaChancePercentPerAttempt", 8f, "Chance (0-100) that a valid thunderstorm-ocean attempt actually spawns a giga wave.");
		cfgGigaMinAttemptSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Giga Wave", "GigaMinSecondsBetweenAttempts", 120f, "Minimum seconds between giga spawn attempts while conditions are valid.");
		cfgGigaMaxAttemptSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Giga Wave", "GigaMaxSecondsBetweenAttempts", 300f, "Maximum seconds between giga spawn attempts.");
		cfgGigaRequiresThunderstorm = ((BaseUnityPlugin)this).Config.Bind<bool>("Giga Wave", "GigaRequiresThunderstorm", true, "Giga waves only attempt to spawn during thunderstorm-style weather.");
		cfgGigaRequiresOcean = ((BaseUnityPlugin)this).Config.Bind<bool>("Giga Wave", "GigaRequiresOcean", true, "Giga waves only attempt to spawn when the player is surrounded by Ocean biome.");
		cfgGigaOceanRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Giga Wave", "OceanRadiusCheckMeters", 140f, "The player must be surrounded by Ocean biome within this radius for a giga attempt.");
		cfgGigaCrestLength = ((BaseUnityPlugin)this).Config.Bind<float>("Giga Wave", "CrestLengthMeters", 340f, "Base front-to-back size of the giga wave. Randomized 75%-135% per wave.");
		cfgGigaCrestWidth = ((BaseUnityPlugin)this).Config.Bind<float>("Giga Wave", "CrestWidthMeters", 1100f, "Base side-to-side spread of the giga wave. Randomized 75%-135% per wave.");
		cfgGigaMinSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Giga Wave", "MinTravelSpeedMetersPerSecond", 12f, "Minimum giga wave travel speed.");
		cfgGigaMaxSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Giga Wave", "MaxTravelSpeedMetersPerSecond", 18f, "Maximum giga wave travel speed.");
		cfgGigaMinSpawnDist = ((BaseUnityPlugin)this).Config.Bind<float>("Giga Wave", "MinSpawnDistanceMeters", 320f, "Minimum distance at which the giga crest starts.");
		cfgGigaMaxSpawnDist = ((BaseUnityPlugin)this).Config.Bind<float>("Giga Wave", "MaxSpawnDistanceMeters", 480f, "Maximum distance at which the giga crest starts.");
		cfgGigaDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Giga Wave", "DurationSeconds", 95f, "How long a giga wave lives.");
		cfgGigaDamageEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Giga Wave", "GigaDamageEnabled", true, "Giga waves damage boats near the crest. Rafts/karves are in serious danger; longship-class boats can survive if handled well (bow into the wave).");
		cfgGigaDamagePercentPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("Giga Wave", "GigaDamagePercentPerSecond", 6f, "Percent of a LONGSHIP-CLASS boat's max health dealt per second at the giga crest, broadside. Smaller boats take proportionally more, bow-on takes about a third.");
		cfgLongshipReferenceHealth = ((BaseUnityPlugin)this).Config.Bind<float>("Giga Wave", "LongshipReferenceHealth", 1000f, "Reference max health (vanilla longship = 1000). Boats with max health at or above this take the base damage rate; weaker boats take more.");
		cfgStormWindChaosMult = ((BaseUnityPlugin)this).Config.Bind<float>("Storm", "StormWindChaosMultiplier", 1.25f, "Multiplies wind intensity targets during thunderstorms (affects sails, ocean physics AND the rendered waves consistently). 1 = off. Modded clients see stormier seas than unmodded ones.");
		cfgThunderWeightMult = ((BaseUnityPlugin)this).Config.Bind<float>("Storm", "ThunderstormWeightMultiplier", 1.5f, "Multiplies the weather-table weight of thunderstorm environments in the Ocean biome, making them a bit more common. 1 = off. NOTE: weather is computed per-client from a shared seed, so give every player the same value or their skies will disagree (cosmetic only, no server validation).");
		shipBodyField = AccessTools.Field(typeof(Ship), "m_body");
		harmony = new Harmony("eden.valheim.roguewaves");
		ApplyPatches();
		ScheduleNextWave(20f, 45f);
		ScheduleNextGigaAttempt(45f, 90f);
		log.LogInfo((object)("Guak Rogue Waves 2.0.1 loaded. wavePatch=" + wavePatchApplied + " shipPatch=" + shipPatchApplied + " windPatch=" + windPatchApplied));
	}

	private void OnDestroy()
	{
		if (harmony != null)
		{
			harmony.UnpatchSelf();
		}
	}

	private void ApplyPatches()
	{
		//IL_0082: Unknown result type (might be due to invalid IL or missing references)
		//IL_008f: Expected O, but got Unknown
		//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f6: Expected O, but got Unknown
		//IL_013f: Unknown result type (might be due to invalid IL or missing references)
		//IL_014c: Expected O, but got Unknown
		try
		{
			MethodInfo method = typeof(WaterVolume).GetMethod("CalcWave", BindingFlags.Instance | BindingFlags.Public, null, new Type[4]
			{
				typeof(Vector3),
				typeof(float),
				typeof(float),
				typeof(float)
			}, null);
			if (method != null)
			{
				harmony.Patch((MethodBase)method, (HarmonyMethod)null, new HarmonyMethod(typeof(RogueWavesPlugin).GetMethod("CalcWavePostfix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				wavePatchApplied = true;
			}
			else
			{
				log.LogWarning((object)"WaterVolume.CalcWave(Vector3,float,float,float) not found; rogue waves disabled.");
			}
		}
		catch (Exception ex)
		{
			log.LogWarning((object)("Failed to patch WaterVolume.CalcWave: " + ex.Message));
		}
		try
		{
			MethodInfo methodInfo = AccessTools.Method(typeof(Ship), "CustomFixedUpdate", new Type[1] { typeof(float) }, (Type[])null);
			if (methodInfo == null)
			{
				methodInfo = AccessTools.Method(typeof(Ship), "FixedUpdate", Type.EmptyTypes, (Type[])null);
			}
			if (methodInfo != null)
			{
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(RogueWavesPlugin).GetMethod("ShipTickPostfix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				shipPatchApplied = true;
			}
			else
			{
				log.LogWarning((object)"No Ship.CustomFixedUpdate/FixedUpdate found; boat stabilization and giga damage disabled.");
			}
		}
		catch (Exception ex2)
		{
			log.LogWarning((object)("Failed to patch Ship physics tick: " + ex2.Message));
		}
		try
		{
			MethodInfo methodInfo2 = AccessTools.Method(typeof(EnvMan), "SetTargetWind", new Type[2]
			{
				typeof(Vector3),
				typeof(float)
			}, (Type[])null);
			if (methodInfo2 != null)
			{
				harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(RogueWavesPlugin).GetMethod("SetTargetWindPrefix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				windPatchApplied = true;
			}
			else
			{
				log.LogInfo((object)"EnvMan.SetTargetWind not found; StormWindChaosMultiplier disabled (safe).");
			}
		}
		catch (Exception ex3)
		{
			log.LogWarning((object)("Failed to patch EnvMan.SetTargetWind: " + ex3.Message));
		}
	}

	private static void CalcWavePostfix(Vector3 worldPos, ref float __result)
	{
		//IL_0003: Unknown result type (might be due to invalid IL or missing references)
		__result += ExtraWaveHeight(worldPos);
	}

	private static void ShipTickPostfix(Ship __instance)
	{
		try
		{
			HandleShipPhysics(__instance);
		}
		catch (Exception)
		{
		}
	}

	private static void SetTargetWindPrefix(ref float intensity)
	{
		try
		{
			if (cfgEnabled.Value)
			{
				float value = cfgStormWindChaosMult.Value;
				if (value > 1.001f && GetWeatherTier() == 2)
				{
					intensity = Mathf.Clamp01(intensity * Mathf.Min(value, 3f));
				}
			}
		}
		catch (Exception)
		{
		}
	}

	private void Update()
	{
		//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
		//IL_0199: Unknown result type (might be due to invalid IL or missing references)
		//IL_019e: Unknown result type (might be due to invalid IL or missing references)
		//IL_019f: Unknown result type (might be due to invalid IL or missing references)
		TryRegisterRpc();
		TryBoostThunderWeights();
		if (!cfgEnabled.Value)
		{
			if (waves.Count > 0)
			{
				waves.Clear();
			}
			if (Time.time > nextWaveTime)
			{
				ScheduleNextWave(30f, 90f);
			}
			if (Time.time > nextGigaAttemptTime)
			{
				ScheduleNextGigaAttempt(45f, 120f);
			}
			return;
		}
		if ((Object)(object)ZNet.instance == (Object)null && waves.Count > 0)
		{
			waves.Clear();
			gigaDamageAccum.Clear();
			lastWeatherTier = -1;
		}
		double networkTime = GetNetworkTime();
		PruneExpiredWaves(networkTime);
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null)
		{
			if (Time.time > nextWaveTime)
			{
				ScheduleNextWave(8f, 18f);
			}
			if (Time.time > nextGigaAttemptTime)
			{
				ScheduleNextGigaAttempt(20f, 40f);
			}
			return;
		}
		if (!IsNearOceanOrLargeWater(((Component)localPlayer).transform.position, Mathf.Max(20f, cfgShoreSpectacleDistanceFeet.Value) * 0.3048f))
		{
			if (waves.Count > 0)
			{
				waves.Clear();
				gigaDamageAccum.Clear();
			}
			if (Time.time > nextWaveTime)
			{
				ScheduleNextWave(30f, 90f);
			}
			if (Time.time > nextGigaAttemptTime)
			{
				ScheduleNextGigaAttempt(45f, 120f);
			}
			return;
		}
		RebroadcastLocalWaves();
		int weatherTier = GetWeatherTier();
		if (weatherTier != lastWeatherTier)
		{
			lastWeatherTier = weatherTier;
			ScheduleNextWaveForTier(weatherTier);
		}
		RefreshWaveDepthScales(localPlayer);
		Vector3 position = ((Component)localPlayer).transform.position;
		bool flag = AnyWaveNear(position, networkTime);
		if (!flag && Time.time >= nextWaveTime)
		{
			StartNormalWave(localPlayer, weatherTier);
			ScheduleNextWaveForTier(weatherTier);
		}
		if (Time.time >= nextGigaAttemptTime)
		{
			if (!flag)
			{
				TryStartGigaWave(localPlayer);
			}
			ScheduleNextGigaAttempt(cfgGigaMinAttemptSeconds.Value, cfgGigaMaxAttemptSeconds.Value);
		}
		UpdateScreenShake(localPlayer, networkTime);
	}

	private static int GetWeatherTier()
	{
		try
		{
			EnvMan instance = EnvMan.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return 0;
			}
			EnvSetup currentEnvironment = instance.GetCurrentEnvironment();
			if (currentEnvironment == null || string.IsNullOrEmpty(currentEnvironment.m_name))
			{
				return 0;
			}
			string text = currentEnvironment.m_name.ToLowerInvariant();
			if (text.Contains("thunder"))
			{
				return 2;
			}
			if (currentEnvironment.m_isWet || currentEnvironment.m_windMax >= 0.75f)
			{
				return 1;
			}
			return 0;
		}
		catch (Exception)
		{
			return 0;
		}
	}

	private static void ScheduleNextWaveForTier(int tier)
	{
		float minSeconds;
		float maxSeconds;
		switch (tier)
		{
		case 2:
		{
			float num = Mathf.Max(0.25f, cfgStormFrequencyMult.Value);
			minSeconds = cfgStormMinSeconds.Value / num;
			maxSeconds = cfgStormMaxSeconds.Value / num;
			break;
		}
		case 1:
			minSeconds = cfgBadMinSeconds.Value;
			maxSeconds = cfgBadMaxSeconds.Value;
			break;
		default:
			minSeconds = cfgCalmMinSeconds.Value;
			maxSeconds = cfgCalmMaxSeconds.Value;
			break;
		}
		ScheduleNextWave(minSeconds, maxSeconds);
	}

	private static void ScheduleNextWave(float minSeconds, float maxSeconds)
	{
		float num = Mathf.Max(10f, Mathf.Min(minSeconds, maxSeconds));
		float num2 = Mathf.Max(num + 1f, Mathf.Max(minSeconds, maxSeconds));
		nextWaveTime = Time.time + Mathf.Lerp(num, num2, Next01());
	}

	private static void ScheduleNextGigaAttempt(float minSeconds, float maxSeconds)
	{
		float num = Mathf.Max(20f, Mathf.Min(minSeconds, maxSeconds));
		float num2 = Mathf.Max(num + 1f, Mathf.Max(minSeconds, maxSeconds));
		nextGigaAttemptTime = Time.time + Mathf.Lerp(num, num2, Next01());
	}

	private static void TryBoostThunderWeights()
	{
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_0080: Invalid comparison between Unknown and I4
		try
		{
			EnvMan instance = EnvMan.instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance == (Object)(object)weightPatchedEnvMan)
			{
				return;
			}
			weightPatchedEnvMan = instance;
			float num = Mathf.Clamp(cfgThunderWeightMult.Value, 1f, 5f);
			if (num <= 1.001f || instance.m_biomes == null)
			{
				return;
			}
			int num2 = 0;
			for (int i = 0; i < instance.m_biomes.Count; i++)
			{
				BiomeEnvSetup val = instance.m_biomes[i];
				if (val == null || (int)val.m_biome != 256 || val.m_environments == null)
				{
					continue;
				}
				for (int j = 0; j < val.m_environments.Count; j++)
				{
					EnvEntry val2 = val.m_environments[j];
					if (val2 != null && !string.IsNullOrEmpty(val2.m_environment) && val2.m_environment.ToLowerInvariant().Contains("thunder"))
					{
						val2.m_weight *= num;
						num2++;
					}
				}
			}
			if (num2 > 0 && log != null)
			{
				log.LogInfo((object)("Boosted " + num2 + " ocean thunderstorm weather weight(s) x" + num));
			}
		}
		catch (Exception)
		{
		}
	}

	private static void StartNormalWave(Player player, int tier)
	{
		float num = Mathf.Lerp(Mathf.Min(cfgNormalMinHeightFeet.Value, cfgNormalMaxHeightFeet.Value), Mathf.Max(cfgNormalMinHeightFeet.Value, cfgNormalMaxHeightFeet.Value), Next01());
		if (tier == 2)
		{
			float num2 = Mathf.Max(cfgNormalMinHeightFeet.Value, cfgNormalMaxHeightFeet.Value);
			num = Mathf.Lerp(num, num2, 0.35f);
		}
		SpawnWave(player, isGiga: false, Mathf.Clamp(num * 0.3048f, 0.5f, 30f), Mathf.Max(20f, cfgNormalDuration.Value), RandomAround(cfgNormalCrestLength.Value, 40f), RandomAround(cfgNormalCrestWidth.Value, 80f), RandomRange(cfgNormalMinSpeed.Value, cfgNormalMaxSpeed.Value, 2f), RandomRange(cfgNormalMinSpawnDist.Value, cfgNormalMaxSpawnDist.Value, 40f));
	}

	private static void TryStartGigaWave(Player player)
	{
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		if (cfgGigaEnabled.Value && (!cfgGigaRequiresThunderstorm.Value || GetWeatherTier() == 2) && (!cfgGigaRequiresOcean.Value || IsSurroundedByOcean(((Component)player).transform.position, Mathf.Max(40f, cfgGigaOceanRadius.Value))) && !(Next01() * 100f > Mathf.Clamp(cfgGigaChancePercent.Value, 0f, 100f)))
		{
			float num = Mathf.Lerp(Mathf.Min(cfgGigaMinHeightFeet.Value, cfgGigaMaxHeightFeet.Value), Mathf.Max(cfgGigaMinHeightFeet.Value, cfgGigaMaxHeightFeet.Value), Next01());
			SpawnWave(player, isGiga: true, Mathf.Clamp(num * 0.3048f, 1f, 60f), Mathf.Max(30f, cfgGigaDuration.Value), RandomAround(cfgGigaCrestLength.Value, 80f), RandomAround(cfgGigaCrestWidth.Value, 160f), RandomRange(cfgGigaMinSpeed.Value, cfgGigaMaxSpeed.Value, 3f), RandomRange(cfgGigaMinSpawnDist.Value, cfgGigaMaxSpawnDist.Value, 80f));
		}
	}

	private static void SpawnWave(Player player, bool isGiga, float heightMeters, float duration, float length, float width, float speed, float spawnDistance)
	{
		//IL_0037: 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_004a: 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_0054: 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)
		float num = Next01() * 360f * ((float)Math.PI / 180f);
		Vector3 val = default(Vector3);
		((Vector3)(ref val))..ctor(Mathf.Sin(num), 0f, Mathf.Cos(num));
		((Vector3)(ref val)).Normalize();
		Vector3 origin = ((Component)player).transform.position + val * (speed * duration * 0.5f - spawnDistance);
		long id = DateTime.UtcNow.Ticks ^ ((long)rng.Next() << 32) ^ rng.Next();
		RogueWave rogueWave = new RogueWave(id, GetNetworkTime(), origin, val, heightMeters, duration, length, width, speed, isGiga);
		rogueWave.IsLocal = true;
		rogueWave.NextRebroadcastAt = Time.time + 8f;
		rogueWave.DepthScale = ComputeDepthScale(rogueWave, GetNetworkTime());
		AcceptWave(rogueWave, local: true);
		BroadcastWave(rogueWave);
	}

	private static void RebroadcastLocalWaves()
	{
		double networkTime = GetNetworkTime();
		for (int i = 0; i < waves.Count; i++)
		{
			RogueWave rogueWave = waves[i];
			if (rogueWave.IsLocal && !rogueWave.IsExpired(networkTime) && Time.time >= rogueWave.NextRebroadcastAt)
			{
				rogueWave.NextRebroadcastAt = Time.time + 8f;
				BroadcastWave(rogueWave);
			}
		}
	}

	private static float RandomAround(float baseValue, float min)
	{
		return Mathf.Max(min, baseValue * (0.75f + Next01() * 0.6f));
	}

	private static float RandomRange(float a, float b, float floor)
	{
		return Mathf.Max(floor, Mathf.Lerp(Mathf.Min(a, b), Mathf.Max(a, b), Next01()));
	}

	private static float Next01()
	{
		return (float)rng.NextDouble();
	}

	private static void AcceptWave(RogueWave wave, bool local)
	{
		//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
		if (wave == null || recentIds.Contains(wave.Id))
		{
			return;
		}
		recentIds.Add(wave.Id);
		recentIdQueue.Enqueue(wave.Id);
		while (recentIdQueue.Count > 64)
		{
			recentIds.Remove(recentIdQueue.Dequeue());
		}
		while (waves.Count >= 8)
		{
			waves.RemoveAt(0);
		}
		waves.Add(wave);
		if (cfgChatWarning.Value && (Object)(object)MessageHud.instance != (Object)null && (Object)(object)Player.m_localPlayer != (Object)null)
		{
			float num = Vector3.Distance(((Component)Player.m_localPlayer).transform.position, wave.Origin);
			if (num < wave.CullRadius)
			{
				MessageHud.instance.ShowMessage((MessageType)2, wave.IsGiga ? "THE SEA RISES - GIGA WAVE" : "Rogue wave incoming", 0, (Sprite)null, false);
			}
		}
	}

	private static void PruneExpiredWaves(double now)
	{
		for (int num = waves.Count - 1; num >= 0; num--)
		{
			if (waves[num].IsExpired(now))
			{
				waves.RemoveAt(num);
			}
		}
		if (waves.Count == 0 && gigaDamageAccum.Count > 0)
		{
			gigaDamageAccum.Clear();
		}
	}

	private static bool AnyWaveNear(Vector3 pos, double now)
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: 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)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		for (int i = 0; i < waves.Count; i++)
		{
			RogueWave rogueWave = waves[i];
			if (!rogueWave.IsExpired(now))
			{
				Vector3 val = pos - rogueWave.Origin;
				val.y = 0f;
				if (((Vector3)(ref val)).sqrMagnitude < rogueWave.CullRadius * rogueWave.CullRadius)
				{
					return true;
				}
			}
		}
		return false;
	}

	private static void RefreshWaveDepthScales(Player player)
	{
		if (!(Time.time < nextDepthRefreshTime))
		{
			nextDepthRefreshTime = Time.time + 1f;
			double networkTime = GetNetworkTime();
			for (int i = 0; i < waves.Count; i++)
			{
				waves[i].DepthScale = ComputeDepthScale(waves[i], networkTime);
			}
		}
	}

	private static float ComputeDepthScale(RogueWave wave, double now)
	{
		//IL_0029: 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)
		//IL_008e: Unknown result type (might be due to invalid IL or missing references)
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0099: Invalid comparison between Unknown and I4
		if (cfgAllowFullWavesEverywhere.Value)
		{
			return 1f;
		}
		try
		{
			WorldGenerator instance = WorldGenerator.instance;
			if (instance == null)
			{
				return 1f;
			}
			Vector3 crestCenter = wave.GetCrestCenter(now);
			float num = (((Object)(object)ZoneSystem.instance != (Object)null) ? ZoneSystem.instance.m_waterLevel : 30f);
			float height = instance.GetHeight(crestCenter.x, crestCenter.z);
			float num2 = num - height;
			float num3 = Mathf.Clamp01(num2 / Mathf.Max(2f, cfgShallowDepthMeters.Value));
			float num4 = 1f;
			if ((int)instance.GetBiome(crestCenter) != 256)
			{
				num4 = 0.55f;
			}
			return Mathf.Min(num3, num4);
		}
		catch (Exception)
		{
			return 1f;
		}
	}

	private static bool IsSurroundedByOcean(Vector3 center, float radius)
	{
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: Invalid comparison between Unknown and I4
		//IL_000a: 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_0015: Invalid comparison between Unknown and I4
		//IL_004c: 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_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Invalid comparison between Unknown and I4
		try
		{
			WorldGenerator instance = WorldGenerator.instance;
			if (instance != null)
			{
				if ((int)instance.GetBiome(center) != 256)
				{
					return false;
				}
				Vector3 val = default(Vector3);
				for (int i = 0; i < 8; i++)
				{
					float num = (float)i * (float)Math.PI * 0.25f;
					((Vector3)(ref val))..ctor(Mathf.Sin(num) * radius, 0f, Mathf.Cos(num) * radius);
					if ((int)instance.GetBiome(center + val) != 256)
					{
						return false;
					}
				}
				return true;
			}
			return (int)Heightmap.FindBiome(center) == 256;
		}
		catch (Exception)
		{
			return false;
		}
	}

	private static bool IsNearOceanOrLargeWater(Vector3 center, float radius)
	{
		//IL_0009: 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)
		//IL_0014: Invalid comparison between Unknown and I4
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b4: 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)
		try
		{
			WorldGenerator instance = WorldGenerator.instance;
			if (instance == null)
			{
				return (int)Heightmap.FindBiome(center) == 256;
			}
			float sea = (((Object)(object)ZoneSystem.instance != (Object)null) ? ZoneSystem.instance.m_waterLevel : 30f);
			if (IsOceanOrDeepWater(instance, center, sea))
			{
				return true;
			}
			float[] array = new float[2]
			{
				radius * 0.5f,
				radius
			};
			Vector3 val = default(Vector3);
			for (int i = 0; i < array.Length; i++)
			{
				float num = Mathf.Max(4f, array[i]);
				for (int j = 0; j < 16; j++)
				{
					float num2 = (float)j * (float)Math.PI * 0.125f;
					((Vector3)(ref val))..ctor(Mathf.Sin(num2) * num, 0f, Mathf.Cos(num2) * num);
					if (IsOceanOrDeepWater(instance, center + val, sea))
					{
						return true;
					}
				}
			}
		}
		catch (Exception)
		{
		}
		return false;
	}

	private static bool IsOceanOrDeepWater(WorldGenerator gen, Vector3 pos, float sea)
	{
		//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_000c: Invalid comparison between Unknown and I4
		if ((int)gen.GetBiome(pos) == 256)
		{
			return true;
		}
		float height = gen.GetHeight(pos.x, pos.z);
		return sea - height >= 3f;
	}

	public static float ExtraWaveHeight(Vector3 worldPos)
	{
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		if (waves.Count == 0 || !cfgEnabled.Value)
		{
			return 0f;
		}
		double networkTimeCached = GetNetworkTimeCached();
		float num = 0f;
		for (int i = 0; i < waves.Count; i++)
		{
			num += waves[i].GetHeight(worldPos, networkTimeCached);
		}
		return num;
	}

	private static void HandleShipPhysics(Ship ship)
	{
		//IL_0037: 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_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_0119: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)ship == (Object)null || !cfgEnabled.Value || waves.Count == 0 || !ship.IsOwner())
		{
			return;
		}
		double networkTimeCached = GetNetworkTimeCached();
		Vector3 position = ((Component)ship).transform.position;
		RogueWave rogueWave = null;
		float num = 0f;
		for (int i = 0; i < waves.Count; i++)
		{
			float influence = waves[i].GetInfluence(position, networkTimeCached);
			if (influence > num)
			{
				num = influence;
				rogueWave = waves[i];
			}
		}
		if (rogueWave == null || num < 0.1f)
		{
			return;
		}
		Rigidbody val = null;
		if (shipBodyField != null)
		{
			object? value = shipBodyField.GetValue(ship);
			val = (Rigidbody)((value is Rigidbody) ? value : null);
		}
		if ((Object)(object)val == (Object)null)
		{
			val = ((Component)ship).GetComponent<Rigidbody>();
		}
		if ((Object)(object)val == (Object)null)
		{
			return;
		}
		float fixedDeltaTime = Time.fixedDeltaTime;
		if (rogueWave.IsGiga)
		{
			DampAngular(ship, val, 0.6f * num, 0f, 0.3f * num, fixedDeltaTime);
			ClampAngularSpeed(val, 2.5f);
			if (cfgGigaDamageEnabled.Value)
			{
				ApplyGigaDamage(ship, rogueWave, position, networkTimeCached);
			}
		}
		else if (cfgBoatStabilizer.Value)
		{
			float num2 = Mathf.Clamp01(cfgBoatStability.Value);
			if (!(num2 <= 0f))
			{
				float num3 = (cfgAllowNearVerticalPitch.Value ? 0.25f : 2.5f);
				DampAngular(ship, val, 5f * num2 * num, num3 * num2 * num, 2.2f * num2 * num, fixedDeltaTime);
				ClampAngularSpeed(val, Mathf.Lerp(2.6f, 1.5f, num2));
				Vector3 val2 = Vector3.Cross(((Component)ship).transform.up, Vector3.up);
				Vector3 forward = ((Component)ship).transform.forward;
				float num4 = Vector3.Dot(val2, forward);
				val.AddTorque(forward * num4 * num2 * 2.4f * num, (ForceMode)5);
			}
		}
	}

	private static void DampAngular(Ship ship, Rigidbody body, float rollRate, float pitchRate, float yawRate, float dt)
	{
		//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)
		//IL_0011: 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_0081: Unknown result type (might be due to invalid IL or missing references)
		Vector3 val = ((Component)ship).transform.InverseTransformDirection(body.angularVelocity);
		val.x *= Mathf.Exp((0f - Mathf.Max(0f, pitchRate)) * dt);
		val.y *= Mathf.Exp((0f - Mathf.Max(0f, yawRate)) * dt);
		val.z *= Mathf.Exp((0f - Mathf.Max(0f, rollRate)) * dt);
		body.angularVelocity = ((Component)ship).transform.TransformDirection(val);
	}

	private static void ClampAngularSpeed(Rigidbody body, float maxRadiansPerSecond)
	{
		//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_0014: 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)
		Vector3 angularVelocity = body.angularVelocity;
		float magnitude = ((Vector3)(ref angularVelocity)).magnitude;
		if (magnitude > maxRadiansPerSecond)
		{
			body.angularVelocity = angularVelocity * (maxRadiansPerSecond / magnitude);
		}
	}

	private static void ApplyGigaDamage(Ship ship, RogueWave wave, Vector3 shipPos, double now)
	{
		//IL_001f: 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_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0107: Unknown result type (might be due to invalid IL or missing references)
		//IL_010e: Expected O, but got Unknown
		//IL_011e: Unknown result type (might be due to invalid IL or missing references)
		//IL_011f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0127: Unknown result type (might be due to invalid IL or missing references)
		//IL_012c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0135: Unknown result type (might be due to invalid IL or missing references)
		WearNTear component = ((Component)ship).GetComponent<WearNTear>();
		if ((Object)(object)component == (Object)null || component.m_health <= 0f)
		{
			return;
		}
		float crestCloseness = wave.GetCrestCloseness(shipPos, now);
		if (crestCloseness < 0.25f)
		{
			return;
		}
		float health = component.m_health;
		float num = Mathf.Clamp(Mathf.Max(1f, cfgLongshipReferenceHealth.Value) / health, 0.5f, 4f);
		Vector3 forward = ((Component)ship).transform.forward;
		float num2 = Mathf.Abs(Vector3.Dot(((Vector3)(ref forward)).normalized, wave.Direction));
		float num3 = Mathf.Lerp(1f, 0.35f, num2);
		float num4 = Mathf.Clamp(cfgGigaDamagePercentPerSecond.Value, 0f, 100f) / 100f;
		float num5 = health * num4 * Mathf.Pow(crestCloseness, 1.2f) * num * num3;
		float num6 = num5 * Time.fixedDeltaTime;
		int instanceID = ((Object)ship).GetInstanceID();
		if (!gigaDamageAccum.TryGetValue(instanceID, out var value))
		{
			value = 0f;
		}
		value += num6;
		if (value >= 5f)
		{
			try
			{
				HitData val = new HitData();
				val.m_damage.m_damage = value;
				val.m_point = shipPos;
				val.m_dir = wave.Direction;
				val.m_hitType = (HitType)17;
				component.Damage(val);
			}
			catch (Exception)
			{
			}
			value = 0f;
		}
		gigaDamageAccum[instanceID] = value;
	}

	private static void UpdateScreenShake(Player player, double now)
	{
		//IL_0033: 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_0052: 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)
		if (!cfgScreenShake.Value || Time.time < nextShakeTime)
		{
			return;
		}
		try
		{
			GameCamera instance = GameCamera.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			Vector3 position = ((Component)player).transform.position;
			float num = 0f;
			bool flag = false;
			for (int i = 0; i < waves.Count; i++)
			{
				float influence = waves[i].GetInfluence(position, now);
				if (influence > num)
				{
					num = influence;
					flag = waves[i].IsGiga;
				}
			}
			if (num > 0.3f)
			{
				float num2 = (flag ? 0.09f : 0.045f) * num;
				instance.AddShake(position, 50f, num2, false);
				nextShakeTime = Time.time + 0.45f;
			}
		}
		catch (Exception)
		{
		}
	}

	private static void TryRegisterRpc()
	{
		ZRoutedRpc instance = ZRoutedRpc.instance;
		if (instance == null || registeredRpc == instance)
		{
			return;
		}
		try
		{
			instance.Register<ZPackage>("GuakRogueWaves_Wave_v2", (Action<long, ZPackage>)RPC_Wave);
			registeredRpc = instance;
		}
		catch (Exception ex)
		{
			if (log != null)
			{
				log.LogWarning((object)("RPC register failed: " + ex.Message));
			}
			registeredRpc = instance;
		}
	}

	private static void BroadcastWave(RogueWave wave)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Expected O, but got Unknown
		//IL_003b: 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)
		if (!cfgSyncWaves.Value || ZRoutedRpc.instance == null)
		{
			return;
		}
		try
		{
			ZPackage val = new ZPackage();
			val.Write(2);
			val.Write(wave.Id);
			val.Write(wave.StartTime);
			val.Write(wave.Origin);
			val.Write(wave.Direction);
			val.Write(wave.Height);
			val.Write(wave.Duration);
			val.Write(wave.Length);
			val.Write(wave.Width);
			val.Write(wave.Speed);
			val.Write(wave.IsGiga);
			ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "GuakRogueWaves_Wave_v2", new object[1] { val });
		}
		catch (Exception ex)
		{
			if (log != null)
			{
				log.LogWarning((object)("Wave broadcast failed: " + ex.Message));
			}
		}
	}

	private static bool IsFinite(float v)
	{
		if (!float.IsNaN(v))
		{
			return !float.IsInfinity(v);
		}
		return false;
	}

	private static bool IsFinite(Vector3 v)
	{
		if (IsFinite(v.x) && IsFinite(v.y))
		{
			return IsFinite(v.z);
		}
		return false;
	}

	private static void RPC_Wave(long sender, ZPackage package)
	{
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_014d: Unknown result type (might be due to invalid IL or missing references)
		//IL_014e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0180: Unknown result type (might be due to invalid IL or missing references)
		//IL_01af: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
		if (package == null || !cfgEnabled.Value || !cfgSyncWaves.Value)
		{
			return;
		}
		try
		{
			int num = package.ReadInt();
			if (num < 2)
			{
				return;
			}
			long id = package.ReadLong();
			double num2 = package.ReadDouble();
			Vector3 val = package.ReadVector3();
			Vector3 val2 = package.ReadVector3();
			float num3 = Mathf.Clamp(package.ReadSingle(), 0f, 60f);
			float num4 = Mathf.Clamp(package.ReadSingle(), 5f, 600f);
			float num5 = Mathf.Clamp(package.ReadSingle(), 20f, 2000f);
			float num6 = Mathf.Clamp(package.ReadSingle(), 40f, 5000f);
			float num7 = Mathf.Clamp(package.ReadSingle(), 1f, 60f);
			bool isGiga = package.ReadBool();
			if (double.IsNaN(num2) || double.IsInfinity(num2) || !IsFinite(val) || !IsFinite(val2) || !IsFinite(num3) || !IsFinite(num4) || !IsFinite(num5) || !IsFinite(num6) || !IsFinite(num7) || ((Vector3)(ref val2)).sqrMagnitude < 0.001f || Mathf.Abs(val.x) > 100000f || Mathf.Abs(val.z) > 100000f)
			{
				return;
			}
			RogueWave rogueWave = new RogueWave(id, num2, val, val2, num3, num4, num5, num6, num7, isGiga);
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && IsNearOceanOrLargeWater(((Component)localPlayer).transform.position, Mathf.Max(20f, cfgShoreSpectacleDistanceFeet.Value) * 0.3048f))
			{
				Vector3 val3 = ((Component)localPlayer).transform.position - rogueWave.Origin;
				val3.y = 0f;
				float num8 = rogueWave.CullRadius * 1.25f;
				if (!(((Vector3)(ref val3)).sqrMagnitude > num8 * num8))
				{
					rogueWave.DepthScale = ComputeDepthScale(rogueWave, GetNetworkTime());
					AcceptWave(rogueWave, local: false);
				}
			}
		}
		catch (Exception)
		{
		}
	}

	private static double GetNetworkTime()
	{
		ZNet instance = ZNet.instance;
		if ((Object)(object)instance != (Object)null)
		{
			return instance.GetTimeSeconds();
		}
		return Time.time;
	}

	private static double GetNetworkTimeCached()
	{
		int frameCount = Time.frameCount;
		if (frameCount != frameNetFrame)
		{
			frameNetFrame = frameCount;
			frameNetTime = GetNetworkTime();
		}
		return frameNetTime;
	}
}