Decompiled source of SnowDay v1.4.4

plugins/SnowDay.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using TMPro;
using Unity.Collections;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace SnowDay;

internal enum RoofState : byte
{
	Open,
	Edge,
	Roofed
}
internal enum BuildKind : byte
{
	Nothing,
	Settled,
	UnderRoof,
	Raised,
	Full,
	Held,
	Left,
	Melted
}
internal enum OldKind : byte
{
	Below,
	Lowered,
	Held,
	NotNorth
}
internal sealed class TreeSet
{
	internal static readonly TreeSet Empty = new TreeSet(new Dictionary<long, byte[]>(), 0);

	internal const float Full = 250f;

	private readonly Dictionary<long, byte[]> m_grids;

	internal readonly int Version;

	internal int Count => m_grids.Count;

	internal IEnumerable<long> Keys => m_grids.Keys;

	internal TreeSet(Dictionary<long, byte[]> grids, int version)
	{
		m_grids = grids;
		Version = version;
	}

	internal byte[] Grid(long key)
	{
		if (m_grids.Count == 0 || !m_grids.TryGetValue(key, out var value))
		{
			return null;
		}
		return value;
	}

	internal float Open(float x, float z)
	{
		if (m_grids.Count == 0)
		{
			return 1f;
		}
		int num = BuildupMath.ZoneOf(x);
		int num2 = BuildupMath.ZoneOf(z);
		byte[] array = Grid(BuildupMath.Key(num, num2));
		if (array == null)
		{
			return 1f;
		}
		return (float)(int)array[BuildupMath.PointOf(z, num2) * 65 + BuildupMath.PointOf(x, num)] / 250f;
	}
}
internal struct TreeSpot
{
	internal float X;

	internal float Z;

	internal float R;

	internal TreeSpot(float x, float z, float r)
	{
		X = x;
		Z = z;
		R = r;
	}
}
internal sealed class RoofSet
{
	internal static readonly RoofSet Empty = new RoofSet(new Dictionary<long, byte[]>(), 0);

	private readonly Dictionary<long, byte[]> m_grids;

	internal readonly int Version;

	internal int Count => m_grids.Count;

	internal IEnumerable<long> Keys => m_grids.Keys;

	internal RoofSet(Dictionary<long, byte[]> grids, int version)
	{
		m_grids = grids;
		Version = version;
	}

	internal byte[] Grid(long key)
	{
		if (m_grids.Count == 0 || !m_grids.TryGetValue(key, out var value))
		{
			return null;
		}
		return value;
	}

	internal RoofState At(float x, float z)
	{
		if (m_grids.Count == 0)
		{
			return RoofState.Open;
		}
		int num = BuildupMath.ZoneOf(x);
		int num2 = BuildupMath.ZoneOf(z);
		byte[] array = Grid(BuildupMath.Key(num, num2));
		if (array == null)
		{
			return RoofState.Open;
		}
		return (RoofState)array[BuildupMath.PointOf(z, num2) * 65 + BuildupMath.PointOf(x, num)];
	}

	internal bool Roofed(float x, float z)
	{
		return At(x, z) == RoofState.Roofed;
	}
}
internal static class BuildupMath
{
	internal const int Steps = 50;

	internal const int ZoneSize = 64;

	internal const int Half = 32;

	internal const int Pitch = 65;

	internal const int Border = 5;

	internal const int CPitch = 75;

	internal const float MaxEdge = 5f;

	internal const float MinRise = 0.005f;

	internal const float Eps = 0.002f;

	internal const float CoverStart = 0.05f;

	internal const float CoverRadius = 0.1f;

	internal const float CoverReach = 100f;

	internal const float FloorFrom = 2f;

	internal const float FloorReach = 1.95f;

	internal static int Level(float amount)
	{
		if (!(amount <= 0f))
		{
			if (!(amount >= 1f))
			{
				return (int)Math.Floor((double)(amount * 50f) + 0.0001);
			}
			return 50;
		}
		return 0;
	}

	internal static float AmountOf(int level)
	{
		return (float)((level >= 0) ? ((level > 50) ? 50 : level) : 0) / 50f;
	}

	internal static float FullSeconds(float days, float dayLengthSec)
	{
		return Math.Max(0.01f, days) * ((dayLengthSec >= 60f) ? dayLengthSec : 1800f);
	}

	internal static float Advance(float amount, double snowSeconds, float fullSeconds)
	{
		if (snowSeconds <= 0.0 || fullSeconds <= 0f)
		{
			return Clamp01(amount);
		}
		return Clamp01((float)((double)amount + snowSeconds / (double)fullSeconds));
	}

	internal static double SnowSeconds(double from, double to, long period, Func<long, bool> snows)
	{
		if (to <= from || period <= 0 || snows == null)
		{
			return 0.0;
		}
		double num = 0.0;
		long num2 = (long)Math.Floor(from / (double)period);
		long num3 = (long)Math.Floor(to / (double)period);
		for (long num4 = num2; num4 <= num3; num4++)
		{
			double num5 = Math.Max(from, (double)num4 * (double)period);
			double num6 = Math.Min(to, (double)(num4 + 1) * (double)period);
			if (num6 > num5 && snows(num4))
			{
				num += num6 - num5;
			}
		}
		return num;
	}

	internal static float SnowShare(float[] weights, bool[] snows)
	{
		double num = 0.0;
		double num2 = 0.0;
		for (int i = 0; i < weights.Length; i++)
		{
			if (!(weights[i] <= 0f))
			{
				num += (double)weights[i];
				if (snows[i])
				{
					num2 += (double)weights[i];
				}
			}
		}
		if (!(num <= 0.0))
		{
			return (float)(num2 / num);
		}
		return 0f;
	}

	internal static float PlayHours(float days, float dayLengthSec, float share)
	{
		if (!(share <= 0f))
		{
			return FullSeconds(days, dayLengthSec) / 3600f / share;
		}
		return float.PositiveInfinity;
	}

	internal static float FullG(float g0, float top, float range)
	{
		return Math.Max(g0, SnowMath.RemapUntouched(g0, top, range));
	}

	internal static float Untouched(float g0, float top, float range, float amount, bool roofed)
	{
		return Untouched(g0, top, range, amount, roofed, 1f, 1f);
	}

	internal static float Untouched(float g0, float top, float range, float amount, bool roofed, float open, float trunkShare)
	{
		if (roofed)
		{
			return g0;
		}
		float num = ((amount <= 0f) ? g0 : (g0 + Clamp01(amount) * (FullG(g0, top, range) - g0)));
		if (open >= 1f)
		{
			return num;
		}
		float num2 = g0 * Clamp01(trunkShare);
		return num2 + Clamp01(open) * (num - num2);
	}

	internal static float WellOpen(float d, float r)
	{
		if (r <= 0f || d >= r)
		{
			return 1f;
		}
		float num = Clamp01(d / r);
		return num * num * (3f - 2f * num);
	}

	internal static byte[] WellGrid(int zx, int zz, IList<TreeSpot> trees)
	{
		if (trees == null || trees.Count == 0)
		{
			return null;
		}
		byte[] array = null;
		float num = PointWorld(0, zx);
		float num2 = PointWorld(0, zz);
		foreach (TreeSpot tree in trees)
		{
			if (tree.R <= 0f)
			{
				continue;
			}
			int num3 = Math.Max(0, (int)Math.Floor(tree.X - tree.R - num));
			int num4 = Math.Min(64, (int)Math.Ceiling(tree.X + tree.R - num));
			int num5 = Math.Max(0, (int)Math.Floor(tree.Z - tree.R - num2));
			int num6 = Math.Min(64, (int)Math.Ceiling(tree.Z + tree.R - num2));
			for (int i = num5; i <= num6; i++)
			{
				for (int j = num3; j <= num4; j++)
				{
					float num7 = num + (float)j - tree.X;
					float num8 = num2 + (float)i - tree.Z;
					float num9 = (float)Math.Sqrt(num7 * num7 + num8 * num8);
					if (num9 >= tree.R)
					{
						continue;
					}
					byte b = (byte)Math.Round(WellOpen(num9, tree.R) * 250f);
					if (array == null)
					{
						array = new byte[4225];
						for (int k = 0; k < array.Length; k++)
						{
							array[k] = 250;
						}
					}
					int num10 = i * 65 + j;
					if (b < array[num10])
					{
						array[num10] = b;
					}
				}
			}
		}
		if (array == null)
		{
			return null;
		}
		byte[] array2 = array;
		for (int l = 0; l < array2.Length; l++)
		{
			if (array2[l] < 250)
			{
				return array;
			}
		}
		return null;
	}

	internal static float WellRadius(float setting, float treeScale)
	{
		float num = ((treeScale > 0f) ? Clamp(treeScale, 0.75f, 1.5f) : 1f);
		return Clamp(setting * num, 0f, 5f);
	}

	internal static int SeasonIndex(string name)
	{
		switch ((name ?? "").Trim().ToLowerInvariant())
		{
		case "winter":
			return 0;
		case "fall":
		case "autumn":
			return 1;
		case "spring":
			return 2;
		case "summer":
			return 3;
		default:
			return -1;
		}
	}

	internal static float SeasonFactor(int season, float[] factors)
	{
		if (season < 0 || factors == null || season >= factors.Length)
		{
			return 1f;
		}
		return Math.Max(0f, factors[season]);
	}

	internal static float Melt(float amount, double seconds, float meltDays, float dayLengthSec)
	{
		if (seconds <= 0.0 || meltDays <= 0f)
		{
			return Clamp01(amount);
		}
		return Clamp01((float)((double)amount - seconds / (double)FullSeconds(meltDays, dayLengthSec)));
	}

	internal static float YearChange(float[] seasonDays, float[] factors, float snowShare, float buildDays, float meltDays)
	{
		double num = 0.0;
		double num2 = 0.0;
		for (int i = 0; i < 4 && i < seasonDays.Length; i++)
		{
			num += (double)(seasonDays[i] * snowShare * SeasonFactor(i, factors) / Math.Max(0.01f, buildDays));
			if (i == 3 && meltDays > 0f)
			{
				num2 += (double)(seasonDays[i] / meltDays);
			}
		}
		return (float)(num - num2);
	}

	internal static byte[] ClassifyRoofs(bool[] covered, float edge, out int roofed, out int edges, out int coveredCount)
	{
		byte[] array = new byte[4225];
		roofed = (edges = (coveredCount = 0));
		float num = Clamp(edge, 0f, 5f);
		int num2 = Math.Min(5, (int)Math.Ceiling((double)num - 0.0001));
		float num3 = num * num + 0.0001f;
		for (int i = 0; i < 65; i++)
		{
			for (int j = 0; j < 65; j++)
			{
				int num4 = j + 5;
				int num5 = i + 5;
				if (!covered[num5 * 75 + num4])
				{
					continue;
				}
				coveredCount++;
				bool flag = false;
				for (int k = -num2; k <= num2; k++)
				{
					if (flag)
					{
						break;
					}
					for (int l = -num2; l <= num2; l++)
					{
						if (!((float)(l * l + k * k) > num3) && !covered[(num5 + k) * 75 + num4 + l])
						{
							flag = true;
							break;
						}
					}
				}
				if (flag)
				{
					array[i * 65 + j] = 1;
					edges++;
				}
				else
				{
					array[i * 65 + j] = 2;
					roofed++;
				}
			}
		}
		return array;
	}

	internal static float OpenSkyDistance(bool[] covered, int x, int y)
	{
		int num = x + 5;
		int num2 = y + 5;
		if (!covered[num2 * 75 + num])
		{
			return 0f;
		}
		float num3 = 6f;
		for (int i = -5; i <= 5; i++)
		{
			for (int j = -5; j <= 5; j++)
			{
				if (!covered[(num2 + i) * 75 + num + j])
				{
					num3 = Math.Min(num3, (float)Math.Sqrt(j * j + i * i));
				}
			}
		}
		return num3;
	}

	internal static bool SameGrid(byte[] a, byte[] b)
	{
		if (a == b)
		{
			return true;
		}
		if (a == null || b == null || a.Length != b.Length)
		{
			return false;
		}
		for (int i = 0; i < a.Length; i++)
		{
			if (a[i] != b[i])
			{
				return false;
			}
		}
		return true;
	}

	internal static int ZoneOf(float v)
	{
		return (int)Math.Floor((float)(((double)v + 32.0) / 64.0));
	}

	internal static long Key(int zx, int zz)
	{
		return ((long)zx << 32) | (uint)zz;
	}

