Decompiled source of DogHausClientTweaks v1.0.4

plugins/DogHausClientTweaks.dll

Decompiled 2 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text.RegularExpressions;
using System.Threading;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using DogHausBalance;
using DogHausPad;
using HarmonyLib;
using UnityEngine;

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

internal class SE_DogHausClock : StatusEffect
{
	internal const string Name = "SE_DogHausClock";

	private static Texture2D s_tex;

	private static Sprite s_sprite;

	private static byte[] s_px;

	private static int s_drawnStep = -1;

	private static bool s_drawnDay;

	private static float s_rise = 0.15f;

	private static float s_set = 0.85f;

	private static string[] s_hhmm;

	private static bool s_warned;

	private static MethodInfo s_rescale;

	private static readonly object[] s_arg = new object[1];

	internal static int Hour()
	{
		return Mathf.Clamp((int)Mathf.Floor(Frac() * 24f), 0, 23);
	}

	internal static float Frac()
	{
		if ((Object)(object)EnvMan.instance == (Object)null || (Object)(object)ZNet.instance == (Object)null || EnvMan.instance.m_dayLengthSec <= 0)
		{
			return 0.5f;
		}
		double num = EnvMan.instance.m_dayLengthSec;
		return Mathf.Clamp01((float)(ZNet.instance.GetTimeSeconds() % num / num));
	}

	internal static void SunTimes(out float sunrise, out float sunset)
	{
		sunrise = 0.15f;
		sunset = 0.85f;
		try
		{
			if (!((Object)(object)EnvMan.instance == (Object)null))
			{
				if (s_rescale == null)
				{
					s_rescale = AccessTools.Method(typeof(EnvMan), "RescaleDayFraction", (Type[])null, (Type[])null);
				}
				if (!(s_rescale == null))
				{
					sunrise = Cross(0f, 0.5f, 0.25f);
					sunset = Cross(0.5f, 1f, 0.75f);
				}
			}
		}
		catch (Exception e)
		{
			Quiet.Once("Clock: SE_DogHausClock.SunTimes", e);
			sunrise = 0.15f;
			sunset = 0.85f;
		}
	}

	private static float Cross(float lo, float hi, float target)
	{
		for (int i = 0; i < 20; i++)
		{
			float num = (lo + hi) * 0.5f;
			s_arg[0] = num;
			float num2 = (float)s_rescale.Invoke(EnvMan.instance, s_arg);
			if (num2 < target)
			{
				lo = num;
			}
			else
			{
				hi = num;
			}
		}
		return (lo + hi) * 0.5f;
	}

	internal static string Label(int h)
	{
		if (h == 0)
		{
			return "Midnight";
		}
		if (h == 12)
		{
			return "Noon";
		}
		if (h >= 12)
		{
			return h - 12 + " PM";
		}
		return h + " AM";
	}

	internal static SE_DogHausClock Make()
	{
		SE_DogHausClock sE_DogHausClock = ScriptableObject.CreateInstance<SE_DogHausClock>();
		((Object)sE_DogHausClock).name = "SE_DogHausClock";
		((StatusEffect)sE_DogHausClock).m_name = "Sundial";
		((StatusEffect)sE_DogHausClock).m_tooltip = "A sundial at Paris's latitude: the shadow shows the time of day, and the time under it is the 24-hour game clock. The two bright lines through the centre are today's sunrise and sunset; the starry band below them is the night, which shrinks in summer and grows in winter.";
		((StatusEffect)sE_DogHausClock).m_ttl = 0f;
		((StatusEffect)sE_DogHausClock).m_icon = Icon(Frac());
		return sE_DogHausClock;
	}

	public override void UpdateStatusEffect(float dt)
	{
		((StatusEffect)this).UpdateStatusEffect(dt);
		float num = Frac();
		bool flag = num >= s_rise && num < s_set;
		if ((int)(num * 96f) != s_drawnStep || flag != s_drawnDay)
		{
			base.m_icon = Icon(num);
		}
	}

	public override string GetIconText()
	{
		int num = Mathf.Clamp((int)(Frac() * 1440f), 0, 1439);
		if (s_hhmm == null)
		{
			s_hhmm = new string[1440];
		}
		string text = s_hhmm[num];
		if (text == null)
		{
			int num2 = num / 60;
			int num3 = num % 60;
			text = new string(new char[5]
			{
				(char)(48 + num2 / 10),
				(char)(48 + num2 % 10),
				':',
				(char)(48 + num3 / 10),
				(char)(48 + num3 % 10)
			});
			s_hhmm[num] = text;
		}
		return text;
	}

	private static Sprite Icon(float frac)
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: Expected O, but got Unknown
		//IL_006d: 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)
		if ((Object)(object)s_tex == (Object)null)
		{
			s_tex = new Texture2D(128, 128, (TextureFormat)4, -1, false, false, new MipmapLimitDescriptor(false, (string)null));
			((Texture)s_tex).filterMode = (FilterMode)2;
			((Texture)s_tex).wrapMode = (TextureWrapMode)1;
			((Texture)s_tex).mipMapBias = -0.75f;
			s_sprite = Sprite.Create(s_tex, new Rect(0f, 0f, 128f, 128f), new Vector2(0.5f, 0.5f));
			s_px = new byte[65536];
			s_tex.SetPixelData<byte>(s_px, 0, 0);
			s_tex.Apply(true, false);
		}
		if (!SkyforgeDial.Ready)
		{
			SkyforgeDial.BuildAsync();
			if (SkyforgeDial.BuildError != null && !s_warned)
			{
				s_warned = true;
				Debug.LogWarning((object)("[DogHaus] sundial: could not build the dial: " + SkyforgeDial.BuildError));
			}
			s_drawnStep = -2;
			return s_sprite;
		}
		SunTimes(out var sunrise, out var sunset);
		SkyforgeDial.Paint(frac, sunrise, sunset, s_px);
		s_tex.SetPixelData<byte>(s_px, 0, 0);
		s_tex.Apply(true, false);
		s_drawnStep = (int)(frac * 96f);
		s_rise = sunrise;
		s_set = sunset;
		s_drawnDay = frac >= sunrise && frac < sunset;
		return s_sprite;
	}
}
internal static class SkyforgeDial
{
	private struct Rgb
	{
		public double R;

		public double G;

		public double B;

		public Rgb(double r, double g, double b)
		{
			R = r;
			G = g;
			B = b;
		}

		public static Rgb Lerp(Rgb a, Rgb b, double t)
		{
			return new Rgb(a.R + (b.R - a.R) * t, a.G + (b.G - a.G) * t, a.B + (b.B - a.B) * t);
		}
	}

	internal const int N = 128;

	private const double E = 1.12;

	private const double PX = 0.0175;

	private const int SS = 4;

	private const double SPX = 0.004375;

	private const double R_RING = 0.78;

	private const double R_RIM_IN = 0.93;

	private const double OY = 0.18;

	private const double ORB_R = 0.075;

	private const double GLOW = 1.35;

	private const double RING_HW = 0.012;

	private const double LAT = 0.8527678725244294;

	private const double GNOMON = 156.0 / 425.0;

	private const double SHADOW_MIN = 0.27529411764705886;

	private const int STARS = 160;

	private static readonly Rgb Glow = new Rgb(0.8, 0.92, 1.0);

	private static readonly Rgb White = new Rgb(1.0, 1.0, 1.0);

	private static readonly Rgb Line = new Rgb(0.07, 0.11, 0.21);

	private static readonly Rgb Shadow = new Rgb(0.02, 0.03, 0.07);

	private static readonly Rgb Star = new Rgb(0.92, 0.96, 1.0);

	private static readonly Rgb FaceDay = new Rgb(0.26, 0.38, 0.58);

	private static readonly Rgb FaceNight = new Rgb(0.09, 0.13, 0.23);

	private static readonly Rgb Iron = new Rgb(0.13, 0.14, 0.17);

	private static readonly Rgb Lip = new Rgb(0.45, 0.55, 0.7);

	private static readonly Rgb Rivet = new Rgb(0.62, 0.68, 0.78);

	private static readonly Rgb RivetShade = new Rgb(0.2, 0.22, 0.27);

	private static readonly Rgb Gnomon = new Rgb(0.84, 0.92, 1.0);

	private static readonly Rgb GnomonShade = new Rgb(0.5, 0.62, 0.82);

	private static readonly Rgb Gold = new Rgb(1.0, 0.88, 0.6);

	private static float[] s_a;

	private static float[] s_rimR;

	private static float[] s_rimG;

	private static float[] s_rimB;

	private static float[] s_faceT;

	private static float[] s_faceTO;

	private static float[] s_inner;

	private static float[] s_linK;

	private static float[] s_halo;

	private static float[] s_ovK;

	private static float[] s_ovR;

	private static float[] s_ovG;

	private static float[] s_ovB;

	private static float[] s_gnK;

	private static float[] s_gnR;

	private static float[] s_gnG;

	private static float[] s_gnB;

	private static float[] s_orbG;

	private static float[] s_orbCore;

	private static float[] s_orbIn;

	private static float[] s_rx;

	private static float[] s_ry;

	private static float[] s_pa;

	private static float[] s_hzK;

	private static float[] s_hzR;

	private static float[] s_hzG;

	private static float[] s_hzB;

	private static float[] s_star;

	private static float[] s_night;

	private static double s_seasonRise = -1.0;

	private static double s_seasonSet = -1.0;

	private static double[] s_starU;

	private static double[] s_starV;

	private static double[] s_starW;

	private static volatile bool s_ready;

	private static int s_building;

	internal static volatile string BuildError;

	private static double s_fineMean;

	private static double s_fineMax = 1.0;

	private static double s_stoneMean;

	private static double s_stoneMax = 1.0;

	internal static bool Ready => s_ready;

	internal static void BuildAsync()
	{
		if (Interlocked.Exchange(ref s_building, 1) != 0)
		{
			return;
		}
		ThreadPool.QueueUserWorkItem(delegate
		{
			try
			{
				Build();
				s_ready = true;
			}
			catch (Exception ex)
			{
				BuildError = ex.Message;
			}
		});
	}

	internal static double DialAngle(double H)
	{
		return Math.Atan2(Math.Sin(0.8527678725244294) * Math.Sin(H), Math.Cos(H));
	}

