Decompiled source of WildWeather v0.1.1

WildWeather.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
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: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace WildWeather;

public enum Kind
{
	None,
	Blizzard,
	Storm
}
[BepInPlugin("com.burks.wildweather", "Wild Weather", "0.1.1")]
public class WildWeatherPlugin : BaseUnityPlugin
{
	public const string GUID = "com.burks.wildweather";

	public const string NAME = "Wild Weather";

	public const string VERSION = "0.1.1";

	public static ManualLogSource Log;

	public static ConfigEntry<float> ChancePerDay;

	public static ConfigEntry<float> BlizzardShare;

	public static ConfigEntry<float> DurationSeconds;

	public static ConfigEntry<float> WarningSeconds;

	public static ConfigEntry<float> StrikeMin;

	public static ConfigEntry<float> StrikeMax;

	public static ConfigEntry<float> StrikeMinDistance;

	public static ConfigEntry<string> BlizzardBiomes;

	public static ConfigEntry<string> StormBiomes;

	public static ConfigEntry<string> BlizzardEnv;

	public static ConfigEntry<string> StormEnv;

	public static ConfigEntry<string> BlizzardWarnEnv;

	public static ConfigEntry<string> StormWarnEnv;

	public static ConfigEntry<string> LightningPrefab;

	public static ConfigEntry<bool> Messages;

	public static ConfigEntry<bool> Lightning;

	private bool _headless;

	private float _next;

	private void Awake()
	{
		//IL_0244: Unknown result type (might be due to invalid IL or missing references)
		//IL_024a: Invalid comparison between Unknown and I4
		//IL_026f: Unknown result type (might be due to invalid IL or missing references)
		Log = ((BaseUnityPlugin)this).Logger;
		ChancePerDay = ((BaseUnityPlugin)this).Config.Bind<float>("Schedule", "ChancePerDay", 0.15f, "Chance (0-1) that a weather event happens on any given day. 0.15 is roughly one a week. Every player must use the same schedule settings.");
		BlizzardShare = ((BaseUnityPlugin)this).Config.Bind<float>("Schedule", "BlizzardShare", 0.5f, "Share of events that are blizzards (0-1); the rest are severe thunderstorms.");
		DurationSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Schedule", "DurationSeconds", 420f, "How long an event lasts, in real seconds.");
		WarningSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Schedule", "WarningSeconds", 300f, "How long before an event the sky starts to change, in real seconds.");
		BlizzardBiomes = ((BaseUnityPlugin)this).Config.Bind<string>("Where", "BlizzardBiomes", "Meadows,BlackForest", "Biomes where you get the blizzard (game biome names, comma-separated).");
		StormBiomes = ((BaseUnityPlugin)this).Config.Bind<string>("Where", "StormBiomes", "Meadows,BlackForest,Swamp,Plains,Ocean", "Biomes where you get the thunderstorm.");
		BlizzardEnv = ((BaseUnityPlugin)this).Config.Bind<string>("Weather", "BlizzardWeather", "SnowStorm", "The game weather used for the blizzard.");
		StormEnv = ((BaseUnityPlugin)this).Config.Bind<string>("Weather", "StormWeather", "ThunderStorm", "The game weather used for the thunderstorm.");
		BlizzardWarnEnv = ((BaseUnityPlugin)this).Config.Bind<string>("Weather", "BlizzardBuildUpWeather", "Snow", "Weather for the last part of the warning before a blizzard. Empty = none.");
		StormWarnEnv = ((BaseUnityPlugin)this).Config.Bind<string>("Weather", "StormBuildUpWeather", "LightRain", "Weather for the last part of the warning before a thunderstorm. Empty = none.");
		Messages = ((BaseUnityPlugin)this).Config.Bind<bool>("Weather", "Messages", true, "Show a short message when an event starts and ends (never during the warning).");
		Lightning = ((BaseUnityPlugin)this).Config.Bind<bool>("Lightning", "LightningStrikes", true, "Lightning hits the ground around you during a thunderstorm.");
		StrikeMin = ((BaseUnityPlugin)this).Config.Bind<float>("Lightning", "SecondsBetweenStrikesMin", 12f, "Shortest gap between strikes.");
		StrikeMax = ((BaseUnityPlugin)this).Config.Bind<float>("Lightning", "SecondsBetweenStrikesMax", 30f, "Longest gap between strikes.");
		StrikeMinDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Lightning", "MinDistance", 10f, "Strikes land at least this far from you (and up to 50 m away).");
		LightningPrefab = ((BaseUnityPlugin)this).Config.Bind<string>("Lightning", "Prefab", "lightningAOE", "Game object spawned for a strike.");
		_headless = (int)SystemInfo.graphicsDeviceType == 4;
		if (_headless)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Headless server detected; Wild Weather runs on the players' games.");
			return;
		}
		new Harmony("com.burks.wildweather").PatchAll(Assembly.GetExecutingAssembly());
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Wild Weather 0.1.1 loaded.");
	}

	private void Update()
	{
		if (_headless)
		{
			return;
		}
		float unscaledTime = Time.unscaledTime;
		if (unscaledTime >= _next)
		{
			_next = unscaledTime + 1f;
			try
			{
				Weather.Tick();
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Weather check failed: " + ex));
				_next = unscaledTime + 30f;
			}
		}
		try
		{
			Weather.Frame(Time.unscaledDeltaTime);
		}
		catch (Exception)
		{
		}
	}
}
public static class Schedule
{
	public static Kind ForcedKind;