	internal static void Unkey(long key, out int zx, out int zz)
	{
		zx = (int)(key >> 32);
		zz = (int)(key & 0xFFFFFFFFu);
	}

	internal static int PointOf(float v, int zone)
	{
		int num = (int)Math.Round((double)v - ((double)zone * 64.0 - 32.0));
		if (num >= 0)
		{
			if (num < 65)
			{
				return num;
			}
			return 64;
		}
		return 0;
	}

	internal static float PointWorld(int i, int zone)
	{
		return zone * 64 - 32 + i;
	}

	internal static float BuildUp(float g, float target, float rise)
	{
		if (!(rise <= 0f) && !(g >= target - 0.002f))
		{
			return Math.Min(target, g + rise);
		}
		return g;
	}

	internal static float Settle(float g, float target)
	{
		if (!(g > target + 0.002f))
		{
			return g;
		}
		return target;
	}

	internal static BuildKind Decide(RoofState roof, float g, float target, float seen, bool trodden, bool deepNorth, bool path, RefillSkip area, bool waiting, out float newG, out bool consume)
	{
		newG = g;
		consume = false;
		if (roof == RoofState.Roofed)
		{
			consume = true;
			float num = Settle(g, target);
			if (num >= g)
			{
				return BuildKind.UnderRoof;
			}
			newG = num;
			return BuildKind.Settled;
		}
		float num2 = target - seen;
		if (num2 < -1E-06f && g > target + 0.002f)
		{
			if (!trodden || !deepNorth || path || area == RefillSkip.Fire || area == RefillSkip.Location)
			{
				consume = true;
				return BuildKind.Left;
			}
			if (area == RefillSkip.Player || waiting)
			{
				return BuildKind.Held;
			}
			consume = true;
			newG = Math.Max(target, g + num2);
			return BuildKind.Melted;
		}
		if (num2 <= 1E-06f)
		{
			consume = num2 < 0f;
			return BuildKind.Nothing;
		}
		if (!trodden || !deepNorth || target < 0.02f || path || area == RefillSkip.Fire || area == RefillSkip.Location)
		{
			consume = true;
			return BuildKind.Left;
		}
		if (area == RefillSkip.Player || waiting)
		{
			return BuildKind.Held;
		}
		consume = true;
		float num3 = BuildUp(g, target, num2);
		if (num3 <= g + 1E-05f)
		{
			return BuildKind.Full;
		}
		newG = num3;
		return BuildKind.Raised;
	}

	internal static OldKind LowerOld(float g, float target, bool deepNorth, bool someoneThere, out float newG)
	{
		newG = g;
		if (!deepNorth)
		{
			return OldKind.NotNorth;
		}
		float num = Settle(g, target);
		if (num >= g)
		{
			return OldKind.Below;
		}
		if (someoneThere)
		{
			return OldKind.Held;
		}
		newG = num;
		return OldKind.Lowered;
	}

	internal static float Clamp01(float v)
	{
		if (!(v < 0f))
		{
			if (!(v > 1f))
			{
				return v;
			}
			return 1f;
		}
		return 0f;
	}

	internal static float Clamp(float v, float lo, float hi)
	{
		if (!(v < lo))
		{
			if (!(v > hi))
			{
				return v;
			}
			return hi;
		}
		return lo;
	}
}
internal static class CameraMath
{
	internal sealed class Follow
	{
		internal float Value;

		internal float HoldLeft;

		internal float Pump;

		internal int Last;

		internal int Reversals;

		internal float Behind;

		internal bool Active => !float.IsPositiveInfinity(Value);

		internal Follow(float value)
		{
			Value = value;
		}

		internal void Reset(float value)
		{
			Value = value;
			HoldLeft = (Pump = (Behind = 0f));
			Last = 0;
		}

		internal void More()
		{
			if (Last > 0)
			{
				Reversals++;
				Pump += 1f;
			}
			Last = -1;
			HoldLeft = HoldFor(Pump);
		}

		internal void Still()
		{
			HoldLeft = HoldFor(Pump);
		}

		internal void Decay(float dt)
		{
			Pump = Math.Max(0f, Pump - Math.Max(0f, dt) * 0.5f);
		}
	}

	internal sealed class State
	{
		internal readonly Follow Dist = new Follow(float.PositiveInfinity);

		internal readonly Follow Lift = new Follow(0f);

		internal float LastDist = float.PositiveInfinity;

		internal float Room = float.PositiveInfinity;

		internal float PlanDist;

		internal float PlanLift;

		internal void Reset()
		{
			Dist.Reset(float.PositiveInfinity);
			Lift.Reset(0f);
			LastDist = (Room = float.PositiveInfinity);
		}
	}

	internal const float Clearance = 0.3f;

	internal const float SoftenRaise = 0.1f;

	internal const float NearSkip = 0.6f;

	internal const float RampEnd = 1.5f;

	internal const float LiftSlope = 0.25f;

	internal const float LiftCap = 1.2f;

	internal const float SampleStep = 0.25f;

	internal const int MaxSamples = 160;

	internal const float MinDistance = 1f;

	internal const float InTime = 0.08f;

	internal const float InSpeed = 15f;

	internal const float LiftInSpeed = 6f;

	internal const float OutTime = 0.6f;

	internal const float OutSpeed = 2f;

	internal const float LiftOutSpeed = 1f;

	internal const float Hold = 0.4f;

	internal const float PumpDecay = 0.5f;

	internal const float Done = 0.01f;

	internal const float BehindFor = 2f;

	internal static float Clamp01(float v)
	{
		if (!(v < 0f))
		{
			if (!(v > 1f))
			{
				return v;
			}
			return 1f;
		}
		return 0f;
	}

	internal static float CellTop(float h00, float h10, float h01, float h11, float fx, float fz)
	{
		fx = Clamp01(fx);
		fz = Clamp01(fz);
		float val = ((fx >= fz) ? (h00 + (h10 - h00) * fx + (h11 - h10) * fz) : (h00 + (h01 - h00) * fz + (h11 - h01) * fx));
		float val2 = ((fx + fz <= 1f) ? (h00 + (h10 - h00) * fx + (h01 - h00) * fz) : (h11 + (h01 - h11) * (1f - fx) + (h10 - h11) * (1f - fz)));
		return Math.Max(val, val2);
	}

	internal static float Bilinear(float v00, float v10, float v01, float v11, float fx, float fz)
	{
		fx = Clamp01(fx);
		fz = Clamp01(fz);
		return (v00 * (1f - fx) + v10 * fx) * (1f - fz) + (v01 * (1f - fx) + v11 * fx) * fz;
	}

	internal static float Margin(float depth, float s)
	{
		if (!(depth > 0.001f))
		{
			return 0f;
		}
		float num = Clamp01((depth - 0.1f) / 0.4f);
		float num2 = Clamp01((s - 0.6f) / 0.9f);
		return 0.1f * Clamp01(depth / 0.1f) + 0.3f * num * num2;
	}

	internal static int SampleCount(float length, out float step)
	{
		step = 0.25f;
		if (!(length > 0.6f))
		{
			return 0;
		}
		int num = (int)Math.Ceiling((length - 0.6f) / step) + 1;
		if (num > 160)
		{
			num = 160;
			step = (length - 0.6f) / (float)(num - 1);
		}
		return num;
	}

	internal static float SampleAt(int i, int n, float step, float length)
	{
		if (i < n - 1)
		{
			return 0.6f + (float)i * step;
		}
		return length;
	}

	internal static float LiftRoom(float d, float room)
	{
		return Math.Max(0f, Math.Min(Math.Min(0.25f * d, 1.2f), room));
	}

	internal static float LiftAt(float[] s, float[] gap, int n, float d)
	{
		float num = 0f;
		for (int i = 0; i < n && s[i] <= d + 0.0001f; i++)
		{
			float num2 = gap[i];
			if (num2 > 0f && s[i] > 0f)
			{
				num = Math.Max(num, num2 / s[i]);
			}
		}
		return d * num;
	}

	internal static float Plan(float[] s, float[] gap, int n, float gameDist, float solidAt, float room, out float lift)
	{
		float num = gameDist;
		float num2 = 0f;
		float num3 = 0f;
		float num4 = 0f;
		float num5 = -0.25f;
		for (int i = 0; i < n; i++)
		{
			float num6 = s[i];
			if (num6 > gameDist + 0.0001f)
			{
				break;
			}
			float num7 = gap[i];
			float num8 = ((num7 > 0f && num6 > 0f) ? (num7 / num6) : 0f);
			float num9 = Math.Max(num2, num8);
			float num10 = ((num6 > 0f) ? Math.Min(0.25f, Math.Max(0f, Math.Min(1.2f, room)) / num6) : 0.25f);
			float num11 = num9 - num10;
			if (num11 > 0f)
			{
				float num12 = ((num11 - num5 > 1E-06f) ? Clamp01((0f - num5) / (num11 - num5)) : 0f);
				num = num3 + (num6 - num3) * num12;
				float num13 = Math.Max(num2, num4 + (num8 - num4) * num12);
				lift = Math.Min(num * num13, LiftRoom(num, room));
				if (solidAt < num)
				{
					return Solid(s, gap, n, solidAt, room, out lift);
				}
				return num;
			}
			num2 = num9;
			num3 = num6;
			num4 = num8;
			num5 = num11;
		}
		if (solidAt < num)
		{
			return Solid(s, gap, n, solidAt, room, out lift);
		}
		lift = Math.Min(num * num2, LiftRoom(num, room));
		return num;
	}

	private static float Solid(float[] s, float[] gap, int n, float solidAt, float room, out float lift)
	{
		float num = Math.Max(0f, solidAt);
		lift = Math.Min(LiftAt(s, gap, n, num), LiftRoom(num, room));
		return num;
	}

	internal static float Toward(float value, float target, float dt, float time, float speed)
	{
		if (!(dt > 0f) || value == target)
		{
			return value;
		}
		float num = ((time > 0f) ? (1f - (float)Math.Exp((0f - dt) / time)) : 1f);
		float num2 = (target - value) * num;
		float num3 = speed * dt;
		if (num2 > num3)
		{
			num2 = num3;
		}
		else if (num2 < 0f - num3)
		{
			num2 = 0f - num3;
		}
		float num4 = value + num2;
		if ((target - value) * (target - num4) < 0f)
		{
			num4 = target;
		}
		return num4;
	}

	internal static float HoldFor(float pump)
	{
		return 0.4f * (1f + Math.Min(3f, Math.Max(0f, pump)));
	}

	internal static int Gaps(float ex, float ey, float ez, float dx, float dy, float dz, float length, Func<int, int, float> ground, Func<int, int, float> depth, float[] s, float[] gap, out float worst, out float worstAt)
	{
		worst = float.NegativeInfinity;
		worstAt = 0f;
		float step;
		int num = Math.Min(SampleCount(length, out step), Math.Min(s.Length, gap.Length));
		for (int i = 0; i < num; i++)
		{
			float num2 = SampleAt(i, num, step, length);
			float x = ex + dx * num2;
			float y = ey + dy * num2;
			float z = ez + dz * num2;
			s[i] = num2;
			gap[i] = GapAt(x, y, z, num2, ground, depth);
			if (gap[i] > worst)
			{
				worst = gap[i];
				worstAt = num2;
			}
		}
		return num;
	}

	internal static float GapAt(float x, float y, float z, float s, Func<int, int, float> ground, Func<int, int, float> depth)
	{
		float d;
		float num = TopAt(x, z, ground, depth, out d);
		if (!float.IsNaN(num))
		{
			return num + Margin(d, s) - y;
		}
		return float.NaN;
	}

	internal static float TopAt(float x, float z, Func<int, int, float> ground, Func<int, int, float> depth, out float d)
	{
		int num = (int)Math.Floor(x);
		int num2 = (int)Math.Floor(z);
		float fx = x - (float)num;
		float fz = z - (float)num2;
		float num3 = ground(num, num2);
		float num4 = ground(num + 1, num2);
		float num5 = ground(num, num2 + 1);
		float num6 = ground(num + 1, num2 + 1);
		d = float.NaN;
		if (float.IsNaN(num3) || float.IsNaN(num4) || float.IsNaN(num5) || float.IsNaN(num6))
		{
			return float.NaN;
		}
		float num7 = Math.Max(0f, depth(num, num2));
		float num8 = Math.Max(0f, depth(num + 1, num2));
		float num9 = Math.Max(0f, depth(num, num2 + 1));
		float num10 = Math.Max(0f, depth(num + 1, num2 + 1));
		if (!(num7 > 0.001f) && !(num8 > 0.001f) && !(num9 > 0.001f) && !(num10 > 0.001f))
		{
			return float.NaN;
		}
		d = Bilinear(num7, num8, num9, num10, fx, fz);
		return CellTop(num3 + num7, num4 + num8, num5 + num9, num6 + num10, fx, fz);
	}