	internal static void Paint(double frac, double sunrise, double sunset, byte[] rgba)
	{
		if (!s_ready)
		{
			Build();
			s_ready = true;
		}
		double num = (sunrise + sunset) * 0.5;
		double num2 = Clamp((sunset - sunrise) * 0.5, 0.01, 0.49) * Math.PI * 2.0;
		double num3 = Math.Atan((0.0 - Math.Cos(num2)) / Math.Tan(0.8527678725244294));
		double num4 = DeltaAngle((frac - num) * 360.0) * Math.PI / 180.0;
		bool flag = Math.Abs(num4) < num2;
		double v = Math.Sin(0.8527678725244294) * Math.Sin(num3) + Math.Cos(0.8527678725244294) * Math.Cos(num3) * Math.Cos(num4);
		double num5 = Math.Asin(Clamp(v, -1.0, 1.0));
		double num6 = num5 * 180.0 / Math.PI;
		double num7 = DialAngle(0.0 - num2);
		double num8 = DialAngle(num2);
		if (num7 != s_seasonRise || num8 != s_seasonSet)
		{
			BuildSeason(num7, num8);
		}
		double num9 = Smooth01((num6 + 6.0) / 9.0);
		Rgb rgb = Rgb.Lerp(FaceNight, FaceDay, num9);
		double num10 = Smooth01(num6 / 35.0) * 0.1 * num9;
		Rgb rgb2 = Rgb.Lerp(White, new Rgb(1.9, 1.5, 0.9), num10);
		Rgb rgb3 = Rgb.Lerp(Glow, Gold, num10 * 0.8);
		double num11 = 0.22 * num9;
		double num12 = 0.35100000000000003 * (0.6 + 0.4 * num9);
		double num13 = (0.22 + 0.78 * (1.0 - num9)) * 1.1;
		double num14 = 0.72 + 0.28 * num9;
		double num15 = (flag ? Smooth01(num6 / 2.5) : 0.0);
		double num16 = 0.0;
		double num17 = 0.0;
		double num18 = 0.0;
		if (num15 > 0.0)
		{
			double num19 = DialAngle(num4);
			num16 = Math.Sin(num19);
			num17 = Math.Cos(num19);
			num18 = Clamp(156.0 / 425.0 / Math.Tan(Math.Max(num5, 0.02)), 0.27529411764705886, RayToCircle(num19, 0.78) - 0.01);
		}
		for (int i = 0; i < 16384; i++)
		{
			int num20 = i * 4;
			double num21 = s_a[i];
			if (num21 <= 0.0)
			{
				rgba[num20] = 0;
				rgba[num20 + 1] = 0;
				rgba[num20 + 2] = 0;
				rgba[num20 + 3] = 0;
				continue;
			}
			double num22 = 1.0 - num11 * (double)s_night[i];
			double num23 = (double)s_rimR[i] + rgb.R * num22 * ((double)s_faceT[i] + rgb2.R * (double)s_faceTO[i]);
			double num24 = (double)s_rimG[i] + rgb.G * num22 * ((double)s_faceT[i] + rgb2.G * (double)s_faceTO[i]);
			double num25 = (double)s_rimB[i] + rgb.B * num22 * ((double)s_faceT[i] + rgb2.B * (double)s_faceTO[i]);
			double num26 = s_linK[i];
			num23 = num23 * num26 + Line.R * (1.0 - num26);
			num24 = num24 * num26 + Line.G * (1.0 - num26);
			num25 = num25 * num26 + Line.B * (1.0 - num26);
			num26 = s_hzK[i];
			num23 = num23 * num26 + (double)s_hzR[i];
			num24 = num24 * num26 + (double)s_hzG[i];
			num25 = num25 * num26 + (double)s_hzB[i];
			if (num15 > 0.0 && s_inner[i] > 0f)
			{
				double num27 = s_rx[i];
				double num28 = s_ry[i];
				double num29 = num27 * num16 + num28 * num17;
				double num30 = Math.Abs(num27 * num17 - num28 * num16);
				double num31 = 0.03 + 0.025 * Clamp(num29 / num18, 0.0, 1.0);
				double num32 = Cov(Math.Max(num29 - num18, 0.02 - num29), 0.0175) * Cov(num30 - num31, 0.0175) * 0.85 * (double)s_inner[i] * num15;
				if (num32 > 0.0)
				{
					num23 = num23 * (1.0 - num32) + Shadow.R * num32;
					num24 = num24 * (1.0 - num32) + Shadow.G * num32;
					num25 = num25 * (1.0 - num32) + Shadow.B * num32;
				}
			}
			double num33 = (double)s_halo[i] * num12;
			num23 += Glow.R * num33;
			num24 += Glow.G * num33;
			num25 += Glow.B * num33;
			num26 = s_ovK[i];
			num23 = num23 * num26 + (double)s_ovR[i];
			num24 = num24 * num26 + (double)s_ovG[i];
			num25 = num25 * num26 + (double)s_ovB[i];
			double num34 = (double)s_star[i] * num13;
			num23 += Star.R * num34;
			num24 += Star.G * num34;
			num25 += Star.B * num34;
			num26 = s_gnK[i];
			num23 = num23 * num26 + (double)s_gnR[i];
			num24 = num24 * num26 + (double)s_gnG[i];
			num25 = num25 * num26 + (double)s_gnB[i];
			double num35 = s_orbG[i];
			double num36 = s_orbCore[i];
			double num37 = s_orbIn[i];
			num23 = ((num23 + rgb3.R * num35) * (1.0 - num36) + rgb3.R * num36) * (1.0 - num37) + num37;
			num24 = ((num24 + rgb3.G * num35) * (1.0 - num36) + rgb3.G * num36) * (1.0 - num37) + num37;
			num25 = ((num25 + rgb3.B * num35) * (1.0 - num36) + rgb3.B * num36) * (1.0 - num37) + num37;
			num23 = Clamp(num23 * num14, 0.0, 1.0);
			num24 = Clamp(num24 * num14, 0.0, 1.0);
			num25 = Clamp(num25 * num14, 0.0, 1.0);
			if (num21 < 1.0)
			{
				num23 = Math.Min(num23 / num21, 1.0);
				num24 = Math.Min(num24 / num21, 1.0);
				num25 = Math.Min(num25 / num21, 1.0);
			}
			rgba[num20] = (byte)(num23 * 255.0 + 0.5);
			rgba[num20 + 1] = (byte)(num24 * 255.0 + 0.5);
			rgba[num20 + 2] = (byte)(num25 * 255.0 + 0.5);
			rgba[num20 + 3] = (byte)(num21 * 255.0 + 0.5);
		}
	}

	private static void Build()
	{
		int num = 16384;
		s_a = new float[num];
		s_rimR = new float[num];
		s_rimG = new float[num];
		s_rimB = new float[num];
		s_faceT = new float[num];
		s_faceTO = new float[num];
		s_inner = new float[num];
		s_linK = new float[num];
		s_halo = new float[num];
		s_ovK = new float[num];
		s_ovR = new float[num];
		s_ovG = new float[num];
		s_ovB = new float[num];
		s_gnK = new float[num];
		s_gnR = new float[num];
		s_gnG = new float[num];
		s_gnB = new float[num];
		s_orbG = new float[num];
		s_orbCore = new float[num];
		s_orbIn = new float[num];
		s_rx = new float[num];
		s_ry = new float[num];
		s_pa = new float[num];
		s_hzK = new float[num];
		s_hzR = new float[num];
		s_hzG = new float[num];
		s_hzB = new float[num];
		s_star = new float[num];
		s_night = new float[num];
		NoiseStats();
		double[] array = new double[19];
		double[] array2 = new double[19];
		for (int i = 3; i <= 21; i++)
		{
			array[i - 3] = DialAngle((double)(i - 12) * 15.0 * Math.PI / 180.0);
			array2[i - 3] = RayToCircle(array[i - 3], 0.78);
		}
		double[] array3 = new double[17];
		double[] array4 = new double[17];
		double[] array5 = new double[17];
		double[] array6 = new double[17];
		double[] array7 = new double[17];
		double[] array8 = new double[17];
		for (int j = 4; j <= 20; j++)
		{
			int num2 = j - 4;
			double num3 = DialAngle((double)(j - 12) * 15.0 * Math.PI / 180.0);
			bool flag = j % 3 == 0;
			double num4 = RayToCircle(num3, 0.81);
			double num5 = RayToCircle(num3, 0.81 + (flag ? 0.055 : 0.03));
			array5[num2] = Math.Sin(num3);
			array6[num2] = Math.Cos(num3);
			array3[num2] = num4 * array5[num2];
			array4[num2] = -0.18 + num4 * array6[num2];
			array7[num2] = num5 - num4;
			array8[num2] = (flag ? 3.0 : 1.5) * 0.004375;
		}
		double num6 = 0.014000000000000002 * Math.Sqrt(2.0);
		Rgb c = Rgb.Lerp(Glow, White, 0.4);
		Rgb c2 = Rgb.Lerp(Glow, White, 0.35);
		double num7 = 0.96;
		double num8 = 0.0625;
		for (int k = 0; k < 128; k++)
		{
			for (int l = 0; l < 128; l++)
			{
				int num9 = k * 128 + l;
				double num10 = ((double)l + 0.5) * 0.0175 - 1.12;
				double num11 = ((double)k + 0.5) * 0.0175 - 1.12;
				s_rx[num9] = (float)num10;
				s_ry[num9] = (float)(num11 + 0.18);
				s_pa[num9] = (float)Math.Atan2(num10, num11 + 0.18);
				s_linK[num9] = 1f;
				s_ovK[num9] = 1f;
				s_gnK[num9] = 1f;
				s_hzK[num9] = 1f;
				if (Math.Sqrt(num10 * num10 + num11 * num11) > 1.0175)
				{
					continue;
				}
				double num12 = 0.0;
				double num13 = 0.0;
				double num14 = 0.0;
				double num15 = 0.0;
				double num16 = 0.0;
				double num17 = 0.0;
				double num18 = 0.0;
				double num19 = 0.0;
				double num20 = 0.0;
				double num21 = 0.0;
				double num22 = 0.0;
				double num23 = 0.0;
				double num24 = 0.0;
				double num25 = 0.0;
				double num26 = 0.0;
				double num27 = 0.0;
				double num28 = 0.0;
				double num29 = 0.0;
				double num30 = 0.0;
				double num31 = 0.0;
				for (int m = 0; m < 4; m++)
				{
					for (int n = 0; n < 4; n++)
					{
						double num32 = ((double)l + ((double)n + 0.5) / 4.0) * 0.0175 - 1.12;
						double num33 = ((double)k + ((double)m + 0.5) / 4.0) * 0.0175 - 1.12;
						double num34 = Math.Sqrt(num32 * num32 + num33 * num33);
						double num35 = num32;
						double num36 = num33 + 0.18;
						double num37 = Math.Sqrt(num35 * num35 + num36 * num36);
						double num38 = Cov(num34 - 1.0, 0.004375);
						num12 += num38;
						double num39 = Fbm(num32, num33, fine: true);
						double num40 = Fbm(num32, num33, fine: false);
						double num41 = num38 * (1.0 - Cov(num34 - 0.93, 0.004375));
						double num42 = (1.0 + 0.1 * num39) * (1.0 + 0.35 * ((0.0 - num32 + num33) / 1.4) * SmoothStep(0.93, 1.0, num34)) * num41;
						double num43 = Iron.R * num42;
						double num44 = Iron.G * num42;
						double num45 = Iron.B * num42;
						double num46 = Cov(Math.Abs(num34 - 0.9420000000000001) - 0.01, 0.004375) * 0.35;
						num43 = num43 * (1.0 - num46) + Lip.R * num46;
						num44 = num44 * (1.0 - num46) + Lip.G * num46;
						num45 = num45 * (1.0 - num46) + Lip.B * num46;
						if (num34 > 0.92)
						{
							for (int num47 = 0; num47 < 12; num47++)
							{
								double num48 = (double)(num47 * 30 + 15) * Math.PI / 180.0;
								double num49 = 0.965 * Math.Sin(num48);
								double num50 = 0.965 * Math.Cos(num48);
								double num51 = Math.Sqrt((num32 - num49) * (num32 - num49) + (num33 - num50) * (num33 - num50)) - 0.022;
								if (!(num51 > 0.05))
								{
									num46 = Cov(num51, 0.004375);
									num43 = num43 * (1.0 - num46) + Rivet.R * num46;
									num44 = num44 * (1.0 - num46) + Rivet.G * num46;
									num45 = num45 * (1.0 - num46) + Rivet.B * num46;
									double value = num32 - num49 - (num33 - num50);
									num46 = Cov(num51 + 0.01, 0.004375) * (0.5 + 0.5 * (double)Math.Sign(value)) * 0.6;
									num43 = num43 * (1.0 - num46) + RivetShade.R * num46;
									num44 = num44 * (1.0 - num46) + RivetShade.G * num46;
									num45 = num45 * (1.0 - num46) + RivetShade.B * num46;
								}
							}
						}
						double num52 = Cov(num34 - 0.93, 0.004375);
						num13 += num43 * (1.0 - num52);
						num14 += num44 * (1.0 - num52);
						num15 += num45 * (1.0 - num52);
						double num53 = 1.0 + 0.1 * num40 + Math.Sin(Math.Atan2(num32, num33) * 180.0 + num39 * 6.0) * 0.05;
						double num54 = Math.Exp((0.0 - num37) / 0.45) * 0.29500000000000004;
						num16 += num52 * num53;
						num17 += num52 * num53 * num54;
						double num55 = Cov(num34 - 0.768, 0.004375);
						num18 += num55;
						double num56 = 1.0;
						if (num55 > 0.0)
						{
							double num57 = 0.0;
							double num58 = 0.0;
							double num59 = Math.Atan2(num35, num36);
							double num60 = Math.Max(num37 - 0.1, 0.0);
							for (int num61 = 0; num61 < 19; num61++)
							{
								double num62 = array[num61];
								double num63 = Math.Abs(Math.IEEERemainder(num59 - num62, Math.PI * 2.0));
								if (!(num63 > 1.4) && !(num60 * Math.Sin(num63) > 0.03))
								{
									double num64 = Math.Sin(num62);
									double num65 = Math.Cos(num62);
									double num66 = SegDist(num32, num33, 0.12 * num64, -0.18 + 0.12 * num65, array2[num61] * num64, -0.18 + array2[num61] * num65);
									if (num61 % 3 == 0)
									{
										num58 += Cov(num66 - 0.0075, 0.004375);
									}
									else
									{
										num57 += Cov(num66 - 0.0045, 0.004375);
									}
								}
							}
							num56 = (1.0 - Math.Min(num57, 1.0) * num55 * 0.55) * (1.0 - Math.Min(num58, 1.0) * num55 * 0.8);
						}
						num19 += num56;
						double num67 = Math.Abs(num34 - 0.78);
						num20 += Math.Exp((0.0 - num67) / 0.0409) * num38;
						double k2 = 1.0;
						double r = 0.0;
						double g = 0.0;
						double b = 0.0;
						num46 = Cov(num67 - 0.012, 0.004375);
						Over(ref k2, ref r, ref g, ref b, c, num46);
						if (num34 > 0.72 && num34 < 0.95)
						{
							double num68 = 0.0;
							double num69 = 0.0;
							for (int num70 = 0; num70 < 17; num70++)
							{
								double num71 = num32 - array3[num70];
								double num72 = num33 - array4[num70];
								double num73 = num71 * array5[num70] + num72 * array6[num70];
								double num74 = num71 * array6[num70] - num72 * array5[num70];
								if (!(num73 < -0.06) && !(num73 > array7[num70] + 0.06) && !(Math.Abs(num74) > 0.07))
								{
									num68 += Cov(Math.Max(Math.Max(0.0 - num73, num73 - array7[num70]), Math.Abs(num74) - array8[num70]), 0.004375);
									num69 += 0.25 * (Erf((array8[num70] - num74) / num6) + Erf((array8[num70] + num74) / num6)) * (Erf(num73 / num6) - Erf((num73 - array7[num70]) / num6));
								}
							}
							double num75 = Math.Min(num69, 1.0) * 0.22 * 1.35;
							r += Glow.R * num75;
							g += Glow.G * num75;
							b += Glow.B * num75;
							Over(ref k2, ref r, ref g, ref b, c2, Math.Min(num68, 1.0));
						}
						num21 += k2;
						num22 += r;
						num23 += g;
						num24 += b;
						k2 = 1.0;
						r = 0.0;
						g = 0.0;
						b = 0.0;
						if (Math.Abs(num35) < 0.25)
						{
							double num76 = Cov(Math.Max(num36 - num7, 0.0 - num36), 0.004375);
							double num77 = num76 * Cov(Math.Abs(num35) - 0.02, 0.004375);
							double num78 = Math.Exp((0.0 - Math.Max(Math.Abs(num35) - 0.02, 0.0)) / 0.03) * num76 * 0.35 * 1.35;
							r += Glow.R * num78;
							g += Glow.G * num78;
							b += Glow.B * num78;
							Over(ref k2, ref r, ref g, ref b, Gnomon, num77);
							Over(ref k2, ref r, ref g, ref b, White, num77 * ((num35 < -0.006) ? 0.6 : 0.0));
							Over(ref k2, ref r, ref g, ref b, GnomonShade, num77 * ((num35 > 0.008) ? 0.5 : 0.0));
						}
						num25 += k2;
						num26 += r;
						num27 += g;
						num28 += b;
						num29 += Math.Exp((0.0 - num37) / 0.1305) * 0.5 * 1.35;
						num30 += Cov(num37 - 0.075, 0.004375);
						num31 += Cov(num37 - 33.0 / 800.0, 0.004375) * 0.85;
					}
				}
				s_a[num9] = (float)(num12 * num8);
				s_rimR[num9] = (float)(num13 * num8);
				s_rimG[num9] = (float)(num14 * num8);
				s_rimB[num9] = (float)(num15 * num8);
				s_faceT[num9] = (float)(num16 * num8);
				s_faceTO[num9] = (float)(num17 * num8);
				s_inner[num9] = (float)(num18 * num8);
				s_linK[num9] = (float)(num19 * num8);
				s_halo[num9] = (float)(num20 * num8);
				s_ovK[num9] = (float)(num21 * num8);
				s_ovR[num9] = (float)(num22 * num8);
				s_ovG[num9] = (float)(num23 * num8);
				s_ovB[num9] = (float)(num24 * num8);
				s_gnK[num9] = (float)(num25 * num8);
				s_gnR[num9] = (float)(num26 * num8);
				s_gnG[num9] = (float)(num27 * num8);
				s_gnB[num9] = (float)(num28 * num8);
				s_orbG[num9] = (float)(num29 * num8);
				s_orbCore[num9] = (float)(num30 * num8);
				s_orbIn[num9] = (float)(num31 * num8);
			}
		}
		s_starU = new double[160];
		s_starV = new double[160];
		s_starW = new double[160];
		uint s = 1010u;
		for (int num79 = 0; num79 < 160; num79++)
		{
			s_starU[num79] = Rand(ref s);
			s_starV[num79] = Rand(ref s);
			s_starW[num79] = Rand(ref s);
		}
	}

