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 PlsCollapse v1.0.0
PlsCollapse.dll
Decompiled 2 weeks agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")] [assembly: AssemblyCompany("PlsCollapse")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("PlsCollapse")] [assembly: AssemblyTitle("PlsCollapse")] [assembly: AssemblyVersion("1.0.0.0")] [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 PlsCollapse { [BepInPlugin("Iteravio.PlsCollapse", "PlsCollapse", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] [SynchronizationMode(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "Iteravio.PlsCollapse"; public const string PluginName = "PlsCollapse"; public const string PluginVersion = "1.0.0"; private const string SettingsSection = "Pls Collapse"; internal static ManualLogSource Log; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<int> FootingPercent; internal static ConfigEntry<int> BoxSizePercent; internal static ConfigEntry<bool> LogChecks; private void Awake() { //IL_00c8: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Pls Collapse", "Enabled", true, Synced("Rock pieces fall once nothing really holds them up. Vanilla: off.", null, 3)); FootingPercent = ((BaseUnityPlugin)this).Config.Bind<int>("Pls Collapse", "PercentFootingNeeded", 15, Synced("How much of a rock's footing must remain for it to stay up; mine past that and the whole rock drops. 0 turns this off. Vanilla: off.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 90), 2)); BoxSizePercent = ((BaseUnityPlugin)this).Config.Bind<int>("Pls Collapse", "PercentSupportBoxSize", 100, Synced("Size of each piece's support box relative to the piece. Lower makes pieces fall sooner.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(25, 150), 1)); LogChecks = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "LogSupportChecks", false, "Log a line each time a rock checks support (when one of its pieces breaks). Local only, not synced."); CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new StatusCommand()); new Harmony("Iteravio.PlsCollapse").PatchAll(); if (RockSupport.Ready) { Log.LogInfo((object)("Ready: " + GetSettingsSummary())); } else { Log.LogError((object)"MineRock5 internals not found (game update?). Rocks keep vanilla support."); } } private static ConfigDescription Synced(string description, AcceptableValueBase range, int order) { //IL_000a: 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_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown return new ConfigDescription(description, range, new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true, Order = order } }); } internal static string GetSettingsSummary() { if (!Enabled.Value) { return "off (vanilla support)"; } return $"on, footing {FootingPercent.Value}%, boxes {BoxSizePercent.Value}%"; } internal static string GetSettingsSource() { ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null) { return "local config"; } if (!instance.IsServer()) { return "synced from host"; } return "this machine (host/solo)"; } } internal static class RockSupport { private sealed class FootingMemory { public int Max; } private const float GroundContactTolerance = 0.3f; private const int GroundSamplesPerAxis = 5; private const float GroundSampleInset = 0.02f; internal static readonly bool Ready; internal static int Checks; internal static int Collapsed; internal static int FootingDrops; private static readonly FieldInfo HitAreasField; private static readonly FieldInfo RayMaskField; private static readonly FieldInfo ColliderField; private static readonly FieldInfo HealthField; private static readonly FieldInfo SupportedField; private static readonly FieldInfo BoundField; private static readonly FieldInfo BoundPosField; private static readonly FieldInfo BoundRotField; private static readonly FieldInfo BoundSizeField; private static readonly Func<MineRock5, Collider, bool> GetSupport; private static readonly Collider[] Overlaps; private static int terrainLayer; private static int terrainMask; private static readonly ConditionalWeakTable<MineRock5, FootingMemory> Footing; static RockSupport() { Overlaps = (Collider[])(object)new Collider[128]; terrainLayer = -1; Footing = new ConditionalWeakTable<MineRock5, FootingMemory>(); try { Type type = AccessTools.Inner(typeof(MineRock5), "HitArea"); Type type2 = AccessTools.Inner(typeof(MineRock5), "BoundData"); HitAreasField = AccessTools.Field(typeof(MineRock5), "m_hitAreas"); RayMaskField = AccessTools.Field(typeof(MineRock5), "m_rayMask"); ColliderField = AccessTools.Field(type, "m_collider"); HealthField = AccessTools.Field(type, "m_health"); SupportedField = AccessTools.Field(type, "m_supported"); BoundField = AccessTools.Field(type, "m_bound"); BoundPosField = AccessTools.Field(type2, "m_pos"); BoundRotField = AccessTools.Field(type2, "m_rot"); BoundSizeField = AccessTools.Field(type2, "m_size"); GetSupport = (Func<MineRock5, Collider, bool>)Delegate.CreateDelegate(typeof(Func<MineRock5, Collider, bool>), AccessTools.Method(typeof(MineRock5), "GetSupport", (Type[])null, (Type[])null)); Ready = HitAreasField != null && RayMaskField != null && ColliderField != null && HealthField != null && SupportedField != null && BoundField != null && BoundPosField != null && BoundRotField != null && BoundSizeField != null; } catch (Exception ex) { Plugin.Log.LogError((object)ex); Ready = false; } } internal static void FitBounds(MineRock5 rock) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) if (!Ready || !Plugin.Enabled.Value) { return; } float num = (float)Plugin.BoxSizePercent.Value / 100f; Vector3 position = ((Component)rock).transform.position; foreach (object item in (IList)HitAreasField.GetValue(rock)) { Collider val = (Collider)ColliderField.GetValue(item); if (!((Object)(object)val == (Object)null) && TryGetLocalBounds(val, out var bounds)) { Transform transform = ((Component)val).transform; Vector3 lossyScale = transform.lossyScale; Vector3 val2 = Vector3.Scale(((Bounds)(ref bounds)).extents, new Vector3(Mathf.Abs(lossyScale.x), Mathf.Abs(lossyScale.y), Mathf.Abs(lossyScale.z))) * num; object value = BoundField.GetValue(item); BoundPosField.SetValue(value, transform.TransformPoint(((Bounds)(ref bounds)).center) - position); BoundRotField.SetValue(value, transform.rotation); BoundSizeField.SetValue(value, val2); BoundField.SetValue(item, value); } } } private static bool TryGetLocalBounds(Collider collider, out Bounds bounds) { //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: 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_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) MeshCollider val = (MeshCollider)(object)((collider is MeshCollider) ? collider : null); if (val == null) { BoxCollider val2 = (BoxCollider)(object)((collider is BoxCollider) ? collider : null); if (val2 != null) { bounds = new Bounds(val2.center, val2.size); return true; } SphereCollider val3 = (SphereCollider)(object)((collider is SphereCollider) ? collider : null); if (val3 != null) { bounds = new Bounds(val3.center, Vector3.one * (val3.radius * 2f)); return true; } CapsuleCollider val4 = (CapsuleCollider)(object)((collider is CapsuleCollider) ? collider : null); if (val4 != null) { Vector3 val5 = Vector3.one * (val4.radius * 2f); ((Vector3)(ref val5))[val4.direction] = Mathf.Max(val4.height, val4.radius * 2f); bounds = new Bounds(val4.center, val5); return true; } } else if ((Object)(object)val.sharedMesh != (Object)null) { bounds = val.sharedMesh.bounds; return true; } bounds = default(Bounds); return false; } internal static void AfterUpdateSupport(MineRock5 rock) { if (!Ready) { return; } IList list = (IList)HitAreasField.GetValue(rock); string text = (Plugin.Enabled.Value ? Recompute(rock, list) : "vanilla"); int num = 0; int num2 = 0; foreach (object item in list) { if (!((float)HealthField.GetValue(item) <= 0f)) { num++; if ((bool)SupportedField.GetValue(item)) { num2++; } } } Checks++; Collapsed += num - num2; if (Plugin.LogChecks.Value) { Plugin.Log.LogInfo((object)($"{GetPrefabName((Component)(object)rock)}: {num2}/{num} pieces supported ({text}), " + $"{num - num2} collapsing ({Plugin.GetSettingsSummary()})")); } } private static string Recompute(MineRock5 rock, IList areas) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Expected O, but got Unknown //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Expected O, but got Unknown //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) if (terrainLayer < 0) { terrainLayer = LayerMask.NameToLayer("terrain"); terrainMask = LayerMask.GetMask(new string[1] { "terrain" }); } int num = (int)RayMaskField.GetValue(null); Vector3 position = ((Component)rock).transform.position; int count = areas.Count; bool[] array = new bool[count]; Dictionary<Collider, int> dictionary = new Dictionary<Collider, int>(count); for (int i = 0; i < count; i++) { array[i] = (float)HealthField.GetValue(areas[i]) > 0f; Collider val = (Collider)ColliderField.GetValue(areas[i]); if ((Object)(object)val != (Object)null) { dictionary[val] = i; } } bool[] array2 = new bool[count]; List<int>[] array3 = new List<int>[count]; int num2 = 0; int num3 = 0; Dictionary<string, int> dictionary2 = new Dictionary<string, int>(); float num4 = 0f; float num5 = 0f; for (int j = 0; j < count; j++) { array3[j] = new List<int>(); if (!array[j]) { continue; } Collider val2 = (Collider)ColliderField.GetValue(areas[j]); object value = BoundField.GetValue(areas[j]); Vector3 val3 = (Vector3)BoundSizeField.GetValue(value); Bounds bounds = val2.bounds; Vector3 extents = ((Bounds)(ref bounds)).extents; num4 += val3.x * val3.y * val3.z; num5 += extents.x * extents.y * extents.z; int num6 = Physics.OverlapBoxNonAlloc(position + (Vector3)BoundPosField.GetValue(value), val3, Overlaps, (Quaternion)BoundRotField.GetValue(value), num); bool flag = false; string text = null; for (int k = 0; k < num6; k++) { Collider val4 = Overlaps[k]; if (!((Object)(object)val4 == (Object)(object)val2) && !((Object)(object)val4.attachedRigidbody != (Object)null) && !val4.isTrigger) { int value2; if (((Component)val4).gameObject.layer == terrainLayer) { flag = true; } else if (dictionary.TryGetValue(val4, out value2)) { array3[j].Add(value2); } else if (text == null && GetSupport(rock, val4)) { text = GetPrefabName((Component)(object)val4); } } } if (flag && RestsOnGround(val2)) { array2[j] = true; num2++; } else if (text != null) { array2[j] = true; dictionary2[text] = ((!dictionary2.TryGetValue(text, out var value3)) ? 1 : (value3 + 1)); } else if (flag) { num3++; } } bool[] supported = (bool[])array2.Clone(); bool flag2 = true; while (flag2) { flag2 = false; for (int l = 0; l < count; l++) { if (array[l] && !supported[l] && array3[l].Any((int num11) => supported[num11])) { supported[l] = true; flag2 = true; } } } int num7 = array2.Count((bool a) => a); FootingMemory value4 = Footing.GetValue(rock, (MineRock5 _) => new FootingMemory()); value4.Max = Math.Max(value4.Max, num7); bool flag3 = num7 * 100 < value4.Max * Plugin.FootingPercent.Value; if (flag3) { FootingDrops++; } int num8 = 0; for (int num9 = 0; num9 < count; num9++) { if (array[num9]) { bool flag4 = supported[num9] && !flag3; SupportedField.SetValue(areas[num9], flag4); if (flag4 && !array2[num9]) { num8++; } } } string text2 = ((dictionary2.Count == 0) ? "" : (", on " + string.Join(", ", dictionary2.Select((KeyValuePair<string, int> kv) => $"{kv.Key} x{kv.Value}")))); float num10 = ((num5 > 0f) ? (num4 / num5) : 1f); return $"{num2} on ground{text2}, {num3} only grazing the ground, {num8} via other pieces; " + string.Format("footing {0}/{1}{2}; boxes {3:0.00}x vanilla volume", num7, value4.Max, flag3 ? " too little, dropping all" : "", num10); } private static bool RestsOnGround(Collider piece) { //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_0009: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0060: 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_0099: 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_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: 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_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) Bounds bounds = piece.bounds; float num = ((Bounds)(ref bounds)).max.y + 1f; RaycastHit val = default(RaycastHit); RaycastHit val2 = default(RaycastHit); for (int i = 0; i < 5; i++) { for (int j = 0; j < 5; j++) { float num2 = Mathf.Lerp(((Bounds)(ref bounds)).min.x, ((Bounds)(ref bounds)).max.x, Mathf.Lerp(0.02f, 0.98f, (float)i / 4f)); float num3 = Mathf.Lerp(((Bounds)(ref bounds)).min.z, ((Bounds)(ref bounds)).max.z, Mathf.Lerp(0.02f, 0.98f, (float)j / 4f)); if (Physics.Raycast(new Vector3(num2, num, num3), Vector3.down, ref val, num - ((Bounds)(ref bounds)).min.y + 50f, terrainMask)) { float num4 = Mathf.Min(((RaycastHit)(ref val)).point.y, ((Bounds)(ref bounds)).min.y) - 1f; if (piece.Raycast(new Ray(new Vector3(num2, num4, num3), Vector3.up), ref val2, num - num4) && ((RaycastHit)(ref val2)).point.y <= ((RaycastHit)(ref val)).point.y + 0.3f) { return true; } } } } return false; } private static string GetPrefabName(Component component) { ZNetView componentInParent = component.GetComponentInParent<ZNetView>(); ZDO val = (Object.op_Implicit((Object)(object)componentInParent) ? componentInParent.GetZDO() : null); GameObject val2 = ((val != null && Object.op_Implicit((Object)(object)ZNetScene.instance)) ? ZNetScene.instance.GetPrefab(val.GetPrefab()) : null); if (!Object.op_Implicit((Object)(object)val2)) { return ((Object)component.transform.root).name.Replace("(Clone)", ""); } return ((Object)val2).name; } } [HarmonyPatch(typeof(MineRock5), "UpdateSupport")] internal static class UpdateSupportPatch { private static void Prefix(ref bool ___m_haveSetupBounds) { ___m_haveSetupBounds = false; } private static void Postfix(MineRock5 __instance) { RockSupport.AfterUpdateSupport(__instance); } } [HarmonyPatch(typeof(MineRock5), "SetupColliders")] internal static class SetupCollidersPatch { private static void Postfix(MineRock5 __instance) { RockSupport.FitBounds(__instance); } } internal class StatusCommand : ConsoleCommand { public override string Name => "plscollapse"; public override string Help => "Show PlsCollapse settings in effect and this session's rock collapse counts"; public override void Run(string[] args, Terminal context) { if (!((Object)(object)context == (Object)null)) { context.AddString("PlsCollapse 1.0.0"); if (!RockSupport.Ready) { context.AddString("Inactive: game internals not found, rocks use vanilla support. See the BepInEx log."); return; } context.AddString("Settings (" + Plugin.GetSettingsSource() + "): " + Plugin.GetSettingsSummary()); context.AddString($"This session on this machine: {RockSupport.Checks} support checks, " + $"{RockSupport.Collapsed} pieces collapsed, {RockSupport.FootingDrops} rocks dropped by the footing rule"); } } } }