	internal static float FrameDistance(State st, float[] s, float[] gap, int n, float gameDist, float solidAt, float dt)
	{
		st.PlanDist = Plan(s, gap, n, gameDist, solidAt, st.Room, out st.PlanLift);
		float target = ((st.PlanDist < gameDist - 0.01f) ? st.PlanDist : float.PositiveInfinity);
		float val = StepDistance(st.Dist, target, gameDist, st.LastDist, dt);
		return st.LastDist = Math.Min(gameDist, val);
	}

	internal static float FrameLift(State st, float[] s, float[] gap, int n, float dist, float room, float dt)
	{
		st.Room = room;
		float target = Math.Min(LiftAt(s, gap, n, dist), LiftRoom(dist, room));
		return StepLift(st.Lift, target, room, dt);
	}

	internal static float StepDistance(Follow f, float target, float gameDist, float lastDist, float dt)
	{
		if (!f.Active)
		{
			if (!(target < gameDist - 0.01f))
			{
				return f.Value;
			}
			f.Reset(Math.Min(gameDist, lastDist));
		}
		if (target < f.Value - 0.01f)
		{
			f.More();
			f.Value = Toward(f.Value, target, dt, 0.08f, 15f);
			f.Behind = 0f;
		}
		else if (target <= f.Value + 0.01f)
		{
			f.Still();
			f.Behind = 0f;
		}
		else if (gameDist < f.Value - 0.01f)
		{
			f.Behind += Math.Max(0f, dt);
			if (f.HoldLeft > 0f)
			{
				f.HoldLeft -= dt;
			}
			if (f.Behind > 2f)
			{
				f.Reset(float.PositiveInfinity);
			}
		}
		else
		{
			f.Behind = 0f;
			float num = Math.Min(target, gameDist);
			if (f.HoldLeft > 0f)
			{
				f.HoldLeft -= dt;
			}
			else if (num > f.Value + 0.01f)
			{
				f.Value = Toward(f.Value, num, dt, 0.6f, 2f);
				f.Last = 1;
			}
			if (!(target < gameDist) && f.Value >= gameDist - 0.01f)
			{
				f.Reset(float.PositiveInfinity);
			}
		}
		f.Decay(dt);
		return f.Value;
	}

	internal static float StepLift(Follow f, float target, float room, float dt)
	{
		room = Math.Max(0f, room);
		target = Math.Max(0f, Math.Min(target, room));
		if (target > f.Value + 0.01f)
		{
			f.More();
			f.Value = Toward(f.Value, target, dt, 0.08f, 6f);
		}
		else if (target > 0f && target >= f.Value - 0.01f)
		{
			f.Still();
		}
		else
		{
			if (f.HoldLeft > 0f)
			{
				f.HoldLeft -= dt;
			}
			else if (target < f.Value - 0.01f || (target <= 0f && f.Value > 0f))
			{
				f.Value = Toward(f.Value, target, dt, 0.6f, 1f);
				f.Last = 1;
			}
			if (f.Value <= 0.01f && target <= 0f && f.HoldLeft <= 0f)
			{
				f.Reset(0f);
			}
		}
		if (f.Value > room)
		{
			f.Value = room;
		}
		f.Decay(dt);
		return f.Value;
	}
}
internal static class Commands
{
	internal const string Name = "snowday";

	internal static void Add()
	{
		//IL_0011: 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_0030: Expected O, but got Unknown
		//IL_0030: Expected O, but got Unknown
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			new ConsoleCommand("snowday", "SnowDay: 'snowday info' shows the snow where you stand and the settings; 'snowday look off|on|soft|soft2|soft3|round|hires4|hires2|plain|blur|point|bilinear|setting' switches the snow look until you quit ('snowday look seams' switches closing the seams between pieces of ground); 'snowday roofs' shows the roof snow near you and checks the piece you look at; 'snowday refill' shows how the snow fills back in near you; 'snowday buildup' shows how far the snow has built up and the roof under you ('snowday buildup <0-1>' (cheat, on the host) sets it); 'snowday blocks' shows the snow blocks and their melting ('snowday blocks look <name>' tries another look until you quit); 'snowday volume' shows the solid snow loaded (chunks, meshes, network); 'snowday clearvolume <radius>' (cheat) removes solid snow near you.", new ConsoleEvent(Run), false, false, false, false, false, false, new ConsoleOptionsFetcher(Options), false, false, false);
		}
		catch (Exception ex)
		{
			Logs.Warn("cmd", "The snowday console command could not be added: " + ex.Message);
		}
	}

	private static List<string> Options()
	{
		return new List<string> { "info", "look", "roofs", "refill", "buildup", "blocks", "volume", "clearvolume" };
	}

	private static void Run(ConsoleEventArgs args)
	{
		string text = ((args.Length > 1) ? (args[1] ?? "").ToLowerInvariant() : "info");
		IEnumerable<string> enumerable;
		try
		{
			enumerable = text switch
			{
				"blocks" => SnowBlocks.Command((args.Length > 2) ? args[2] : null, (args.Length > 3) ? args[3] : null), 
				"buildup" => SnowBuildup.Command((args.Length > 2) ? args[2] : null), 
				"refill" => SnowRefill.Command((args.Length > 2) ? args[2] : null), 
				"roofs" => RoofSnow.Command((args.Length > 2) ? args[2] : null), 
				"look" => SnowLook.Command((args.Length > 2) ? args[2] : null), 
				_ => SolidSnow.Command(text, args) ?? Info(), 
			};
		}
		catch (Exception ex)
		{
			enumerable = new string[1] { "snowday: " + ex.GetType().Name + ": " + ex.Message };
		}
		foreach (string item in enumerable)
		{
			Terminal context = args.Context;
			if (context != null)
			{
				context.AddString(item);
			}
			Logs.Always("snowday " + text + ": " + item);
		}
	}

	internal unsafe static IEnumerable<string> Info()
	{
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		//IL_0043: 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_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: 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_00a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00da: Unknown result type (might be due to invalid IL or missing references)
		//IL_0153: Unknown result type (might be due to invalid IL or missing references)
		//IL_0156: Invalid comparison between Unknown and I4
		//IL_0160: Unknown result type (might be due to invalid IL or missing references)
		//IL_0166: Unknown result type (might be due to invalid IL or missing references)
		//IL_0184: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
		List<string> list = new List<string> { "SnowDay 1.4.4" };
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null)
		{
			list.Add("No player in the world yet.");
		}
		else
		{
			Vector3 position = ((Component)localPlayer).transform.position;
			Biome val = Heightmap.FindBiome(position);
			float num = Snow.GroundAt(position);
			float num2 = Snow.GAt(position);
			list.Add("Here " + Snow.Pos(position) + ", height " + Snow.M(position.y) + ": " + ((object)(*(Biome*)(&val))/*cast due to .constrained prefix*/).ToString() + (WorldGenerator.IsDeepnorth(position.x, position.z) ? " (inside the Deep North's area)" : "") + "; ground at " + Snow.M(num) + ", you are " + Snow.M(position.y - num) + " above it" + (((Object)(object)((Character)localPlayer).GetLastGroundCollider() != (Object)null) ? (", standing on " + Utils.GetPrefabName(((Component)((Component)((Character)localPlayer).GetLastGroundCollider()).transform.root).gameObject)) : "") + ".");
			string text = "";
			if (WorldGenerator.instance != null && (int)val == 64)
			{
				Color val2 = default(Color);
				WorldGenerator.instance.GetHeight(position.x, position.z, ref val2);
				text = "; untouched snow here would be " + Snow.M(SnowMath.HeightOfG(val2.g)) + " (g " + Snow.F(val2.g) + ")" + ((Mathf.Abs(val2.g - num2) > 0.02f) ? ": this spot was shovelled, trodden, melted or added to" : "");
			}
			list.Add("Snow here: " + Snow.M(SnowMath.HeightOfG(num2)) + " deep (g " + Snow.F(num2) + ")" + text + ".");
		}
		SnowDayPlugin.Feature[] features = SnowDayPlugin.Features;
		foreach (SnowDayPlugin.Feature feature in features)
		{
			if (!feature.Ready)
			{
				list.Add(feature.Name + ": not running" + ((feature.Error != null) ? (" (" + feature.Error + ")") : "") + ".");
			}
			else
			{
				if (feature.Status == null)
				{
					continue;
				}
				bool flag = true;
				foreach (string item in feature.Status())
				{
					list.Add(flag ? ("Setting: " + item + ".") : item);
					flag = false;
				}
			}
		}
		return list;
	}
}
internal static class FileLog
{
	private static DiskLogListener s_disk;

	private static bool s_looked;

	internal static void Info(ManualLogSource src, string msg)
	{
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Expected O, but got Unknown
		if (src == null)
		{
			return;
		}
		try
		{
			if (!s_looked)
			{
				s_looked = true;
				foreach (ILogListener listener in Logger.Listeners)
				{
					DiskLogListener val = (DiskLogListener)(object)((listener is DiskLogListener) ? listener : null);
					if (val != null)
					{
						s_disk = val;
						break;
					}
				}
			}
			if (s_disk != null)
			{
				s_disk.LogEvent((object)src, new LogEventArgs((object)msg, (LogLevel)16, (ILogSource)(object)src));
				return;
			}
		}
		catch
		{
			s_disk = null;
		}
		try
		{
			src.LogDebug((object)msg);
		}
		catch
		{
		}
	}
}
internal static class GrassSnow
{
	internal static ConfigEntry<float> HideDepth;

	private static float s_hideG = 2f;

	private static int s_hidden;

	private static int s_kept;

	private static long s_hiddenTotal;