	private static void BuildSeason(double riseAng, double setAng)
	{
		s_seasonRise = riseAng;
		s_seasonSet = setAng;
		double num = Mod2Pi(riseAng - setAng);
		double[] array = new double[2] { riseAng, setAng };
		double[] array2 = new double[2];
		double[] array3 = new double[2];
		double[] array4 = new double[2];
		double[] array5 = new double[2];
		for (int i = 0; i < 2; i++)
		{
			array4[i] = Math.Sin(array[i]);
			array5[i] = Math.Cos(array[i]);
			double num2 = RayToCircle(array[i], 0.78);
			array2[i] = num2 * array4[i];
			array3[i] = -0.18 + num2 * array5[i];
		}
		for (int j = 0; j < 16384; j++)
		{
			s_star[j] = 0f;
			s_night[j] = ((Mod2Pi((double)s_pa[j] - setAng) < num) ? 1f : 0f);
			s_hzK[j] = 1f;
			s_hzR[j] = 0f;
			s_hzG[j] = 0f;
			s_hzB[j] = 0f;
			if (s_a[j] <= 0f)
			{
				continue;
			}
			double num3 = s_rx[j];
			double num4 = (double)s_ry[j] - 0.18;
			double num5 = 9.0;
			for (int k = 0; k < 2; k++)
			{
				num5 = Math.Min(num5, SegDist(num3, num4, 0.13 * array4[k], -0.18 + 0.13 * array5[k], array2[k], array3[k]));
				num5 = Math.Min(num5, Math.Sqrt((num3 - array2[k]) * (num3 - array2[k]) + (num4 - array3[k]) * (num4 - array3[k])) - 0.1);
			}
			if (num5 > 0.22)
			{
				continue;
			}
			double num6 = 0.0;
			double num7 = 0.0;
			double num8 = 0.0;
			double num9 = 0.0;
			for (int l = 0; l < 2; l++)
			{
				for (int m = 0; m < 2; m++)
				{
					double num10 = num3 + (((double)m + 0.5) / 2.0 - 0.5) * 0.0175;
					double num11 = num4 + (((double)l + 0.5) / 2.0 - 0.5) * 0.0175;
					double num12 = Cov(Math.Sqrt(num10 * num10 + num11 * num11) - 0.768, 7.0 / 800.0);
					double k2 = 1.0;
					double r = 0.0;
					double g = 0.0;
					double b = 0.0;
					for (int n = 0; n < 2; n++)
					{
						double num13 = SegDist(num10, num11, 0.13 * array4[n], -0.18 + 0.13 * array5[n], array2[n], array3[n]);
						Over(ref k2, ref r, ref g, ref b, Glow, Cov(num13 - 0.0055, 7.0 / 800.0) * num12 * 0.8);
						double num14 = Math.Exp((0.0 - num13) / 0.028) * num12 * 0.14 * 1.35;
						r += Glow.R * num14;
						g += Glow.G * num14;
						b += Glow.B * num14;
						double num15 = Math.Sqrt((num10 - array2[n]) * (num10 - array2[n]) + (num11 - array3[n]) * (num11 - array3[n]));
						Over(ref k2, ref r, ref g, ref b, White, Cov(num15 - 0.022, 7.0 / 800.0));
						num14 = Math.Exp((0.0 - num15) / 0.05) * 0.5 * 1.35;
						r += Glow.R * num14;
						g += Glow.G * num14;
						b += Glow.B * num14;
					}
					num6 += k2;
					num7 += r;
					num8 += g;
					num9 += b;
				}
			}
			double num16 = 0.25;
			s_hzK[j] = (float)(num6 * num16);
			s_hzR[j] = (float)(num7 * num16);
			s_hzG[j] = (float)(num8 * num16);
			s_hzB[j] = (float)(num9 * num16);
		}
		for (int num17 = 0; num17 < 160; num17++)
		{
			double num18 = Math.PI + (s_starU[num17] - 0.5) * 2.0 * Math.PI;
			double num19 = Mod2Pi(num18 - setAng);
			if (num19 > num - 0.05 || num19 < 0.05)
			{
				continue;
			}
			double num20 = 0.22 + s_starV[num17] * (RayToCircle(num18, 0.78) - 0.3);
			double num21 = num20 * Math.Sin(num18);
			double num22 = -0.18 + num20 * Math.Cos(num18);
			double num23 = 0.008 + 0.012 * s_starW[num17];
			double num24 = (0.5 + 0.5 * s_starW[num17]) * 1.15;
			int num25 = Math.Max(0, (int)((num21 - 3.0 * num23 + 1.12) / 0.0175));
			int num26 = Math.Min(127, (int)((num21 + 3.0 * num23 + 1.12) / 0.0175));
			int num27 = Math.Max(0, (int)((num22 - 3.0 * num23 + 1.12) / 0.0175));
			int num28 = Math.Min(127, (int)((num22 + 3.0 * num23 + 1.12) / 0.0175));
			for (int num29 = num27; num29 <= num28; num29++)
			{
				for (int num30 = num25; num30 <= num26; num30++)
				{
					double num31 = 0.0;
					for (int num32 = 0; num32 < 4; num32++)
					{
						for (int num33 = 0; num33 < 4; num33++)
						{
							double num34 = ((double)num30 + ((double)num33 + 0.5) / 4.0) * 0.0175 - 1.12 - num21;
							double num35 = ((double)num29 + ((double)num32 + 0.5) / 4.0) * 0.0175 - 1.12 - num22;
							num31 += Math.Exp((0.0 - (num34 * num34 + num35 * num35)) / (num23 * num23));
						}
					}
					s_star[num29 * 128 + num30] += (float)(num31 / 16.0 * num24);
				}
			}
		}
		for (int num36 = 0; num36 < 16384; num36++)
		{
			s_star[num36] = Math.Min(s_star[num36], 1f) * s_night[num36];
		}
	}

	private static void Over(ref double k, ref double r, ref double g, ref double b, Rgb c, double m)
	{
		if (!(m <= 0.0))
		{
			k *= 1.0 - m;
			r = r * (1.0 - m) + c.R * m;
			g = g * (1.0 - m) + c.G * m;
			b = b * (1.0 - m) + c.B * m;
		}
	}

	private static double Cov(double sd, double px)
	{
		return Clamp(0.5 - sd / px, 0.0, 1.0);
	}

	private static double Clamp(double v, double lo, double hi)
	{
		if (!(v < lo))
		{
			if (!(v > hi))
			{
				return v;
			}
			return hi;
		}
		return lo;
	}

	private static double Smooth01(double t)
	{
		t = Clamp(t, 0.0, 1.0);
		return t * t * (3.0 - 2.0 * t);
	}

	private static double SmoothStep(double e0, double e1, double x)
	{
		return Smooth01((x - e0) / (e1 - e0));
	}

	private static double Mod2Pi(double a)
	{
		double num = Math.PI * 2.0;
		a %= num;
		if (!(a < 0.0))
		{
			return a;
		}
		return a + num;
	}

	private static double DeltaAngle(double deg)
	{
		double num = deg - Math.Floor(deg / 360.0) * 360.0;
		if (num > 180.0)
		{
			num -= 360.0;
		}
		return num;
	}

	private static double RayToCircle(double ang, double R)
	{
		Math.Sin(ang);
		double num = Math.Cos(ang);
		double num2 = -0.18 * num;
		double num3 = 0.0324 - R * R;
		return 0.0 - num2 + Math.Sqrt(Math.Max(num2 * num2 - num3, 0.0));
	}

	private static double SegDist(double x, double y, double x0, double y0, double x1, double y1)
	{
		double num = x1 - x0;
		double num2 = y1 - y0;
		double num3 = Clamp(((x - x0) * num + (y - y0) * num2) / (num * num + num2 * num2 + 1E-09), 0.0, 1.0);
		double num4 = x - (x0 + num3 * num);
		double num5 = y - (y0 + num3 * num2);
		return Math.Sqrt(num4 * num4 + num5 * num5);
	}

	private static double Erf(double x)
	{
		double num = ((!(x < 0.0)) ? 1 : (-1));
		x = Math.Abs(x);
		double num2 = 1.0 / (1.0 + 0.3275911 * x);
		double num3 = 1.0 - ((((1.061405429 * num2 - 1.453152027) * num2 + 1.421413741) * num2 - 0.284496736) * num2 + 0.254829592) * num2 * Math.Exp((0.0 - x) * x);
		return num * num3;
	}

	private static double Rand(ref uint s)
	{
		s ^= s << 13;
		s ^= s >> 17;
		s ^= s << 5;
		return (double)(s & 0xFFFFFF) / 16777216.0;
	}

	private static double Fbm(double x, double y, bool fine)
	{
		double num = (fine ? (0.4 * VNoise(x, y, 32, 111) + 0.35 * VNoise(x, y, 64, 118) + 0.25 * VNoise(x, y, 128, 125)) : (0.5 * VNoise(x, y, 6, 11) + 0.25 * VNoise(x, y, 12, 18) + 0.15 * VNoise(x, y, 24, 25) + 0.1 * VNoise(x, y, 48, 32)));
		if (!fine)
		{
			return (num - s_stoneMean) / s_stoneMax;
		}
		return (num - s_fineMean) / s_fineMax;
	}

	private static void NoiseStats()
	{
		double num = 0.0;
		double num2 = 0.0;
		int num3 = 0;
		double num4 = 9.0;
		double num5 = -9.0;
		double num6 = 9.0;
		double num7 = -9.0;
		s_fineMean = 0.0;
		s_fineMax = 1.0;
		s_stoneMean = 0.0;
		s_stoneMax = 1.0;
		for (int i = 0; i < 256; i++)
		{
			for (int j = 0; j < 256; j++)
			{
				double x = ((double)j + 0.5) / 256.0 * 2.0 * 1.12 - 1.12;
				double y = ((double)i + 0.5) / 256.0 * 2.0 * 1.12 - 1.12;
				double num8 = Fbm(x, y, fine: true);
				double num9 = Fbm(x, y, fine: false);
				num += num8;
				num2 += num9;
				num3++;
				num4 = Math.Min(num4, num8);
				num5 = Math.Max(num5, num8);
				num6 = Math.Min(num6, num9);
				num7 = Math.Max(num7, num9);
			}
		}
		s_fineMean = num / (double)num3;
		s_stoneMean = num2 / (double)num3;
		s_fineMax = Math.Max(Math.Max(num5 - s_fineMean, s_fineMean - num4), 1E-06);
		s_stoneMax = Math.Max(Math.Max(num7 - s_stoneMean, s_stoneMean - num6), 1E-06);
	}

