Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of StabilityView v0.1.0
plugins/StabilityView.dll
Decompiled 20 hours agousing 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) { } } }