	internal static void Bind(ConfigFile cfg)
	{
		HideDepth = cfg.Bind<float>("9 - Look and logs", "Hide grass in snow deeper than", 0.5f, SnowDayPlugin.Mine("Grass and other ground clutter in the Deep North is put on the ground under the snow, so where the snow is deep it is buried and only its tips stick out of the snow in places. No grass is put where the snow is deeper than this, in metres; grass in trails, shovelled spots and thin snow stays, and it comes back when the snow there is dug away. Only how it looks (less grass to draw, too). 0: off, grass everywhere as in the game.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2.1f)));
	}

	internal static void Apply(Harmony h)
	{
		Recalc();
		h.PatchAll(typeof(GrassSnow));
		HideDepth.SettingChanged += delegate
		{
			Recalc();
			if ((Object)(object)ClutterSystem.instance != (Object)null)
			{
				ClutterSystem.instance.ClearAll();
			}
			Logs.Always("Grass: " + Describe() + " (grass near you redone).");
		};
	}

	private static void Recalc()
	{
		s_hideG = ((HideDepth.Value <= 0f) ? 2f : SnowMath.GOfHeight(HideDepth.Value));
	}

	internal static string Describe()
	{
		if (!(HideDepth.Value <= 0f))
		{
			return "no grass where the snow is deeper than " + Snow.M(HideDepth.Value);
		}
		return "grass in deep snow as in the game";
	}

	[HarmonyPatch(typeof(ClutterSystem), "GetGroundInfo")]
	[HarmonyPostfix]
	private static void AfterGround(ref bool __result, ref Vector3 point, ref Heightmap hmap, ref Biome biome)
	{
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		if (__result && !(s_hideG > 1f) && !((Object)(object)hmap == (Object)null) && (int)biome == 64)
		{
			if (hmap.GetCultivationMask(point) > s_hideG)
			{
				__result = false;
				s_hidden++;
			}
			else
			{
				s_kept++;
			}
		}
	}

	internal static void Summary()
	{
		if (s_hidden + s_kept > 0)
		{
			Logs.Info("grass-minute", "Grass: in the last minute " + s_hidden + " grass and clutter spots in the Deep North left out under snow deeper than " + Snow.M(HideDepth.Value) + ", " + s_kept + " put down where the snow is thinner.", 50f);
		}
		s_hiddenTotal += s_hidden;
		s_hidden = (s_kept = 0);
	}

	internal static string Status()
	{
		return "Grass: " + Describe() + "; " + (s_hiddenTotal + s_hidden) + " spots left out under snow this session.";
	}
}
internal static class HouseSnow
{
	internal const string Section = "2 - Houses";

	internal const string ClearOpPrefix = "anwo_sd_snow_clear_";

	internal static ConfigEntry<bool> BuildInDeepSnow;

	internal static ConfigEntry<bool> ClearUnderFires;

	internal static ConfigEntry<float> ClearMargin;

	internal static ConfigEntry<bool> FiresMelt;

	private static GameObject s_ghost;

	private static Piece s_ghostPiece;

	private static bool s_ghostOwn;

	private static readonly GameObject[] s_ops = (GameObject[])(object)new GameObject[SnowMath.ClearSizes.Length];

	private static int s_placedInSnow;

	private static int s_firesCleared;

	private static int s_meltSkipped;

	internal static void Bind(ConfigFile cfg)
	{
		BuildInDeepSnow = cfg.Bind<bool>("2 - Houses", "Build in deep snow", true, SnowDayPlugin.Host("Every piece can be placed in deep snow. Off: as in the game, most pieces need the snow shovelled away first (\"Too much snow\")."));
		ClearUnderFires = cfg.Bind<bool>("2 - Houses", "Clear snow under new fires", true, SnowDayPlugin.Host("A fire, brazier, torch or anything else that burns, placed in deep snow, clears the snow under it and a little around it, so it isn't buried. Only when it stands on or in the snow, not on a floor above it. Floors and other pieces never clear the snow under them. Off: fires are placed into the snow as in the game."));
		ClearMargin = cfg.Bind<float>("2 - Houses", "Fire clear margin", 0.5f, SnowDayPlugin.Host("How far beyond a new fire's edge the snow is cleared, in metres. The snow then slopes back up over about one more metre.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3f)));
		FiresMelt = cfg.Bind<bool>("2 - Houses", "Fires melt snow", true, SnowDayPlugin.Host("Burning fires in the Deep North slowly melt the snow around them, as in the game. Off: fires never melt the snow around them."));
	}

	internal static void Apply(Harmony h)
	{
		h.PatchAll(typeof(HouseSnow));
		PrefabManager.OnVanillaPrefabsAvailable += MakeClearOps;
		ItemManager.OnItemsRegistered += delegate
		{
			EnsureClearOps();
		};
	}

	[HarmonyPatch(typeof(Player), "UpdatePlacementGhost")]
	[HarmonyPrefix]
	private static void BeforeGhost(GameObject ___m_placementGhost)
	{
		if ((Object)(object)___m_placementGhost == (Object)null)
		{
			return;
		}
		if (___m_placementGhost != s_ghost)
		{
			s_ghost = ___m_placementGhost;
			s_ghostPiece = s_ghost.GetComponent<Piece>();
			s_ghostOwn = (Object)(object)s_ghostPiece != (Object)null && s_ghostPiece.m_allowedInDeepSnow;
		}
		if (!((Object)(object)s_ghostPiece == (Object)null))
		{
			bool flag = BuildInDeepSnow.Value || s_ghostOwn;
			if (s_ghostPiece.m_allowedInDeepSnow != flag)
			{
				s_ghostPiece.m_allowedInDeepSnow = flag;
			}
		}
	}

	[HarmonyPatch(typeof(Player), "PlacePiece")]
	[HarmonyPostfix]
	private static void AfterPlacePiece(Player __instance, Piece piece, Vector3 pos)
	{
		//IL_0020: 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_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_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fa: 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)
		if ((Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || (Object)(object)piece == (Object)null || !Snow.DeepSnowHere(pos))
		{
			return;
		}
		float num = Snow.DepthAt(pos);
		if (num <= 0f)
		{
			return;
		}
		bool flag = pos.y - Snow.GroundAt(pos) <= num + 0.5f;
		if (BuildInDeepSnow.Value && flag && !piece.m_allowedInDeepSnow && Snow.GAt(pos) > __instance.m_deepSnowBuildHeight)
		{
			s_placedInSnow++;
			Logs.Info("build", "Building: " + ((Object)((Component)piece).gameObject).name + " placed at " + Snow.Pos(pos) + " where the snow is " + Snow.M(num) + " deep (the game asks for shovelling first).");
		}
		if (ClearUnderFires.Value && !((Object)(object)((Component)piece).GetComponentInChildren<Fireplace>(true) == (Object)null))
		{
			GameObject val = Newest(piece, pos);
			if ((Object)(object)val != (Object)null)
			{
				ClearUnder(val, num);
			}
		}
	}

	private static GameObject Newest(Piece prefab, Vector3 pos)
	{
		//IL_00b4: 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_0074: 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)
		//IL_007a: Unknown result type (might be due to invalid IL or missing references)
		if (!(AccessTools.Field(typeof(Piece), "s_allPieces")?.GetValue(null) is List<Piece> { Count: not 0 } list))
		{
			return null;
		}
		Piece val = list[list.Count - 1];
		if (!((Object)(object)val == (Object)null) && !(Utils.GetPrefabName(((Component)val).gameObject) != ((Object)((Component)prefab).gameObject).name))
		{
			Vector3 val2 = ((Component)val).transform.position - pos;
			if (!(((Vector3)(ref val2)).sqrMagnitude > 0.01f))
			{
				return ((Component)val).gameObject;
			}
		}
		Logs.Info("fire-find", "Fires: couldn't find the " + ((Object)((Component)prefab).gameObject).name + " just placed at " + Snow.Pos(pos) + " (another mod placed it?), so no snow is cleared under it.");
		return null;
	}

	private static void ClearUnder(GameObject fire, float depth)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: 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)
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_009d: 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_005e: 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_00c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00af: 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_00e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_015e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0160: 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)
		Vector3 position = fire.transform.position;
		float num = Snow.GroundAt(position);
		string prefabName = Utils.GetPrefabName(fire);
		if (position.y - num > depth + 0.5f)
		{
			Logs.Info("fire-high", "Fires: " + prefabName + " at " + Snow.Pos(position) + " stands " + Snow.M(position.y - num) + " above the ground, over the " + Snow.M(depth) + " of snow: nothing cleared.");
			return;
		}
		bool any;
		Bounds val = Footprint(fire, out any);
		Vector3 val2 = (any ? new Vector3(((Bounds)(ref val)).center.x, num, ((Bounds)(ref val)).center.z) : new Vector3(position.x, num, position.z));
		float num2 = SnowMath.FireRadius(any ? ((Bounds)(ref val)).extents.x : 0.5f, any ? ((Bounds)(ref val)).extents.z : 0.5f, ClearMargin.Value);
		int num3 = SnowMath.ClearSizeIndex(num2);
		GameObject val3 = (EnsureClearOps() ? s_ops[num3] : null);
		if ((Object)(object)val3 == (Object)null)
		{
			Logs.Warn("fire-noop", "Fires: the snow-clearing terrain op isn't ready, so no snow is cleared under " + prefabName + ".");
			return;
		}
		Object.Instantiate<GameObject>(val3, val2, Quaternion.identity);
		s_firesCleared++;
		Logs.Info("fire-clear", "Fires: cleared the snow under " + prefabName + " at " + Snow.Pos(val2) + ": " + Snow.M(SnowMath.ClearSizes[num3]) + " round (needed " + Snow.M(num2) + "), then sloping back up over " + Snow.M(1f) + "; the snow there was " + Snow.M(depth) + " deep.");
	}

	private static Bounds Footprint(GameObject go, out bool any)
	{
		//IL_0005: 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_00af: 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_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_009a: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: Unknown result type (might be due to invalid IL or missing references)
		any = false;
		Bounds result = default(Bounds);
		Collider[] componentsInChildren = go.GetComponentsInChildren<Collider>();
		foreach (Collider val in componentsInChildren)
		{
			if (!((Object)(object)val == (Object)null) && val.enabled && !val.isTrigger)
			{
				if (!any)
				{
					result = val.bounds;
					any = true;
				}
				else
				{
					((Bounds)(ref result)).Encapsulate(val.bounds);
				}
			}
		}
		if (any)
		{
			return result;
		}
		Renderer[] componentsInChildren2 = go.GetComponentsInChildren<Renderer>();
		foreach (Renderer val2 in componentsInChildren2)
		{
			if (!((Object)(object)val2 == (Object)null) && val2.enabled)
			{
				if (!any)
				{
					result = val2.bounds;
					any = true;
				}
				else
				{
					((Bounds)(ref result)).Encapsulate(val2.bounds);
				}
			}
		}
		return result;
	}

	[HarmonyPatch(typeof(Fireplace), "UpdateSnowMelt")]
	[HarmonyPrefix]
	private static bool BeforeSnowMelt(Fireplace __instance)
	{
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		if (FiresMelt.Value)
		{
			return true;
		}
		s_meltSkipped++;
		Logs.Info("melt-off", "Fires: " + Utils.GetPrefabName(((Component)__instance).gameObject) + " at " + Snow.Pos(((Component)__instance).transform.position) + " doesn't melt the snow around it (Fires melt snow is off).", 60f);
		return false;
	}

	private static void MakeClearOps()
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Expected O, but got Unknown
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Expected O, but got Unknown
		//IL_0076: 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_0082: 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_0090: 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_00a0: 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_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00be: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00de: 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_00f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_010b: Expected O, but got Unknown
		//IL_010c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0116: Expected O, but got Unknown
		PrefabManager.OnVanillaPrefabsAvailable -= MakeClearOps;
		try
		{
			GameObject val = new GameObject("anwo_sd_prefab_holder");
			val.SetActive(false);
			Object.DontDestroyOnLoad((Object)(object)val);
			for (int i = 0; i < SnowMath.ClearSizes.Length; i++)
			{
				float num = SnowMath.ClearSizes[i];
				GameObject val2 = new GameObject("anwo_sd_snow_clear_" + Mathf.RoundToInt(num * 10f));
				val2.transform.SetParent(val.transform, false);
				TerrainOp obj = val2.AddComponent<TerrainOp>();
				obj.m_settings = new Settings
				{
					m_level = false,
					m_raise = false,
					m_smooth = false,
					m_paintCleared = true,
					m_paintHeightCheck = false,
					m_paintType = (PaintType)1,
					m_paintRadius = num + 1f,
					m_paintStrength = SnowMath.ClearStrength(num),
					m_paintExp = 0.5f,
					m_paintCurve = null,
					m_rotation = false,
					m_sides = false,
					m_addMedianMax = 0f,
					m_centerMultiplicationFactor = 0f,
					m_pointMultiplicationFactor = 0f,
					m_halfOffset = false
				};
				obj.m_onPlacedEffect = new EffectList();
				obj.m_spawnOnPlaced = null;
				PrefabManager.Instance.AddPrefab(val2);
				s_ops[i] = val2;
			}
			Logs.ToFile("Fires: " + s_ops.Length + " snow-clearing terrain ops made (" + Snow.M(SnowMath.ClearSizes[0]) + " to " + Snow.M(SnowMath.ClearSizes[SnowMath.ClearSizes.Length - 1]) + " round).");
		}
		catch (Exception ex)
		{
			Logs.Warn("fire-make", "Fires: making the snow-clearing terrain ops failed, so new fires don't clear snow: " + ex.Message);
		}
	}

	private static bool EnsureClearOps()
	{
		ObjectDB instance = ObjectDB.instance;
		if ((Object)(object)instance == (Object)null || (Object)(object)s_ops[0] == (Object)null)
		{
			return false;
		}
		int num = 0;
		GameObject[] array = s_ops;
		TerrainOp val2 = default(TerrainOp);
		foreach (GameObject val in array)
		{
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			if (!instance.TryGetTerrainOp(((Object)val).name, ref val2))
			{
				TerrainOp component = val.GetComponent<TerrainOp>();
				if (!instance.m_terrainOps.Contains(component))
				{
					instance.m_terrainOps.Add(component);
				}
				instance.m_terrainOpsByHash[instance.GetPrefabHash(val)] = component;
				num++;
			}
		}
		if (num > 0)
		{
			Logs.ToFileOnce("fire-registered", "Fires: " + num + " snow-clearing terrain ops added to the game's list (the zone owner needs them to apply a clearing).");
		}
		return true;
	}

	internal static IEnumerable<string> Status()
	{
		yield return "build in deep snow " + Snow.OnOff(BuildInDeepSnow.Value) + ", new fires clear snow " + (ClearUnderFires.Value ? ("(+" + Snow.M(ClearMargin.Value) + ")") : "off") + ", fires melt snow " + Snow.OnOff(FiresMelt.Value);
		yield return "Houses: " + s_placedInSnow + " pieces placed in deep snow, " + s_firesCleared + " fires cleared, " + s_meltSkipped + " fire melts skipped this session; clearing ops " + (((Object)(object)s_ops[0] != (Object)null) ? "ready" : "not made") + ".";
	}
}
internal static class Logs
{
	private sealed class Counter
	{
		internal int Shown;