	private static double VNoise(double x, double y, int cells, int seed)
	{
		double num = (x + 1.12) / 2.24 * (double)cells - 0.5;
		double num2 = (y + 1.12) / 2.24 * (double)cells - 0.5;
		int num3 = (int)Math.Floor(num);
		int num4 = (int)Math.Floor(num2);
		double num5 = num - (double)num3;
		double num6 = num2 - (double)num4;
		num5 = num5 * num5 * (3.0 - 2.0 * num5);
		num6 = num6 * num6 * (3.0 - 2.0 * num6);
		double num7 = Lattice(num3, num4, cells, seed);
		double num8 = Lattice(num3 + 1, num4, cells, seed);
		double num9 = Lattice(num3, num4 + 1, cells, seed);
		double num10 = Lattice(num3 + 1, num4 + 1, cells, seed);
		return (num7 + (num8 - num7) * num5) * (1.0 - num6) + (num9 + (num10 - num9) * num5) * num6;
	}

	private static double Lattice(int i, int j, int cells, int seed)
	{
		i = ((i >= 0) ? ((i >= cells) ? (cells - 1) : i) : 0);
		j = ((j >= 0) ? ((j >= cells) ? (cells - 1) : j) : 0);
		uint num = (uint)((i * 73856093) ^ (j * 19349663) ^ (seed * 83492791));
		num ^= num >> 13;
		num *= 1540483477;
		num ^= num >> 15;
		return (double)(num & 0xFFFFFF) / 16777216.0;
	}
}
[HarmonyPatch(typeof(Player), "Update")]
internal static class Player_Update_Clock
{
	private static float s_next;

	private static SE_DogHausClock s_template;

	internal static void CheckNow()
	{
		s_next = 0f;
	}

	private static void Postfix(Player __instance)
	{
		if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || Time.time < s_next)
		{
			return;
		}
		s_next = Time.time + 3f;
		try
		{
			SEMan sEMan = ((Character)__instance).GetSEMan();
			if (sEMan == null)
			{
				return;
			}
			bool flag = Features.On(Features.Sundial) && BalanceExtra.Flag("clock", "enabled", true);
			if ((Object)(object)s_template == (Object)null)
			{
				if (!flag)
				{
					return;
				}
				s_template = SE_DogHausClock.Make();
			}
			int num = ((StatusEffect)s_template).NameHash();
			bool flag2 = sEMan.HaveStatusEffect(num);
			if (flag && !flag2)
			{
				sEMan.AddStatusEffect((StatusEffect)(object)s_template, false, 0, 0f, (short)(-1));
			}
			else if (!flag && flag2)
			{
				sEMan.RemoveStatusEffect(num, true);
			}
		}
		catch (Exception e)
		{
			Quiet.Once("Clock: Player_Update_Clock.Postfix", e);
		}
	}
}
internal class BuildGrid : MonoBehaviour
{
	internal const string ConfigName = "doghaus.buildgrid.cfg";

	internal static bool Ready;

	internal static ConfigFile Settings;

	private Camera m_cam;

	private Vector3 m_lastBuildPos;

	private float m_lastBuildTime = -100f;

	private float m_lastBuildRadius;

	private float m_lastBuildSpacing;

	private bool m_failedOnce;

	private GUIStyle m_style;

	private GUIStyle m_shadow;

	internal static bool Bind(BepInPlugin owner)
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Expected O, but got Unknown
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0078: Expected O, but got Unknown
		//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Expected O, but got Unknown
		//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_013f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0149: Expected O, but got Unknown
		try
		{
			ConfigFile val = (Settings = new ConfigFile(Path.Combine(Paths.ConfigPath, "doghaus.buildgrid.cfg"), true, owner));
			GridState.ToggleKey = val.Bind<KeyboardShortcut>("Grid", "toggle_key", new KeyboardShortcut((KeyCode)106, (KeyCode[])(object)new KeyCode[0]), "Key that turns the world grid on and off. Ignored while you type in chat, the console, a text box, or have a menu or the inventory open. J is not used by vanilla gameplay or by the other mods in the pack.");
			GridState.Radius = val.Bind<float>("Grid", "radius", 8f, new ConfigDescription("How far around you the grid lines are drawn, in metres.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 16f), new object[0]));
			GridState.LineSpacing = val.Bind<float>("Grid", "line_spacing", 1f, new ConfigDescription("Distance between drawn lines, in metres (lines stay lined up with world coordinates).", (AcceptableValueBase)(object)new AcceptableValueList<float>(new float[4] { 0.5f, 1f, 2f, 4f }), new object[0]));
			GridState.LineColor = val.Bind<Color>("Grid", "line_color", new Color(1f, 1f, 1f, 0.25f), "Colour of the grid lines. The last pair of digits (alpha) is how see-through they are; 40 hex is about 25 percent.");
			GridState.SnapSize = val.Bind<float>("Snap", "snap_size", 1f, new ConfigDescription("Placement snap, in metres: a piece's centre snaps to a multiple of this in world X and Z.", (AcceptableValueBase)(object)new AcceptableValueList<float>(new float[2] { 0.5f, 1f }), new object[0]));
			GridState.SnapPlacement = val.Bind<bool>("Snap", "snap_position", true, "While the grid is on, snap the placement ghost's X and Z to the grid.");
			GridState.SnapRotation = val.Bind<bool>("Snap", "snap_rotation", true, "While the grid is on, keep the placement ghost's turn to 90-degree steps.");
			GridState.ShowReadout = val.Bind<bool>("Readout", "show_position", true, "While the grid is on, show your world X, Z and height at the bottom of the screen.");
			Ready = true;
		}
		catch (Exception ex)
		{
			ClientTweaksPlugin.Log.LogWarning((object)("Build grid off: could not read doghaus.buildgrid.cfg (" + ex.Message + ")."));
			Ready = false;
		}
		return Ready;
	}

	private void Awake()
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Expected O, but got Unknown
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Expected O, but got Unknown
		Camera.onPostRender = (CameraCallback)Delegate.Combine((Delegate?)(object)Camera.onPostRender, (Delegate?)new CameraCallback(OnCameraPostRender));
	}

	private void OnDestroy()
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Expected O, but got Unknown
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Expected O, but got Unknown
		Camera.onPostRender = (CameraCallback)Delegate.Remove((Delegate?)(object)Camera.onPostRender, (Delegate?)new CameraCallback(OnCameraPostRender));
	}

	private void Update()
	{
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_0162: Unknown result type (might be due to invalid IL or missing references)
		//IL_0163: 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_0169: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a4: 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_00bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0118: Unknown result type (might be due to invalid IL or missing references)
		//IL_0122: Unknown result type (might be due to invalid IL or missing references)
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null || !Features.On(Features.BuildGrid))
		{
			if (GridState.Enabled)
			{
				GridState.Enabled = false;
				GridLines.Clear();
			}
			return;
		}
		bool flag = false;
		try
		{
			flag = ((Character)localPlayer).InPlaceMode() && Pad.LtX_Down();
		}
		catch (Exception e)
		{
			Quiet.Once("BuildGrid: controller toggle", e);
		}
		if ((GridState.Pressed(GridState.ToggleKey.Value) || flag) && !GridState.InputBlocked())
		{
			GridState.Enabled = !GridState.Enabled;
			((Character)localPlayer).Message((MessageType)1, GridState.Enabled ? "Build grid on" : "Build grid off", 0, (Sprite)null, false);
		}
		if (!GridState.Enabled)
		{
			return;
		}
		Vector3 val = GridCentre.For(localPlayer);
		float value = GridState.Radius.Value;
		float value2 = GridState.LineSpacing.Value;
		Vector3 val2 = val - m_lastBuildPos;
		bool flag2 = ((Vector3)(ref val2)).sqrMagnitude > 0.25f;
		bool flag3 = Time.unscaledTime - m_lastBuildTime > 1f;
		bool flag4 = value != m_lastBuildRadius || value2 != m_lastBuildSpacing;
		if (!flag2 && !flag3 && !flag4)
		{
			return;
		}
		try
		{
			GridLines.Rebuild(val, value, value2, GridState.LineColor.Value);
		}
		catch (Exception ex)
		{
			GridLines.Clear();
			if (!m_failedOnce)
			{
				m_failedOnce = true;
				ClientTweaksPlugin.Log.LogWarning((object)("Build grid: could not build the grid lines this frame (will keep retrying): " + ex.Message));
			}
		}
		m_lastBuildPos = val;
		GridCentre.Last = val;
		GridCentre.LastOnCamera = GridCentre.OnCamera;
		m_lastBuildTime = Time.unscaledTime;
		m_lastBuildRadius = value;
		m_lastBuildSpacing = value2;
	}

	private void OnCameraPostRender(Camera cam)
	{
		if (GridState.Enabled && !((Object)(object)cam == (Object)null) && GridLines.Count != 0)
		{
			if ((Object)(object)m_cam == (Object)null && (Object)(object)GameCamera.instance != (Object)null)
			{
				m_cam = ((Component)GameCamera.instance).GetComponent<Camera>();
			}
			if (!((Object)(object)m_cam == (Object)null) && !((Object)(object)cam != (Object)(object)m_cam) && !Hud.IsUserHidden())
			{
				GridLines.Draw();
			}
		}
	}

	private void OnGUI()
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Invalid comparison between Unknown and I4
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Expected O, but got Unknown
		//IL_009e: 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_00b9: Expected O, but got Unknown
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_012b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0124: Unknown result type (might be due to invalid IL or missing references)
		//IL_0130: Unknown result type (might be due to invalid IL or missing references)
		//IL_021f: Unknown result type (might be due to invalid IL or missing references)
		//IL_022e: Unknown result type (might be due to invalid IL or missing references)
		if (!GridState.Enabled || !GridState.ShowReadout.Value || Event.current == null || (int)Event.current.type != 7)
		{
			return;
		}
		Player localPlayer = Player.m_localPlayer;
		if (!((Object)(object)localPlayer == (Object)null) && !Hud.IsUserHidden() && !GridState.MenuOpen())
		{
			if (m_style == null)
			{
				m_style = new GUIStyle(GUI.skin.label);
				m_style.alignment = (TextAnchor)4;
				m_style.fontStyle = (FontStyle)1;
				m_style.normal.textColor = new Color(1f, 1f, 1f, 0.9f);
				m_shadow = new GUIStyle(m_style);
				m_shadow.normal.textColor = new Color(0f, 0f, 0f, 0.8f);
			}
			int num = Mathf.Clamp(Mathf.RoundToInt((float)Screen.height / 62f), 13, 30);
			m_style.fontSize = num;
			m_shadow.fontSize = num;
			bool onCamera = GridCentre.OnCamera;
			Vector3 val = (onCamera ? GridCentre.Current : ((Component)localPlayer).transform.position);
			string text = "x " + Mathf.RoundToInt(val.x) + "  z " + Mathf.RoundToInt(val.z) + "  height " + val.y.ToString("0.0", CultureInfo.InvariantCulture) + " m";
			if (onCamera)
			{
				text += "  (build camera)";
			}
			Rect val2 = default(Rect);
			((Rect)(ref val2))..ctor((float)Screen.width * 0.5f - 300f, (float)Screen.height - (float)num * 4.2f, 600f, (float)num * 1.6f);
			Rect val3 = default(Rect);
			((Rect)(ref val3))..ctor(((Rect)(ref val2)).x + 1f, ((Rect)(ref val2)).y + 1f, ((Rect)(ref val2)).width, ((Rect)(ref val2)).height);
			GUI.Label(val3, text, m_shadow);
			GUI.Label(val2, text, m_style);
		}
	}
}
internal static class GridState
{
	internal static bool Enabled;

	internal static ConfigEntry<KeyboardShortcut> ToggleKey;

	internal static ConfigEntry<float> Radius;

	internal static ConfigEntry<float> LineSpacing;

	internal static ConfigEntry<Color> LineColor;

	internal static ConfigEntry<float> SnapSize;

	internal static ConfigEntry<bool> SnapPlacement;

	internal static ConfigEntry<bool> SnapRotation;

	internal static ConfigEntry<bool> ShowReadout;

	internal static bool MenuOpen()
	{
		if (!Console.IsVisible() && !TextInput.IsVisible() && !Menu.IsVisible() && !InventoryGui.IsVisible() && !Minimap.IsOpen())
		{
			return StoreGui.IsVisible();
		}
		return true;
	}

	internal static bool Pressed(KeyboardShortcut k)
	{
		//IL_0002: 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_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		if ((int)((KeyboardShortcut)(ref k)).MainKey == 0 || !ZInput.GetKeyDown(((KeyboardShortcut)(ref k)).MainKey, false))
		{
			return false;
		}
		foreach (KeyCode modifier in ((KeyboardShortcut)(ref k)).Modifiers)
		{
			if (!ZInput.GetKey(modifier, false))
			{
				return false;
			}
		}
		return true;
	}

	internal static bool InputBlocked()
	{
		if ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus())
		{
			return true;
		}
		if (!MenuOpen() && !Minimap.InTextInput())
		{
			return Hud.IsPieceSelectionVisible();
		}
		return true;
	}

	internal static float Snap(float v, float size)
	{
		if (size <= 0f)
		{
			return v;
		}
		return Mathf.Round(v / size) * size;
	}
}
internal static class CarturCam
{
	internal const string CARTUR_GUID = "com.jekkle.valheim.carturbuildcamera";

