Decompiled source of StabilityView v0.1.0

plugins/StabilityView.dll

Decompiled 20 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("StabilityView")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Shows structure support values, where support comes from, and how changes affect it.")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0+086d7068c2fc7fe142ebc0b7381d609b64c96ac9")]
[assembly: AssemblyProduct("StabilityView")]
[assembly: AssemblyTitle("StabilityView")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace StabilityView
{
	internal sealed class Overlay : MonoBehaviour
	{
		private sealed class Entry
		{
			public WearNTear Piece;

			public Color Color;

			public string Text;

			public string Plain;
		}

		private const float RefreshInterval = 0.25f;

		private const float SourceMaxAge = 1f;

		private const int SourcesPerFrame = 25;

		private static readonly int EmissionColorId = Shader.PropertyToID("_EmissionColor");

		private static readonly Color IncreaseColor = new Color(0.35f, 1f, 0.4f);

		private static readonly Color DecreaseColor = new Color(1f, 0.3f, 0.25f);

		private static readonly Color NewColor = new Color(0.55f, 0.8f, 1f);

		private static readonly KeyCode[] ModifierKeys;

		private bool _enabled;

		private readonly List<Entry> _entries = new List<Entry>();

		private readonly Dictionary<WearNTear, SourceInfo> _sources = new Dictionary<WearNTear, SourceInfo>();

		private HashSet<GameObject> _highlighted = new HashSet<GameObject>();

		private HashSet<GameObject> _nextHighlighted = new HashSet<GameObject>();

		private float _nextRefresh;

		private int _sourceCursor;

		private int _hiddenByLimit;

		private int _hiddenByRadius;

		private GUIStyle _style;

		private GUIStyle _shadowStyle;

		private Material _lineMaterial;

		private bool _lineMaterialFailed;

		private bool _analysisErrorLogged;

		public static Overlay Instance { get; private set; }

		public bool IsShowing { get; private set; }

		private void Awake()
		{
			Instance = this;
		}

		private void OnDestroy()
		{
			Hide();
		}

		private void Update()
		{
			HandleKeys();
			if (!_enabled || !CanShow())
			{
				if (IsShowing)
				{
					Hide();
				}
				return;
			}
			IsShowing = true;
			if (Time.time >= _nextRefresh)
			{
				_nextRefresh = Time.time + 0.25f;
				Refresh();
			}
			if (Settings.ShowSourceLines.Value)
			{
				AnalyzeSources();
			}
		}

		private static bool CanShow()
		{
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)localPlayer) || !Object.op_Implicit((Object)(object)GameCamera.instance))
			{
				return false;
			}
			if (Settings.OnlyInBuildMode.Value)
			{
				return ((Character)localPlayer).InPlaceMode();
			}
			return true;
		}

		private void Hide()
		{
			IsShowing = false;
			_entries.Clear();
			_sources.Clear();
			_nextHighlighted.Clear();
			ApplyHighlightChanges();
		}

		private void HandleKeys()
		{
			if (!IsTyping())
			{
				if (Pressed(Settings.ToggleOverlay))
				{
					_enabled = !_enabled;
					Message((!_enabled) ? "Stability overlay off" : (Settings.OnlyInBuildMode.Value ? "Stability overlay on (shown while building)" : "Stability overlay on"));
				}
				if (Pressed(Settings.ToggleSourceLines))
				{
					Settings.ShowSourceLines.Value = !Settings.ShowSourceLines.Value;
					Message(Settings.ShowSourceLines.Value ? "Support source lines on" : "Support source lines off");
				}
				if (Pressed(Settings.ClearSnapshot))
				{
					Snapshot.Clear();
					Message("Stability snapshot cleared");
				}
				if (Pressed(Settings.TakeSnapshot))
				{
					Snapshot.Capture(manual: true);
					Message(Settings.AutoSnapshot.Value ? "Stability snapshot taken (automatic snapshots paused until cleared)" : "Stability snapshot taken");
				}
			}
		}

		private static bool IsTyping()
		{
			if (!Console.IsVisible() && !TextInput.IsVisible() && !Menu.IsVisible() && !InventoryGui.IsVisible() && !Minimap.InTextInput())
			{
				if (Object.op_Implicit((Object)(object)Chat.instance))
				{
					return Chat.instance.HasFocus();
				}
				return false;
			}
			return true;
		}

		private static bool Pressed(ConfigEntry<KeyboardShortcut> entry)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: 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)
			KeyboardShortcut value = entry.Value;
			if ((int)((KeyboardShortcut)(ref value)).MainKey == 0 || !ZInput.GetKeyDown(((KeyboardShortcut)(ref value)).MainKey, false))
			{
				return false;
			}
			List<KeyCode> modifiers = ((KeyboardShortcut)(ref value)).Modifiers.ToList();
			if (modifiers.Any((KeyCode key) => !ZInput.GetKey(key, false)))
			{
				return false;
			}
			return !ModifierKeys.Any((KeyCode key) => !modifiers.Contains(key) && ZInput.GetKey(key, false));
		}

		private static void Message(string text)
		{
			Player localPlayer = Player.m_localPlayer;
			if (localPlayer != null)
			{
				((Character)localPlayer).Message((MessageType)1, text, 0, (Sprite)null, false);
			}
		}

		private void Refresh()
		{
			//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_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_0257: Unknown result type (might be due to invalid IL or missing references)
			//IL_026a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Unknown result type (might be due to invalid IL or missing references)
			//IL_024b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			Camera camera = GameCamera.instance.m_camera;
			if (!Object.op_Implicit((Object)(object)camera))
			{
				return;
			}
			Vector3 position = ((Component)camera).transform.position;
			float num = Settings.Radius.Value * Settings.Radius.Value;
			int num2 = 0;
			List<KeyValuePair<float, WearNTear>> list = new List<KeyValuePair<float, WearNTear>>();
			foreach (WearNTear allInstance in WearNTear.GetAllInstances())
			{
				if (!Object.op_Implicit((Object)(object)allInstance) || !Stability.UsesSupport(allInstance))
				{
					continue;
				}
				Vector3 val = Stability.CenterOfMass(allInstance);
				if (IsOnScreen(camera, val))
				{
					Vector3 val2 = val - position;
					float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
					if (sqrMagnitude <= num)
					{
						list.Add(new KeyValuePair<float, WearNTear>(sqrMagnitude, allInstance));
					}
					else
					{
						num2++;
					}
				}
			}
			list.Sort((KeyValuePair<float, WearNTear> a, KeyValuePair<float, WearNTear> b) => a.Key.CompareTo(b.Key));
			int value = Settings.MaxPieces.Value;
			_hiddenByLimit = Math.Max(0, list.Count - value);
			_hiddenByRadius = num2;
			bool active = Snapshot.Active;
			_entries.Clear();
			_nextHighlighted.Clear();
			foreach (KeyValuePair<float, WearNTear> item in list.Take(value))
			{
				WearNTear value2 = item.Value;
				float num3 = Stability.Support(value2);
				MaterialInfo material = Stability.Material(value2);
				float num4 = 0f;
				bool flag = false;
				bool flag2 = false;
				if (active)
				{
					if (Snapshot.TryGet(value2, out var support))
					{
						num4 = num3 - support;
						flag = Mathf.Abs(num4) >= Settings.ChangeThreshold.Value;
					}
					else
					{
						flag2 = true;
					}
				}
				if (!Settings.HideFullySupported.Value || !Stability.IsAtMax(num3, material) || flag || flag2)
				{
					Entry entry = new Entry
					{
						Piece = value2,
						Color = Stability.ColorFor(num3, material)
					};
					BuildText(entry, value2, num3, material, flag ? new float?(num4) : ((float?)null), flag2);
					_entries.Add(entry);
					if (Settings.HighlightChanges.Value && (flag || flag2))
					{
						Color val3 = (flag2 ? NewColor : ((num4 > 0f) ? IncreaseColor : DecreaseColor));
						MaterialMan.instance.SetValue<Color>(((Component)value2).gameObject, EmissionColorId, val3 * 0.4f, false);
						_nextHighlighted.Add(((Component)value2).gameObject);
					}
				}
			}
			ApplyHighlightChanges();
			HashSet<WearNTear> visible = new HashSet<WearNTear>(_entries.Select((Entry e) => e.Piece));
			foreach (WearNTear item2 in _sources.Keys.Where((WearNTear k) => !Object.op_Implicit((Object)(object)k) || !visible.Contains(k)).ToList())
			{
				_sources.Remove(item2);
			}
		}

		private static bool IsOnScreen(Camera camera, Vector3 position)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: 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_003c: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = camera.WorldToViewportPoint(position);
			if (val.z > 0f && val.x >= -0.05f && val.x <= 1.05f && val.y >= -0.05f)
			{
				return val.y <= 1.05f;
			}
			return false;
		}

		private static void BuildText(Entry entry, WearNTear wnt, float support, MaterialInfo material, float? delta, bool isNew)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: 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_0110: Unknown result type (might be due to invalid IL or missing references)
			StringBuilder stringBuilder = new StringBuilder();
			if (Settings.ShowMaterial.Value)
			{
				stringBuilder.Append(wnt.m_materialType).Append(' ');
			}
			stringBuilder.Append(support.ToString("0.#"));
			if (Settings.ShowMaxSupport.Value)
			{
				stringBuilder.Append('/').Append(material.Max.ToString("0"));
			}
			if (Settings.ShowBreakThreshold.Value)
			{
				stringBuilder.Append(" (min ").Append(material.Min.ToString("0")).Append(')');
			}
			string text = null;
			Color color = Color.white;
			if (isNew)
			{
				text = "new";
				color = NewColor;
			}
			else if (delta.HasValue)
			{
				text = ((delta.Value > 0f) ? "+" : "") + delta.Value.ToString("0.#");
				color = ((delta.Value > 0f) ? IncreaseColor : DecreaseColor);
			}
			string text2 = stringBuilder.ToString();
			entry.Plain = ((text == null) ? text2 : (text2 + "\n" + text));
			entry.Text = Colored(text2, entry.Color) + ((text == null) ? "" : ("\n" + Colored(text, color)));
		}

		private static string Colored(string text, Color color)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			return "<color=#" + ColorUtility.ToHtmlStringRGB(color) + ">" + text + "</color>";
		}

		private void ApplyHighlightChanges()
		{
			foreach (GameObject item in _highlighted)
			{
				if (Object.op_Implicit((Object)(object)item) && !_nextHighlighted.Contains(item))
				{
					MaterialMan.instance.ResetValue(item, EmissionColorId);
				}
			}
			HashSet<GameObject> nextHighlighted = _nextHighlighted;
			HashSet<GameObject> highlighted = _highlighted;
			_highlighted = nextHighlighted;
			_nextHighlighted = highlighted;
			_nextHighlighted.Clear();
		}

		private void AnalyzeSources()
		{
			if (_entries.Count == 0)
			{
				return;
			}
			int num = Math.Min(25, _entries.Count);
			for (int i = 0; i < num; i++)
			{
				_sourceCursor = (_sourceCursor + 1) % _entries.Count;
				WearNTear piece = _entries[_sourceCursor].Piece;
				if (!Object.op_Implicit((Object)(object)piece) || (_sources.TryGetValue(piece, out var value) && Time.time - value.AnalyzedAt < 1f))
				{
					continue;
				}
				try
				{
					_sources[piece] = SupportAnalyzer.Analyze(piece);
				}
				catch (Exception arg)
				{
					if (!_analysisErrorLogged)
					{
						Debug.LogWarning((object)$"[StabilityView] Support source analysis failed: {arg}");
						_analysisErrorLogged = true;
					}
					_sources[piece] = new SourceInfo
					{
						Kind = SourceKind.None,
						AnalyzedAt = Time.time
					};
				}
			}
		}

		private void OnGUI()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Invalid comparison between Unknown and I4
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			if (!IsShowing || (int)Event.current.type != 7)
			{
				return;
			}
			Camera val = (Object.op_Implicit((Object)(object)GameCamera.instance) ? GameCamera.instance.m_camera : null);
			if (!Object.op_Implicit((Object)(object)val))
			{
				return;
			}
			EnsureStyles();
			if (Settings.ShowStatus.Value)
			{
				DrawStatus();
			}
			Rect val3 = default(Rect);
			foreach (Entry entry in _entries)
			{
				if (Object.op_Implicit((Object)(object)entry.Piece))
				{
					Vector3 val2 = val.WorldToScreenPoint(Stability.CenterOfMass(entry.Piece));
					if (!(val2.z <= 0f))
					{
						((Rect)(ref val3))..ctor(val2.x - 100f, (float)Screen.height - val2.y - 20f, 200f, 40f);
						GUI.Label(new Rect(((Rect)(ref val3)).x + 1f, ((Rect)(ref val3)).y + 1f, ((Rect)(ref val3)).width, ((Rect)(ref val3)).height), entry.Plain, _shadowStyle);
						GUI.Label(val3, entry.Text, _style);
					}
				}
			}
		}

		private void DrawStatus()
		{
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			StringBuilder stringBuilder = new StringBuilder("StabilityView: ").Append(_entries.Count).Append(" shown");
			if (_hiddenByLimit > 0)
			{
				stringBuilder.Append(" · ").Append(_hiddenByLimit).Append(" hidden by MaxPieces (")
					.Append(Settings.MaxPieces.Value)
					.Append(')');
			}
			if (_hiddenByRadius > 0)
			{
				stringBuilder.Append(" · ").Append(_hiddenByRadius).Append(" beyond ")
					.Append(Settings.Radius.Value.ToString("0"))
					.Append(" m");
			}
			if (Snapshot.Active)
			{
				stringBuilder.Append(Snapshot.IsManual ? $" · changes since manual snapshot ({Settings.ClearSnapshot.Value} clears)" : " · showing changes");
			}
			string text = stringBuilder.ToString();
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(0f, 44f, (float)Screen.width, 24f);
			GUI.Label(new Rect(((Rect)(ref val)).x + 1f, ((Rect)(ref val)).y + 1f, ((Rect)(ref val)).width, ((Rect)(ref val)).height), text, _shadowStyle);
			GUI.Label(val, text, _style);
		}

		private void EnsureStyles()
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Expected O, but got Unknown
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			int value = Settings.FontSize.Value;
			if (_style == null || _style.fontSize != value)
			{
				_style = new GUIStyle(GUI.skin.label)
				{
					alignment = (TextAnchor)4,
					richText = true,
					fontSize = value,
					fontStyle = (FontStyle)1
				};
				_style.normal.textColor = Color.white;
				_shadowStyle = new GUIStyle(_style)
				{
					richText = false
				};
				_shadowStyle.normal.textColor = new Color(0f, 0f, 0f, 0.85f);
			}
		}

		private void OnRenderObject()
		{
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: 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)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			if (!IsShowing || !Settings.ShowSourceLines.Value || _sources.Count == 0)
			{
				return;
			}
			Camera val = (Object.op_Implicit((Object)(object)GameCamera.instance) ? GameCamera.instance.m_camera : null);
			if (!Object.op_Implicit((Object)(object)val) || (Object)(object)Camera.current != (Object)(object)val || !EnsureLineMaterial())
			{
				return;
			}
			_lineMaterial.SetInt("_ZTest", Settings.LinesThroughWalls.Value ? 8 : 4);
			_lineMaterial.SetPass(0);
			GL.PushMatrix();
			GL.Begin(1);
			foreach (Entry entry in _entries)
			{
				if (Object.op_Implicit((Object)(object)entry.Piece) && _sources.TryGetValue(entry.Piece, out var value))
				{
					Vector3 val2 = Stability.CenterOfMass(entry.Piece);
					if (Object.op_Implicit((Object)(object)value.A))
					{
						Line(val2, Stability.CenterOfMass(value.A), entry.Color);
					}
					if (Object.op_Implicit((Object)(object)value.B))
					{
						Line(val2, Stability.CenterOfMass(value.B), entry.Color);
					}
				}
			}
			GL.End();
			GL.PopMatrix();
		}

		private static void Line(Vector3 from, Vector3 to, Color color)
		{
			//IL_0000: 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_000c: 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_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			GL.Color(color);
			GL.Vertex(from);
			GL.Color(new Color(color.r, color.g, color.b, 0.25f));
			GL.Vertex(to);
		}

		private bool EnsureLineMaterial()
		{
			//IL_0041: 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_0053: Expected O, but got Unknown
			if (Object.op_Implicit((Object)(object)_lineMaterial))
			{
				return true;
			}
			if (_lineMaterialFailed)
			{
				return false;
			}
			Shader val = Shader.Find("Hidden/Internal-Colored");
			if (!Object.op_Implicit((Object)(object)val))
			{
				Debug.LogWarning((object)"[StabilityView] Line shader not found; support source lines are disabled");
				_lineMaterialFailed = true;
				return false;
			}
			_lineMaterial = new Material(val)
			{
				hideFlags = (HideFlags)61
			};
			_lineMaterial.SetInt("_SrcBlend", 5);
			_lineMaterial.SetInt("_DstBlend", 10);
			_lineMaterial.SetInt("_Cull", 0);
			_lineMaterial.SetInt("_ZWrite", 0);
			return true;
		}

		static Overlay()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_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)
			KeyCode[] array = new KeyCode[6];
			RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
			ModifierKeys = (KeyCode[])(object)array;
		}
	}
	[HarmonyPatch]
	internal static class AutoSnapshotPatches
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(Player), "PlacePiece")]
		private static void BeforePlace(Player __instance)
		{
			Capture(__instance);
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Player), "RemovePiece")]
		private static void BeforeRemove(Player __instance)
		{
			Capture(__instance);
		}

		private static void Capture(Player player)
		{
			if ((Object)(object)player == (Object)(object)Player.m_localPlayer && Settings.AutoSnapshot.Value && !Snapshot.IsManual && Object.op_Implicit((Object)(object)Overlay.Instance) && Overlay.Instance.IsShowing)
			{
				Snapshot.Capture(manual: false);
			}
		}
	}
	[BepInPlugin("s992.StabilityView", "StabilityView", "0.1.0")]
	public class Plugin : BaseUnityPlugin
	{
		private void Awake()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			Settings.Bind(((BaseUnityPlugin)this).Config);
			new Harmony("s992.StabilityView").PatchAll();
			((Component)this).gameObject.AddComponent<Overlay>();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"StabilityView 0.1.0 loaded");
		}
	}
	internal static class Settings
	{
		public static ConfigEntry<KeyboardShortcut> ToggleOverlay;

		public static ConfigEntry<KeyboardShortcut> ToggleSourceLines;

		public static ConfigEntry<KeyboardShortcut> TakeSnapshot;

		public static ConfigEntry<KeyboardShortcut> ClearSnapshot;

		public static ConfigEntry<bool> OnlyInBuildMode;

		public static ConfigEntry<float> Radius;

		public static ConfigEntry<int> MaxPieces;

		public static ConfigEntry<bool> ShowStatus;

		public static ConfigEntry<int> FontSize;

		public static ConfigEntry<bool> ShowMaterial;

		public static ConfigEntry<bool> ShowMaxSupport;

		public static ConfigEntry<bool> ShowBreakThreshold;

		public static ConfigEntry<bool> HideFullySupported;

		public static ConfigEntry<bool> ShowSourceLines;

		public static ConfigEntry<bool> LinesThroughWalls;

		public static ConfigEntry<bool> AutoSnapshot;

		public static ConfigEntry<bool> HighlightChanges;

		public static ConfigEntry<float> ChangeThreshold;

		public static ConfigEntry<float> ChangeDuration;

		public static void Bind(ConfigFile config)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: 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)
			//IL_00fb: Expected O, but got Unknown
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Expected O, but got Unknown
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Expected O, but got Unknown
			//IL_027e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Expected O, but got Unknown
			//IL_02b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c0: Expected O, but got Unknown
			ToggleOverlay = config.Bind<KeyboardShortcut>("Keys", "ToggleOverlay", new KeyboardShortcut((KeyCode)288, Array.Empty<KeyCode>()), "Show or hide the stability overlay.");
			ToggleSourceLines = config.Bind<KeyboardShortcut>("Keys", "ToggleSourceLines", new KeyboardShortcut((KeyCode)290, Array.Empty<KeyCode>()), "Show or hide the lines to where each piece gets its support.");
			TakeSnapshot = config.Bind<KeyboardShortcut>("Keys", "TakeSnapshot", new KeyboardShortcut((KeyCode)289, Array.Empty<KeyCode>()), "Record current support values; changes are then shown relative to them, and automatic snapshots pause until it's cleared.");
			ClearSnapshot = config.Bind<KeyboardShortcut>("Keys", "ClearSnapshot", new KeyboardShortcut((KeyCode)289, (KeyCode[])(object)new KeyCode[1] { (KeyCode)304 }), "Forget the snapshot and stop showing changes (resumes automatic snapshots).");
			OnlyInBuildMode = config.Bind<bool>("Display", "OnlyInBuildMode", true, "Only show the overlay while a building tool (hammer, hoe, ...) is equipped.");
			Radius = config.Bind<float>("Display", "Radius", 30f, new ConfigDescription("Show on-screen pieces within this many metres of the camera.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 150f), Array.Empty<object>()));
			MaxPieces = config.Bind<int>("Display", "MaxPieces", 200, new ConfigDescription("Show at most this many on-screen pieces (closest to the camera first).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000), Array.Empty<object>()));
			ShowStatus = config.Bind<bool>("Display", "ShowStatus", true, "Show a status line with how many pieces are labelled and how many were left out.");
			FontSize = config.Bind<int>("Display", "FontSize", 13, new ConfigDescription("Label font size.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(8, 32), Array.Empty<object>()));
			ShowMaterial = config.Bind<bool>("Display", "ShowMaterial", false, "Prefix labels with the piece's material (Wood, Stone, ...).");
			ShowMaxSupport = config.Bind<bool>("Display", "ShowMaxSupport", true, "Show support as current/max instead of just current.");
			ShowBreakThreshold = config.Bind<bool>("Display", "ShowBreakThreshold", false, "Show the support value below which the piece collapses.");
			HideFullySupported = config.Bind<bool>("Display", "HideFullySupported", false, "Skip labels for pieces at their material's maximum (grounded pieces).");
			ShowSourceLines = config.Bind<bool>("Support sources", "ShowSourceLines", true, "Draw a line from each piece to the piece(s) it gets its support from.");
			LinesThroughWalls = config.Bind<bool>("Support sources", "LinesThroughWalls", true, "Draw source lines on top of everything instead of hiding them behind geometry.");
			AutoSnapshot = config.Bind<bool>("Changes", "AutoSnapshot", true, "Take a snapshot automatically just before you place or remove a piece, so each change shows its effect.");
			HighlightChanges = config.Bind<bool>("Changes", "HighlightChanges", true, "Tint pieces whose support changed since the snapshot (green = up, red = down).");
			ChangeThreshold = config.Bind<float>("Changes", "ChangeThreshold", 0.5f, new ConfigDescription("Ignore changes smaller than this.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
			ChangeDuration = config.Bind<float>("Changes", "ChangeDuration", 0f, new ConfigDescription("Stop showing changes this many seconds after the snapshot. 0 = until the next snapshot.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 600f), Array.Empty<object>()));
		}
	}
	internal static class Snapshot
	{
		private static Dictionary<ZDOID, float> s_values;

		private static float s_takenAt;

		public static bool Active
		{
			get
			{
				if (s_values != null)
				{
					if (!(Settings.ChangeDuration.Value <= 0f))
					{
						return Time.time - s_takenAt <= Settings.ChangeDuration.Value;
					}
					return true;
				}
				return false;
			}
		}

		public static bool IsManual { get; private set; }

		public static void Capture(bool manual)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			s_values = new Dictionary<ZDOID, float>();
			foreach (WearNTear allInstance in WearNTear.GetAllInstances())
			{
				if (Stability.UsesSupport(allInstance))
				{
					s_values[allInstance.m_nview.GetZDO().m_uid] = Stability.Support(allInstance);
				}
			}
			s_takenAt = Time.time;
			IsManual = manual;
		}

		public static void Clear()
		{
			s_values = null;
			IsManual = false;
		}

		public static bool TryGet(WearNTear wnt, out float support)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			support = 0f;
			if (s_values != null)
			{
				return s_values.TryGetValue(wnt.m_nview.GetZDO().m_uid, out support);
			}
			return false;
		}
	}
	internal struct MaterialInfo
	{
		public float Max;

		public float Min;

		public float HorizontalLoss;

		public float VerticalLoss;
	}
	internal static class Stability
	{
		public static readonly Color MaxColor = new Color(0.6f, 0.8f, 1f);

		public static bool UsesSupport(WearNTear wnt)
		{
			if (wnt.m_noSupportWear && (Object)(object)wnt.m_nview != (Object)null)
			{
				return wnt.m_nview.IsValid();
			}
			return false;
		}

		public static float Support(WearNTear wnt)
		{
			return wnt.GetSupport();
		}

		public static MaterialInfo Material(WearNTear wnt)
		{
			float max = default(float);
			float min = default(float);
			float horizontalLoss = default(float);
			float verticalLoss = default(float);
			wnt.GetMaterialProperties(ref max, ref min, ref horizontalLoss, ref verticalLoss);
			return new MaterialInfo
			{
				Max = max,
				Min = min,
				HorizontalLoss = horizontalLoss,
				VerticalLoss = verticalLoss
			};
		}

		public static Vector3 CenterOfMass(WearNTear wnt)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return wnt.GetCOM();
		}

		public static float Ratio(float support, MaterialInfo material)
		{
			if (!(material.Max <= material.Min))
			{
				return Mathf.Clamp01((support - material.Min) / (material.Max - material.Min));
			}
			return 1f;
		}

		public static bool IsAtMax(float support, MaterialInfo material)
		{
			return support >= material.Max;
		}

		public static Color ColorFor(float support, MaterialInfo material)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			if (IsAtMax(support, material))
			{
				return MaxColor;
			}
			float num = Ratio(support, material);
			if (!(num < 0.5f))
			{
				return Color.Lerp(new Color(1f, 0.9f, 0.2f), new Color(0.3f, 1f, 0.35f), (num - 0.5f) * 2f);
			}
			return Color.Lerp(new Color(1f, 0.25f, 0.2f), new Color(1f, 0.9f, 0.2f), num * 2f);
		}
	}
	internal enum SourceKind
	{
		Terrain,
		StaticObject,
		Piece,
		Braced,
		None
	}
	internal sealed class SourceInfo
	{
		public SourceKind Kind;

		public WearNTear A;

		public WearNTear B;

		public float Value;

		public float AnalyzedAt;
	}
	internal static class SupportAnalyzer
	{
		private struct SupportPoint
		{
			public Vector3 Point;

			public float Value;

			public WearNTear Piece;
		}

		private static readonly Collider[] Overlaps = (Collider[])(object)new Collider[128];

		private static readonly List<SupportPoint> Points = new List<SupportPoint>();

		public static SourceInfo Analyze(WearNTear wnt)
		{
			//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_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: 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_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: 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: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02de: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: 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_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0334: Unknown result type (might be due to invalid IL or missing references)
			//IL_0339: Unknown result type (might be due to invalid IL or missing references)
			//IL_033a: Unknown result type (might be due to invalid IL or missing references)
			//IL_033f: Unknown result type (might be due to invalid IL or missing references)
			//IL_034d: Unknown result type (might be due to invalid IL or missing references)
			//IL_034f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			SourceInfo sourceInfo = new SourceInfo
			{
				Kind = SourceKind.None,
				AnalyzedAt = Time.time
			};
			if (wnt.m_colliders == null)
			{
				wnt.SetupColliders();
			}
			MaterialInfo materialInfo = Stability.Material(wnt);
			Vector3 cOM = wnt.GetCOM();
			bool flag = false;
			float best = 0f;
			WearNTear bestPiece = null;
			Points.Clear();
			foreach (BoundData bound in wnt.m_bounds)
			{
				int num = Physics.OverlapBoxNonAlloc(bound.m_pos, bound.m_size, Overlaps, bound.m_rot, WearNTear.s_rayMask);
				for (int i = 0; i < num; i++)
				{
					Collider val = Overlaps[i];
					if ((Object)(object)val.attachedRigidbody != (Object)null || val.isTrigger || wnt.m_colliders.Contains(val))
					{
						continue;
					}
					if (((Component)val).gameObject.layer == WearNTear.s_terrainLayer)
					{
						flag = true;
						continue;
					}
					WearNTear componentInParent = ((Component)val).GetComponentInParent<WearNTear>();
					if ((Object)(object)componentInParent == (Object)null)
					{
						sourceInfo.Kind = SourceKind.StaticObject;
						sourceInfo.Value = materialInfo.Max;
						return sourceInfo;
					}
					if (!componentInParent.m_supports)
					{
						continue;
					}
					float num2 = Vector3.Distance(cOM, componentInParent.GetCOM()) + 0.1f;
					float num3 = Vector3.Distance(cOM, ((Component)componentInParent).transform.position) + 0.1f;
					if (num3 < num2 && !wnt.m_forceCorrectCOMCalculation)
					{
						num2 = num3;
					}
					float support = componentInParent.GetSupport();
					Consider(support - materialInfo.HorizontalLoss * num2 * support, componentInParent, ref best, ref bestPiece);
					Vector3 val2 = WearNTear.FindSupportPoint(cOM, componentInParent, val);
					if (val2.y < cOM.y + 0.05f)
					{
						Vector3 val3 = val2 - cOM;
						Vector3 normalized = ((Vector3)(ref val3)).normalized;
						if (normalized.y < 0f)
						{
							float num4 = Mathf.Acos(1f - Mathf.Abs(normalized.y)) / (MathF.PI / 2f);
							float num5 = Mathf.Lerp(materialInfo.HorizontalLoss, materialInfo.VerticalLoss, num4);
							Consider(support - num5 * num2 * support, componentInParent, ref best, ref bestPiece);
						}
						Points.Add(new SupportPoint
						{
							Point = val2,
							Value = support - materialInfo.VerticalLoss * num2 * support,
							Piece = componentInParent
						});
					}
				}
			}
			if (flag)
			{
				sourceInfo.Kind = SourceKind.Terrain;
				sourceInfo.Value = materialInfo.Max;
				return sourceInfo;
			}
			if ((Object)(object)bestPiece != (Object)null)
			{
				sourceInfo.Kind = SourceKind.Piece;
				sourceInfo.A = bestPiece;
			}
			for (int j = 0; j < Points.Count - 1; j++)
			{
				Vector3 val4 = Points[j].Point - cOM;
				val4.y = 0f;
				for (int k = j + 1; k < Points.Count; k++)
				{
					float num6 = (Points[j].Value + Points[k].Value) * 0.5f;
					if (!(num6 <= best))
					{
						Vector3 val5 = Points[k].Point - cOM;
						val5.y = 0f;
						if (Vector3.Angle(val4, val5) >= 100f)
						{
							best = num6;
							sourceInfo.Kind = SourceKind.Braced;
							sourceInfo.A = Points[j].Piece;
							sourceInfo.B = Points[k].Piece;
						}
					}
				}
			}
			sourceInfo.Value = Mathf.Min(best, materialInfo.Max);
			return sourceInfo;
		}

		private static void Consider(float value, WearNTear piece, ref float best, ref WearNTear bestPiece)
		{
			if (value > best)
			{
				best = value;
				bestPiece = piece;
			}
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "s992.StabilityView";

		public const string PLUGIN_NAME = "StabilityView";

		public const string PLUGIN_VERSION = "0.1.0";
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}