	public static double ForcedStart;

	public static float Duration => Mathf.Clamp(WildWeatherPlugin.DurationSeconds.Value, 30f, 1500f);

	public static float Warning => Mathf.Clamp(WildWeatherPlugin.WarningSeconds.Value, 0f, 900f);

	private static ulong Mix(ulong x)
	{
		x ^= x >> 33;
		x *= 18397679294719823053uL;
		x ^= x >> 33;
		x *= 14181476777654086739uL;
		x ^= x >> 33;
		return x;
	}

	private static float Roll(int day, ulong salt)
	{
		return (float)(Mix((ulong)(day * -7046029254386353131L + (long)salt * -3335678366873096957L)) % 100000) / 100000f;
	}

	public static Kind ForDay(int day, double dayLen, out double start)
	{
		start = 0.0;
		if (day < 2)
		{
			return Kind.None;
		}
		if (Roll(day, 1uL) >= Mathf.Clamp01(WildWeatherPlugin.ChancePerDay.Value))
		{
			return Kind.None;
		}
		float num = Mathf.Max(0.25f, 0.95f - Duration / (float)dayLen);
		float num2 = Mathf.Lerp(0.2f, num, Roll(day, 2uL));
		start = (double)day * dayLen + (double)num2 * dayLen;
		if (!(Roll(day, 3uL) < Mathf.Clamp01(WildWeatherPlugin.BlizzardShare.Value)))
		{
			return Kind.Storm;
		}
		return Kind.Blizzard;
	}

	public static Kind Now(out double untilStart, out double untilEnd)
	{
		untilStart = (untilEnd = 0.0);
		if ((Object)(object)ZNet.instance == (Object)null || (Object)(object)EnvMan.instance == (Object)null)
		{
			return Kind.None;
		}
		double timeSeconds = ZNet.instance.GetTimeSeconds();
		if (ForcedKind != Kind.None)
		{
			untilStart = ForcedStart - timeSeconds;
			untilEnd = ForcedStart + (double)Duration - timeSeconds;
			if (untilEnd > 0.0)
			{
				return ForcedKind;
			}
			ForcedKind = Kind.None;
		}
		double num = Math.Max(60L, EnvMan.instance.m_dayLengthSec);
		int num2 = (int)(timeSeconds / num);
		for (int i = num2; i <= num2 + 1; i++)
		{
			double start;
			Kind kind = ForDay(i, num, out start);
			if (kind != Kind.None)
			{
				untilStart = start - timeSeconds;
				untilEnd = start + (double)Duration - timeSeconds;
				if (untilEnd > 0.0 && untilStart <= (double)Warning)
				{
					return kind;
				}
			}
		}
		return Kind.None;
	}
}
public static class Weather
{
	private static string _ours;