	private static bool s_resolved;

	private static bool s_broken;

	private static Func<bool> s_inBuildMode;

	private static FieldInfo s_activeField;

	internal static bool Loaded;

	internal static string How = "not looked up yet";

	internal static Type PluginType;

	internal static Type UtilsType;

	private static void Resolve()
	{
		s_resolved = true;
		try
		{
			Dictionary<string, PluginInfo> pluginInfos = Chainloader.PluginInfos;
			if (pluginInfos == null || !pluginInfos.TryGetValue("com.jekkle.valheim.carturbuildcamera", out var value) || value == null || (Object)(object)value.Instance == (Object)null)
			{
				How = "Cartur's Build Camera is not installed - the grid always follows the player";
				return;
			}
			Loaded = true;
			PluginType = ((object)value.Instance).GetType();
			UtilsType = PluginType.Assembly.GetType("Valheim_Build_Camera.Utils", throwOnError: false);
			string text = ((value.Metadata != null) ? value.Metadata.Version.ToString() : "?");
			MethodInfo methodInfo = ((UtilsType != null) ? UtilsType.GetMethod("InBuildMode", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null) : null);
			if (methodInfo != null && methodInfo.ReturnType == typeof(bool))
			{
				s_inBuildMode = (Func<bool>)Delegate.CreateDelegate(typeof(Func<bool>), methodInfo);
				How = "Cartur's Build Camera " + text + " found - while its camera is on, the grid follows the point the camera aims at (read: Valheim_Build_Camera.Utils.InBuildMode())";
			}
			else
			{
				FieldInfo fieldInfo = AccessTools.Field(PluginType, "BuildCameraActive");
				if (!(fieldInfo != null) || !fieldInfo.IsStatic || !(fieldInfo.FieldType == typeof(bool)))
				{
					s_broken = true;
					How = "Cartur's Build Camera " + text + " found, but neither Valheim_Build_Camera.Utils.InBuildMode() nor " + PluginType.Name + ".BuildCameraActive exists any more - the grid stays around the player";
					Say(warn: true);
					return;
				}
				s_activeField = fieldInfo;
				How = "Cartur's Build Camera " + text + " found - while its camera is on, the grid follows the point the camera aims at (read: " + PluginType.Name + ".BuildCameraActive; Utils.InBuildMode() is gone)";
			}
			Say(warn: false);
		}
		catch (Exception ex)
		{
			s_broken = true;
			How = "could not read Cartur's Build Camera (" + ex.GetType().Name + ": " + ex.Message + ") - the grid stays around the player";
			Say(warn: true);
		}
	}

	private static void Say(bool warn)
	{
		ManualLogSource log = ClientTweaksPlugin.Log;
		if (log != null)
		{
			if (warn)
			{
				log.LogWarning((object)("Build Grid: " + How));
			}
			else
			{
				log.LogInfo((object)("Build Grid: " + How));
			}
		}
	}

	internal static bool Active()
	{
		if (!s_resolved)
		{
			Resolve();
		}
		if (s_broken)
		{
			return false;
		}
		try
		{
			if (s_inBuildMode != null)
			{
				return s_inBuildMode();
			}
			if (s_activeField != null)
			{
				return (bool)s_activeField.GetValue(null);
			}
		}
		catch (Exception ex)
		{
			s_broken = true;
			How = "reading Cartur's Build Camera state failed (" + ex.GetType().Name + ": " + ex.Message + ") - the grid stays around the player from now on";
			Say(warn: true);
		}
		return false;
	}
}
internal static class GridCentre
{
	internal static Vector3 Current;

	internal static bool OnCamera;

	internal static Vector3 Last;

	internal static bool LastOnCamera;

	internal static string Source = "player";

	private static FieldInfo s_maskField;

	private static bool s_maskLooked;

	private static int s_fallbackMask = -1;

	private static Vector3 s_lastAim;

	private static bool s_haveAim;

	internal static Vector3 For(Player player)
	{
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		if (CarturCam.Active() && CameraAim(player, out var at))
		{
			OnCamera = true;
			Current = at;
			return at;
		}
		OnCamera = false;
		s_haveAim = false;
		Source = "player";
		Current = ((Component)player).transform.position;
		return Current;
	}

	internal static int PlaceMask(Player player)
	{
		if (!s_maskLooked)
		{
			s_maskLooked = true;
			s_maskField = AccessTools.Field(typeof(Player), "m_placeRayMask");
		}
		try
		{
			if (s_maskField != null)
			{
				return (int)s_maskField.GetValue(player);
			}
		}
		catch (Exception e)
		{
			Quiet.Once("BuildGrid: GridCentre.PlaceMask", e);
		}
		if (s_fallbackMask == -1)
		{
			s_fallbackMask = LayerMask.GetMask(new string[6] { "Default", "static_solid", "Default_small", "piece", "terrain", "vehicle" });
		}
		return s_fallbackMask;
	}

	private static bool CameraAim(Player player, out Vector3 at)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: 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_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_008e: 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_00a4: 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_00c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
		at = Vector3.zero;
		GameCamera instance = GameCamera.instance;
		if ((Object)(object)instance == (Object)null)
		{
			return false;
		}
		Transform transform = ((Component)instance).transform;
		RaycastHit val = default(RaycastHit);
		if (Physics.Raycast(transform.position, transform.forward, ref val, 50f, PlaceMask(player)))
		{
			at = ((RaycastHit)(ref val)).point;
			s_lastAim = at;
			s_haveAim = true;
			Source = "camera aim";
			return true;
		}
		if (GridLines.SampleHeight(transform.position.x, transform.position.z, out var height))
		{
			at = new Vector3(transform.position.x, height, transform.position.z);
			Source = "under the camera";
			return true;
		}
		if (s_haveAim)
		{
			at = s_lastAim;
			Source = "last aim";
			return true;
		}
		return false;
	}
}
internal static class GridLines
{
	private const float STEP = 0.5f;

	private const float LIFT = 0.03f;

	private const float UNSAMPLED = 12345678f;

	private static Vector3[] s_verts = (Vector3[])(object)new Vector3[0];

	private static Color[] s_cols = (Color[])(object)new Color[0];

	private static int s_count;

	private static float[] s_heights = new float[0];

	private static Material s_mat;

	private static bool s_matFailed;

	private static Heightmap s_hm;

	internal static int Count => s_count;

	internal static void Clear()
	{
		s_count = 0;
	}

	internal static bool SampleHeight(float x, float z, out float height)
	{
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		height = 0f;
		Vector3 val = default(Vector3);
		((Vector3)(ref val))..ctor(x, 0f, z);
		Heightmap val2 = s_hm;
		if ((Object)(object)val2 == (Object)null || !val2.IsPointInside(val, 0f))
		{
			val2 = (s_hm = Heightmap.FindHeightmap(val));
		}
		if ((Object)(object)val2 == (Object)null)
		{
			return false;
		}
		Vector3 position = ((Component)val2).transform.position;
		float num = ((val2.m_scale > 0f) ? val2.m_scale : 1f);
		float num2 = (float)val2.m_width * 0.5f;
		float num3 = (x - position.x) / num + num2;
		float num4 = (z - position.z) / num + num2;
		int num5 = Mathf.FloorToInt(num3);
		int num6 = Mathf.FloorToInt(num4);
		float num7 = num3 - (float)num5;
		float num8 = num4 - (float)num6;
		int width = val2.m_width;
		if (num5 < 0 || num6 < 0 || num5 > width || num6 > width)
		{
			return false;
		}
		int num9 = Mathf.Min(num5 + 1, width);
		int num10 = Mathf.Min(num6 + 1, width);
		float height2 = val2.GetHeight(num5, num6);
		float height3 = val2.GetHeight(num9, num6);
		float height4 = val2.GetHeight(num5, num10);
		float height5 = val2.GetHeight(num9, num10);
		float num11 = height2 + (height3 - height2) * num7;
		float num12 = height4 + (height5 - height4) * num7;
		height = num11 + (num12 - num11) * num8 + position.y;
		return true;
	}

	private static float Height(int i, int j, int i0, int j0, int nx)
	{
		int num = (j - j0) * nx + (i - i0);
		float num2 = s_heights[num];
		if (num2 == 12345678f)
		{
			num2 = (SampleHeight((float)i * 0.5f, (float)j * 0.5f, out var height) ? height : float.NaN);
			s_heights[num] = num2;
		}
		return num2;
	}

	private static bool OnLine(int index, float spacing)
	{
		float num = (float)index * 0.5f;
		return Mathf.Abs(Mathf.Round(num / spacing) * spacing - num) < 0.001f;
	}

	internal static void Rebuild(Vector3 centre, float radius, float spacing, Color baseColor)
	{
		//IL_010c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0110: Unknown result type (might be due to invalid IL or missing references)
		//IL_014e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0152: Unknown result type (might be due to invalid IL or missing references)
		if (spacing < 0.5f)
		{
			spacing = 0.5f;
		}
		int num = Mathf.FloorToInt((centre.x - radius) / 0.5f);
		int num2 = Mathf.CeilToInt((centre.x + radius) / 0.5f);
		int num3 = Mathf.FloorToInt((centre.z - radius) / 0.5f);
		int num4 = Mathf.CeilToInt((centre.z + radius) / 0.5f);
		int num5 = num2 - num + 1;
		int num6 = num4 - num3 + 1;
		int num7 = num5 * num6;
		if (s_heights.Length < num7)
		{
			s_heights = new float[num7];
		}
		for (int i = 0; i < num7; i++)
		{
			s_heights[i] = 12345678f;
		}
		int num8 = 2 * (num5 * num6 + num6 * num5);
		if (s_verts.Length < num8)
		{
			s_verts = (Vector3[])(object)new Vector3[num8];
			s_cols = (Color[])(object)new Color[num8];
		}
		s_count = 0;
		float fadeBand = Mathf.Max(0.5f, radius * 0.3f);
		for (int j = num; j <= num2; j++)
		{
			if (OnLine(j, spacing))
			{
				for (int k = num3; k < num4; k++)
				{
					AddSegment(centre, radius, fadeBand, baseColor, j, k, j, k + 1, num, num3, num5);
				}
			}
		}
		for (int l = num3; l <= num4; l++)
		{
			if (OnLine(l, spacing))
			{
				for (int m = num; m < num2; m++)
				{
					AddSegment(centre, radius, fadeBand, baseColor, m, l, m + 1, l, num, num3, num5);
				}
			}
		}
	}

	private static void AddSegment(Vector3 centre, float radius, float fadeBand, Color baseColor, int ia, int ja, int ib, int jb, int i0, int j0, int nx)
	{
		//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_0104: Unknown result type (might be due to invalid IL or missing references)
		//IL_0137: Unknown result type (might be due to invalid IL or missing references)
		//IL_013c: 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_016b: Unknown result type (might be due to invalid IL or missing references)
		//IL_019e: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
		float num = (float)ia * 0.5f;
		float num2 = (float)ja * 0.5f;
		float num3 = (float)ib * 0.5f;
		float num4 = (float)jb * 0.5f;
		float num5 = Mathf.Sqrt((num - centre.x) * (num - centre.x) + (num2 - centre.z) * (num2 - centre.z));
		float num6 = Mathf.Sqrt((num3 - centre.x) * (num3 - centre.x) + (num4 - centre.z) * (num4 - centre.z));
		float num7 = Mathf.Clamp01((radius - num5) / fadeBand);
		float num8 = Mathf.Clamp01((radius - num6) / fadeBand);
		if (!(num7 <= 0f) || !(num8 <= 0f))
		{
			float num9 = Height(ia, ja, i0, j0, nx);
			float num10 = Height(ib, jb, i0, j0, nx);
			if (!float.IsNaN(num9) && !float.IsNaN(num10))
			{
				ref Vector3 reference = ref s_verts[s_count];
				reference = new Vector3(num, num9 + 0.03f, num2);
				ref Color reference2 = ref s_cols[s_count];
				reference2 = new Color(baseColor.r, baseColor.g, baseColor.b, baseColor.a * num7);
				s_count++;
				ref Vector3 reference3 = ref s_verts[s_count];
				reference3 = new Vector3(num3, num10 + 0.03f, num4);
				ref Color reference4 = ref s_cols[s_count];
				reference4 = new Color(baseColor.r, baseColor.g, baseColor.b, baseColor.a * num8);
				s_count++;
			}
		}
	}

	private static bool EnsureMaterial()
	{
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_0058: Expected O, but got Unknown
		if ((Object)(object)s_mat != (Object)null)
		{
			return true;
		}
		if (s_matFailed)
		{
			return false;
		}
		string[] array = new string[2] { "Hidden/Internal-Colored", "Sprites/Default" };
		for (int i = 0; i < array.Length; i++)
		{
			Shader val = Shader.Find(array[i]);
			if (!((Object)(object)val == (Object)null))
			{
				Material val2 = new Material(val);
				((Object)val2).hideFlags = (HideFlags)61;
				if (val2.HasProperty("_SrcBlend"))
				{
					val2.SetInt("_SrcBlend", 5);
				}
				if (val2.HasProperty("_DstBlend"))
				{
					val2.SetInt("_DstBlend", 10);
				}
				if (val2.HasProperty("_Cull"))
				{
					val2.SetInt("_Cull", 0);
				}
				if (val2.HasProperty("_ZWrite"))
				{
					val2.SetInt("_ZWrite", 0);
				}
				if (val2.HasProperty("_ZTest"))
				{
					val2.SetInt("_ZTest", 4);
				}
				s_mat = val2;
				return true;
			}
		}
		s_matFailed = true;
		ClientTweaksPlugin.Log.LogWarning((object)"Build Grid: no usable shader for the grid lines (Hidden/Internal-Colored and Sprites/Default both missing) - the lines will not draw; snapping still works.");
		return false;
	}

