Decompiled source of Njoror FairWinds v1.0.0

BepInEx\plugins\Njoror_FairWinds\Njoror_FairWinds.dll

Decompiled 11 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using Njoror.Configuration;
using Njoror.Logic;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Njoror
{
	[BepInPlugin("com.bigai.njoror_fairwinds", "Njoror_FairWinds", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class NjororPlugin : BaseUnityPlugin
	{
		public const string PluginGUID = "com.bigai.njoror_fairwinds";

		public const string PluginName = "Njoror_FairWinds";

		public const string PluginVersion = "1.0.0";

		private Harmony? _harmony;

		public static NjororPlugin Instance { get; private set; }

		public static ManualLogSource Log { get; private set; }

		public static void LogDebug(string message)
		{
			if (ModConfig.EnableDebugLogging.Value)
			{
				Log.LogInfo((object)message);
			}
		}

		private void Awake()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			try
			{
				ModConfig.Initialize(((BaseUnityPlugin)this).Config);
				SailingStateNetwork.Initialize();
				_harmony = new Harmony("com.bigai.njoror_fairwinds");
				_harmony.PatchAll(Assembly.GetExecutingAssembly());
				int num = 0;
				foreach (MethodBase patchedMethod in _harmony.GetPatchedMethods())
				{
					num++;
					LogDebug("[Njoror_FairWinds][Diag] Bound Harmony target: " + patchedMethod.DeclaringType?.FullName + "::" + patchedMethod.Name);
				}
				LogDebug(string.Format("[{0}] All Harmony patches applied successfully ({1} target(s)).", "Njoror_FairWinds", num));
				LogDebug("[Njoror_FairWinds] Fair winds, ocean storm modulation, and serpent controls active.");
			}
			catch (Exception arg)
			{
				Log.LogError((object)string.Format("[{0}] Failed to initialize: {1}", "Njoror_FairWinds", arg));
			}
		}

		private void OnDestroy()
		{
			Harmony? harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			LogDebug("[Njoror_FairWinds] Unloaded.");
		}
	}
}
namespace Njoror.Patches
{
	[HarmonyPatch(typeof(EnvMan), "UpdateWind")]
	public static class EnvManWindPatch
	{
		[HarmonyPostfix]
		public static void Postfix(EnvMan __instance, ref Vector4 ___m_wind)
		{
			//IL_009f: 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_00ab: 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_00b8: 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_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance == (Object)null)
			{
				return;
			}
			try
			{
				Vector3 baseWindDirection = default(Vector3);
				((Vector3)(ref baseWindDirection))..ctor(___m_wind.x, ___m_wind.y, ___m_wind.z);
				Vector3 direction;
				float intensity;
				if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
				{
					if (OceanWindEngine.TryGetTimedWindOverride(baseWindDirection, out var windDirection, out var decisionMade))
					{
						___m_wind = new Vector4(windDirection.x, windDirection.y, windDirection.z, ___m_wind.w);
					}
					if (decisionMade)
					{
						SailingStateNetwork.BroadcastAuthoritativeWind(new Vector3(___m_wind.x, ___m_wind.y, ___m_wind.z), ___m_wind.w);
					}
				}
				else if (SailingStateNetwork.TryGetAuthoritativeWind(out direction, out intensity))
				{
					___m_wind = new Vector4(direction.x, direction.y, direction.z, intensity);
				}
			}
			catch (Exception arg)
			{
				NjororPlugin.Log.LogError((object)$"[Njoror] Error during wind adjustment: {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(EnvMan), "SetTargetWind")]
	public static class EnvManTargetWindPatch
	{
		[HarmonyPrefix]
		public static void Prefix(ref Vector3 dir, ref float intensity)
		{
			//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_0033: 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 ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || !ModConfig.CheckDeflectOnWindChange.Value)
			{
				return;
			}
			try
			{
				dir = OceanWindEngine.AdjustWindForSailing(dir);
				intensity = OceanWindEngine.AdjustWindIntensity(intensity);
				SailingStateNetwork.BroadcastAuthoritativeWind(dir, intensity);
				NjororPlugin.LogDebug($"[Njoror][Diag] Wind-cycle fair-wind check completed: direction={dir}, intensity={intensity:F3}.");
			}
			catch (Exception arg)
			{
				NjororPlugin.Log.LogError((object)$"[Njoror] Error during wind-cycle adjustment: {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(EnvMan), "GetAvailableEnvironments")]
	public static class EnvManWeatherPatch
	{
		[HarmonyPostfix]
		public static void Postfix(List<EnvEntry> __result)
		{
			NjororPlugin.LogDebug("[Njoror][Diag] EnvMan.GetAvailableEnvironments postfix entered.");
			if (__result == null)
			{
				NjororPlugin.LogDebug("[Njoror][Diag] Environment tuning skipped: result was null.");
				return;
			}
			try
			{
				OceanWindEngine.ApplyEnvironmentWeights(__result);
			}
			catch (Exception arg)
			{
				NjororPlugin.Log.LogError((object)$"[Njoror] Error during weather weight adjustment: {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(SpawnSystem), "Awake")]
	public static class SpawnSystemSerpentPatch
	{
		[HarmonyPostfix]
		public static void Postfix(SpawnSystem __instance)
		{
			NjororPlugin.LogDebug("[Njoror][Diag] SpawnSystem.Awake postfix entered.");
			if ((Object)(object)__instance == (Object)null)
			{
				NjororPlugin.LogDebug("[Njoror][Diag] Serpent tuning skipped: SpawnSystem instance was null.");
				return;
			}
			if (__instance.m_spawnLists == null)
			{
				NjororPlugin.LogDebug("[Njoror][Diag] Serpent tuning skipped: spawn list was null.");
				return;
			}
			try
			{
				if (!ModConfig.EnableSerpentTuning.Value)
				{
					NjororPlugin.LogDebug("[Njoror][Diag] Serpent tuning skipped: disabled by configuration.");
					return;
				}
				foreach (SpawnSystemList spawnList in __instance.m_spawnLists)
				{
					if ((Object)(object)spawnList == (Object)null || spawnList.m_spawners == null)
					{
						continue;
					}
					foreach (SpawnData spawner in spawnList.m_spawners)
					{
						if (spawner != null && (Object)(object)spawner.m_prefab != (Object)null && ((Object)spawner.m_prefab).name.IndexOf("Serpent", StringComparison.OrdinalIgnoreCase) >= 0)
						{
							spawner.m_spawnInterval = ModConfig.SerpentSpawnIntervalSeconds.Value;
							spawner.m_spawnChance = ModConfig.NighttimeSerpentSpawnChance.Value;
							spawner.m_spawnAtDay = ModConfig.DaytimeSerpentSpawnChance.Value > 0f || ModConfig.AllowCalmWeatherDaySerpents.Value;
							NjororPlugin.LogDebug($"[Njoror][Diag] Configured Serpent spawner: Interval={spawner.m_spawnInterval}s, NightChance={spawner.m_spawnChance}%, DayChance={ModConfig.DaytimeSerpentSpawnChance.Value}%");
						}
					}
				}
			}
			catch (Exception arg)
			{
				NjororPlugin.Log.LogError((object)$"[Njoror] Error configuring Serpent spawners: {arg}");
			}
		}
	}
}
namespace Njoror.Logic
{
	public static class OceanWindEngine
	{
		private static readonly Random _rng = new Random();

		private static Vector3 _timedWindDirection;

		private static bool _hasTimedWindDirection;

		private static float _nextTimedCheckAt;

		public static Vector3 AdjustWindForSailing(Vector3 baseWindDir)
		{
			//IL_0020: 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_003a: 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_004f: 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_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: 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_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			NjororPlugin.LogDebug("[Njoror][Diag] AdjustWindForSailing entered.");
			if (!ModConfig.EnableFairWinds.Value)
			{
				NjororPlugin.LogDebug("[Njoror][Diag] Fair winds skipped: disabled by configuration.");
				return baseWindDir;
			}
			if (!SailingStateNetwork.TryGetActiveSailingState(out var heading, out var inOcean))
			{
				NjororPlugin.LogDebug("[Njoror][Diag] Fair winds skipped: no fresh client sailing-state report.");
				return baseWindDir;
			}
			Vector3 val = baseWindDir;
			val.y = 0f;
			((Vector3)(ref val)).Normalize();
			float num = Vector3.Dot(heading, val);
			if (ModConfig.AlwaysTailwindInOcean.Value && inOcean)
			{
				NjororPlugin.LogDebug("[Njoror][Diag] Ocean tailwind applied.");
				return heading;
			}
			if (num < -0.6f)
			{
				double num2 = _rng.NextDouble() * 100.0;
				if (num2 < (double)ModConfig.HeadwindMitigationPercent.Value)
				{
					float num3 = ((_rng.Next(2) == 0) ? 1f : (-1f));
					Vector3 val2 = Quaternion.Euler(0f, num3 * 80f, 0f) * heading;
					val2.y = 0f;
					NjororPlugin.Log.LogInfo((object)$"[Njoror] Headwind deflected; roll={num2:F2}.");
					return ((Vector3)(ref val2)).normalized;
				}
				NjororPlugin.LogDebug($"[Njoror][Diag] Headwind retained; roll={num2:F2}.");
			}
			NjororPlugin.LogDebug("[Njoror][Diag] Fair winds retained the base direction.");
			return baseWindDir;
		}

		public static float AdjustWindIntensity(float baseIntensity)
		{
			if (!ModConfig.EnableFairWinds.Value)
			{
				return baseIntensity;
			}
			float value = ModConfig.MinimumWindSpeedMultiplier.Value;
			return Mathf.Max(baseIntensity * value, 0.25f);
		}

		public static bool TryGetTimedWindOverride(Vector3 baseWindDirection, out Vector3 windDirection, out bool decisionMade)
		{
			//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_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_0089: 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)
			windDirection = baseWindDirection;
			decisionMade = false;
			if (ModConfig.CheckDeflectOnWindChange.Value || ModConfig.CheckDeflectTimeSeconds.Value <= 0)
			{
				_hasTimedWindDirection = false;
				return false;
			}
			if (Time.unscaledTime >= _nextTimedCheckAt)
			{
				_nextTimedCheckAt = Time.unscaledTime + (float)ModConfig.CheckDeflectTimeSeconds.Value;
				_timedWindDirection = AdjustWindForSailing(baseWindDirection);
				_hasTimedWindDirection = true;
				decisionMade = true;
				NjororPlugin.LogDebug($"[Njoror][Diag] Timed fair-wind check completed; next check in {ModConfig.CheckDeflectTimeSeconds.Value}s.");
			}
			if (!_hasTimedWindDirection)
			{
				return false;
			}
			windDirection = _timedWindDirection;
			return true;
		}

		public static void ApplyEnvironmentWeights(List<EnvEntry> environments)
		{
			NjororPlugin.LogDebug("[Njoror][Diag] ApplyEnvironmentWeights entered.");
			if (!ModConfig.EnableWeatherTuning.Value)
			{
				NjororPlugin.LogDebug("[Njoror][Diag] Environment tuning skipped: disabled by configuration.");
				return;
			}
			if (environments == null)
			{
				NjororPlugin.LogDebug("[Njoror][Diag] Environment tuning skipped: environment list was null.");
				return;
			}
			foreach (EnvEntry environment in environments)
			{
				if (environment != null && environment.m_env != null)
				{
					string text = environment.m_env.m_name.ToLower();
					if (text.Contains("thunder") || text.Contains("storm"))
					{
						environment.m_weight *= ModConfig.StormFrequencyMultiplier.Value;
					}
					else if (text.Contains("rain") || text.Contains("fog"))
					{
						environment.m_weight *= ModConfig.RainFrequencyMultiplier.Value;
					}
					else if (text.Contains("clear") || text.Contains("sun"))
					{
						environment.m_weight *= ModConfig.ClearWeatherFrequencyMultiplier.Value;
					}
				}
			}
			NjororPlugin.LogDebug($"[Njoror][Diag] Environment tuning processed {environments.Count} entry(s).");
		}
	}
	public sealed class SailingStateNetwork : MonoBehaviour
	{
		private struct SailingState
		{
			public Vector3 Heading { get; }

			public bool InOcean { get; }

			public float ReceivedAt { get; }

			public SailingState(Vector3 heading, bool inOcean, float receivedAt)
			{
				//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)
				Heading = heading;
				InOcean = inOcean;
				ReceivedAt = receivedAt;
			}
		}

		private const string SailingStateRpc = "Njoror_SailingState";

		private const string AuthoritativeWindRpc = "Njoror_AuthoritativeWind";

		private const float ReportIntervalSeconds = 0.5f;

		private const float StateExpirySeconds = 2f;

		private const float MinimumWindExpirySeconds = 5f;

		private const float MinimumHeadingMagnitude = 0.8f;

		private const float ShipDetectionRadius = 12f;

		private static readonly Dictionary<long, SailingState> ServerStates = new Dictionary<long, SailingState>();

		private static bool _rpcRegistered;

		private static Vector3 _authoritativeWindDirection;

		private static float _authoritativeWindIntensity;

		private static float _authoritativeWindReceivedAt;

		private static bool _hasAuthoritativeWind;

		private float _nextReportTime;

		public static void Initialize()
		{
			//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)
			//IL_0010: Expected O, but got Unknown
			GameObject val = new GameObject("Njoror_SailingStateNetwork");
			Object.DontDestroyOnLoad((Object)val);
			val.AddComponent<SailingStateNetwork>();
			NjororPlugin.LogDebug("[Njoror] Sailing-state network initialized.");
		}

		private void Update()
		{
			EnsureRpcRegistered();
			if (!((Object)(object)ZNet.instance == (Object)null) && !ZNet.instance.IsServer() && !(Time.unscaledTime < _nextReportTime))
			{
				_nextReportTime = Time.unscaledTime + 0.5f;
				ReportLocalSailingState();
			}
		}

		private static void EnsureRpcRegistered()
		{
			if (_rpcRegistered || ZRoutedRpc.instance == null)
			{
				return;
			}
			_rpcRegistered = true;
			try
			{
				ZRoutedRpc.instance.Register<bool, Vector3>("Njoror_SailingState", (Action<long, bool, Vector3>)RPC_SailingState);
			}
			catch (ArgumentException)
			{
			}
			catch (Exception ex2)
			{
				ManualLogSource log = NjororPlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[Njoror] Failed to register SailingState RPC: " + ex2.Message));
				}
			}
			try
			{
				ZRoutedRpc.instance.Register<Vector3, float>("Njoror_AuthoritativeWind", (Action<long, Vector3, float>)RPC_AuthoritativeWind);
			}
			catch (ArgumentException)
			{
			}
			catch (Exception ex4)
			{
				ManualLogSource log2 = NjororPlugin.Log;
				if (log2 != null)
				{
					log2.LogWarning((object)("[Njoror] Failed to register AuthoritativeWind RPC: " + ex4.Message));
				}
			}
			NjororPlugin.LogDebug("[Njoror] Sailing-state and authoritative-wind RPCs registered.");
		}

		private static void ReportLocalSailingState()
		{
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: 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_0056: 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_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			Ship val = (((Object)(object)localPlayer != (Object)null) ? localPlayer.GetControlledShip() : null);
			string arg = "ship helm";
			if ((Object)(object)val == (Object)null && (Object)(object)localPlayer != (Object)null)
			{
				val = ((Character)localPlayer).GetStandingOnShip();
				arg = "GetStandingOnShip";
			}
			if ((Object)(object)val == (Object)null && (Object)(object)localPlayer != (Object)null)
			{
				val = FindNearbyShip(((Component)localPlayer).transform.position);
				arg = "nearby ship fallback";
			}
			bool flag = (Object)(object)val != (Object)null;
			Vector3 val2 = (((Object)(object)val != (Object)null) ? FlattenAndNormalize(((Component)val).transform.forward) : Vector3.zero);
			ZRoutedRpc.instance.InvokeRoutedRPC(0L, "Njoror_SailingState", new object[2] { flag, val2 });
			NjororPlugin.LogDebug($"[Njoror][Diag] Reported local sailing state: active={flag}, heading={val2}, detection={arg}.");
		}

		private static Ship? FindNearbyShip(Vector3 playerPosition)
		{
			//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_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			Ship result = null;
			float num = 144f;
			Ship[] array = Object.FindObjectsOfType<Ship>();
			foreach (Ship val in array)
			{
				if (!((Object)(object)val == (Object)null))
				{
					Vector3 val2 = ((Component)val).transform.position - playerPosition;
					float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
					if (sqrMagnitude < num)
					{
						result = val;
						num = sqrMagnitude;
					}
				}
			}
			return result;
		}

		private static void RPC_SailingState(long sender, bool reportedSailing, Vector3 reportedHeading)
		{
			//IL_005c: 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_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Invalid comparison between Unknown and I4
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
			{
				return;
			}
			ZNetPeer peer = ZNet.instance.GetPeer(sender);
			if (peer == null || ((ZDOID)(ref peer.m_characterID)).IsNone())
			{
				NjororPlugin.LogDebug($"[Njoror][Diag] Rejected sailing state from {sender}: no connected character.");
				return;
			}
			ZDO val = ((ZDOMan.instance != null) ? ZDOMan.instance.GetZDO(peer.m_characterID) : null);
			if (val == null)
			{
				NjororPlugin.LogDebug($"[Njoror][Diag] Rejected sailing state from {sender}: character ZDO unavailable.");
				return;
			}
			if (!reportedSailing)
			{
				ServerStates.Remove(sender);
				NjororPlugin.LogDebug($"[Njoror][Diag] Cleared sailing state for {sender}.");
				return;
			}
			Vector3 val2 = FlattenAndNormalize(reportedHeading);
			if (((Vector3)(ref val2)).sqrMagnitude < 0.64000005f)
			{
				NjororPlugin.LogDebug($"[Njoror][Diag] Rejected sailing state from {sender}: invalid heading.");
				return;
			}
			Vector3 position = val.GetPosition();
			bool flag = WorldGenerator.instance != null && (int)WorldGenerator.instance.GetBiome(position.x, position.z, 0.02f, false) == 256;
			ServerStates[sender] = new SailingState(val2, flag, Time.unscaledTime);
			NjororPlugin.LogDebug($"[Njoror][Diag] Accepted sailing state from {sender}: ocean={flag}, heading={val2}.");
		}

		private static void RPC_AuthoritativeWind(long sender, Vector3 direction, float intensity)
		{
			//IL_001a: 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_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)ZNet.instance == (Object)null) && !ZNet.instance.IsServer())
			{
				direction = FlattenAndNormalize(direction);
				if (((Vector3)(ref direction)).sqrMagnitude < 0.64000005f || intensity < 0.05f || intensity > 1f)
				{
					NjororPlugin.LogDebug($"[Njoror][Diag] Rejected authoritative wind from {sender}: invalid payload.");
					return;
				}
				_authoritativeWindDirection = direction;
				_authoritativeWindIntensity = intensity;
				_authoritativeWindReceivedAt = Time.unscaledTime;
				_hasAuthoritativeWind = true;
				NjororPlugin.LogDebug($"[Njoror][Diag] Received authoritative wind: direction={direction}, intensity={intensity:F3}.");
			}
		}

		public static void BroadcastAuthoritativeWind(Vector3 direction, float intensity)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || ZRoutedRpc.instance == null)
			{
				return;
			}
			foreach (ZNetPeer peer in ZNet.instance.GetPeers())
			{
				if (peer != null)
				{
					ZRoutedRpc.instance.InvokeRoutedRPC(peer.m_uid, "Njoror_AuthoritativeWind", new object[2] { direction, intensity });
				}
			}
			NjororPlugin.LogDebug($"[Njoror][Diag] Broadcast authoritative wind: direction={direction}, intensity={intensity:F3}.");
		}

		public static bool TryGetAuthoritativeWind(out Vector3 direction, out float intensity)
		{
			//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_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			direction = Vector3.zero;
			intensity = 0f;
			float num = Mathf.Max(5f, (float)ModConfig.CheckDeflectTimeSeconds.Value + 2f);
			if (!_hasAuthoritativeWind || Time.unscaledTime - _authoritativeWindReceivedAt > num)
			{
				return false;
			}
			direction = _authoritativeWindDirection;
			intensity = _authoritativeWindIntensity;
			return true;
		}

		public static bool TryGetActiveSailingState(out Vector3 heading, out bool inOcean)
		{
			//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_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			heading = Vector3.zero;
			inOcean = false;
			if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
			{
				return false;
			}
			long num = 0L;
			float num2 = float.MinValue;
			foreach (KeyValuePair<long, SailingState> serverState in ServerStates)
			{
				if (!(Time.unscaledTime - serverState.Value.ReceivedAt > 2f) && serverState.Value.ReceivedAt > num2)
				{
					num = serverState.Key;
					num2 = serverState.Value.ReceivedAt;
					heading = serverState.Value.Heading;
					inOcean = serverState.Value.InOcean;
				}
			}
			if (num == 0L)
			{
				return false;
			}
			return true;
		}

		private static Vector3 FlattenAndNormalize(Vector3 vector)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			vector.y = 0f;
			if (!(((Vector3)(ref vector)).sqrMagnitude > 0f))
			{
				return Vector3.zero;
			}
			return ((Vector3)(ref vector)).normalized;
		}
	}
}
namespace Njoror.Configuration
{
	public static class ModConfig
	{
		public static ConfigEntry<bool> EnableFairWinds { get; private set; }

		public static ConfigEntry<float> HeadwindMitigationPercent { get; private set; }

		public static ConfigEntry<float> MinimumWindSpeedMultiplier { get; private set; }

		public static ConfigEntry<bool> AlwaysTailwindInOcean { get; private set; }

		public static ConfigEntry<bool> CheckDeflectOnWindChange { get; private set; }

		public static ConfigEntry<int> CheckDeflectTimeSeconds { get; private set; }

		public static ConfigEntry<bool> EnableWeatherTuning { get; private set; }

		public static ConfigEntry<float> StormFrequencyMultiplier { get; private set; }

		public static ConfigEntry<float> RainFrequencyMultiplier { get; private set; }

		public static ConfigEntry<float> ClearWeatherFrequencyMultiplier { get; private set; }

		public static ConfigEntry<bool> EnableSerpentTuning { get; private set; }

		public static ConfigEntry<float> DaytimeSerpentSpawnChance { get; private set; }

		public static ConfigEntry<float> NighttimeSerpentSpawnChance { get; private set; }

		public static ConfigEntry<float> SerpentSpawnIntervalSeconds { get; private set; }

		public static ConfigEntry<bool> AllowCalmWeatherDaySerpents { get; private set; }

		public static ConfigEntry<bool> EnableDebugLogging { get; private set; }

		public static void Initialize(ConfigFile config)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Expected O, but got Unknown
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Expected O, but got Unknown
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: 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_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Expected O, but got Unknown
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Expected O, but got Unknown
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: Expected O, but got Unknown
			//IL_0268: Unknown result type (might be due to invalid IL or missing references)
			//IL_0272: Expected O, but got Unknown
			EnableFairWinds = config.Bind<bool>("1 - Fair Winds", "EnableFairWinds", true, "Enable fair winds while a client with Njoror reports that it is aboard a ship. The server validates and applies the global wind change.");
			HeadwindMitigationPercent = config.Bind<float>("1 - Fair Winds", "HeadwindMitigationPercent", 60f, new ConfigDescription("Chance % to deflect a direct dead-ahead headwind into a tackable crosswind/quarter wind when sailing.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
			MinimumWindSpeedMultiplier = config.Bind<float>("1 - Fair Winds", "MinimumWindSpeedMultiplier", 1f, new ConfigDescription("Minimum wind velocity scaling factor (1.0 = Vanilla, >1.0 ensures ships always have at least moderate breeze).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 2.5f), Array.Empty<object>()));
			AlwaysTailwindInOcean = config.Bind<bool>("1 - Fair Winds", "AlwaysTailwindInOcean", false, "If enabled, an active Njoror client sailing in the Ocean biome receives a global tailwind or broad reach.");
			CheckDeflectOnWindChange = config.Bind<bool>("1 - Fair Winds", "CheckDeflectOnWindChange", true, "If enabled, evaluate fair-wind deflection only when Valheim selects a new wind target. This takes priority over timed checks.");
			CheckDeflectTimeSeconds = config.Bind<int>("1 - Fair Winds", "CheckDeflectTimeSeconds", 0, new ConfigDescription("When CheckDeflectOnWindChange is disabled, re-evaluate fair winds at this interval. Set to 0 to disable timed checks.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 3600), Array.Empty<object>()));
			EnableWeatherTuning = config.Bind<bool>("2 - Weather & Storms", "EnableWeatherTuning", true, "Enable dynamic modulation of ocean storms and atmospheric weather conditions.");
			StormFrequencyMultiplier = config.Bind<float>("2 - Weather & Storms", "StormFrequencyMultiplier", 1f, new ConfigDescription("Multiplier for the frequency and duration of ThunderStorms (1.0 = Vanilla, 0.5 = Calmer, 2.0 = Violent).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 3f), Array.Empty<object>()));
			RainFrequencyMultiplier = config.Bind<float>("2 - Weather & Storms", "RainFrequencyMultiplier", 1f, new ConfigDescription("Multiplier for regular rain and overcast conditions (1.0 = Vanilla).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 3f), Array.Empty<object>()));
			ClearWeatherFrequencyMultiplier = config.Bind<float>("2 - Weather & Storms", "ClearWeatherFrequencyMultiplier", 1f, new ConfigDescription("Multiplier for clear, sunny weather frequency (1.0 = Vanilla, >1.0 for more clear sailing days).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 3f), Array.Empty<object>()));
			EnableSerpentTuning = config.Bind<bool>("3 - Sea Serpents", "EnableSerpentTuning", true, "Enable custom encounter rate tuning for Ocean Sea Serpents.");
			DaytimeSerpentSpawnChance = config.Bind<float>("3 - Sea Serpents", "DaytimeSerpentSpawnChance", 0f, new ConfigDescription("Base chance % for a Sea Serpent to spawn during clear/calm Day conditions. (Vanilla default is 0.0% / storms only).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 30f), Array.Empty<object>()));
			NighttimeSerpentSpawnChance = config.Bind<float>("3 - Sea Serpents", "NighttimeSerpentSpawnChance", 5f, new ConfigDescription("Base chance % for a Sea Serpent to spawn during Night hours. (Vanilla default is 5.0%).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 50f), Array.Empty<object>()));
			SerpentSpawnIntervalSeconds = config.Bind<float>("3 - Sea Serpents", "SerpentSpawnIntervalSeconds", 1000f, new ConfigDescription("Time interval (seconds) between Ocean spawner serpent spawn checks. (Vanilla default is 1000.0s).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(100f, 2000f), Array.Empty<object>()));
			AllowCalmWeatherDaySerpents = config.Bind<bool>("3 - Sea Serpents", "AllowCalmWeatherDaySerpents", false, "If true, Sea Serpents can spawn during daytime even when it is not storming or raining.");
			EnableDebugLogging = config.Bind<bool>("4 - Diagnostics", "EnableDebugLogging", false, "Enable detailed Njoror diagnostic logs. Errors and successful headwind deflections are always logged.");
		}
	}
}