	private static Kind _kind = Kind.None;

	private static int _phase;

	private static float _warnTarget;

	private static float _warn;

	public static Kind TintKind = Kind.None;

	private static float _nextStrike;

	private static readonly HashSet<string> _missing = new HashSet<string>();

	private static bool _prefabWarned;

	public static float TintAmount => _warn;

	private unsafe static bool BiomeIn(string list, Biome b)
	{
		string b2 = ((object)(*(Biome*)(&b))/*cast due to .constrained prefix*/).ToString();
		string[] array = (list ?? "").Split(',');
		for (int i = 0; i < array.Length; i++)
		{
			if (string.Equals(array[i].Trim(), b2, StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
		}
		return false;
	}

	private static bool HasEnv(string name)
	{
		if (string.IsNullOrEmpty(name))
		{
			return false;
		}
		foreach (EnvSetup environment in EnvMan.instance.m_environments)
		{
			if (environment != null && environment.m_name == name)
			{
				return true;
			}
		}
		if (_missing.Add(name))
		{
			WildWeatherPlugin.Log.LogWarning((object)("The game has no weather called '" + name + "'; check the [Weather] settings."));
		}
		return false;
	}

	private static void SetEnv(string name)
	{
		EnvMan instance = EnvMan.instance;
		if ((Object)(object)instance == (Object)null)
		{
			return;
		}
		if (string.IsNullOrEmpty(name))
		{
			if (_ours != null && instance.m_debugEnv == _ours)
			{
				instance.m_debugEnv = "";
			}
			_ours = null;
		}
		else if (string.IsNullOrEmpty(instance.m_debugEnv) || !(instance.m_debugEnv != _ours))
		{
			instance.m_debugEnv = name;
			_ours = name;
		}
	}

	public static void Tick()
	{
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		Commands.Register();
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null || (Object)(object)EnvMan.instance == (Object)null)
		{
			_phase = 0;
			_kind = Kind.None;
			_warnTarget = 0f;
			_ours = null;
			return;
		}
		double untilStart;
		double untilEnd;
		Kind kind = Schedule.Now(out untilStart, out untilEnd);
		bool flag = false;
		if (kind != Kind.None && !((Character)localPlayer).InInterior())
		{
			flag = BiomeIn((kind == Kind.Blizzard) ? WildWeatherPlugin.BlizzardBiomes.Value : WildWeatherPlugin.StormBiomes.Value, localPlayer.GetCurrentBiome());
		}
		int num = (flag ? ((untilStart > 0.0) ? 1 : 2) : 0);
		switch (num)
		{
		case 1:
		{
			float warning = Schedule.Warning;
			float num2 = (_warnTarget = ((warning > 0f) ? Mathf.Clamp01(1f - (float)untilStart / warning) : 1f));
			TintKind = kind;
			string text2 = ((kind == Kind.Blizzard) ? WildWeatherPlugin.BlizzardWarnEnv.Value : WildWeatherPlugin.StormWarnEnv.Value);
			SetEnv((num2 >= 0.6f && HasEnv(text2)) ? text2 : null);
			break;
		}
		case 2:
		{
			_warnTarget = 0.35f;
			TintKind = kind;
			string text = ((kind == Kind.Blizzard) ? WildWeatherPlugin.BlizzardEnv.Value : WildWeatherPlugin.StormEnv.Value);
			SetEnv(HasEnv(text) ? text : null);
			if (kind == Kind.Storm)
			{
				Strike(localPlayer);
			}
			break;
		}
		default:
			_warnTarget = 0f;
			SetEnv(null);
			break;
		}
		if (num != _phase || kind != _kind)
		{
			if (num == 2 && _phase != 2)
			{
				Say((kind == Kind.Blizzard) ? "A blizzard sweeps in." : "A violent storm breaks.");
				_nextStrike = Time.unscaledTime + 8f;
			}
			else if (_phase == 2 && num == 0 && kind == Kind.None)
			{
				Say((_kind == Kind.Blizzard) ? "The blizzard dies down." : "The storm passes.");
			}
			if (num != _phase)
			{
				WildWeatherPlugin.Log.LogInfo(num switch
				{
					1 => kind.ToString() + " building up, starts in " + Mathf.RoundToInt((float)untilStart) + " s.", 
					2 => kind.ToString() + " started.", 
					_ => "No weather event here.", 
				});
			}
			_phase = num;
			_kind = kind;
		}
	}

	public static void Frame(float dt)
	{
		_warn = Mathf.MoveTowards(_warn, _warnTarget, dt / 10f);
	}

	private static void Say(string text)
	{
		if (WildWeatherPlugin.Messages.Value && (Object)(object)MessageHud.instance != (Object)null)
		{
			MessageHud.instance.ShowMessage((MessageType)2, text, 0, (Sprite)null, false, true);
		}
	}

	private static void Strike(Player me)
	{
		//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_0105: 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_0120: Unknown result type (might be due to invalid IL or missing references)
		//IL_0125: Unknown result type (might be due to invalid IL or missing references)
		//IL_012a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0131: Unknown result type (might be due to invalid IL or missing references)
		//IL_013f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0167: Unknown result type (might be due to invalid IL or missing references)
		//IL_017d: Unknown result type (might be due to invalid IL or missing references)
		//IL_017f: Unknown result type (might be due to invalid IL or missing references)
		if (!WildWeatherPlugin.Lightning.Value || Time.unscaledTime < _nextStrike)
		{
			return;
		}
		float num = Mathf.Max(2f, WildWeatherPlugin.StrikeMin.Value);
		_nextStrike = Time.unscaledTime + Random.Range(num, Mathf.Max(num, WildWeatherPlugin.StrikeMax.Value));
		if ((Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ZoneSystem.instance == (Object)null)
		{
			return;
		}
		GameObject prefab = ZNetScene.instance.GetPrefab(WildWeatherPlugin.LightningPrefab.Value);
		if ((Object)(object)prefab == (Object)null)
		{
			if (!_prefabWarned)
			{
				_prefabWarned = true;
				WildWeatherPlugin.Log.LogWarning((object)("No game object called '" + WildWeatherPlugin.LightningPrefab.Value + "'; lightning strikes are off."));
			}
			return;
		}
		Vector3 position = ((Component)me).transform.position;
		float num2 = Mathf.Clamp(WildWeatherPlugin.StrikeMinDistance.Value, 0f, 45f);
		float num5 = default(float);
		for (int i = 0; i < 10; i++)
		{
			float num3 = Random.Range(0f, (float)Math.PI * 2f);
			float num4 = Random.Range(num2, 50f);
			Vector3 val = position + new Vector3(Mathf.Cos(num3), 0f, Mathf.Sin(num3)) * num4;
			if (ZNetScene.instance.IsAreaReady(val) && ZoneSystem.instance.GetSolidHeight(val, ref num5, 1000))
			{
				val.y = Mathf.Max(num5, ZoneSystem.instance.m_waterLevel);
				if (!((Object)(object)EffectArea.IsPointInsideArea(val, (Type)4, 8f) != (Object)null))
				{
					Object.Instantiate<GameObject>(prefab, val, Quaternion.identity);
					break;
				}
			}
		}
	}
}
[HarmonyPatch(typeof(EnvMan), "SetEnv")]
public static class PaleSky
{
	private static readonly int SunFog = Shader.PropertyToID("_SunFogColor");

	private static readonly int Sun = Shader.PropertyToID("_SunColor");

	private static readonly int Ambient = Shader.PropertyToID("_AmbientColor");

	private static Color Pale(Color c, float a, bool blizzard)
	{
		//IL_0000: 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_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: 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_007e: 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)
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		//IL_0082: Unknown result type (might be due to invalid IL or missing references)
		float num = c.r * 0.3f + c.g * 0.59f + c.b * 0.11f;
		Color val = (blizzard ? new Color(num * 0.92f + 0.06f, num * 0.96f + 0.07f, num * 1.02f + 0.09f, c.a) : new Color(num * 0.55f, num * 0.58f, num * 0.64f, c.a));
		return Color.Lerp(c, val, a);
	}

	[HarmonyPostfix]
	public static void Postfix(EnvMan __instance)
	{
		//IL_0028: 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_0039: 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_0097: Unknown result type (might be due to invalid IL or missing references)
		//IL_009e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: 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_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: Unknown result type (might be due to invalid IL or missing references)
		float tintAmount = Weather.TintAmount;
		if (tintAmount <= 0.001f || Weather.TintKind == Kind.None)
		{
			return;
		}
		try
		{
			bool blizzard = Weather.TintKind == Kind.Blizzard;
			tintAmount *= 0.85f;
			RenderSettings.ambientLight = Pale(RenderSettings.ambientLight, tintAmount, blizzard);
			RenderSettings.fogColor = Pale(RenderSettings.fogColor, tintAmount, blizzard);
			RenderSettings.fogDensity *= 1f + 1.6f * tintAmount;
			if ((Object)(object)__instance.m_dirLight != (Object)null)
			{
				__instance.m_dirLight.color = Pale(__instance.m_dirLight.color, tintAmount, blizzard);
			}
			Shader.SetGlobalColor(SunFog, Pale(Shader.GetGlobalColor(SunFog), tintAmount, blizzard));
			Shader.SetGlobalColor(Sun, Pale(Shader.GetGlobalColor(Sun), tintAmount, blizzard));
			Shader.SetGlobalColor(Ambient, Pale(Shader.GetGlobalColor(Ambient), tintAmount, blizzard));
		}
		catch
		{
		}
	}
}
public static class Commands
{
	private static bool _done;

	public static void Register()
	{
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Expected O, but got Unknown
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		if (_done)
		{
			return;
		}
		_done = true;
		try
		{
			new ConsoleCommand("wildweather", "blizzard | storm [now] | stop | status - test weather events on your own game", new ConsoleEvent(Run), false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
		}
		catch (Exception ex)
		{
			WildWeatherPlugin.Log.LogWarning((object)("Could not add the 'wildweather' console command: " + ex.Message));
		}
	}

	private static void Run(ConsoleEventArgs args)
	{
		string text = ((args.Args.Length > 1) ? args.Args[1].ToLowerInvariant() : "status");
		bool flag = args.Args.Length > 2 && args.Args[2].ToLowerInvariant() == "now";
		if ((Object)(object)ZNet.instance == (Object)null || (Object)(object)EnvMan.instance == (Object)null)
		{
			args.Context.AddString("Join a world first.");
			return;
		}
		double timeSeconds = ZNet.instance.GetTimeSeconds();
		switch (text)
		{
		case "blizzard":
		case "storm":
			Schedule.ForcedKind = ((text == "blizzard") ? Kind.Blizzard : Kind.Storm);
			Schedule.ForcedStart = timeSeconds + (double)(flag ? 0f : Schedule.Warning);
			args.Context.AddString(flag ? "Started (your game only)." : ("Warning started; the event begins in " + Mathf.RoundToInt(Schedule.Warning) + " s (your game only). Add 'now' to skip the warning."));
			return;
		case "stop":
			Schedule.ForcedKind = Kind.None;
			args.Context.AddString("Forced event ended.");
			return;
		}
		double num = Math.Max(60L, EnvMan.instance.m_dayLengthSec);
		int num2 = (int)(timeSeconds / num);
		for (int i = num2; i < num2 + 200; i++)
		{
			double start;
			Kind kind = Schedule.ForDay(i, num, out start);
			if (kind != Kind.None && !(start + (double)Schedule.Duration < timeSeconds))
			{
				args.Context.AddString("Next event: " + kind.ToString() + " on day " + i + ((start > timeSeconds) ? (", in " + Mathf.RoundToInt((float)(start - timeSeconds) / 60f) + " min of play time.") : ", running now."));
				return;
			}
		}
		args.Context.AddString("No event in the next 200 days; raise ChancePerDay.");
	}
}