		internal float Last = -1000f;

		internal int Held;
	}

	internal const int First = 5;

	internal const float Every = 10f;

	internal const float SummaryEvery = 60f;

	internal static ConfigEntry<bool> Enabled;

	private static readonly Dictionary<string, Counter> s_keys = new Dictionary<string, Counter>();

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

	private static float s_nextSummary;

	private static bool On
	{
		get
		{
			if (Enabled != null)
			{
				return Enabled.Value;
			}
			return true;
		}
	}

	internal static void Always(string text)
	{
		ManualLogSource log = SnowDayPlugin.Log;
		if (log != null)
		{
			log.LogInfo((object)text);
		}
	}

	internal static void ToFile(string text)
	{
		FileLog.Info(SnowDayPlugin.Log, text);
	}

	internal static void ToFileOnce(string key, string text)
	{
		if (On && s_once.Add(key))
		{
			FileLog.Info(SnowDayPlugin.Log, text);
		}
	}

	internal static void ToFileInfo(string key, string text, float every = 10f)
	{
		if (On && Allow(key, every))
		{
			FileLog.Info(SnowDayPlugin.Log, text);
		}
	}

	internal static void FirstToFile(string key, string text)
	{
		if (s_once.Add("file:" + key))
		{
			FileLog.Info(SnowDayPlugin.Log, text);
			return;
		}
		ManualLogSource log = SnowDayPlugin.Log;
		if (log != null)
		{
			log.LogInfo((object)text);
		}
	}

	internal static void Once(string key, string text)
	{
		if (On && s_once.Add(key))
		{
			ManualLogSource log = SnowDayPlugin.Log;
			if (log != null)
			{
				log.LogInfo((object)text);
			}
		}
	}

	internal static void Info(string key, string text, float every = 10f)
	{
		if (On && Allow(key, every))
		{
			ManualLogSource log = SnowDayPlugin.Log;
			if (log != null)
			{
				log.LogInfo((object)text);
			}
		}
	}

	internal static bool Due(string key, float every = 10f)
	{
		if (!On)
		{
			return false;
		}
		if (!s_keys.TryGetValue(key, out var value))
		{
			return true;
		}
		if (value.Shown >= 5)
		{
			return Time.realtimeSinceStartup - value.Last >= every;
		}
		return true;
	}

	internal static void Warn(string key, string text, float every = 10f)
	{
		if (Allow(key, every))
		{
			ManualLogSource log = SnowDayPlugin.Log;
			if (log != null)
			{
				log.LogWarning((object)text);
			}
		}
	}

	private static bool Allow(string key, float every)
	{
		if (!s_keys.TryGetValue(key, out var value))
		{
			value = (s_keys[key] = new Counter());
		}
		float realtimeSinceStartup = Time.realtimeSinceStartup;
		if (value.Shown < 5 || realtimeSinceStartup - value.Last >= every)
		{
			value.Shown++;
			value.Last = realtimeSinceStartup;
			return true;
		}
		value.Held++;
		return false;
	}

	internal static void Tick()
	{
		float realtimeSinceStartup = Time.realtimeSinceStartup;
		if (realtimeSinceStartup < s_nextSummary)
		{
			return;
		}
		s_nextSummary = realtimeSinceStartup + 60f;
		List<KeyValuePair<string, Counter>> list = (from kv in s_keys
			where kv.Value.Held > 0
			orderby kv.Value.Held descending
			select kv).ToList();
		if (list.Count == 0)
		{
			return;
		}
		int num = list.Sum((KeyValuePair<string, Counter> kv) => kv.Value.Held);
		ManualLogSource log = SnowDayPlugin.Log;
		if (log != null)
		{
			log.LogInfo((object)("Logs: " + num + " repeated lines held back in the last minute (" + string.Join(", ", (from kv in list.Take(8)
				select kv.Key + " " + kv.Value.Held).ToArray()) + ")."));
		}
		foreach (KeyValuePair<string, Counter> item in list)
		{
			item.Value.Held = 0;
		}
	}
}
internal static class LookMath
{
	private sealed class Taps
	{
		internal int[] Idx;

		internal float[] W;
	}

	internal const float RaiseCap = 0.05f;

	private static readonly Dictionary<long, Taps> s_taps = new Dictionary<long, Taps>();

	internal static float[] Weights(int radius)
	{
		int num = Math.Max(0, Math.Min(3, radius));
		int num2 = 2 * num + 1;
		float[] array = new float[num2];
		double num3 = Math.Pow(2.0, num2 - 1);
		for (int i = 0; i < num2; i++)
		{
			array[i] = (float)(Binomial(num2 - 1, i) / num3);
		}
		return array;
	}

	private static double Binomial(int n, int k)
	{
		double num = 1.0;
		for (int i = 1; i <= k; i++)
		{
			num = num * (double)(n - k + i) / (double)i;
		}
		return num;
	}

	internal static int Ring(int x, int y, int n)
	{
		return Math.Min(Math.Min(x, n - 1 - x), Math.Min(y, n - 1 - y));
	}

	internal static void Soften(byte[] src, byte[] dst, int n, int radius, int channel, float raiseCap, float[] tmp)
	{
		Buffer.BlockCopy(src, 0, dst, 0, n * n * 4);
		if (radius <= 0 || n < 3)
		{
			return;
		}
		float[] array = Weights(radius);
		int num = (array.Length - 1) / 2;
		for (int i = 0; i < n; i++)
		{
			for (int j = 0; j < n; j++)
			{
				float num2 = 0f;
				for (int k = -num; k <= num; k++)
				{
					num2 += array[k + num] * (float)(int)src[(i * n + Clamp(j + k, n)) * 4 + channel];
				}
				tmp[i * n + j] = num2;
			}
		}
		float num3 = Math.Max(0f, raiseCap) * 255f;
		for (int l = 1; l < n - 1; l++)
		{
			for (int m = 1; m < n - 1; m++)
			{
				float num4 = 0f;
				for (int num5 = -num; num5 <= num; num5++)
				{
					num4 += array[num5 + num] * tmp[Clamp(l + num5, n) * n + m];
				}
				float num6 = (int)src[(l * n + m) * 4 + channel];
				if (num4 > num6 + num3)
				{
					num4 = num6 + num3;
				}
				dst[(l * n + m) * 4 + channel] = (byte)((!(num4 <= 0f)) ? ((num4 >= 255f) ? byte.MaxValue : ((byte)(num4 + 0.5f))) : 0);
			}
		}
	}

	internal static int SharedCount(int n, int dx, int dz)
	{
		if (dx == 0 || dz == 0)
		{
			return n;
		}
		return 1;
	}

	internal static void Shared(int n, int dx, int dz, int i, out int x, out int y, out int nx, out int ny)
	{
		int num = n - 1;
		x = ((dx > 0) ? num : ((dx >= 0) ? i : 0));
		y = ((dz > 0) ? num : ((dz >= 0) ? i : 0));
		nx = ((dx <= 0) ? ((dx < 0) ? num : i) : 0);
		ny = ((dz <= 0) ? ((dz < 0) ? num : i) : 0);
	}

	internal static int CloseSeam(byte[] own, int n, int dx, int dz, byte[] line, int channel, out int most)
	{
		most = 0;
		int num = 0;
		int num2 = SharedCount(n, dx, dz);
		for (int i = 0; i < num2; i++)
		{
			Shared(n, dx, dz, i, out var x, out var y, out var _, out var _);
			int num3 = (y * n + x) * 4 + channel;
			if (line[i] < own[num3])
			{
				most = Math.Max(most, own[num3] - line[i]);
				own[num3] = line[i];
				num++;
			}
		}
		return num;
	}

	internal static int LineHash(byte[] line, int count)
	{
		int num = -2128831035;
		for (int i = 0; i < count; i++)
		{
			num = (num ^ line[i]) * 16777619;
		}
		if (num != 0)
		{
			return num;
		}
		return 1;
	}

	internal static int Mismatch(byte[] own, int n, int dx, int dz, byte[] line, int channel, int tolerance, out int most, out int at)
	{
		most = 0;
		at = -1;
		int num = SharedCount(n, dx, dz);
		int num2 = 0;
		for (int i = 0; i < num; i++)
		{
			Shared(n, dx, dz, i, out var x, out var y, out var _, out var _);
			int num3 = Math.Abs(own[(y * n + x) * 4 + channel] - line[i]);
			if (num3 > tolerance)
			{
				num2++;
			}
			if (num3 > most)
			{
				most = num3;
				at = i;
			}
		}
		return num2;
	}

	internal static void TapsAt(Kernel kernel, int n, double s, out int i0, out float w0, out float w1, out float w2, out float w3)
	{
		if (s <= 0.0 || s >= (double)(n - 1))
		{
			i0 = ((!(s <= 0.0)) ? (n - 1) : 0);
			w0 = 0f;
			w1 = 1f;
			w2 = 0f;
			w3 = 0f;
		}
		else
		{
			i0 = (int)Math.Floor(s);
			SnowMath.Weights(kernel, (float)(s - (double)i0), out w0, out w1, out w2, out w3);
		}
	}

	private static Taps TapsFor(int n, int k, Kernel kernel)
	{
		long key = ((long)n << 20) | ((long)k << 4) | (long)kernel;
		if (s_taps.TryGetValue(key, out var value))
		{
			return value;
		}
		int num = n * k;
		value = new Taps
		{
			Idx = new int[num * 4],
			W = new float[num * 4]
		};
		for (int i = 0; i < num; i++)
		{
			TapsAt(kernel, n, ((double)i + 0.5) / (double)k - 0.5, out var i2, out var w, out var w2, out var w3, out var w4);
			value.Idx[i * 4] = Clamp(i2 - 1, n);
			value.W[i * 4] = w;
			value.Idx[i * 4 + 1] = Clamp(i2, n);
			value.W[i * 4 + 1] = w2;
			value.Idx[i * 4 + 2] = Clamp(i2 + 1, n);
			value.W[i * 4 + 2] = w3;
			value.Idx[i * 4 + 3] = Clamp(i2 + 2, n);
			value.W[i * 4 + 3] = w4;
		}
		s_taps[key] = value;
		return value;
	}

	internal static void Upsample(byte[] src, int n, int k, Kernel kernel, byte[] dst, float[] tmp)
	{
		int num = n * k;
		Taps taps = TapsFor(n, k, kernel);
		int[] idx = taps.Idx;
		float[] w = taps.W;
		for (int i = 0; i < n; i++)
		{
			int num2 = i * n * 4;
			int num3 = i * num * 4;
			for (int j = 0; j < num; j++)
			{
				int num4 = j * 4;
				int num5 = num2 + idx[num4] * 4;
				int num6 = num2 + idx[num4 + 1] * 4;
				int num7 = num2 + idx[num4 + 2] * 4;
				int num8 = num2 + idx[num4 + 3] * 4;
				float num9 = w[num4];
				float num10 = w[num4 + 1];
				float num11 = w[num4 + 2];
				float num12 = w[num4 + 3];
				int num13 = num3 + j * 4;
				for (int l = 0; l < 4; l++)
				{
					tmp[num13 + l] = (float)(int)src[num5 + l] * num9 + (float)(int)src[num6 + l] * num10 + (float)(int)src[num7 + l] * num11 + (float)(int)src[num8 + l] * num12;
				}
			}
		}
		for (int m = 0; m < num; m++)
		{
			int num14 = m * 4;
			int num15 = idx[num14] * num * 4;
			int num16 = idx[num14 + 1] * num * 4;
			int num17 = idx[num14 + 2] * num * 4;
			int num18 = idx[num14 + 3] * num * 4;
			float num19 = w[num14];
			float num20 = w[num14 + 1];
			float num21 = w[num14 + 2];
			float num22 = w[num14 + 3];
			int num23 = m * num * 4;
			for (int num24 = 0; num24 < num * 4; num24++)
			{
				float num25 = tmp[num15 + num24] * num19 + tmp[num16 + num24] * num20 + tmp[num17 + num24] * num21 + tmp[num18 + num24] * num22;
				dst[num23 + num24] = (byte)((!(num25 <= 0f)) ? ((num25 >= 255f) ? byte.MaxValue : ((byte)(num25 + 0.5f))) : 0);
			}
		}
	}

	internal static float SampleAtVertex(byte[] dst, int n, int k, int vx, int vy, int channel)
	{
		int num = n * k;
		double num2 = (double)vx / (double)(n - 1);
		double num3 = (double)vy / (double)(n - 1);
		return Bilinear(dst, num, num2 * (double)num - 0.5, num3 * (double)num - 0.5, channel);
	}

