using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("ChaoticWind")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.4.3.0")]
[assembly: AssemblyInformationalVersion("1.4.3")]
[assembly: AssemblyProduct("ChaoticWind")]
[assembly: AssemblyTitle("ChaoticWind")]
[assembly: InternalsVisibleTo("ChaoticWind.Tests")]
[assembly: AssemblyVersion("1.4.3.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace ChaoticWind
{
internal static class LandDistance
{
internal const float PlaceholderMinimum = 999999f;
internal const float OceanBonusStart = 1500f;
internal static bool IsMeasured(float distance)
{
return distance < 999999f;
}
internal static bool HasOceanBonus(float distance)
{
return distance > 1500f;
}
}
internal sealed class ConfigurationManagerAttributes
{
public bool? ShowRangeAsPercent;
public string DispName;
public int? Order;
}
internal sealed class SteppedAcceptableValueRange : AcceptableValueRange<float>
{
private readonly float step;
internal SteppedAcceptableValueRange(float minimum, float maximum, float step)
: base(minimum, maximum)
{
this.step = step;
}
public override object Clamp(object value)
{
float num = (float)base.Clamp(value);
return Mathf.Clamp(((AcceptableValueRange<float>)this).MinValue + Mathf.Floor((num - ((AcceptableValueRange<float>)this).MinValue) / step + 0.5f) * step, ((AcceptableValueRange<float>)this).MinValue, ((AcceptableValueRange<float>)this).MaxValue);
}
public override bool IsValid(object value)
{
if (!(value is float num))
{
return false;
}
float num2 = (float)((AcceptableValueBase)this).Clamp((object)num);
return Mathf.Approximately(num, num2);
}
}
[BepInPlugin("com.pete.sailwind.windconfigurator", "Chaotic Wind", "1.4.3")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public sealed class ChaoticWindPlugin : BaseUnityPlugin
{
private enum SimpleTradeWindArea
{
None,
MidLatitude,
UpperMidLatitude,
Northern
}
private static readonly FieldInfo RegionBlenderTargetRegionField = AccessTools.Field(typeof(RegionBlender), "currentTargetRegion");
private static readonly MethodInfo WindSetNewGustTargetMethod = AccessTools.Method(typeof(Wind), "SetNewGustTarget", (Type[])null, (Type[])null);
public const string PluginGuid = "com.pete.sailwind.windconfigurator";
public const string PluginName = "Chaotic Wind";
public const string PluginVersion = "1.4.3";
public const string BorderExpanderGuid = "com.nandbrew.borderexpander";
public const string ClimatePluginGuid = "com.raddude.climate";
private const float DefaultAlAnkhDirectionChaos = 0.14f;
private const float DefaultEmeraldDirectionChaos = 0.18f;
private const float DefaultFireFishDirectionChaos = 0.25f;
private const float DefaultAestrinDirectionChaos = 0.21f;
private const float DefaultChronosDirectionChaos = 0.21f;
private const float DefaultWindChangeTimer = 40f;
private const float DefaultFinalLerpSpeed = 0.5f;
private const float DefaultCombinedBonusCap = 20f;
private const float MidCycleSouthLatitude = 30f;
private const float MidCycleCalmLatitude = 32f;
private const float MidCycleNorthLatitude = 33f;
private const float MidCycleEastLongitudeLimit = 7f;
private ConfigEntry<float> alAnkhDirectionChaos;
private ConfigEntry<float> emeraldDirectionChaos;
private ConfigEntry<float> fireFishDirectionChaos;
private ConfigEntry<float> aestrinDirectionChaos;
private ConfigEntry<float> chronosDirectionChaos;
private ConfigEntry<float> windChangeTimer;
private ConfigEntry<bool> overrideFinalLerpSpeed;
private ConfigEntry<float> finalLerpSpeed;
private ConfigEntry<bool> additionalOceanScaling;
private ConfigEntry<float> combinedBonusCap;
private Harmony harmony;
private Wind trackedWind;
private float capturedWindChangeTimer;
private float capturedFinalLerpSpeed;
private bool hasCapturedFinalLerpSpeed;
private bool finalLerpOverrideApplied;
private int lastTradeWindRetargetSample = int.MinValue;
private bool pendingWindRetarget;
private bool awaitingLandDistance;
public static ChaoticWindPlugin Instance { get; private set; }
public ConfigEntry<bool> EnableTradeWind { get; private set; }
public ConfigEntry<bool> SimpleTradeWindCycle { get; private set; }
public bool TradeWindEnabled
{
get
{
if (EnableTradeWind != null)
{
return EnableTradeWind.Value;
}
return true;
}
}
public bool TradeWindDisabled => !TradeWindEnabled;
public bool TradeWindCycleEnabled
{
get
{
if (TradeWindEnabled)
{
if (SimpleTradeWindCycle != null)
{
return SimpleTradeWindCycle.Value;
}
return true;
}
return false;
}
}
public bool TradeWindOverrideActive
{
get
{
if (TradeWindDisabled)
{
return !ClimateCustomWindsActive();
}
return false;
}
}
private void Awake()
{
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: Expected O, but got Unknown
Instance = this;
BindConfiguration();
SubscribeToConfiguration();
harmony = new Harmony("com.pete.sailwind.windconfigurator");
harmony.PatchAll(Assembly.GetExecutingAssembly());
ClimateCompatibility.Install(harmony);
ApplyRuntimeSettings();
((BaseUnityPlugin)this).Logger.LogInfo((object)"Chaotic Wind 1.4.3 loaded.");
}
private void OnDestroy()
{
UnsubscribeFromConfiguration();
pendingWindRetarget = false;
if ((Object)(object)trackedWind != (Object)null)
{
trackedWind.changeTimer = capturedWindChangeTimer;
if (finalLerpOverrideApplied && hasCapturedFinalLerpSpeed)
{
trackedWind.finalLerpSpeed = capturedFinalLerpSpeed;
}
}
Harmony obj = harmony;
if (obj != null)
{
obj.UnpatchSelf();
}
if ((Object)(object)Instance == (Object)(object)this)
{
Instance = null;
}
}
private void Update()
{
UpdateTradeWindRetargeting();
UpdateLandDistanceRetargeting();
}
private void BindConfiguration()
{
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_003d: Expected O, but got Unknown
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
//IL_007f: Expected O, but got Unknown
EnableTradeWind = ((BaseUnityPlugin)this).Config.Bind<bool>("Trade Wind", "Enable Trade Wind", true, new ConfigDescription("Enable trade winds and allow the optional trade-wind cycle below. Turn this off to disable all trade winds. Ignored while Climate Custom Winds is enabled.", (AcceptableValueBase)null, new object[1]
{
new ConfigurationManagerAttributes
{
Order = 20
}
}));
SimpleTradeWindCycle = ((BaseUnityPlugin)this).Config.Bind<bool>("Trade Wind", "Simple Trade wind cycle", false, new ConfigDescription("Enable a 20-day trade-wind cycle between the Al'Ankh and Emerald trade winds from 30N-33N, up to 7E longitude. During the Emerald cycle, 32N-33N has no trade wind as in vanilla. Above 33N, ENE and ESE follow the same cycle, starting with ENE. Each transition takes one in-game day.", (AcceptableValueBase)null, new object[1]
{
new ConfigurationManagerAttributes
{
Order = 10
}
}));
alAnkhDirectionChaos = BindDirectionChaos("AlAnkh", "Al'Ankh", 0.14f, 50);
emeraldDirectionChaos = BindDirectionChaos("Emerald", "Emerald", 0.18f, 40);
fireFishDirectionChaos = BindDirectionChaos("Fire Fish Lagoon", "Fire Fish Lagoon", 0.25f, 30);
aestrinDirectionChaos = BindDirectionChaos("Aestrin", "Aestrin", 0.21f, 20);
chronosDirectionChaos = BindDirectionChaos("Chronos", "Chronos", 0.21f, 10);
windChangeTimer = BindSlider("Wind Timing", "Wind Change Timer", 40f, 2f, 900f, 1f, "Adjusts in increments of 1 second. The actual change interval is randomly selected from half to double this value. Values above 600 seconds are recommended with extreme Direction Chaos settings.", 10);
overrideFinalLerpSpeed = ((BaseUnityPlugin)this).Config.Bind<bool>("Wind Smoothing", "Override Final Lerp Speed", false, "Enable the Final Lerp Speed slider override for normal wind behavior. A separate storm mod may temporarily override it while inside a storm.");
finalLerpSpeed = BindSlider("Wind Smoothing", "Final Lerp Speed", 0.5f, 0.1f, 60f, 0.01f, "Adjusts in increments of 0.01. Higher values make wind speed change faster. At 60 this setting changes wind speed almost instantly at 60 FPS. USE AT YOUR OWN RISK.", 10);
additionalOceanScaling = ((BaseUnityPlugin)this).Config.Bind<bool>("Open Ocean Wind", "Enable Additional Ocean Scaling", false, "Continue ocean scaling beyond 4,000 units, reaching 2.3 (~1.52x Base Wind as bonus) at 72,000 units. Ignored while Climate Custom Winds is enabled.");
combinedBonusCap = BindSlider("Open Ocean Wind", "Storm + Ocean Bonus Cap", 20f, 0f, 100f, 1f, "Adjusts in increments of 1. Maximum combined storm and ocean wind bonus. Original game value is 20. Also overrides Climate Custom Winds and is available to Better Storm.", 10);
}
private void UpdateTradeWindRetargeting()
{
Wind instance = Wind.instance;
if (!GameState.playing || (Object)(object)instance == (Object)null || (Object)(object)Sun.sun == (Object)null)
{
lastTradeWindRetargetSample = int.MinValue;
return;
}
if (ClimateCustomWindsActive() || !TradeWindCycleEnabled)
{
lastTradeWindRetargetSample = int.MinValue;
return;
}
int retargetSample = TradeWindCycle.GetRetargetSample(GetCurrentAbsoluteDay());
if (lastTradeWindRetargetSample == int.MinValue)
{
lastTradeWindRetargetSample = retargetSample;
}
else if (retargetSample != lastTradeWindRetargetSample)
{
lastTradeWindRetargetSample = retargetSample;
if (TryGetPlayerCoordinates(out var longitude, out var latitude) && GetSimpleTradeWindArea(longitude, latitude) != SimpleTradeWindArea.None)
{
RequestWindRetarget();
}
}
}
private void UpdateLandDistanceRetargeting()
{
if (!awaitingLandDistance)
{
return;
}
float distanceToLand = GameState.distanceToLand;
if (LandDistance.IsMeasured(distanceToLand))
{
awaitingLandDistance = false;
if (LandDistance.HasOceanBonus(distanceToLand))
{
RequestWindRetarget();
}
}
}
private void RequestWindRetarget()
{
if (!((Object)(object)Wind.instance == (Object)null))
{
pendingWindRetarget = true;
Wind.instance.debugChangeWind = true;
}
}
internal void CompleteRequestedWindRetarget(Wind wind)
{
if (!pendingWindRetarget || (Object)(object)wind != (Object)(object)Wind.instance)
{
return;
}
pendingWindRetarget = false;
try
{
WindSetNewGustTargetMethod?.Invoke(wind, null);
}
catch (Exception ex)
{
LogFeatureError("Could not refresh the gust target after a requested wind retarget: " + ex);
}
}
private ConfigEntry<float> BindDirectionChaos(string key, string displayName, float defaultValue, int order)
{
return BindSlider("Direction Chaos", key, defaultValue, 0.01f, 1f, 0.01f, "Direction chaos for " + displayName + ". Adjusts in increments of 0.01.", order, displayName);
}
private ConfigEntry<float> BindSlider(string section, string key, float defaultValue, float minimum, float maximum, float step, string description, int order, string displayName = null)
{
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Expected O, but got Unknown
ConfigurationManagerAttributes configurationManagerAttributes = new ConfigurationManagerAttributes
{
ShowRangeAsPercent = false,
DispName = displayName,
Order = order
};
return ((BaseUnityPlugin)this).Config.Bind<float>(section, key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)(object)new SteppedAcceptableValueRange(minimum, maximum, step), new object[1] { configurationManagerAttributes }));
}
private void SubscribeToConfiguration()
{
alAnkhDirectionChaos.SettingChanged += OnRegionSettingChanged;
emeraldDirectionChaos.SettingChanged += OnRegionSettingChanged;
fireFishDirectionChaos.SettingChanged += OnRegionSettingChanged;
aestrinDirectionChaos.SettingChanged += OnRegionSettingChanged;
chronosDirectionChaos.SettingChanged += OnRegionSettingChanged;
EnableTradeWind.SettingChanged += OnWindSettingChanged;
SimpleTradeWindCycle.SettingChanged += OnWindSettingChanged;
windChangeTimer.SettingChanged += OnWindSettingChanged;
overrideFinalLerpSpeed.SettingChanged += OnWindSettingChanged;
finalLerpSpeed.SettingChanged += OnWindSettingChanged;
}
private void UnsubscribeFromConfiguration()
{
alAnkhDirectionChaos.SettingChanged -= OnRegionSettingChanged;
emeraldDirectionChaos.SettingChanged -= OnRegionSettingChanged;
fireFishDirectionChaos.SettingChanged -= OnRegionSettingChanged;
aestrinDirectionChaos.SettingChanged -= OnRegionSettingChanged;
chronosDirectionChaos.SettingChanged -= OnRegionSettingChanged;
EnableTradeWind.SettingChanged -= OnWindSettingChanged;
SimpleTradeWindCycle.SettingChanged -= OnWindSettingChanged;
windChangeTimer.SettingChanged -= OnWindSettingChanged;
overrideFinalLerpSpeed.SettingChanged -= OnWindSettingChanged;
finalLerpSpeed.SettingChanged -= OnWindSettingChanged;
}
private void OnRegionSettingChanged(object sender, EventArgs e)
{
ApplyRegionSettings();
ApplyActiveRegionChaos();
}
private void OnWindSettingChanged(object sender, EventArgs e)
{
if ((sender == EnableTradeWind || sender == SimpleTradeWindCycle) && (Object)(object)Wind.instance != (Object)null)
{
lastTradeWindRetargetSample = int.MinValue;
RequestWindRetarget();
}
TrackAndApplyWind(Wind.instance);
}
private void ApplyRuntimeSettings()
{
ApplyRegionSettings();
TrackAndApplyWind(Wind.instance);
ApplyActiveRegionChaos();
}
public void ApplyRegionSettings()
{
Region[] array = Object.FindObjectsOfType<Region>();
foreach (Region val in array)
{
if (TryGetChaosForRegion(val, out var chaos))
{
val.windDirChaos = chaos;
}
}
}
internal void ApplyActiveRegionChaos()
{
if (!((Object)(object)Weather.instance == (Object)null) && !((Object)(object)Weather.instance.currentRegion == (Object)null))
{
Region currentGameplayRegion = GetCurrentGameplayRegion();
if (TryGetChaosForRegion(currentGameplayRegion, out var chaos))
{
Weather.instance.currentRegion.windDirChaos = chaos;
}
}
}
internal static Region GetCurrentGameplayRegion()
{
Region regionBlenderTargetRegion = GetRegionBlenderTargetRegion();
if (!((Object)(object)regionBlenderTargetRegion != (Object)null))
{
return Weather.instance?.currentRegion;
}
return regionBlenderTargetRegion;
}
private static Region GetRegionBlenderTargetRegion()
{
if ((Object)(object)RegionBlender.instance == (Object)null)
{
return null;
}
object? obj = RegionBlenderTargetRegionField?.GetValue(RegionBlender.instance);
return (Region)((obj is Region) ? obj : null);
}
private bool TryGetChaosForRegion(Region region, out float chaos)
{
chaos = 0f;
if ((Object)(object)region == (Object)null)
{
return false;
}
switch (((Object)((Component)region).gameObject).name)
{
case "Region Al'ankh":
case "Region Equatorial":
case "Region Mid Latitude":
chaos = alAnkhDirectionChaos.Value;
return true;
case "Region Emerald (new smaller)":
chaos = emeraldDirectionChaos.Value;
return true;
case "Region Emerald Lagoon":
chaos = fireFishDirectionChaos.Value;
return true;
case "Region Medi":
chaos = aestrinDirectionChaos.Value;
return true;
case "Region Medi East":
case "Region Northern":
chaos = chronosDirectionChaos.Value;
return true;
default:
return false;
}
}
public void TrackAndApplyWind(Wind wind)
{
if (!((Object)(object)wind == (Object)null))
{
if ((Object)(object)trackedWind != (Object)(object)wind)
{
pendingWindRetarget = false;
lastTradeWindRetargetSample = int.MinValue;
trackedWind = wind;
capturedWindChangeTimer = wind.changeTimer;
capturedFinalLerpSpeed = wind.finalLerpSpeed;
hasCapturedFinalLerpSpeed = true;
finalLerpOverrideApplied = false;
}
wind.changeTimer = windChangeTimer.Value;
if (overrideFinalLerpSpeed.Value)
{
wind.finalLerpSpeed = finalLerpSpeed.Value;
finalLerpOverrideApplied = true;
}
else if (finalLerpOverrideApplied && hasCapturedFinalLerpSpeed)
{
wind.finalLerpSpeed = capturedFinalLerpSpeed;
finalLerpOverrideApplied = false;
}
}
}
internal void LogFeatureInfo(string message)
{
((BaseUnityPlugin)this).Logger.LogInfo((object)message);
}
internal void LogFeatureWarning(string message)
{
((BaseUnityPlugin)this).Logger.LogWarning((object)message);
}
internal void LogFeatureError(string message)
{
((BaseUnityPlugin)this).Logger.LogError((object)message);
}
public void EnforceTradeWindOverride(Wind wind, ref Vector3 result)
{
//IL_000c: 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 (TryGetTradeWindOverride(wind, out var result2))
{
result = result2;
}
}
internal bool TryGetTradeWindOverride(Wind wind, out Vector3 result)
{
//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_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: 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_0070: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
result = Vector3.zero;
if (ClimateCustomWindsActive())
{
return false;
}
if (TradeWindDisabled)
{
return true;
}
if (!TradeWindCycleEnabled)
{
return false;
}
if (!TryGetPlayerCoordinates(out var longitude, out var latitude))
{
return false;
}
SimpleTradeWindArea simpleTradeWindArea = GetSimpleTradeWindArea(longitude, latitude);
if (simpleTradeWindArea == SimpleTradeWindArea.None)
{
return false;
}
float currentAbsoluteDay = GetCurrentAbsoluteDay();
switch (simpleTradeWindArea)
{
case SimpleTradeWindArea.MidLatitude:
result = TradeWindCycle.GetMidLatitudeDirection(currentAbsoluteDay);
break;
case SimpleTradeWindArea.UpperMidLatitude:
result = TradeWindCycle.GetUpperMidLatitudeDirection(currentAbsoluteDay);
break;
default:
result = TradeWindCycle.GetNorthernDirection(currentAbsoluteDay);
break;
}
return true;
}
private static SimpleTradeWindArea GetSimpleTradeWindArea(float longitude, float latitude)
{
if (latitude > 33f)
{
return SimpleTradeWindArea.Northern;
}
if (latitude < 30f || longitude > 7f)
{
return SimpleTradeWindArea.None;
}
if (!(latitude >= 32f))
{
return SimpleTradeWindArea.MidLatitude;
}
return SimpleTradeWindArea.UpperMidLatitude;
}
private static bool TryGetPlayerCoordinates(out float longitude, out float latitude)
{
//IL_0039: 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_0040: 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)
longitude = 0f;
latitude = 0f;
if ((Object)(object)FloatingOriginManager.instance == (Object)null || (Object)(object)Refs.observerMirror == (Object)null)
{
return false;
}
Vector3 globeCoords = FloatingOriginManager.instance.GetGlobeCoords(((Component)Refs.observerMirror).transform);
longitude = globeCoords.x;
latitude = globeCoords.z;
return true;
}
private static float GetCurrentAbsoluteDay()
{
float num = (((Object)(object)Sun.sun != (Object)null) ? (Mathf.Repeat(Sun.sun.globalTime, 24f) / 24f) : 0f);
return (float)Mathf.Max(0, GameState.day) + num;
}
internal static float GetConfiguredOceanLerp(float originalMinimum, float originalMaximum, float distance)
{
if (IsPlaceholderLandDistance(distance))
{
return 0f;
}
ChaoticWindPlugin instance = Instance;
if ((Object)(object)instance == (Object)null || !instance.additionalOceanScaling.Value)
{
return Mathf.InverseLerp(originalMinimum, originalMaximum, distance);
}
if (!(distance <= 4000f))
{
return Mathf.Lerp(1f, 2.3f, Mathf.InverseLerp(4000f, 72000f, distance));
}
return Mathf.InverseLerp(1500f, 4000f, distance);
}
internal static float GetClimateOceanLerp(float originalMinimum, float originalMaximum, float distance)
{
if (!IsPlaceholderLandDistance(distance))
{
return Mathf.InverseLerp(originalMinimum, originalMaximum, distance);
}
return 0f;
}
private static bool IsPlaceholderLandDistance(float distance)
{
if (LandDistance.IsMeasured(distance))
{
return false;
}
ChaoticWindPlugin instance = Instance;
if ((Object)(object)instance != (Object)null)
{
instance.awaitingLandDistance = true;
}
return true;
}
internal static float GetConfiguredBonusCap()
{
if (!((Object)(object)Instance == (Object)null))
{
return Instance.combinedBonusCap.Value;
}
return 20f;
}
internal static bool ClimateCustomWindsActive()
{
if (!GameState.playing || !Chainloader.PluginInfos.TryGetValue("com.raddude.climate", out var value) || (Object)(object)value.Instance == (Object)null)
{
return false;
}
ConfigEntry<bool> val = default(ConfigEntry<bool>);
if (value.Instance.Config.TryGetEntry<bool>("Settings", "Enable Custom Winds", ref val))
{
return val.Value;
}
return false;
}
}
[HarmonyPatch(typeof(Wind), "GetCurrentTradeWind")]
internal static class GetCurrentTradeWindPatch
{
[HarmonyPrefix]
[HarmonyPriority(600)]
[HarmonyBefore(new string[] { "com.nandbrew.borderexpander" })]
private static bool Prefix(Wind __instance, ref Vector3 __result)
{
//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)
ChaoticWindPlugin instance = ChaoticWindPlugin.Instance;
if ((Object)(object)instance == (Object)null || !instance.TryGetTradeWindOverride(__instance, out var result))
{
return true;
}
__result = result;
return false;
}
[HarmonyPostfix]
[HarmonyAfter(new string[] { "com.nandbrew.borderexpander" })]
private static void Postfix(Wind __instance, ref Vector3 __result)
{
ChaoticWindPlugin.Instance?.EnforceTradeWindOverride(__instance, ref __result);
}
}
[HarmonyPatch(typeof(Wind), "Awake")]
internal static class WindAwakePatch
{
[HarmonyPostfix]
private static void Postfix(Wind __instance)
{
ChaoticWindPlugin.Instance?.TrackAndApplyWind(__instance);
}
}
[HarmonyPatch(typeof(Wind), "SetNewWindTarget")]
internal static class WindSetNewTargetPatch
{
[HarmonyPrefix]
[HarmonyPriority(600)]
[HarmonyBefore(new string[] { "com.raddude.climate" })]
private static void Prefix()
{
ChaoticWindPlugin.Instance?.ApplyActiveRegionChaos();
}
[HarmonyPostfix]
private static void Postfix(Wind __instance)
{
ChaoticWindPlugin.Instance?.CompleteRequestedWindRetarget(__instance);
}
[HarmonyTranspiler]
[HarmonyPriority(0)]
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
return WindIlRewriter.RewriteVanilla(instructions);
}
}
[HarmonyPatch(typeof(RegionBlender), "Start")]
internal static class RegionBlenderStartPatch
{
[HarmonyPostfix]
[HarmonyAfter(new string[] { "com.nandbrew.borderexpander" })]
private static void Postfix()
{
ChaoticWindPlugin.Instance?.ApplyRegionSettings();
ChaoticWindPlugin.Instance?.ApplyActiveRegionChaos();
}
}
internal static class TradeWindCycle
{
internal const float PhaseLengthDays = 20f;
internal const float TransitionLengthDays = 1f;
internal const int TransitionRetargetSteps = 20;
private static readonly Vector3 NorthEast;
private static readonly Vector3 SouthWest;
private static readonly Vector3 EastNorthEast;
private static readonly Vector3 EastSouthEast;
internal static Vector3 GetMidLatitudeDirection(float absoluteDay)
{
//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_000b: Unknown result type (might be due to invalid IL or missing references)
return GetAlternatingDirection(absoluteDay, NorthEast, SouthWest);
}
internal static Vector3 GetNorthernDirection(float absoluteDay)
{
//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_000b: Unknown result type (might be due to invalid IL or missing references)
return GetAlternatingDirection(absoluteDay, EastNorthEast, EastSouthEast);
}
internal static Vector3 GetUpperMidLatitudeDirection(float absoluteDay)
{
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: 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_0049: 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_005e: 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_007b: Unknown result type (might be due to invalid IL or missing references)
//IL_007e: Unknown result type (might be due to invalid IL or missing references)
absoluteDay = Mathf.Max(0f, absoluteDay);
if (absoluteDay < 20f)
{
return NorthEast;
}
int num = Mathf.FloorToInt(absoluteDay / 20f);
float num2 = absoluteDay - (float)num * 20f;
bool flag = num % 2 == 0;
Vector3 val = (flag ? NorthEast : Vector3.zero);
if (num2 >= 1f)
{
return val;
}
Vector3 val2 = (flag ? Vector3.zero : NorthEast);
float num3 = Mathf.SmoothStep(0f, 1f, num2 / 1f);
return Vector3.Lerp(val2, val, num3);
}
private static Vector3 GetAlternatingDirection(float absoluteDay, Vector3 initialDirection, Vector3 alternateDirection)
{
//IL_0015: 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_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_0046: 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_004b: 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_006a: 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_0073: Unknown result type (might be due to invalid IL or missing references)
absoluteDay = Mathf.Max(0f, absoluteDay);
if (absoluteDay < 20f)
{
return initialDirection;
}
int num = Mathf.FloorToInt(absoluteDay / 20f);
float num2 = absoluteDay - (float)num * 20f;
bool flag = num % 2 == 0;
Vector3 val = (flag ? initialDirection : alternateDirection);
if (num2 >= 1f)
{
return val;
}
Vector3 val2 = (flag ? alternateDirection : initialDirection);
float num3 = Mathf.SmoothStep(0f, 1f, num2 / 1f);
Vector3 val3 = Vector3.Slerp(val2, val, num3);
return ((Vector3)(ref val3)).normalized;
}
internal static int GetRetargetSample(float absoluteDay)
{
absoluteDay = Mathf.Max(0f, absoluteDay);
if (absoluteDay < 20f)
{
return 20;
}
int num = Mathf.FloorToInt(absoluteDay / 20f);
float num2 = absoluteDay - (float)num * 20f;
int num3 = 20;
if (num2 < 1f)
{
num3 = Mathf.Min(Mathf.FloorToInt(Mathf.Clamp01(num2 / 1f) * 20f), 19);
}
return num * 21 + num3;
}
static TradeWindCycle()
{
//IL_000f: 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_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: 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_0038: 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_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_0059: 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)
//IL_0072: 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)
//IL_007a: Unknown result type (might be due to invalid IL or missing references)
//IL_007f: Unknown result type (might be due to invalid IL or missing references)
Vector3 val = new Vector3(0.75f, 0f, 0.75f);
NorthEast = ((Vector3)(ref val)).normalized;
val = new Vector3(-1f, 0f, -0.5f);
SouthWest = ((Vector3)(ref val)).normalized;
val = new Vector3(1f, 0f, 0.5f);
EastNorthEast = ((Vector3)(ref val)).normalized;
val = new Vector3(1f, 0f, -0.5f);
EastSouthEast = ((Vector3)(ref val)).normalized;
}
}
internal static class ClimateCompatibility
{
internal static void Install(Harmony harmony)
{
//IL_006c: Unknown result type (might be due to invalid IL or missing references)
//IL_0071: Unknown result type (might be due to invalid IL or missing references)
//IL_007f: Expected O, but got Unknown
if (!Chainloader.PluginInfos.TryGetValue("com.raddude.climate", out var value) || (Object)(object)value.Instance == (Object)null)
{
return;
}
MethodInfo methodInfo = AccessTools.Method(AccessTools.TypeByName("Climate.WeatherPatches+ReplaceWindPatches"), "SetNewWindTarget", (Type[])null, (Type[])null);
if (methodInfo == null)
{
ChaoticWindPlugin.Instance?.LogFeatureError("Climate wind prefix was not found; Climate bonus-cap override and land-distance guard are unavailable.");
return;
}
try
{
harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(ClimateCompatibility), "Transpiler", (Type[])null)
{
priority = 0
}, (HarmonyMethod)null, (HarmonyMethod)null);
ChaoticWindPlugin.Instance?.LogFeatureInfo("Installed Climate custom-wind bonus-cap and land-distance compatibility.");
}
catch (Exception ex)
{
ChaoticWindPlugin.Instance?.LogFeatureError("Climate wind compatibility could not be installed: " + ex);
}
}
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
return WindIlRewriter.RewriteClimate(instructions);
}
}
internal static class WindIlRewriter
{
private static readonly MethodInfo InverseLerp = AccessTools.Method(typeof(Mathf), "InverseLerp", new Type[3]
{
typeof(float),
typeof(float),
typeof(float)
}, (Type[])null);
private static readonly FieldInfo DistanceToLand = AccessTools.Field(typeof(GameState), "distanceToLand");
private static readonly MethodInfo OceanLerpHelper = AccessTools.Method(typeof(ChaoticWindPlugin), "GetConfiguredOceanLerp", (Type[])null, (Type[])null);
private static readonly MethodInfo ClimateOceanLerpHelper = AccessTools.Method(typeof(ChaoticWindPlugin), "GetClimateOceanLerp", (Type[])null, (Type[])null);
private static readonly MethodInfo BonusCapHelper = AccessTools.Method(typeof(ChaoticWindPlugin), "GetConfiguredBonusCap", (Type[])null, (Type[])null);
internal static IEnumerable<CodeInstruction> RewriteVanilla(IEnumerable<CodeInstruction> instructions)
{
List<CodeInstruction> list = new List<CodeInstruction>(instructions);
List<int> list2 = FindInverseLerpCalls(list, 1500f, 4000f, DistanceToLand);
List<int> list3 = FindFloatLoads(list, 20f);
if (list2.Count != 1 || list3.Count != 2)
{
LogPatternError("vanilla Wind.SetNewWindTarget", list2.Count, list3.Count, "The method was left unchanged.");
return list;
}
list[list2[0]].operand = OceanLerpHelper;
ReplaceLoadsWithCall(list, list3, BonusCapHelper);
return list;
}
internal static IEnumerable<CodeInstruction> RewriteClimate(IEnumerable<CodeInstruction> instructions)
{
List<CodeInstruction> list = new List<CodeInstruction>(instructions);
List<int> list2 = FindInverseLerpCalls(list, 1500f, 4000f, DistanceToLand);
List<int> list3 = FindFloatLoads(list, 20f);
bool num = list2.Count == 1;
bool flag = list3.Count == 1 || list3.Count == 2;
if (!num || !flag)
{
LogPatternError("Climate custom-wind prefix", list2.Count, list3.Count, "Only the matching parts were changed.");
}
if (num)
{
list[list2[0]].operand = ClimateOceanLerpHelper;
}
if (flag)
{
ReplaceLoadsWithCall(list, list3, BonusCapHelper);
}
return list;
}
private static List<int> FindInverseLerpCalls(List<CodeInstruction> code, float minimum, float maximum, FieldInfo valueField)
{
List<int> list = new List<int>();
for (int i = 3; i < code.Count; i++)
{
if (object.Equals(code[i].operand, InverseLerp) && LoadsFloat(code[i - 3], minimum) && LoadsFloat(code[i - 2], maximum) && code[i - 1].opcode == OpCodes.Ldsfld && object.Equals(code[i - 1].operand, valueField))
{
list.Add(i);
}
}
return list;
}
private static List<int> FindFloatLoads(List<CodeInstruction> code, float value)
{
List<int> list = new List<int>();
for (int i = 0; i < code.Count; i++)
{
if (LoadsFloat(code[i], value))
{
list.Add(i);
}
}
return list;
}
private static void ReplaceLoadsWithCall(List<CodeInstruction> code, List<int> indexes, MethodInfo helper)
{
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Expected O, but got Unknown
for (int i = 0; i < indexes.Count; i++)
{
int index = indexes[i];
CodeInstruction val = code[index];
CodeInstruction val2 = new CodeInstruction(OpCodes.Call, (object)helper);
val2.labels.AddRange(val.labels);
val2.blocks.AddRange(val.blocks);
code[index] = val2;
}
}
private static bool LoadsFloat(CodeInstruction instruction, float value)
{
if (instruction.opcode == OpCodes.Ldc_R4 && instruction.operand is float num)
{
return num == value;
}
return false;
}
private static void LogPatternError(string target, int oceanCount, int capCount, string outcome)
{
ChaoticWindPlugin.Instance?.LogFeatureError($"Wind IL pattern mismatch in {target}, ocean curves={oceanCount}, cap loads={capCount}. {outcome}");
}
}
}