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 Instant Collapses v1.0.3
plugins\FasterCollapsesMod.dll
Decompiled 2 months agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Logging; using HarmonyLib; using PettersDevTools; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("FasterCollapsesMod")] [assembly: AssemblyDescription("Valheim faster collapses")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("FasterCollapsesMod")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("e3b4c5d6-a7f8-1029-bcda-fe4567890123")] [assembly: AssemblyFileVersion("1.0.3")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.3.0")] namespace FasterCollapsesMod { [BepInPlugin("se.petterhansson.fastercollapsesmod", "FasterCollapsesMod", "1.0.3")] internal class FasterCollapsesMod : BaseUnityPlugin { public const string PluginGUID = "se.petterhansson.fastercollapsesmod"; public const string PluginName = "FasterCollapsesMod"; public const string PluginVersion = "1.0.3"; private Harmony _harmony; public void Awake() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown ((BaseUnityPlugin)this).Logger.LogInfo((object)"Plugin se.petterhansson.fastercollapsesmod is loaded!"); ((Component)this).gameObject.AddComponent<StructuralGraph>(); _harmony = new Harmony("se.petterhansson.fastercollapsesmod"); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Patching methods..."); _harmony.PatchAll(Assembly.GetExecutingAssembly()); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Patches applied successfully"); } public void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } public class StructuralGraph : MonoBehaviour { private readonly Dictionary<WearNTear, HashSet<WearNTear>> _adjacency = new Dictionary<WearNTear, HashSet<WearNTear>>(); private readonly HashSet<WearNTear> _groundedPieces = new HashSet<WearNTear>(); private readonly HashSet<WearNTear> _fullyRegistered = new HashSet<WearNTear>(); private int _terrainLayer; private int _rayMask; private Collider[] _tempColliders = (Collider[])(object)new Collider[128]; public static StructuralGraph Instance { get; private set; } public void Awake() { Instance = this; _terrainLayer = LayerMask.NameToLayer("terrain"); _rayMask = LayerMask.GetMask(new string[5] { "piece", "Default", "static_solid", "Default_small", "terrain" }); RebuildGraph(); } public void OnDestroy() { if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } public void RebuildGraph() { _adjacency.Clear(); _groundedPieces.Clear(); _fullyRegistered.Clear(); List<WearNTear> allInstances = WearNTear.GetAllInstances(); if (allInstances == null) { return; } foreach (WearNTear item in allInstances) { if ((Object)(object)item != (Object)null && ((Component)item).gameObject.activeInHierarchy) { Register(item); } } } public void RegisterDelayed(WearNTear wnt) { if (((Component)this).gameObject.activeInHierarchy) { ((MonoBehaviour)this).StartCoroutine(RegisterCoroutine(wnt)); } } private IEnumerator RegisterCoroutine(WearNTear wnt) { yield return null; Register(wnt); } public void Register(WearNTear wnt) { if ((Object)(object)wnt == (Object)null || _fullyRegistered.Contains(wnt)) { return; } _fullyRegistered.Add(wnt); if (!_adjacency.ContainsKey(wnt)) { _adjacency[wnt] = new HashSet<WearNTear>(); } bool isGrounded = false; Collider[] componentsInChildren = ((Component)wnt).GetComponentsInChildren<Collider>(true); foreach (Collider val in componentsInChildren) { if (!val.isTrigger && !((Object)(object)val.attachedRigidbody != (Object)null)) { FindGroundedNeighborsGivenPieceCollider(wnt, val, ref isGrounded); } } if (isGrounded) { _groundedPieces.Add(wnt); } } private (Vector3 pos, Quaternion rot, Vector3 size) GetColliderBounds(Collider col) { //IL_009e: 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_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: 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) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: 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) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: 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_004d: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0069: 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_0085: 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_0096: Unknown result type (might be due to invalid IL or missing references) BoxCollider val = (BoxCollider)(object)((col is BoxCollider) ? col : null); if (val != null) { Quaternion rotation = ((Component)val).transform.rotation; Vector3 item = ((Component)val).transform.position + ((Component)val).transform.TransformVector(val.center); Vector3 item2 = default(Vector3); ((Vector3)(ref item2))..ctor(((Component)val).transform.lossyScale.x * val.size.x, ((Component)val).transform.lossyScale.y * val.size.y, ((Component)val).transform.lossyScale.z * val.size.z); return (pos: item, rot: rotation, size: item2); } Bounds bounds = col.bounds; Vector3 center = ((Bounds)(ref bounds)).center; Quaternion identity = Quaternion.identity; bounds = col.bounds; return (pos: center, rot: identity, size: ((Bounds)(ref bounds)).size); } private Vector3 GetInflatedBoundsForGroundingCheck(Vector3 size) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) size.x += 0.3f; size.y += 0.3f; size.z += 0.3f; size *= 0.5f; return size; } private void FindGroundedNeighborsGivenPieceCollider(WearNTear wnt, Collider collider, ref bool isGrounded) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: 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_0014: 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_001a: 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_0022: 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_0024: 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) (Vector3 pos, Quaternion rot, Vector3 size) colliderBounds = GetColliderBounds(collider); Vector3 item = colliderBounds.pos; Quaternion item2 = colliderBounds.rot; Vector3 item3 = colliderBounds.size; item3 = GetInflatedBoundsForGroundingCheck(item3); int num = Physics.OverlapBoxNonAlloc(item, item3, _tempColliders, item2, _rayMask); for (int i = 0; i < num; i++) { Collider val = _tempColliders[i]; if ((Object)(object)val.attachedRigidbody != (Object)null || val.isTrigger || ((Component)val).transform.IsChildOf(((Component)wnt).transform)) { continue; } if (((Component)val).gameObject.layer == _terrainLayer) { isGrounded = true; continue; } WearNTear componentInParent = ((Component)val).GetComponentInParent<WearNTear>(); if ((Object)(object)componentInParent == (Object)null) { isGrounded = true; } else if (componentInParent.m_supports) { AddAdjacency(wnt, componentInParent); } } } private void AddAdjacency(WearNTear wnt, WearNTear neighborWnt) { _adjacency[wnt].Add(neighborWnt); if (!_adjacency.TryGetValue(neighborWnt, out var value)) { value = new HashSet<WearNTear>(); _adjacency[neighborWnt] = value; } value.Add(wnt); } public void Unregister(WearNTear wnt) { if ((Object)(object)wnt == (Object)null) { return; } _fullyRegistered.Remove(wnt); if (!_adjacency.TryGetValue(wnt, out var value)) { return; } foreach (WearNTear item in value) { if (_adjacency.TryGetValue(item, out var value2)) { value2.Remove(wnt); } } _adjacency.Remove(wnt); _groundedPieces.Remove(wnt); } private static bool IsPositionNearUnloadedZone(Vector3 pos) { //IL_000f: 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_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0026: 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_0040: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ZoneSystem.instance == (Object)null) { return false; } Vector2s zone = ZoneSystem.GetZone(pos); Vector2s testZone = default(Vector2s); for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { if (i != 0 || j != 0) { ((Vector2s)(ref testZone))..ctor(zone.x + i, zone.y + j); if (!ZoneSystem.instance.IsZoneLoaded(testZone) && IsPositionInExpandedZone(ref pos, ref testZone)) { return true; } } } } return false; } private static bool IsPositionInExpandedZone(ref Vector3 pos, ref Vector2s testZone) { //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_000b: 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_0026: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) Vector3 zonePos = ZoneSystem.GetZonePos(testZone); if (pos.x >= zonePos.x - 42f && pos.x <= zonePos.x + 42f && pos.z >= zonePos.z - 42f) { return pos.z <= zonePos.z + 42f; } return false; } public void OnPieceDestroyed(WearNTear destroyedPiece) { List<WearNTear> list = new List<WearNTear>(); if ((Object)(object)destroyedPiece == (Object)null || !_adjacency.TryGetValue(destroyedPiece, out var value)) { return; } List<WearNTear> list2 = new List<WearNTear>(value); Unregister(destroyedPiece); HashSet<WearNTear> hashSet = new HashSet<WearNTear>(); Queue<WearNTear> queue = new Queue<WearNTear>(); foreach (WearNTear item in list2) { if (!hashSet.Contains(item)) { bool foundGround; HashSet<WearNTear> collection = VisitConnectedComponent(item, out foundGround, queue, hashSet); if (!foundGround) { list.AddRange(collection); } } } if (list.Count == 0) { return; } foreach (WearNTear item2 in list) { if (!((Object)(object)item2 == (Object)null)) { Unregister(item2); ZNetView component = ((Component)item2).GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid() && component.IsOwner()) { item2.Remove(false); } } } } private HashSet<WearNTear> VisitConnectedComponent(WearNTear start, out bool foundGround, Queue<WearNTear> queue, HashSet<WearNTear> visitedGlobal) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) HashSet<WearNTear> hashSet = new HashSet<WearNTear>(); foundGround = false; queue.Clear(); queue.Enqueue(start); hashSet.Add(start); visitedGlobal.Add(start); while (queue.Count > 0) { WearNTear val = queue.Dequeue(); if (_groundedPieces.Contains(val)) { foundGround = true; break; } if (IsPositionNearUnloadedZone(((Component)val).transform.position)) { foundGround = true; break; } if (!_adjacency.TryGetValue(val, out var value)) { continue; } foreach (WearNTear item in value) { if (!visitedGlobal.Contains(item)) { visitedGlobal.Add(item); hashSet.Add(item); queue.Enqueue(item); } } } return hashSet; } [Conditional("DEBUG")] private void DebugMarkDestruction(IEnumerable<WearNTear> pieces) { } } internal static class ModVersion { public const string Version = "1.0.3"; } } namespace FasterCollapsesMod.Patches { [HarmonyPatch(typeof(WearNTear))] public static class StructuralGraphPatches { [HarmonyPatch("Awake")] [HarmonyPostfix] public static void Awake_Postfix(WearNTear __instance) { using (new TimingScope(typeof(StructuralGraphPatches), "Awake_Postfix")) { if ((Object)(object)StructuralGraph.Instance != (Object)null) { StructuralGraph.Instance.RegisterDelayed(__instance); } } } [HarmonyPatch("Destroy")] [HarmonyPrefix] public static void Destroy_Prefix(WearNTear __instance) { using (new TimingScope(typeof(StructuralGraphPatches), "Destroy_Prefix")) { if ((Object)(object)StructuralGraph.Instance != (Object)null) { StructuralGraph.Instance.OnPieceDestroyed(__instance); } } } [HarmonyPatch("OnDestroy")] [HarmonyPrefix] public static void OnDestroy_Prefix(WearNTear __instance) { using (new TimingScope(typeof(StructuralGraphPatches), "OnDestroy_Prefix")) { if ((Object)(object)StructuralGraph.Instance != (Object)null) { StructuralGraph.Instance.Unregister(__instance); } } } } } namespace PettersDevTools { internal class DebugLine { private static Dictionary<string, DebugLine> s_activeLines = new Dictionary<string, DebugLine>(); private LineRenderer m_line; private Transform m_hostTransform; private Transform m_targetTransform; private Vector3 m_targetPosition; private bool m_useTransformTarget; private Vector3 m_startOffset = Vector3.up; private Vector3 m_endOffset = Vector3.up; public Transform TargetTransform => m_targetTransform; private DebugLine(LineRenderer line, Transform host) { //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_000c: 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) m_line = line; m_hostTransform = host; } public static DebugLine GetOrCreate(GameObject host, string name, Color color) { return null; } public void SetTarget(Transform target, Vector3 startOffset, Vector3 endOffset) { } public void SetTarget(Vector3 staticTarget, Vector3 startOffset, Vector3 endOffset) { } public void Hide() { } public void UpdateLine() { } public static void UpdateAllFor(GameObject host) { } public static void ClearAllFor(GameObject host) { } } internal static class Log { public static ManualLogSource Handle { get; set; } public static void Info(params object[] args) { if (Handle == null) { Debug.LogError((object)"[PettersDevTools] Cannot log because Log.Handle is null!"); } else { Handle.LogInfo((object)string.Join(" ", args)); } } } [HarmonyPatch(typeof(MonsterAI), "UpdateAI")] internal static class DebugLineUpdaterPatch { public static void Postfix(MonsterAI __instance) { } } internal static class StatsManager { private static readonly Dictionary<string, object> _stats = new Dictionary<string, object>(); [Conditional("DEBUG")] public static void SetStat(string key, object value) { _stats[key] = value; } [Conditional("DEBUG")] public static void IncrementStat(string key, int amount = 1) { if (_stats.TryGetValue(key, out var value) && value is int num) { _stats[key] = num + amount; } else { _stats[key] = amount; } } public static void Clear() { _stats.Clear(); } public static IEnumerable<KeyValuePair<string, object>> GetStats() { return _stats; } } internal interface ITimingRegistry { void SubmitTime(Type theclass, string method, long stopwatchTicks); void Clear(); } internal class TimingManager : MonoBehaviour, ITimingRegistry { private struct TimingInfo { public long TotalTicks; public long LongestCall; public int Calls; public long AverageCall => TotalTicks / Mathf.Max(1, Calls); } private enum WindowState { Closed, Profiler, Stats } private static readonly double _conversionFactor = 1.0 / (double)Stopwatch.Frequency; private Dictionary<(Type, string), TimingInfo> _timings; private List<((Type, string), TimingInfo)> _worklist; private WindowState _windowState; public static ITimingRegistry Instance { get; private set; } private void Awake() { _timings = new Dictionary<(Type, string), TimingInfo>(); _worklist = new List<((Type, string), TimingInfo)>(); _windowState = WindowState.Closed; Instance = this; } private static double GetTime(long ticks) { return _conversionFactor * (double)ticks; } public void Clear() { _timings?.Clear(); } public void SubmitTime(Type theclass, string method, long stopwatchTicks) { (Type, string) key = (theclass, method); if (!_timings.TryGetValue(key, out var value)) { value = default(TimingInfo); } value.TotalTicks += stopwatchTicks; value.LongestCall = Math.Max(value.LongestCall, stopwatchTicks); value.Calls++; _timings[key] = value; } private IEnumerable<string> GetTopCallStrings(int maxCount = 10) { List<((Type, string), TimingInfo)> worklist = _worklist; worklist.Clear(); foreach (KeyValuePair<(Type, string), TimingInfo> timing in _timings) { worklist.Add((timing.Key, timing.Value)); } worklist.Sort((((Type, string), TimingInfo) a, ((Type, string), TimingInfo) b) => b.Item2.LongestCall.CompareTo(a.Item2.LongestCall)); int count = 0; foreach (var item5 in worklist) { (Type, string) item = item5.Item1; Type item2 = item.Item1; string item3 = item.Item2; TimingInfo item4 = item5.Item2; yield return item2.Name + "." + item3 + ": " + (1000.0 * GetTime(item4.LongestCall)).ToString("F1") + " ms"; int num = count + 1; count = num; if (num >= maxCount) { break; } } } private void CopyToClipboard() { StringBuilder stringBuilder = new StringBuilder(); if (_windowState == WindowState.Profiler) { stringBuilder.AppendLine("Longest calls:"); foreach (string topCallString in GetTopCallStrings()) { stringBuilder.AppendLine(topCallString); } } else if (_windowState == WindowState.Stats) { stringBuilder.AppendLine("Stats:"); List<KeyValuePair<string, object>> list = new List<KeyValuePair<string, object>>(StatsManager.GetStats()); list.Sort((KeyValuePair<string, object> a, KeyValuePair<string, object> b) => string.Compare(a.Key, b.Key, StringComparison.OrdinalIgnoreCase)); foreach (KeyValuePair<string, object> item in list) { stringBuilder.AppendLine($"{item.Key}: {item.Value}"); } } GUIUtility.systemCopyBuffer = stringBuilder.ToString(); } private void Update() { if (Input.GetKeyDown((KeyCode)290) && !Console.IsVisible()) { _windowState = (WindowState)((int)(_windowState + 1) % 3); } if (Input.GetKeyDown((KeyCode)291) && !Console.IsVisible()) { CopyToClipboard(); } if (Input.GetKeyDown((KeyCode)293) && !Console.IsVisible()) { Clear(); StatsManager.Clear(); } } private void OnGUI() { //IL_0024: 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_0035: Invalid comparison between Unknown and I4 //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Invalid comparison between Unknown and I4 //IL_006c: Unknown result type (might be due to invalid IL or missing references) if (_windowState == WindowState.Closed) { return; } Rect val = default(Rect); ((Rect)(ref val))..ctor(200f, 200f, 500f, 400f); GUILayout.BeginArea(val); if ((int)Event.current.type == 8 || (int)Event.current.type == 7) { GUILayout.Button("", (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true) }); } GUILayout.EndArea(); GUILayout.BeginArea(val); GUILayout.BeginVertical(Array.Empty<GUILayoutOption>()); if (_windowState == WindowState.Profiler) { GUILayout.Label("Longest calls:", Array.Empty<GUILayoutOption>()); foreach (string topCallString in GetTopCallStrings()) { GUILayout.Label(topCallString, Array.Empty<GUILayoutOption>()); } } else if (_windowState == WindowState.Stats) { GUILayout.Label("Stats:", Array.Empty<GUILayoutOption>()); List<KeyValuePair<string, object>> list = new List<KeyValuePair<string, object>>(StatsManager.GetStats()); list.Sort((KeyValuePair<string, object> a, KeyValuePair<string, object> b) => string.Compare(a.Key, b.Key, StringComparison.OrdinalIgnoreCase)); foreach (KeyValuePair<string, object> item in list) { GUILayout.Label($"{item.Key}: {item.Value}", Array.Empty<GUILayoutOption>()); } } GUILayout.FlexibleSpace(); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); if (GUILayout.Button("Next (F9)", Array.Empty<GUILayoutOption>())) { _windowState = (WindowState)((int)(_windowState + 1) % 3); } if (GUILayout.Button("Copy (F10)", Array.Empty<GUILayoutOption>())) { CopyToClipboard(); } if (GUILayout.Button("Reset (F12)", Array.Empty<GUILayoutOption>())) { Clear(); StatsManager.Clear(); } GUILayout.EndHorizontal(); GUILayout.EndVertical(); GUILayout.EndArea(); } } [StructLayout(LayoutKind.Sequential, Size = 1)] internal struct TimingScope : IDisposable { public TimingScope(Type theclass, string method) { } public void Dispose() { } } }