	internal static float SampleOwnAtVertex(byte[] src, int n, int vx, int vy, int channel)
	{
		double num = (double)vx / (double)(n - 1);
		double num2 = (double)vy / (double)(n - 1);
		return Bilinear(src, n, num * (double)n - 0.5, num2 * (double)n - 0.5, channel);
	}

	internal static double MapUV(double local, double scale, int w)
	{
		return (local / ((scale > 0.0) ? scale : 1.0) + (double)((w + 1) / 2)) / (double)w;
	}

	internal static void BilinearTaps(double u, int size, out int i0, out int i1, out float f)
	{
		double num = u * (double)size - 0.5;
		int num2 = (int)Math.Floor(num);
		f = (float)(num - (double)num2);
		i0 = Clamp(num2, size);
		i1 = Clamp(num2 + 1, size);
	}

	internal static float SampleAt(byte[] t, int size, int stride, int channel, double u, double v)
	{
		BilinearTaps(u, size, out var i, out var i2, out var f);
		BilinearTaps(v, size, out var i3, out var i4, out var f2);
		float num = (int)t[(i3 * size + i) * stride + channel];
		float num2 = (int)t[(i3 * size + i2) * stride + channel];
		float num3 = (int)t[(i4 * size + i) * stride + channel];
		float num4 = (int)t[(i4 * size + i2) * stride + channel];
		return (num * (1f - f) + num2 * f) * (1f - f2) + (num3 * (1f - f) + num4 * f) * f2;
	}

	private static float Bilinear(byte[] t, int size, double sx, double sy, int channel)
	{
		int num = (int)Math.Floor(sx);
		int num2 = (int)Math.Floor(sy);
		float num3 = (float)(sx - (double)num);
		float num4 = (float)(sy - (double)num2);
		float num5 = (int)t[(Clamp(num2, size) * size + Clamp(num, size)) * 4 + channel];
		float num6 = (int)t[(Clamp(num2, size) * size + Clamp(num + 1, size)) * 4 + channel];
		float num7 = (int)t[(Clamp(num2 + 1, size) * size + Clamp(num, size)) * 4 + channel];
		float num8 = (int)t[(Clamp(num2 + 1, size) * size + Clamp(num + 1, size)) * 4 + channel];
		return (num5 * (1f - num3) + num6 * num3) * (1f - num4) + (num7 * (1f - num3) + num8 * num3) * num4;
	}

	private static int Clamp(int i, int n)
	{
		if (i >= 0)
		{
			if (i < n)
			{
				return i;
			}
			return n - 1;
		}
		return 0;
	}
}
public static class Melting
{
	internal const string Section = "7 - Melting";

	internal const float CheckSeconds = 5f;

	internal const float HeatRadius = 0.5f;

	internal const string WaterEffectName = "fx_land_water";

	internal static ConfigEntry<bool> Enabled;

	internal static ConfigEntry<float> HeatSeconds;

	internal static ConfigEntry<float> WarmMinutes;

	internal static ConfigEntry<string> ColdBiomes;

	internal static ConfigEntry<MeltLeftover> Leftover;

	private static Biome s_cold = (Biome)68;

	private static string s_coldText = "DeepNorth, Mountain";

	private static MethodInfo s_destroy;

	private static EffectList s_none;

	private static EffectList s_water;

	private static bool s_waterLooked;

	private static int s_next;

	private static int s_minute;

	private static float s_allow;

	private static float s_nextSummary;

	private static float s_maxElapsed = 15f;

	private static int s_looked;

	private static int s_kept;

	private static int s_heat;

	private static int s_warm;

	private static int s_removed;

	private static readonly Dictionary<string, int> s_reasons = new Dictionary<string, int>();

	private static long s_removedTotal;

	private static long s_writes;

	internal static string ColdText => s_coldText;

	internal static void Bind(ConfigFile cfg)
	{
		Enabled = cfg.Bind<bool>("7 - Melting", "Snow blocks melt", true, SnowDayPlugin.Host("Snow blocks melt away near fires and other heat, and slowly anywhere outside the cold biomes (see Cold biomes). Melting wears a block's health down by the same amount every few seconds, so a block at full health is gone after the melt time below; the hammer's health bar shows how far it has gone, and repairing it with the hammer packs it full again. A block that has melted away leaves nothing to pick up. Snow in your inventory and in chests never melts. The game of the player who owns a block (usually whoever is nearest) does the melting. Off: snow blocks never melt."));
		HeatSeconds = cfg.Bind<float>("7 - Melting", "Melt time near heat", 600f, SnowDayPlugin.Host("Seconds for a snow block at full health to melt away when it is near a burning fire, brazier, hearth, torch or anything else that gives off heat (the same heat that warms you up). That warmth reaches about 8 m from a campfire or fire pit, 13 m from a hearth, 15 m from a bonfire, 5 to 8 m from a brazier, 6 m from a sconce and 3 m from a standing wood torch; a block melts when that warmth comes within half the block's size of its middle. Heat melts snow blocks in every biome, the Deep North too. 600: a fire inside an igloo takes it down in about 10 minutes. 0: heat never melts them.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3600f)));
		WarmMinutes = cfg.Bind<float>("7 - Melting", "Melt time in warm places", 30f, SnowDayPlugin.Host("Minutes for a snow block at full health to melt away anywhere outside the cold biomes when there is no heat near it. 0: outside the cold biomes they keep too, unless there is heat.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1440f)));
		ColdBiomes = cfg.Bind<string>("7 - Melting", "Cold biomes", "DeepNorth, Mountain", SnowDayPlugin.Host("Biomes where snow blocks and solid snow never melt on their own (only heat melts them there), separated by commas. The game's names: Meadows, BlackForest, Swamp, Mountain, Plains, Mistlands, AshLands, DeepNorth, Ocean. The biome is the one the world was made with at that exact spot, so at a biome's edge snow blocks and solid snow keep or melt alike."));
		Leftover = cfg.Bind<MeltLeftover>("7 - Melting", "Melted blocks leave", MeltLeftover.Water, SnowDayPlugin.Host("Water: a snow block that melts away ends with a small splash of water (shown on the game of the player who melted it). Nothing: it simply disappears. Either way there is nothing to pick up."));
	}

	internal static void Apply(Harmony h)
	{
		//IL_0052: 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_0068: Expected O, but got Unknown
		s_destroy = AccessTools.Method(typeof(WearNTear), "Destroy", new Type[2]
		{
			typeof(HitData),
			typeof(bool)
		}, (Type[])null);
		if (s_destroy == null)
		{
			throw new MissingMethodException("WearNTear.Destroy(HitData, bool) not found");
		}
		s_none = new EffectList
		{
			m_effectPrefabs = (EffectData[])(object)new EffectData[0]
		};
		ParseCold();
		ColdBiomes.SettingChanged += delegate
		{
			ParseCold();
			Logs.Always("Melting: cold biomes (snow blocks and solid snow) are now " + s_coldText + ".");
		};
		Enabled.SettingChanged += delegate
		{
			Logs.Always("Melting: snow blocks melt " + Snow.OnOff(Enabled.Value) + ".");
		};
		HeatSeconds.SettingChanged += delegate
		{
			Logs.Always("Melting: melt time near heat is now " + SnowBlockMath.Duration(HeatSeconds.Value) + ".");
		};
		WarmMinutes.SettingChanged += delegate
		{
			Logs.Always("Melting: melt time in warm places is now " + SnowBlockMath.Duration(WarmMinutes.Value * 60f) + ".");
		};
	}

	private unsafe static void ParseCold()
	{
		//IL_0001: 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_0079: 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_003e: 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_0041: 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)
		Biome val = (Biome)0;
		List<string> list = new List<string>();
		List<string> list2 = new List<string>();
		foreach (string item in SnowBlockMath.BiomeNames(ColdBiomes.Value))
		{
			if (Enum.TryParse<Biome>(item, ignoreCase: true, out Biome result) && (int)result != 0)
			{
				val |= result;
				list.Add(((object)(*(Biome*)(&result))/*cast due to .constrained prefix*/).ToString());
			}
			else
			{
				list2.Add(item);
			}
		}
		s_cold = val;
		s_coldText = ((list.Count == 0) ? "none" : string.Join(", ", list.ToArray()));
		if (list2.Count > 0)
		{
			Logs.Warn("cold-names", "Melting: Cold biomes has names the game doesn't know, left out: " + string.Join(", ", list2.ToArray()) + " (the game's names: Meadows, BlackForest, Swamp, Mountain, Plains, Mistlands, AshLands, DeepNorth, Ocean).", 60f);
		}
	}

	public static Warmth WarmthAt(Vector3 pos, out string why)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		return WarmthAt(pos, 0.5f, out why);
	}

	public static Warmth WarmthAt(Vector3 pos, float radius, out string why)
	{
		//IL_0000: 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_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0043: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: Invalid comparison between Unknown and I4
		EffectArea val = EffectArea.IsPointInsideArea(pos, (Type)1, Mathf.Max(0f, radius));
		if ((Object)(object)val != (Object)null)
		{
			why = "heat from " + HeatName(val);
			return Warmth.Heat;
		}
		Biome biome;
		bool flag = ColdAt(pos, out biome);
		why = BiomeWhy(flag, biome);
		return SnowBlockMath.Decide(nearHeat: false, (int)biome > 0, flag);
	}

	public static bool ColdAt(Vector3 pos, out Biome biome)
	{
		//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_0008: Expected I4, but got Unknown
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Invalid comparison between Unknown and I4
		biome = (Biome)(int)BiomeAt(pos);
		if (biome)
		{
			return (s_cold & biome) > 0;
		}
		return true;
	}

	internal static Biome BiomeAt(Vector3 pos)
	{
		//IL_0013: 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_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		if (WorldGenerator.instance == null)
		{
			return Heightmap.FindBiome(pos);
		}
		return WorldGenerator.instance.GetBiome(pos);
	}

	internal unsafe static string BiomeWhy(bool cold, Biome biome)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		if ((int)biome != 0)
		{
			return (cold ? "cold biome " : "warm biome ") + ((object)(*(Biome*)(&biome))/*cast due to .constrained prefix*/).ToString();
		}
		return "biome not known here";
	}

	private static string HeatName(EffectArea area)
	{
		Transform transform = ((Component)area).transform;
		ZNetView componentInParent = ((Component)transform).GetComponentInParent<ZNetView>();
		return Utils.GetPrefabName(((Object)(object)componentInParent != (Object)null) ? ((Component)componentInParent).gameObject : ((Component)transform.root).gameObject);
	}

	internal static float MeltSeconds(Warmth w)
	{
		if (Enabled.Value)
		{
			switch (w)
			{
			case Warmth.None:
				break;
			default:
				return WarmMinutes.Value * 60f;
			case Warmth.Heat:
				return HeatSeconds.Value;
			}
		}
		return 0f;
	}

	internal static string Fate(Warmth w, string why)
	{
		if (!Enabled.Value)
		{
			return "melting is off, so it keeps";
		}
		float num = MeltSeconds(w);
		if (w == Warmth.None)
		{
			return "it keeps (" + why + ")";
		}
		if (num <= 0f)
		{
			return "it keeps (" + why + ", but that melt time is 0)";
		}
		return "it melts away in about " + SnowBlockMath.Duration(num) + " (" + why + ")";
	}

	internal static void Tick(float dt)
	{
		Summary();
		if (!Enabled.Value || (Object)(object)ZNet.instance == (Object)null)
		{
			return;
		}
		List<SnowBlock> s_all = SnowBlock.s_all;
		int count = s_all.Count;
		if (count == 0)
		{
			return;
		}
		float num = SnowMath.RoofRate(count, 5f, 200f);
		s_allow = Mathf.Min(s_allow + dt * num, 200f);
		int num2 = Mathf.Min((int)s_allow, count);
		s_allow -= num2;
		s_maxElapsed = Mathf.Max(15f, 2f * (float)count / num);
		float time = Time.time;
		for (int i = 0; i < num2; i++)
		{
			if (s_all.Count <= 0)
			{
				break;
			}
			if (s_next >= s_all.Count)
			{
				s_next = 0;
			}
			Check(s_all[s_next++], time);
		}
	}

	private static void Check(SnowBlock b, float now)
	{
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0236: Unknown result type (might be due to invalid IL or missing references)
		//IL_033f: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)b == (Object)null || b.m_spec == null)
		{
			return;
		}
		ZNetView nview = b.m_nview;
		WearNTear wear = b.m_wear;
		if ((Object)(object)nview == (Object)null || (Object)(object)wear == (Object)null || !nview.IsValid())
		{
			return;
		}
		if (!nview.IsOwner())
		{
			b.m_lastCheck = -1f;
			b.m_pending = 0f;
			return;
		}
		float elapsed = ((b.m_lastCheck < 0f) ? 0f : (now - b.m_lastCheck));
		b.m_lastCheck = now;
		s_looked++;
		string why;
		Warmth warmth = WarmthAt(b.Centre, b.m_spec.HeatReach, out why);
		float health = wear.m_health;
		float num = SnowBlockMath.MeltPerSecond(warmth, health, HeatSeconds.Value, WarmMinutes.Value * 60f);
		if (num <= 0f)
		{
			s_kept++;
			return;
		}
		if (b.m_minute != s_minute)
		{
			b.m_minute = s_minute;
			if (warmth == Warmth.Heat)
			{
				s_heat++;
			}
			else
			{
				s_warm++;
			}
			string key = ((warmth == Warmth.Heat) ? why.Replace("heat from ", "near heat: ") : why.Replace("warm biome ", "in "));
			s_reasons.TryGetValue(key, out var value);
			s_reasons[key] = value + 1;
		}
		ZDO zDO = nview.GetZDO();
		float health2 = Mathf.Min(zDO.GetFloat(ZDOVars.s_health, health), health);
		float left;
		switch (SnowBlockMath.MeltCheck(num, elapsed, s_maxElapsed, health2, health, ref b.m_pending, out left))
		{
		case SnowBlockMath.MeltAction.Remove:
			MeltAway(b, why);
			break;
		case SnowBlockMath.MeltAction.Write:
		{
			zDO.Set(ZDOVars.s_health, left);
			nview.InvokeRPC(ZNetView.Everybody, "RPC_HealthChanged", new object[1] { left });
			s_writes++;
			int num2 = SnowBlockMath.Quarter(left, health);
			if (b.m_quarter < 0)
			{
				Logs.Info("melt-start", "Melting: " + b.m_spec.Name + " at " + Snow.Pos(((Component)b).transform.position) + " is melting (" + why + "): " + Snow.F(num * 5f, "0.###") + " of its " + Snow.F(health, "0") + " health every " + Snow.F(5f, "0") + " s, so a full block goes in " + SnowBlockMath.Duration(health / num) + "; " + Snow.F(left, "0.0") + " health left.");
			}
			if (num2 != b.m_quarter)
			{
				if (b.m_quarter >= 0 && num2 > b.m_quarter)
				{
					Logs.Info("melt-step", "Melting: " + b.m_spec.Name + " at " + Snow.Pos(((Component)b).transform.position) + " is " + num2 * 25 + " % melted (" + why + "; " + Snow.F(left, "0.0") + " of " + Snow.F(health, "0") + " health left).");
				}
				b.m_quarter = num2;
			}
			break;
		}
		}
	}

	private static void MeltAway(SnowBlock b, string why)
	{
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0126: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
		WearNTear wear = b.m_wear;
		Vector3 position = ((Component)b).transform.position;
		string name = b.m_spec.Name;
		EffectList destroyedEffect = wear.m_destroyedEffect;
		EffectList val = ((Leftover.Value == MeltLeftover.Water) ? WaterEffect() : null);
		wear.m_destroyedEffect = val ?? s_none;
		try
		{
			s_destroy.Invoke(wear, new object[2] { null, true });
			s_removed++;
			s_removedTotal++;
			Logs.Info("melt-gone", "Melting: " + name + " at " + Snow.Pos(position) + " melted away (" + why + ")" + ((val != null) ? ", leaving a little water." : ", leaving nothing."));
		}
		catch (Exception ex)
		{
			Exception ex2 = ((ex is TargetInvocationException && ex.InnerException != null) ? ex.InnerException : ex);
			Logs.Warn("melt-fail", "Melting: removing the melted " + name + " at " + Snow.Pos(position) + " failed: " + ex2.GetType().Name + ": " + ex2.Message, 60f);
		}
		finally
		{
			if ((Object)(object)wear != (Object)null)
			{
				wear.m_destroyedEffect = destroyedEffect;
			}
		}
	}

	private static EffectList WaterEffect()
	{
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Expected O, but got Unknown
		//IL_003f: 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_004b: 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_005a: Expected O, but got Unknown
		if (!s_waterLooked)
		{
			s_waterLooked = true;
			GameObject val = null;
			try
			{
				val = PrefabManager.Instance.GetPrefab("fx_land_water");
			}
			catch (Exception)
			{
			}
			if ((Object)(object)val != (Object)null)
			{
				EffectList val2 = new EffectList();
				val2.m_effectPrefabs = (EffectData[])(object)new EffectData[1]
				{
					new EffectData
					{
						m_prefab = val,
						m_enabled = true,
						m_variant = -1
					}
				};
				s_water = val2;
			}
			Logs.Always("Melting: " + (((Object)(object)val != (Object)null) ? "melted snow blocks leave the game's fx_land_water splash" : "the game's fx_land_water splash wasn't found, so melted snow blocks just disappear") + ".");
		}
		return s_water;
	}

	private static void Summary()
	{
		float realtimeSinceStartup = Time.realtimeSinceStartup;
		if (realtimeSinceStartup < s_nextSummary)
		{
			return;
		}
		s_nextSummary = realtimeSinceStartup + 60f;
		if (s_heat + s_warm + s_removed > 0)
		{
			string text = string.Join(", ", (from kv in s_reasons.OrderByDescending((KeyValuePair<string, int> kv) => kv.Value).Take(6)
				select kv.Key + " " + kv.Value).ToArray());
			Logs.Info("melt-minute", "Melting: " + (s_heat + s_warm) + " snow blocks melting in the last minute (" + s_heat + " near heat, " + s_warm + " in warm places" + ((text.Length > 0) ? ("; " + text) : "") + "), " + s_removed + " melted away; " + s_looked + " checks by this game, " + s_kept + " of them where snow keeps.", 50f);
		}
		s_looked = (s_kept = (s_heat = (s_warm = (s_removed = 0))));
		s_reasons.Clear();
		s_minute++;
	}

	internal static IEnumerable<string> Status()
	{
		yield return Enabled.Value ? ("melting on (near heat " + SnowBlockMath.Duration(HeatSeconds.Value) + ", warm places " + SnowBlockMath.Duration(WarmMinutes.Value * 60f) + ", cold " + s_coldText + ")") : "melting off";
		int num = 0;
		foreach (SnowBlock item in SnowBlock.s_all)
		{
			if ((Object)(object)item != (Object)null && (Object)(object)item.m_nview != (Object)null && item.m_nview.IsValid() && item.m_nview.IsOwner())
			{
				num++;
			}
		}
		yield return "Melting: " + s_removedTotal + " snow blocks melted away this session (" + s_writes + " health updates); " + num + " of " + SnowBlock.s_all.Count + " loaded snow blocks are melted by this game; melted blocks leave " + ((Leftover.Value == MeltLeftover.Water) ? "a little water" : "nothing") + ".";
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer != (Object)null)
		{
			string why;
			Warmth w = WarmthAt(((Component)localPlayer).transform.position, out why);
			yield return "Melting where you stand: " + w.ToString() + " (" + why + "): a snow block here " + Fate(w, why) + ".";
		}
	}
}
internal enum ShovelSwing
{
	Shove,
	Collect
}
internal static class PlowMath
{
	internal struct Spot
	{
		internal int I;

