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 StableStructures v1.0.0
StableStructures.dll
Decompiled 4 days agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("StableStructures")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("StableStructures")] [assembly: AssemblyTitle("StableStructures")] [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 StableStructures { [BepInPlugin("com.dreich.stablestructures", "Stable Structures", "1.0.0")] public class StableStructures : BaseUnityPlugin { public const string Guid = "com.dreich.stablestructures"; public const string Name = "Stable Structures"; public const string Version = "1.0.0"; internal static ManualLogSource Log; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<int> SettleChecks; internal static ConfigEntry<float> RecheckSeconds; internal static ConfigEntry<float> WakeRadius; internal static ConfigEntry<bool> LogStats; private float nextStats; private void Awake() { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Expected O, but got Unknown //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Expected O, but got Unknown //IL_00fc: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Let building pieces whose support hasn't changed stop re-checking it until something nearby changes."); SettleChecks = ((BaseUnityPlugin)this).Config.Bind<int>("General", "SettleChecks", 5, new ConfigDescription("How many support checks in a row must come out unchanged before a piece settles.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(2, 60), Array.Empty<object>())); RecheckSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("General", "RecheckSeconds", 60f, new ConfigDescription("A settled piece still re-checks its support about this often, as a safety net.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 600f), Array.Empty<object>())); WakeRadius = ((BaseUnityPlugin)this).Config.Bind<float>("General", "WakeRadius", 8f, new ConfigDescription("Building, destroying or a support change wakes settled pieces within this many meters.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 32f), Array.Empty<object>())); LogStats = ((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "LogStats", false, "Every 30 seconds, write how many support checks ran, how many were skipped and how long they took."); new Harmony("com.dreich.stablestructures").PatchAll(); } private void Update() { if (LogStats.Value && !(Time.time < nextStats)) { nextStats = Time.time + 30f; SupportSleep.ReportStats(); } } } internal static class SupportSleep { private sealed class State { public Vector3Int Cell; public int Stable; public bool Asleep; public float NextVerify; public float LastCheck = -1f; public float SupportBefore; } private const float CellSize = 8f; private const float GapSeconds = 5f; private static readonly FieldRef<WearNTear, float> SupportField = AccessTools.FieldRefAccess<WearNTear, float>("m_support"); private static readonly Func<WearNTear, bool> HaveSupport = AccessTools.MethodDelegate<Func<WearNTear, bool>>(AccessTools.Method(typeof(WearNTear), "HaveSupport", (Type[])null, (Type[])null), (object)null, true); private static readonly Dictionary<WearNTear, State> states = new Dictionary<WearNTear, State>(); private static readonly Dictionary<Vector3Int, List<WearNTear>> grid = new Dictionary<Vector3Int, List<WearNTear>>(); private static readonly Stopwatch watch = new Stopwatch(); private static WearNTear updating; private static int ran; private static int skipped; private static Vector3Int CellOf(Vector3 position) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0022: 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) return new Vector3Int(Mathf.FloorToInt(position.x / 8f), Mathf.FloorToInt(position.y / 8f), Mathf.FloorToInt(position.z / 8f)); } internal static void Register(WearNTear piece) { //IL_001a: 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_0024: 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_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) if (!states.ContainsKey(piece)) { State state = new State { Cell = CellOf(((Component)piece).transform.position) }; states[piece] = state; if (!grid.TryGetValue(state.Cell, out var value)) { value = new List<WearNTear>(); grid[state.Cell] = value; } value.Add(piece); WakeAround(((Component)piece).transform.position, piece); } } internal static void Unregister(WearNTear piece) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0057: 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) if (!states.TryGetValue(piece, out var value)) { return; } states.Remove(piece); if (grid.TryGetValue(value.Cell, out var value2)) { value2.Remove(piece); if (value2.Count == 0) { grid.Remove(value.Cell); } } WakeAround(((Component)piece).transform.position, piece); } internal static void Wake(WearNTear piece) { if (!((Object)(object)piece == (Object)null) && !((Object)(object)piece == (Object)(object)updating) && states.TryGetValue(piece, out var value)) { value.Asleep = false; value.Stable = 0; } } private static void WakeAround(Vector3 position, WearNTear except) { //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_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //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_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0027: 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) //IL_0032: 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_0072: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: 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_00ba: Unknown result type (might be due to invalid IL or missing references) float value = StableStructures.WakeRadius.Value; float num = value * value; Vector3Int val = CellOf(position - Vector3.one * value); Vector3Int val2 = CellOf(position + Vector3.one * value); for (int i = ((Vector3Int)(ref val)).x; i <= ((Vector3Int)(ref val2)).x; i++) { for (int j = ((Vector3Int)(ref val)).y; j <= ((Vector3Int)(ref val2)).y; j++) { for (int k = ((Vector3Int)(ref val)).z; k <= ((Vector3Int)(ref val2)).z; k++) { if (!grid.TryGetValue(new Vector3Int(i, j, k), out var value2)) { continue; } foreach (WearNTear item in value2) { if (!((Object)(object)item == (Object)null) && !((Object)(object)item == (Object)(object)except)) { Vector3 val3 = ((Component)item).transform.position - position; if (!(((Vector3)(ref val3)).sqrMagnitude > num) && states.TryGetValue(item, out var value3)) { value3.Asleep = false; value3.Stable = 0; } } } } } } } internal static bool BeforeUpdate(WearNTear piece) { if (!StableStructures.Enabled.Value || !states.TryGetValue(piece, out var value)) { return true; } float time = Time.time; bool flag = value.LastCheck < 0f || time - value.LastCheck > 5f; value.LastCheck = time; if (value.Asleep && !flag && time < value.NextVerify) { skipped++; return false; } value.SupportBefore = SupportField.Invoke(piece); updating = piece; ran++; watch.Start(); return true; } internal static void AfterUpdate(WearNTear piece) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)updating != (Object)(object)piece) { return; } watch.Stop(); updating = null; if (!states.TryGetValue(piece, out var value)) { return; } if (!Mathf.Approximately(SupportField.Invoke(piece), value.SupportBefore)) { value.Stable = 0; value.Asleep = false; WakeAround(((Component)piece).transform.position, piece); return; } if (!HaveSupport(piece)) { value.Stable = 0; return; } value.Stable++; if (value.Stable >= StableStructures.SettleChecks.Value) { value.Asleep = true; value.NextVerify = Time.time + StableStructures.RecheckSeconds.Value * Random.Range(0.75f, 1.25f); } } internal static void ReportStats() { int num = 0; foreach (State value in states.Values) { if (value.Asleep) { num++; } } double totalMilliseconds = watch.Elapsed.TotalMilliseconds; StableStructures.Log.LogInfo((object)("Support checks in the last 30 s: " + ran + " ran (" + totalMilliseconds.ToString("F1") + " ms total), " + skipped + " skipped. Pieces settled: " + num + " of " + states.Count + ".")); ran = 0; skipped = 0; watch.Reset(); } } [HarmonyPatch(typeof(WearNTear), "Awake")] internal static class WearNTearAwakePatch { private static void Postfix(WearNTear __instance, ZNetView ___m_nview) { if ((Object)(object)___m_nview != (Object)null && ___m_nview.GetZDO() != null) { SupportSleep.Register(__instance); } } } [HarmonyPatch(typeof(WearNTear), "OnDestroy")] internal static class WearNTearDestroyPatch { private static void Prefix(WearNTear __instance) { SupportSleep.Unregister(__instance); } } [HarmonyPatch(typeof(WearNTear), "ClearCachedSupport")] internal static class WearNTearClearCachePatch { private static void Postfix(WearNTear __instance) { SupportSleep.Wake(__instance); } } [HarmonyPatch(typeof(WearNTear), "UpdateSupport")] internal static class WearNTearUpdateSupportPatch { [HarmonyPriority(800)] private static bool Prefix(WearNTear __instance) { return SupportSleep.BeforeUpdate(__instance); } private static Exception Finalizer(WearNTear __instance, Exception __exception) { SupportSleep.AfterUpdate(__instance); return __exception; } } }