	internal static void Draw()
	{
		//IL_002e: 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)
		if (EnsureMaterial())
		{
			GL.PushMatrix();
			s_mat.SetPass(0);
			GL.Begin(1);
			for (int i = 0; i < s_count; i++)
			{
				GL.Color(s_cols[i]);
				GL.Vertex(s_verts[i]);
			}
			GL.End();
			GL.PopMatrix();
		}
	}
}
[HarmonyPriority(0)]
[HarmonyPatch(typeof(Player), "PieceRayTest")]
internal static class Player_PieceRayTest_Grid
{
	internal static bool DidShift;

	internal static Vector2 RayXZ;

	internal static Vector2 TargetXZ;

	internal static Vector2 LastOffset;

	internal static bool HaveOffset;

	private static void Postfix(bool __result, ref Vector3 point, Piece piece, Collider waterSurface, Heightmap heightmap)
	{
		//IL_0043: 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_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d2: 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_00e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
		if (Player_UpdatePlacementGhost_Grid.Applicable && GridState.SnapPlacement.Value && __result && !((Object)(object)piece != (Object)null) && !((Object)(object)waterSurface != (Object)null))
		{
			float value = GridState.SnapSize.Value;
			Vector2 val = (HaveOffset ? LastOffset : Vector2.zero);
			float num = GridState.Snap(point.x + val.x, value);
			float num2 = GridState.Snap(point.z + val.y, value);
			float num3 = num - val.x;
			float num4 = num2 - val.y;
			float num5 = point.y;
			if ((Object)(object)heightmap != (Object)null && GridLines.SampleHeight(point.x, point.z, out var height) && GridLines.SampleHeight(num3, num4, out var height2))
			{
				num5 = point.y + (height2 - height);
			}
			point = new Vector3(num3, num5, num4);
			RayXZ = new Vector2(num3, num4);
			TargetXZ = new Vector2(num, num2);
			DidShift = true;
		}
	}
}
[HarmonyPatch(typeof(Player), "UpdatePlacementGhost")]
[HarmonyPriority(0)]
internal static class Player_UpdatePlacementGhost_Grid
{
	internal static bool Applicable;

	private static GameObject s_lastGhost;

	private static int s_lastRot;

	private static bool s_rotValid;

	private static MethodInfo s_findSnap;

	private static object[] s_snapArgs;

	private static readonly List<Piece> s_tmpPieces = new List<Piece>();

	private static void Prefix(Player __instance, GameObject ___m_placementGhost, PieceTable ___m_buildPieces, ref int ___m_placeRotation, float ___m_placeRotationDegrees)
	{
		Player_PieceRayTest_Grid.DidShift = false;
		Applicable = GridState.Enabled && Applies(__instance, ___m_buildPieces);
		if (!Applicable)
		{
			s_rotValid = false;
			return;
		}
		if ((Object)(object)___m_placementGhost != (Object)(object)s_lastGhost)
		{
			s_lastGhost = ___m_placementGhost;
			Player_PieceRayTest_Grid.HaveOffset = false;
		}
		if (!GridState.SnapRotation.Value)
		{
			s_rotValid = false;
			return;
		}
		int num = Mathf.Max(1, Mathf.RoundToInt(90f / Mathf.Max(1f, ___m_placeRotationDegrees)));
		int num2 = ___m_placeRotation;
		if (!s_rotValid || num2 != s_lastRot)
		{
			num2 = ((!s_rotValid || (num2 - s_lastRot != 1 && num2 - s_lastRot != -1)) ? (Mathf.RoundToInt((float)num2 / (float)num) * num) : (s_lastRot + ((num2 > s_lastRot) ? num : (-num))));
		}
		___m_placeRotation = num2;
		s_lastRot = num2;
		s_rotValid = true;
	}

	private static void Postfix(Player __instance, GameObject ___m_placementGhost)
	{
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_0084: Unknown result type (might be due to invalid IL or missing references)
		//IL_0085: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
		if (!Applicable || !GridState.SnapPlacement.Value || !Player_PieceRayTest_Grid.DidShift)
		{
			return;
		}
		Player_PieceRayTest_Grid.DidShift = false;
		if (!((Object)(object)___m_placementGhost == (Object)null) && ___m_placementGhost.activeInHierarchy && !SnappedToPiece(__instance, ___m_placementGhost))
		{
			Vector3 position = ___m_placementGhost.transform.position;
			Vector2 lastOffset = default(Vector2);
			((Vector2)(ref lastOffset))..ctor(position.x - Player_PieceRayTest_Grid.RayXZ.x, position.z - Player_PieceRayTest_Grid.RayXZ.y);
			if (((Vector2)(ref lastOffset)).magnitude < 4f)
			{
				Player_PieceRayTest_Grid.LastOffset = lastOffset;
				Player_PieceRayTest_Grid.HaveOffset = true;
			}
			Vector2 val = Player_PieceRayTest_Grid.TargetXZ - new Vector2(position.x, position.z);
			float magnitude = ((Vector2)(ref val)).magnitude;
			if (magnitude > 0.02f && magnitude < 0.3f)
			{
				___m_placementGhost.transform.position = new Vector3(Player_PieceRayTest_Grid.TargetXZ.x, position.y, Player_PieceRayTest_Grid.TargetXZ.y);
			}
		}
	}

	private static bool Applies(Player player, PieceTable table)
	{
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Invalid comparison between Unknown and I4
		try
		{
			ItemData val = null;
			foreach (ItemData allItem in ((Humanoid)player).GetInventory().GetAllItems())
			{
				if (allItem != null && allItem.m_equipped && allItem.m_shared != null && (int)allItem.m_shared.m_itemType == 19)
				{
					val = allItem;
					break;
				}
			}
			GameObject val2 = (((Object)(object)table != (Object)null) ? table.GetSelectedPrefab() : null);
			if ((Object)(object)val2 != (Object)null && (Object)(object)val2.GetComponent<Plant>() != (Object)null && (Object)(object)val2.GetComponent<TerrainOp>() == (Object)null)
			{
				return true;
			}
			if (val != null && val.m_shared != null)
			{
				string name = val.m_shared.m_name;
				if (name == "$item_hoe" || name == "$item_cultivator")
				{
					return false;
				}
				if ((Object)(object)val.m_dropPrefab != (Object)null)
				{
					string name2 = ((Object)val.m_dropPrefab).name;
					if (name2 == "Hoe" || name2 == "Cultivator")
					{
						return false;
					}
				}
			}
			GameObject val3 = (((Object)(object)table != (Object)null) ? table.GetSelectedPrefab() : null);
			if ((Object)(object)val3 != (Object)null && ((Object)(object)val3.GetComponent<TerrainOp>() != (Object)null || (Object)(object)val3.GetComponent<TerrainModifier>() != (Object)null))
			{
				return false;
			}
			return true;
		}
		catch (Exception e)
		{
			Quiet.Once("BuildGrid: Player_UpdatePlacementGhost_Grid.Applies", e);
			return false;
		}
	}

	private static bool SnappedToPiece(Player player, GameObject ghost)
	{
		try
		{
			if ((!ZInput.IsNonClassicFunctionality() || !ZInput.IsGamepadActive()) ? (ZInput.GetButton("AltPlace") || (ZInput.GetButton("JoyAltPlace") && !ZInput.GetButton("JoyRotate"))) : player.AlternativePlacementActive)
			{
				return false;
			}
			if (s_findSnap == null)
			{
				s_findSnap = AccessTools.Method(typeof(Player), "FindClosestSnapPoints", (Type[])null, (Type[])null);
			}
			if (s_findSnap == null)
			{
				return true;
			}
			if (s_snapArgs == null)
			{
				s_snapArgs = new object[5] { null, 0.5f, null, null, null };
			}
			s_snapArgs[0] = ghost.transform;
			s_snapArgs[2] = null;
			s_snapArgs[3] = null;
			s_snapArgs[4] = s_tmpPieces;
			bool result = (bool)s_findSnap.Invoke(player, s_snapArgs);
			s_snapArgs[0] = null;
			s_snapArgs[2] = null;
			s_snapArgs[3] = null;
			return result;
		}
		catch (Exception e)
		{
			Quiet.Once("BuildGrid: Player_UpdatePlacementGhost_Grid.SnappedToPiece", e);
			return true;
		}
	}
}
internal static class ModSource
{
	private static MethodInfo s_getPrefab;

	private static PropertyInfo s_sourceMod;

	private static bool s_ready;

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

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

	private static Object s_missesFor;

	internal static bool Ready => s_ready;

	internal static void Enable()
	{
		Type type = AccessTools.TypeByName("Jotunn.Utils.ModQuery");
		if (type == null)
		{
			ClientTweaksPlugin.Log.LogWarning((object)"Jotunn not found - build menu search by mod is off.");
			return;
		}
		MethodInfo methodInfo = AccessTools.Method(type, "Enable", (Type[])null, (Type[])null);
		s_getPrefab = AccessTools.Method(type, "GetPrefab", new Type[1] { typeof(string) }, (Type[])null);
		Type type2 = AccessTools.TypeByName("Jotunn.Utils.IModPrefab") ?? AccessTools.TypeByName("Jotunn.Entities.IModPrefab");
		s_sourceMod = ((type2 != null) ? type2.GetProperty("SourceMod") : null);
		if (methodInfo == null || s_getPrefab == null || s_sourceMod == null)
		{
			ClientTweaksPlugin.Log.LogWarning((object)"Jotunn found, but its ModQuery.Enable / GetPrefab / IModPrefab.SourceMod changed - build menu search by mod is off.");
			return;
		}
		try
		{
			methodInfo.Invoke(null, null);
			s_ready = true;
		}
		catch (Exception ex)
		{
			ClientTweaksPlugin.Log.LogWarning((object)("Build menu search by mod is off: " + ex.Message));
		}
	}

	internal static string[] Terms(string prefabName)
	{
		if (!object.ReferenceEquals(s_missesFor, ZNetScene.instance))
		{
			s_misses.Clear();
			s_missesFor = (Object)(object)ZNetScene.instance;
		}
		string value;
		if (s_misses.Contains(prefabName))
		{
			value = "";
		}
		else if (!s_cache.TryGetValue(prefabName, out value))
		{
			value = "";
			if (s_ready)
			{
				try
				{
					object obj = s_getPrefab.Invoke(null, new object[1] { prefabName });
					if (obj != null)
					{
						object? value2 = s_sourceMod.GetValue(obj, null);
						BepInPlugin val = (BepInPlugin)((value2 is BepInPlugin) ? value2 : null);
						if (val != null && !string.IsNullOrEmpty(val.Name))
						{
							value = val.Name.ToLowerInvariant().Replace(" ", "");
						}
					}
				}
				catch (Exception e)
				{
					Quiet.Once("BuildSearchByMod: ModSource.Terms", e);
					value = "";
				}
			}
			if (value.Length > 0)
			{
				s_cache[prefabName] = value;
			}
			else if (s_ready)
			{
				s_misses.Add(prefabName);
			}
		}
		if (value.Length == 0)
		{
			return new string[2] { "valheim", "vanilla" };
		}
		return new string[1] { value };
	}
}
[HarmonyPatch(typeof(BuildUiPieceButton), "Setup")]
internal static class BuildUiPieceButton_Setup_ModTerm
{
	internal static void Postfix(BuildUiPieceButton __instance, Piece pieceInfo)
	{
		if ((Object)(object)pieceInfo == (Object)null || !Features.On(Features.BuildSearchByMod) || !Balance.Current.BuildSearchByMod)
		{
			return;
		}
		string[] array = ModSource.Terms(Utils.GetPrefabName(((Component)pieceInfo).gameObject));
		foreach (string item in array)
		{
			if (!__instance.LocalizedSearchTerms.Contains(item))
			{
				__instance.LocalizedSearchTerms.Add(item);
			}
		}
	}
}
[HarmonyPatch(typeof(Hud), "UpdateCrosshair")]
[HarmonyPriority(0)]
internal static class BuildingHealthHud
{
	private sealed class Line
	{
		internal readonly string Name;

		internal Transform T;

		internal Component Label;

		internal int A = int.MinValue;

		internal int B;

		internal int C;

		internal string Text;

		internal Line(string name)
		{
			Name = name;
		}
	}

	internal const string OldModGuid = "cjayride.BuildingHealthDisplay";

	internal static bool OldModPresent;

	internal static Piece TestPiece;

	private static bool s_checked;

	private static bool s_off;

	private static readonly FieldInfo s_healthTextField = AccessTools.Field(typeof(Hud), "m_healthText");

	private static readonly MethodInfo s_getSupport = AccessTools.Method(typeof(WearNTear), "GetSupport", (Type[])null, (Type[])null);