		internal int J;

		internal float Along;

		internal float Side;
	}

	internal const float PlowNear = 0.2f;

	internal const float PlowFar = 1.6f;

	internal const float ShoveNear = 0.4f;

	internal const float ShoveFar = 1.9f;

	internal const float MinG = 0.03f;

	internal const float MinSpeed = 0.3f;

	internal const float ResendLocal = 0.25f;

	internal const float ResendRemote = 0.6f;

	internal const int MostOpsPerSecond = 20;

	internal const int MostShoveOps = 16;

	private static readonly Comparison<Spot> Nearer = (Spot a, Spot b) => (a.Along == b.Along) ? Math.Abs(a.Side).CompareTo(Math.Abs(b.Side)) : a.Along.CompareTo(b.Along);

	internal static bool SendAgain(float since, bool local, float gNow)
	{
		if (gNow >= 0.03f)
		{
			return since >= (local ? 0.25f : 0.6f);
		}
		return false;
	}

	internal static List<Spot> Window(float px, float pz, float fx, float fz, float width, float near, float far, float scale, float ox, float oz)
	{
		return Window(px, pz, fx, fz, width, near, far, scale, ox, oz, new List<Spot>());
	}

	internal static List<Spot> Window(float px, float pz, float fx, float fz, float width, float near, float far, float scale, float ox, float oz, List<Spot> list)
	{
		list.Clear();
		double num = Math.Sqrt(fx * fx + fz * fz);
		if (num < 1E-06 || scale <= 0f || far < near)
		{
			return list;
		}
		float num2 = (float)((double)fx / num);
		float num3 = (float)((double)fz / num);
		float num4 = Math.Max(0f, width) * 0.5f + scale * 0.5f;
		float num5 = Math.Max(Math.Abs(far), Math.Abs(near)) + num4 + scale;
		int num6 = (int)Math.Floor((px - num5 - ox) / scale);
		int num7 = (int)Math.Ceiling((px + num5 - ox) / scale);
		int num8 = (int)Math.Floor((pz - num5 - oz) / scale);
		int num9 = (int)Math.Ceiling((pz + num5 - oz) / scale);
		for (int i = num8; i <= num9; i++)
		{
			for (int j = num6; j <= num7; j++)
			{
				float num10 = ox + (float)j * scale - px;
				float num11 = oz + (float)i * scale - pz;
				float num12 = num10 * num2 + num11 * num3;
				float num13 = num11 * num2 - num10 * num3;
				if (!(num12 < near - 0.0001f) && !(num12 > far + 0.0001f) && !(Math.Abs(num13) > num4 + 0.0001f))
				{
					list.Add(new Spot
					{
						I = j,
						J = i,
						Along = num12,
						Side = num13
					});
				}
			}
		}
		list.Sort(Nearer);
		return list;
	}

	internal static int Index(float w, float origin, float scale)
	{
		return (int)Math.Floor((w - origin) / scale + 0.5f);
	}

	internal static bool Shoves(ShovelSwing normal, bool crouching, bool shoveOn)
	{
		if (shoveOn)
		{
			return normal == ShovelSwing.Shove != crouching;
		}
		return false;
	}

	internal static bool Crouched(bool toggled, bool pose)
	{
		return toggled || pose;
	}

	internal static bool MovingForward(float vx, float vz, float fx, float fz)
	{
		double num = Math.Sqrt(fx * fx + fz * fz);
		if (num < 1E-06)
		{
			return false;
		}
		return (double)(vx * fx + vz * fz) / num >= 0.30000001192092896;
	}

	internal static int BladeEnd(float min, float max, float widthAtMin, float widthAtMax)
	{
		if (widthAtMin > 0f && widthAtMax > 0f && Math.Abs(widthAtMax - widthAtMin) > 0.15f * Math.Max(widthAtMax, widthAtMin))
		{
			if (!(widthAtMax > widthAtMin))
			{
				return -1;
			}
			return 1;
		}
		if (!(Math.Abs(max) >= Math.Abs(min)))
		{
			return -1;
		}
		return 1;
	}

	internal static float CubicMetres(float g, float scale)
	{
		return PushMath.CubicMetres(g, scale);
	}
}
[DefaultExecutionOrder(10000)]
internal sealed class PlowPose : MonoBehaviour
{
	private sealed class Rig
	{
		internal Player P;

		internal VisEquipment Vis;

		internal bool BonesSearched;

		internal Transform Spine;

		internal Transform[] Right;

		internal Transform[] Left;

		internal GameObject Item;

		internal bool Aligned;

		internal Vector3 GripInHand;

		internal Vector3 TipInHand;

		internal float Weight;

		internal int Frames;

		internal Quaternion SpineBefore;

		internal Quaternion SpineAfter;

		internal bool SpineSet;

		internal int SpineKept;
	}

	internal const float Lean = 18f;

	internal const float BladeAhead = 1.15f;

	internal const float BladeUp = 0.05f;

	internal const float GripHeight = 0.5f;

	internal const float GripAhead = 0.3f;

	internal const float GripSide = 0.1f;

	internal const float LeftDown = 0.4f;

	internal const float Blend = 0.15f;

	private static readonly Dictionary<Player, Rig> s_rigs = new Dictionary<Player, Rig>();

	private static readonly List<Player> s_gone = new List<Player>();

	private static GameObject s_go;

	private static bool s_failed;

	private static bool s_boneWarned;

	private static int s_rigsMade;

	private static int s_frames;

	private static int s_measured;

	private static int s_spineKept;

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

	internal static void Begin()
	{
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Expected O, but got Unknown
		if (!((Object)(object)s_go != (Object)null))
		{
			s_go = new GameObject("anwo_sd_plow_pose");
			Object.DontDestroyOnLoad((Object)(object)s_go);
			s_go.AddComponent<PlowPose>();
			Logs.Always("Plow pose: chosen: SnowDay bends the bones of every player it sees blocking with the Snow Shovel (with Plow on), after the game's own animation each frame, on each game: the body leans " + Snow.F(18f, "0") + "° into the shovel, the right hand turns it to point down and forward with its blade " + Snow.M(1.15f) + " in front of the feet on the snow, and the left hand takes the shaft lower down. The game has no plowing animation, and the other games only see the animator states the game itself sends (ZSyncAnimation), so each game draws it from what it already gets: that the player blocks and holds the Snow Shovel. Only the look: the block, its stamina and hits are the game's. Plow pose (each player's own) is " + Snow.OnOff(ShovelPlow.Pose.Value) + " here; a game without 1.4.1 draws the game's block pose.");
		}
	}

	internal static string StatusText()
	{
		return "plow pose " + Snow.OnOff(ShovelPlow.Pose.Value) + ": drawn " + s_frames + " frames this session for " + s_rigsMade + " players" + ((s_who.Count > 0) ? (" (" + string.Join(", ", s_who.ToArray()) + ")") : "") + ", " + s_measured + " shovels measured, " + s_spineKept + " frames whose lean was put back first (the animation hadn't redrawn the spine)";
	}

	private static bool Wanted(Player p, VisEquipment vis)
	{
		if (ShovelPlow.Pose == null || !ShovelPlow.Pose.Value || ShovelPlow.Plow == null || !ShovelPlow.Plow.Value)
		{
			return false;
		}
		if ((Object)(object)p == (Object)null || ((Character)p).IsDead() || !((Character)p).IsBlocking())
		{
			return false;
		}
		if (p == Player.m_localPlayer && SnowShaping.Active)
		{
			return false;
		}
		return ShovelPlow.ShovelInHand(p, vis);
	}

	private void LateUpdate()
	{
		if (s_failed)
		{
			return;
		}
		try
		{
			float deltaTime = Time.deltaTime;
			List<Player> allPlayers = Player.GetAllPlayers();
			for (int i = 0; i < allPlayers.Count; i++)
			{
				Player val = allPlayers[i];
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				s_rigs.TryGetValue(val, out var value);
				VisEquipment vis = ((value != null) ? value.Vis : ((Component)val).GetComponent<VisEquipment>());
				bool flag = Wanted(val, vis);
				if (flag || value != null)
				{
					if (value == null)
					{
						Dictionary<Player, Rig> dictionary = s_rigs;
						Rig obj = new Rig
						{
							P = val,
							Vis = vis
						};
						value = obj;
						dictionary[val] = obj;
						s_rigsMade++;
					}
					value.Weight = Mathf.Clamp01(value.Weight + (flag ? deltaTime : (0f - deltaTime)) / 0.15f);
					if (!(value.Weight <= 0f))
					{
						Pose(value);
					}
				}
			}
			s_gone.Clear();
			foreach (KeyValuePair<Player, Rig> s_rig in s_rigs)
			{
				if ((Object)(object)s_rig.Key == (Object)null || (s_rig.Value.Weight <= 0f && !Wanted(s_rig.Key, s_rig.Value.Vis)))
				{
					s_gone.Add(s_rig.Key);
				}
			}
			foreach (Player item in s_gone)
			{
				s_rigs.Remove(item);
			}
		}
		catch (Exception ex)
		{
			s_failed = true;
			Logs.Warn("pose-fail", "Plow pose: drawing it failed, so players blocking with the Snow Shovel show the game's block pose for the rest of this session: " + ex, 600f);
		}
	}

	private static void Pose(Rig rig)
	{
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_0077: 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_007d: 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)
		//IL_012e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0133: Unknown result type (might be due to invalid IL or missing references)
		//IL_0145: Unknown result type (might be due to invalid IL or missing references)
		//IL_0147: Unknown result type (might be due to invalid IL or missing references)
		//IL_0152: Unknown result type (might be due to invalid IL or missing references)
		//IL_0157: Unknown result type (might be due to invalid IL or missing references)
		//IL_0168: Unknown result type (might be due to invalid IL or missing references)
		//IL_016d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c3: 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_01b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bf: 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_01ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01da: Unknown result type (might be due to invalid IL or missing references)
		//IL_01db: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0202: Unknown result type (might be due to invalid IL or missing references)
		//IL_0209: Unknown result type (might be due to invalid IL or missing references)
		//IL_020e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0213: Unknown result type (might be due to invalid IL or missing references)
		//IL_0215: Unknown result type (might be due to invalid IL or missing references)
		//IL_0217: Unknown result type (might be due to invalid IL or missing references)
		//IL_0219: Unknown result type (might be due to invalid IL or missing references)
		//IL_021e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0239: Unknown result type (might be due to invalid IL or missing references)
		//IL_023e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0243: Unknown result type (might be due to invalid IL or missing references)
		//IL_0248: Unknown result type (might be due to invalid IL or missing references)
		//IL_024d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0252: Unknown result type (might be due to invalid IL or missing references)
		//IL_0254: Unknown result type (might be due to invalid IL or missing references)
		//IL_0259: Unknown result type (might be due to invalid IL or missing references)
		//IL_026e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0270: Unknown result type (might be due to invalid IL or missing references)
		//IL_0274: Unknown result type (might be due to invalid IL or missing references)
		//IL_0279: Unknown result type (might be due to invalid IL or missing references)
		//IL_027e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0280: Unknown result type (might be due to invalid IL or missing references)
		//IL_0282: Unknown result type (might be due to invalid IL or missing references)
		//IL_0284: Unknown result type (might be due to invalid IL or missing references)
		//IL_0289: Unknown result type (might be due to invalid IL or missing references)
		//IL_028d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0292: Unknown result type (might be due to invalid IL or missing references)
		//IL_0296: Unknown result type (might be due to invalid IL or missing references)
		//IL_029b: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_02af: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_02db: Unknown result type (might be due to invalid IL or missing references)
		//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e8: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_02fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_0308: Unknown result type (might be due to invalid IL or missing references)
		//IL_0312: Unknown result type (might be due to invalid IL or missing references)
		//IL_0317: Unknown result type (might be due to invalid IL or missing references)
		//IL_031c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0321: Unknown result type (might be due to invalid IL or missing references)
		//IL_0326: Unknown result type (might be due to invalid IL or missing references)
		//IL_032b: Unknown result type (might be due to invalid IL or missing references)
		//IL_032d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0332: Unknown result type (might be due to invalid IL or missing references)
		//IL_0343: Unknown result type (might be due to invalid IL or missing references)
		//IL_0347: Unknown result type (might be due to invalid IL or missing references)
		//IL_035e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0363: Unknown result type (might be due to invalid IL or missing references)
		//IL_0368: Unknown result type (might be due to invalid IL or missing references)
		//IL_0378: Unknown result type (might be due to invalid IL or missing references)
		//IL_037d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0380: Unknown result type (might be due to invalid IL or missing references)
		//IL_0385: Unknown result type (might be due to invalid IL or missing references)
		//IL_0387: Unknown result type (might be due to invalid IL or missing references)
		//IL_038c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0392: Unknown result type (might be due to invalid IL or missing references)
		//IL_0397: Unknown result type (might be due to invalid IL or missing references)
		//IL_039c: Unknown result type (might be due to invalid IL or missing references)
		//IL_03a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_03ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_03ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_03cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_03f8: Unknown result type (might be due to invalid IL or missing references)
		//IL_03fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_03fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0400: Unknown result type (might be due to invalid IL or missing references)
		//IL_0416: Unknown result type (might be due to invalid IL or missing references)
		//IL_041d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0463: Unknown result type (might be due to invalid IL or missing references)
		//IL_0468: Unknown result type (might be due to invalid IL or missing references)
		//IL_046a: Unknown result type (might be due to invalid IL or missing references)
		//IL_046c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0470: Unknown result type (might be due to invalid IL or missing references)
		//IL_0475: Unknown result type (might be due to invalid IL or missing references)
		//IL_047a: Unknown result type (might be due to invalid IL or missing references)
		//IL_047f: Unknown result type (might be due to invalid IL or missing references)
		Player p = rig.P;
		if (!rig.BonesSearched)
		{
			FindBones(rig);
		}
		if ((Object)(object)rig.Spine == (Object)null && rig.Right == null)
		{
			return;
		}
		float num = Mathf.SmoothStep(0f, 1f, rig.Weight);
		Transform transform = ((Component)p).transform;
		Vector3 position = transform.position;
		Vector3 forward = transform.forward;
		forward.y = 0f;
		if (((Vector3)(ref forward)).sqrMagnitude < 1E-06f)
		{
			return;
		}
		((Vector3)(ref forward)).Normalize();
		Vector3 val = Vector3.Cross(Vector3.up, forward);
		rig.Frames++;
		s_frames++;
		if ((Object)(object)rig.Spine != (Object)null)
		{
			if (rig.SpineSet && rig.Spine.localRotation == rig.SpineAfter)
			{
				rig.Spine.localRotation = rig.SpineBefore;
				rig.SpineKept++;
				s_spineKept++;
				if (rig.SpineKept == 1)
				{
					Logs.Info("pose-spine", "Plow pose: the game's animation hadn't redrawn " + p.GetPlayerName() + "'s spine since the last frame (it updates with the physics steps, or the player is out of sight), so the lean was put back first and doesn't add up.", 60f);
				}
			}
			rig.SpineBefore = rig.Spine.localRotation;
			rig.Spine.rotation = Quaternion.AngleAxis(18f * num, val) * rig.Spine.rotation;
			rig.SpineAfter = rig.Spine.localRotation;
			rig.SpineSet = true;
		}
		if (rig.Right == null || rig.Left == null || !Measure(rig))
		{
			return;
		}
		Transform val2 = rig.Right[2];
		float num2 = Mathf.Clamp(((Character)p).GetHeight(), 1f, 3f);
		Vector3 val3 = position + forward * 1.15f + Vector3.up * 0.05f;
		Vector3 val4 = position + Vector3.up * (0.5f * num2) + forward * 0.3f + val * 0.1f;
		Vector3 val5 = val3 - val4;
		if (((Vector3)(ref val5)).sqrMagnitude < 1E-06f)
		{
			return;
		}
		((Vector3)(ref val5)).Normalize();
		Vector3 val6 = val2.TransformPoint(rig.GripInHand);
		Vector3 val7 = val2.TransformPoint(rig.TipInHand) - val6;
		float magnitude = ((Vector3)(ref val7)).magnitude;
		if (magnitude < 0.05f)
		{
			return;
		}
		Vector3 val8 = val3 - val5 * magnitude;
		Quaternion val9 = Quaternion.FromToRotation(val7, val5);
		Quaternion rotation = Quaternion.Slerp(val2.rotation, val9 * val2.rotation, num);
		Vector3 target = Vector3.Lerp(val2.position, val8 - val9 * (val6 - val2.position), num);
		SolveArm(rig.Right, target, val - forward * 0.3f + Vector3.down * 0.5f);
		val2.rotation = rotation;
		Vector3 val10 = val2.TransformPoint(rig.GripInHand);
		Vector3 val11 = val2.TransformPoint(rig.TipInHand) - val10;
		if (!(((Vector3)(ref val11)).sqrMagnitude < 1E-06f))
		{
			Vector3 val12 = val10 + ((Vector3)(ref val11)).normalized * Mathf.Min(0.4f, magnitude * 0.6f);
			SolveArm(rig.Left, Vector3.Lerp(rig.Left[2].position, val12, num), -val - forward * 0.3f + Vector3.down * 0.5f);
			if (rig.Frames == 30)
			{
				Vector3 val13 = val2.TransformPoint(rig.TipInHand);
				Logs.Info("pose-check", "Plow pose: " + p.GetPlayerName() + "'s Snow Shovel blade drawn " + Snow.M(Vector3.Dot(val13 - position, forward)) + " in front of the feet, " + Snow.M(val13.y - position.y) + " above them (wanted " + Snow.M(1.15f) + " and " + Snow.M(0.05f) + "), right hand