	private static readonly MethodInfo s_getMaxSupport = AccessTools.Method(typeof(WearNTear), "GetMaxSupport", (Type[])null, (Type[])null);

	private static PropertyInfo s_text;

	private static PropertyInfo s_fontSize;

	private static PropertyInfo s_maxChars;

	private static readonly Line s_health = new Line("_HealthText");

	private static readonly Line s_integrity = new Line("_IntegrityText");

	private static bool s_shown;

	private static bool Disabled()
	{
		if (!s_checked)
		{
			s_checked = true;
			if (!OldModPresent && Chainloader.PluginInfos.ContainsKey("cjayride.BuildingHealthDisplay"))
			{
				OldModPresent = true;
				ClientTweaksPlugin.Log.LogInfo((object)"Old Building Health Display mod found - standing aside.");
			}
			if (s_healthTextField == null || s_getSupport == null || s_getMaxSupport == null)
			{
				s_off = true;
				ClientTweaksPlugin.Log.LogWarning((object)"Hud.m_healthText or WearNTear.GetSupport/GetMaxSupport not found - building health display off.");
			}
		}
		if (!OldModPresent)
		{
			return s_off;
		}
		return true;
	}

	private static void Postfix(Hud __instance, Player player)
	{
		//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00be: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
		if (Disabled() || !Features.On(Features.BuildingHealth) || !Balance.Current.BuildingHealth)
		{
			HideTexts(__instance);
		}
		else
		{
			if ((Object)(object)player == (Object)null || (Object)(object)__instance.m_pieceHealthBar == (Object)null || (Object)(object)__instance.m_pieceHealthRoot == (Object)null)
			{
				return;
			}
			Piece val = (((Object)(object)TestPiece != (Object)null) ? TestPiece : player.GetHoveringPiece());
			if (!Object.op_Implicit((Object)(object)val))
			{
				return;
			}
			WearNTear component = ((Component)val).GetComponent<WearNTear>();
			ZNetView component2 = ((Component)val).GetComponent<ZNetView>();
			if (Object.op_Implicit((Object)(object)component) && !((Object)(object)component2 == (Object)null) && component2.IsValid())
			{
				float healthPercentage = component.GetHealthPercentage();
				__instance.m_pieceHealthBar.SetValue(healthPercentage);
				if (healthPercentage < 0.5f)
				{
					__instance.m_pieceHealthBar.SetColor(Color.Lerp(Color.red, Color.yellow, healthPercentage * 2f));
				}
				else
				{
					__instance.m_pieceHealthBar.SetColor(Color.Lerp(Color.yellow, Color.green, (healthPercentage - 0.5f) * 2f));
				}
				ZDO zDO = component2.GetZDO();
				float num = ((zDO != null) ? zDO.GetFloat(ZDOVars.s_health, component.m_health) : component.m_health);
				ShowText(__instance, s_health, Mathf.RoundToInt(num), Mathf.RoundToInt(component.m_health), Mathf.RoundToInt(healthPercentage * 100f), 40f);
				float num2 = (float)s_getSupport.Invoke(component, null);
				float num3 = (float)s_getMaxSupport.Invoke(component, null);
				if (num3 >= num2 && num3 > 0f)
				{
					ShowText(__instance, s_integrity, Mathf.RoundToInt(num2), Mathf.RoundToInt(num3), Mathf.RoundToInt(num2 / num3 * 100f), -40f);
				}
				else
				{
					HideText(__instance, s_integrity);
				}
			}
		}
	}

	internal static string ShownHealthText()
	{
		Transform t = s_health.T;
		if ((Object)(object)t == (Object)null || !((Component)t).gameObject.activeSelf)
		{
			return null;
		}
		return s_health.Text;
	}

	private static void HideTexts(Hud hud)
	{
		if (s_shown && !((Object)(object)hud == (Object)null))
		{
			s_shown = false;
			HideText(hud, s_health);
			HideText(hud, s_integrity);
		}
	}

	private static void HideText(Hud hud, Line line)
	{
		try
		{
			Transform pieceHealthRoot = (Transform)(object)hud.m_pieceHealthRoot;
			Transform val = (((Object)(object)line.T != (Object)null && (Object)(object)pieceHealthRoot != (Object)null && (Object)(object)line.T.parent == (Object)(object)pieceHealthRoot) ? line.T : (((Object)(object)pieceHealthRoot != (Object)null) ? pieceHealthRoot.Find(line.Name) : null));
			if ((Object)(object)val != (Object)null && ((Component)val).gameObject.activeSelf)
			{
				((Component)val).gameObject.SetActive(false);
			}
		}
		catch (Exception e)
		{
			Quiet.Once("BuildingHealth: BuildingHealthHud.HideText", e);
		}
	}

	private static void ShowText(Hud hud, Line line, int a, int b, int c, float x)
	{
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		//IL_0249: Unknown result type (might be due to invalid IL or missing references)
		//IL_024e: 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)
		Transform pieceHealthRoot = (Transform)(object)hud.m_pieceHealthRoot;
		Transform val = line.T;
		if ((Object)(object)val == (Object)null || (Object)(object)val.parent != (Object)(object)pieceHealthRoot)
		{
			object? value = s_healthTextField.GetValue(hud);
			Component val2 = (Component)((value is Component) ? value : null);
			if ((Object)(object)val2 == (Object)null)
			{
				return;
			}
			val = pieceHealthRoot.Find(line.Name);
			if ((Object)(object)val == (Object)null)
			{
				Component val3 = Object.Instantiate<Component>(val2, pieceHealthRoot);
				val = val3.transform;
				((Object)val).name = line.Name;
				((Transform)((Component)val).GetComponent<RectTransform>()).localEulerAngles = new Vector3(0f, 0f, -90f);
			}
			line.T = val;
			line.Label = null;
			line.Text = null;
		}
		Type fieldType = s_healthTextField.FieldType;
		if (s_text == null)
		{
			s_text = fieldType.GetProperty("text");
			s_fontSize = fieldType.GetProperty("fontSize");
			s_maxChars = fieldType.GetProperty("maxVisibleCharacters");
			if (s_text == null || s_fontSize == null || s_maxChars == null)
			{
				s_off = true;
				ClientTweaksPlugin.Log.LogWarning((object)"TMP_Text properties not found - building health display off.");
				return;
			}
		}
		Component val4 = line.Label;
		if ((Object)(object)val4 == (Object)null)
		{
			val4 = ((Component)val).GetComponent(fieldType);
			if ((Object)(object)val4 == (Object)null)
			{
				return;
			}
			line.Label = val4;
		}
		if (!((Component)val).gameObject.activeSelf)
		{
			((Component)val).gameObject.SetActive(true);
		}
		s_shown = true;
		if (line.Text == null || a != line.A || b != line.B || c != line.C)
		{
			string text = $"{a}/{b} ({c}%)";
			line.A = a;
			line.B = b;
			line.C = c;
			line.Text = text;
			s_text.SetValue(val4, text, null);
			s_maxChars.SetValue(val4, text.Length, null);
		}
		s_fontSize.SetValue(val4, 18f, null);
		RectTransform val5 = (RectTransform)(object)((val is RectTransform) ? val : null);
		if ((Object)(object)val5 == (Object)null)
		{
			val5 = ((Component)val).GetComponent<RectTransform>();
		}
		Vector2 val6 = default(Vector2);
		((Vector2)(ref val6))..ctor(x, 0f);
		if (val5.anchoredPosition != val6)
		{
			val5.anchoredPosition = val6;
		}
	}
}
internal static class Quiet
{
	private static readonly HashSet<string> s_seen = new HashSet<string>();

	internal static void Once(string where, Exception e)
	{
		try
		{
			lock (s_seen)
			{
				if (!s_seen.Add(where))
				{
					return;
				}
			}
			Exception ex = ((e != null && e.InnerException != null) ? e.InnerException : e);
			string text = where + " failed (first time; later failures here are not logged): " + ((ex != null) ? (ex.GetType().Name + ": " + ex.Message) : "?");
			if (ClientTweaksPlugin.Log != null)
			{
				ClientTweaksPlugin.Log.LogWarning((object)text);
			}
			else
			{
				Debug.LogWarning((object)("[DogHaus Client Tweaks] " + text));
			}
		}
		catch (Exception)
		{
		}
	}
}
[HarmonyPatch(typeof(CraftingStation), "Interact")]
internal static class CraftingStation_Interact_Repair
{
	private static readonly Dictionary<string, Recipe> s_recipes = new Dictionary<string, Recipe>();

	private static ObjectDB s_recipesFor;

	internal static int LastRepaired = -1;

	private static void Postfix(CraftingStation __instance, Humanoid user, bool repeat)
	{
		if (!repeat && Features.On(Features.AutoRepair) && Balance.Current.AutoRepair)
		{
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)user != (Object)(object)localPlayer) && !((Object)(object)__instance != (Object)(object)localPlayer.GetCurrentCraftingStation()))
			{
				LastRepaired = RepairAll(localPlayer, __instance);
			}
		}
	}

	private static int RepairAll(Player player, CraftingStation station)
	{
		//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00db: 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_00ef: Unknown result type (might be due to invalid IL or missing references)
		bool flag = player.NoCostCheat();
		string name = station.m_name;
		int level = Mathf.Min(station.GetLevel(true), 4);
		int num = 0;
		foreach (ItemData allItem in ((Humanoid)player).GetInventory().GetAllItems())
		{
			if (allItem.m_shared.m_useDurability && allItem.m_shared.m_canBeReparied)
			{
				float maxDurability = allItem.GetMaxDurability(allItem.m_quality);
				if (!(allItem.m_durability >= maxDurability) && (flag || CanRepair(allItem, name, level)))
				{
					((Character)player).RaiseSkill((SkillType)107, 1f - allItem.m_durability / maxDurability);
					allItem.m_durability = maxDurability;
					num++;
				}
			}
		}
		if (num > 0 && station.m_repairItemDoneEffects != null)
		{
			station.m_repairItemDoneEffects.Create(((Component)station).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
		}
		return num;
	}

	private static bool CanRepair(ItemData item, string stationName, int level)
	{
		Recipe val = RecipeFor(item);
		if ((Object)(object)val == (Object)null || ((Object)(object)val.m_craftingStation == (Object)null && (Object)(object)val.m_repairStation == (Object)null))
		{
			return false;
		}
		if (((Object)(object)val.m_repairStation != (Object)null && val.m_repairStation.m_name == stationName) || ((Object)(object)val.m_craftingStation != (Object)null && val.m_craftingStation.m_name == stationName) || item.m_worldLevel < Game.m_worldLevel)
		{
			return level >= val.m_minStationLevel;
		}
		return false;
	}

	private static Recipe RecipeFor(ItemData item)
	{
		if ((Object)(object)ObjectDB.instance == (Object)null)
		{
			return null;
		}
		if ((Object)(object)s_recipesFor != (Object)(object)ObjectDB.instance)
		{
			s_recipes.Clear();
			s_recipesFor = ObjectDB.instance;
		}
		string name = item.m_shared.m_name;
		if (s_recipes.TryGetValue(name, out var value))
		{
			return value;
		}
		value = null;
		foreach (Recipe recipe in ObjectDB.instance.m_recipes)
		{
			if ((Object)(object)recipe != (Object)null && (Object)(object)recipe.m_item != (Object)null && recipe.m_item.m_itemData.m_shared.m_name == name)
			{
				value = recipe;
				break;
			}
		}
		if ((Object)(object)value != (Object)null)
		{
			s_recipes[name] = value;
		}
		return value;
	}
}
[HarmonyPatch(typeof(Hud), "SetupPieceInfo")]
internal static class Hud_SetupPieceInfo_Stats
{
	private sealed class Lines
	{
		internal string Add;

		internal Balance For;

		internal int WorldLevel;

		internal float Health;

		internal int Comfort;

		internal ComfortGroup Group;

		internal MaterialType Material;
	}

	private static readonly FieldInfo s_desc = AccessTools.Field(typeof(Hud), "m_pieceDescription");

	private static PropertyInfo s_text;

	private static readonly MethodInfo s_matProps = AccessTools.Method(typeof(WearNTear), "GetMaterialProperties", (Type[])null, (Type[])null);

	private static readonly FieldInfo[] s_dmgFields = typeof(DamageModifiers).GetFields(BindingFlags.Instance | BindingFlags.Public);

	private static readonly Dictionary<Piece, Lines> s_lines = new Dictionary<Piece, Lines>();

	private static void Postfix(Hud __instance, Piece piece)
	{
		if ((Object)(object)piece == (Object)null || s_desc == null || !Features.On(Features.PieceStats))
		{
			return;
		}
		try
		{
			AddLines(__instance, piece);
		}
		catch (Exception e)
		{
			Quiet.Once("PieceStats: Hud_SetupPieceInfo_Stats.Postfix", e);
		}
	}

	private static string CachedAdd(Piece piece)
	{
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0081: Unknown result type (might be due to invalid IL or missing references)
		//IL_0087: 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_0095: Unknown result type (might be due to invalid IL or missing references)
		//IL_0139: Unknown result type (might be due to invalid IL or missing references)
		//IL_013e: 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)
		WearNTear component = ((Component)piece).GetComponent<WearNTear>();
		Balance current = Balance.Current;
		int worldLevel = Game.m_worldLevel;
		float num = (((Object)(object)component != (Object)null) ? component.m_health : (-1f));
		MaterialType val = (MaterialType)(((Object)(object)component != (Object)null) ? ((int)component.m_materialType) : 0);
		if (s_lines.TryGetValue(piece, out var value) && object.ReferenceEquals(value.For, current) && value.WorldLevel == worldLevel && value.Health == num && value.Comfort == piece.m_comfort && value.Group == piece.m_comfortGroup && value.Material == val)
		{
			return value.Add;
		}
		string text = StatsLine(piece);
		string text2 = ((piece.m_comfort > 0) ? ComfortLine(piece) : null);
		if (s_lines.Count > 4000)
		{
			s_lines.Clear();
		}
		value = new Lines();
		value.Add = ((text == null && text2 == null) ? null : ((text != null && text2 != null) ? (text + "\n" + text2) : (text ?? text2)));
		value.For = current;
		value.WorldLevel = worldLevel;
		value.Health = num;
		value.Comfort = piece.m_comfort;
		value.Group = piece.m_comfortGroup;
		value.Material = val;
		s_lines[piece] = value;
		return value.Add;
	}

	private static void AddLines(Hud __instance, Piece piece)
	{
		string text = CachedAdd(piece);
		if (text == null)
		{
			return;
		}
		object value = s_desc.GetValue(__instance);
		if (value != null)
		{
			if (s_text == null)
			{
				s_text = value.GetType().GetProperty("text");
			}
			if (!(s_text == null))
			{
				string text2 = s_text.GetValue(value, null) as string;
				s_text.SetValue(value, string.IsNullOrEmpty(text2) ? text : (text2 + "\n\n" + text), null);
			}
		}
	}

	private static string ComfortLine(Piece piece)
	{
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		string text = "<color=orange>Comfort +" + piece.m_comfort + "</color>";
		string text2 = GroupName(piece.m_comfortGroup);
		if (text2 == null)
		{
			return text + " (counts once per piece type)";
		}
		string text3 = text;
		return text3 + " - " + text2 + " group (only your best " + text2 + " piece counts)";
	}

	private static string StatsLine(Piece piece)
	{
		//IL_0075: Unknown result type (might be due to invalid IL or missing references)
		//IL_0125: Unknown result type (might be due to invalid IL or missing references)
		WearNTear component = ((Component)piece).GetComponent<WearNTear>();
		if ((Object)(object)component == (Object)null)
		{
			return null;
		}
		try
		{
			float num = component.m_health;
			if (Game.m_worldLevel > 0 && (Object)(object)Game.instance != (Object)null)
			{
				num += (float)Game.m_worldLevel * Game.instance.m_worldLevelPieceHPMultiplier * num;
			}
			string text = ((num >= 1000000f) ? "<color=#8fd16a>Unbreakable</color>" : ("<color=#8fd16a>Health " + Mathf.RoundToInt(num) + "</color>"));
			text = text + " - " + MaterialName(component.m_materialType);
			if (component.m_supports)
			{
				text += " structure";
			}
			if (component.m_supports && s_matProps != null)
			{
				object[] array = new object[4];
				s_matProps.Invoke(component, array);
				float num2 = ((array[0] is float) ? ((float)array[0]) : 0f);
				if (num2 > 0f)
				{
					object obj = text;
					text = string.Concat(obj, " (support ", Mathf.RoundToInt(num2), ")");
				}
			}
			string text2 = Weaknesses(component.m_damages);
			if (text2.Length > 0)
			{
				text = text + " - <color=#e8826a>weak to " + text2 + "</color>";
			}
			return text;
		}
		catch (Exception e)
		{
			Quiet.Once("PieceStats: Hud_SetupPieceInfo_Stats.StatsLine", e);
			return null;
		}
	}

	private static string MaterialName(MaterialType m)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		return ((object)m).ToString() switch
		{
			"HardWood" => "Core wood", 
			"Marble" => "Black marble", 
			"Ashstone" => "Grausten", 
			"Timberwood" => "Timber", 
			_ => ((object)m).ToString(), 
		};
	}

	private static string Weaknesses(DamageModifiers d)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		object obj = d;
		List<string> list = new List<string>();
		FieldInfo[] array = s_dmgFields;
		foreach (FieldInfo fieldInfo in array)
		{
			if (!(fieldInfo.FieldType != typeof(DamageModifier)))
			{
				string text = fieldInfo.GetValue(obj).ToString();
				if (text.IndexOf("Weak", StringComparison.Ordinal) >= 0)
				{
					string text2 = (fieldInfo.Name.StartsWith("m_") ? fieldInfo.Name.Substring(2) : fieldInfo.Name);
					list.Add((text == "VeryWeak") ? (text2 + " (very)") : ((text == "SlightlyWeak") ? (text2 + " (slightly)") : text2));
				}
			}
		}
		return string.Join(", ", list.ToArray());
	}

	private static string GroupName(ComfortGroup g)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Expected I4, but got Unknown
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Expected I4, but got Unknown
		if ((int)g == 0)
		{
			return null;
		}
		switch ((int)g)
		{
		case 1000:
			return "Herbs and plants";
		case 1001:
			return "Clutter";
		case 1002:
			return "Statues";
		case 1006:
			return "Books";
		default:
			if (!Enum.IsDefined(typeof(ComfortGroup), g))
			{
				return "Group " + (int)g;
			}
			return ((object)g).ToString();
		}
	}
}
[HarmonyPatch(typeof(GameCamera), "UpdateCamera")]
internal static class GameCamera_UpdateCamera_PassengerZoom
{
	private static bool s_set;

	private static float s_saved;

	internal static float LastLimit = -1f;

	internal static bool TestPassenger;

	internal static Ship PassengerShip(Player player)
	{
		if ((Object)(object)player == (Object)null || (Object)(object)player.GetControlledShip() != (Object)null || !((Character)player).IsAttachedToShip())
		{
			return null;
		}
		Transform attachPoint = player.GetAttachPoint();
		if (!((Object)(object)attachPoint != (Object)null))
		{
			return null;
		}
		return ((Component)attachPoint).GetComponentInParent<Ship>();
	}

	[HarmonyPriority(0)]
	private static void Prefix(GameCamera __instance)
	{
		s_set = false;
		LastLimit = -1f;
		try
		{
			if (!((Object)(object)__instance == (Object)null) && Features.On(Features.PassengerZoom) && Balance.Current.ShipPassengerZoom && (TestPassenger || !((Object)(object)PassengerShip(Player.m_localPlayer) == (Object)null)))
			{
				s_saved = __instance.m_maxDistance;
				__instance.m_maxDistance = __instance.m_maxDistanceBoat;
				LastLimit = __instance.m_maxDistanceBoat;
				s_set = true;
			}
		}
		catch (Exception e)
		{
			Quiet.Once("PassengerZoom: GameCamera_UpdateCamera_PassengerZoom.Prefix", e);
		}
	}

	private static void Finalizer(GameCamera __instance)
	{
		if (s_set)
		{
			s_set = false;
			if ((Object)(object)__instance != (Object)null)
			{
				__instance.m_maxDistance = s_saved;
			}
		}
	}
}
internal class RepairKey : MonoBehaviour
{
	internal sealed class Saved
	{
		internal PieceCategory Category;

		internal Vector2Int Index;

		internal Piece Piece;
	}

	internal const string RepairName = "$piece_repair";

	private static readonly Dictionary<PieceTable, Saved> s_saved = new Dictionary<PieceTable, Saved>();

	private static readonly FieldInfo F_buildPieces = AccessTools.Field(typeof(Player), "m_buildPieces");

	private static readonly MethodInfo M_setupGhost = AccessTools.Method(typeof(Player), "SetupPlacementGhost", (Type[])null, (Type[])null);

	internal static string LastMessage;

	private void Update()
	{
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			if (Features.RepairKeyShortcut != null && Features.On(Features.RepairKey))
			{
				Player localPlayer = Player.m_localPlayer;
				if (!((Object)(object)localPlayer == (Object)null) && GridState.Pressed(Features.RepairKeyShortcut.Value))
				{
					OnKey(localPlayer);
				}
			}
		}
		catch (Exception e)
		{
			Quiet.Once("RepairKey: key", e);
		}
	}

	internal static bool OnKey(Player p)
	{
		if ((Object)(object)p == (Object)null || !Features.On(Features.RepairKey) || Blocked(p))
		{
			return false;
		}
		return Toggle(p);
	}

	internal static bool Blocked(Player p)
	{
		if (((Character)p).IsDead() || ((Character)p).InCutscene() || ((Character)p).IsTeleporting())
		{
			return true;
		}
		if ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus())
		{
			return true;
		}
		if (Console.IsVisible() || TextInput.IsVisible() || Menu.IsVisible() || InventoryGui.IsVisible() || StoreGui.IsVisible())
		{
			return true;
		}
		if (Minimap.IsOpen() || Minimap.InTextInput())
		{
			return true;
		}
		if ((Object)(object)TextViewer.instance != (Object)null && TextViewer.instance.IsVisible())
		{
			return true;
		}
		if (PlayerCustomizaton.IsBarberGuiVisible() || GameCamera.InFreeFly())
		{
			return true;
		}
		if (Hud.IsPieceSelectionVisible() || Hud.InRadial())
		{
			return true;
		}
		if ((Object)(object)Hud.instance != (Object)null && (Object)(object)Hud.instance.m_buildUi != (Object)null && Hud.instance.m_buildUi.SearchFieldFocused)
		{
			return true;
		}
		return false;
	}

	internal static PieceTable Table(Player p)
	{
		if ((Object)(object)p == (Object)null || !((Character)p).InPlaceMode() || F_buildPieces == null)
		{
			return null;
		}
		object? value = F_buildPieces.GetValue(p);
		return (PieceTable)((value is PieceTable) ? value : null);
	}

	internal static bool IsRepair(Piece piece)
	{
		if ((Object)(object)piece != (Object)null)
		{
			if (!piece.m_repairPiece)
			{
				return piece.m_name == "$piece_repair";
			}
			return true;
		}
		return false;
	}

	internal static bool Toggle(Player p)
	{
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		//IL_008e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0095: 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_00b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
		PieceTable val = Table(p);
		if ((Object)(object)val == (Object)null)
		{
			return false;
		}
		Piece selectedPiece = val.GetSelectedPiece();
		Saved value;
		if (IsRepair(selectedPiece))
		{
			if (!s_saved.TryGetValue(val, out value) || value == null)
			{
				return false;
			}
			s_saved.Remove(val);
			Restore(p, val, value);
			Piece selectedPiece2 = val.GetSelectedPiece();
			Show(p, ((Object)(object)selectedPiece2 != (Object)null) ? Localize(selectedPiece2.m_name) : "?");
			return true;
		}
		if (!FindRepair(val, out var cat, out var idx))
		{
			return false;
		}
		value = new Saved();
		value.Category = val.GetSelectedCategory();
		value.Index = val.GetSelectedIndex();
		value.Piece = selectedPiece;
		s_saved[val] = value;
		Select(p, val, cat, idx);
		Show(p, "Repair");
		return IsRepair(val.GetSelectedPiece());
	}

	internal static bool FindRepair(PieceTable t, out PieceCategory cat, out Vector2Int idx)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: 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_0014: Expected I4, but got Unknown
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Expected I4, but got Unknown
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: 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: Expected I4, but got Unknown
		PieceCategory selectedCategory = t.GetSelectedCategory();
		if (FindIn(t, selectedCategory, out idx))
		{
			cat = (PieceCategory)(int)selectedCategory;
			return true;
		}
		if (t.m_categories != null)
		{
			foreach (PieceCategory category in t.m_categories)
			{
				if (category != selectedCategory && FindIn(t, category, out idx))
				{
					cat = (PieceCategory)(int)category;
					return true;
				}
			}
		}
		cat = (PieceCategory)(int)selectedCategory;
		idx = Vector2Int.zero;
		return false;
	}

	private static bool FindIn(PieceTable t, PieceCategory c, out Vector2Int idx)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: 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_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		int availablePiecesInCategory = t.GetAvailablePiecesInCategory(c);
		Vector2Int val = default(Vector2Int);
		for (int i = 0; i < availablePiecesInCategory; i++)
		{
			((Vector2Int)(ref val))..ctor(i % 15, i / 15);
			if (IsRepair(t.GetPiece(c, val)))
			{
				idx = val;
				return true;
			}
		}
		idx = Vector2Int.zero;
		return false;
	}

	internal static void Select(Player p, PieceTable t, PieceCategory cat, Vector2Int idx)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		if (t.GetSelectedCategory() != cat)
		{
			p.SetBuildCategory(cat);
		}
		if (t.GetSelectedIndex() != idx)
		{
			p.SetSelectedPiece(idx);
		}
		else if (M_setupGhost != null)
		{
			M_setupGhost.Invoke(p, null);
		}
	}

	private static void Restore(Player p, PieceTable t, Saved s)
	{
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)s.Piece != (Object)null && (Object)(object)t.GetPiece(s.Category, s.Index) != (Object)(object)s.Piece && p.SetSelectedPiece(s.Piece))
		{
			if (M_setupGhost != null)
			{
				M_setupGhost.Invoke(p, null);
			}
		}
		else
		{
			Select(p, t, s.Category, s.Index);
		}
	}

	internal static void Forget(PieceTable t)
	{
		if ((Object)(object)t != (Object