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 balrond better build v0.1.0
plugins/BalrondBetterBuild.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BalrondBetterBuild.Config; using BalrondBetterBuild.Core; using BalrondBetterBuild.Runtime; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using JetBrains.Annotations; using Microsoft.CodeAnalysis; using ServerSync; using TMPro; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("BalrondBetterBuild")] [assembly: AssemblyDescription("Event-driven cached structural integrity replacement for Valheim.")] [assembly: AssemblyCompany("Balrond")] [assembly: AssemblyProduct("BalrondBetterBuild")] [assembly: AssemblyCopyright("Copyright © Balrond 2026")] [assembly: ComVisible(false)] [assembly: Guid("d46e22d2-04cd-4df4-b90f-b4ea0c812b48")] [assembly: AssemblyFileVersion("0.3.7.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.3.7.0")] [module: UnverifiableCode] namespace BalrondBetterBuild { [BepInPlugin("balrond.astafaraios.BalrondBetterBuild", "BalrondBetterBuild", "0.1.0")] public sealed class Launch : BaseUnityPlugin { public const string PluginGuid = "balrond.astafaraios.BalrondBetterBuild"; public const string PluginName = "BalrondBetterBuild"; public const string PluginVersion = "0.1.0"; private readonly Harmony harmony = new Harmony("balrond.astafaraios.BalrondBetterBuild"); internal static Launch Instance; internal static Harmony Harmony; internal static IntegrityService Integrity; internal static readonly ConfigSync ConfigSync = new ConfigSync("balrond.astafaraios.BalrondBetterBuild") { DisplayName = "BalrondBetterBuild", CurrentVersion = "0.1.0", MinimumRequiredVersion = "0.1.0" }; private bool worldSessionActive; internal static IntegrityMode RuntimeMode { get; private set; } internal static DiagnosticsLevel RuntimeDiagnostics { get; private set; } internal static bool InformationLoggingEnabled { get; private set; } internal static bool RuntimeStatisticsEnabled => InformationLoggingEnabled && RuntimeDiagnostics != DiagnosticsLevel.Off; internal static bool ProfilingEnabled => InformationLoggingEnabled && RuntimeDiagnostics == DiagnosticsLevel.Profiling; internal BetterBuildConfig Settings { get; private set; } internal static bool WorldSessionActive => (Object)(object)Instance != (Object)null && Instance.worldSessionActive; internal ConfigEntry<T> SyncedConfig<T>(string section, string key, T defaultValue, string description, bool synchronizedSetting) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown ConfigEntry<T> val = ((BaseUnityPlugin)this).Config.Bind<T>(section, key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>())); SyncedConfigEntry<T> syncedConfigEntry = ConfigSync.AddConfigEntry<T>(val); syncedConfigEntry.SynchronizedConfig = synchronizedSetting; return val; } internal static void LogInfo(object message) { if (InformationLoggingEnabled) { if ((Object)(object)Instance != (Object)null) { ((BaseUnityPlugin)Instance).Logger.LogInfo(message); } else { Debug.Log((object)("[BalrondBetterBuild] " + message)); } } } internal static void LogWarning(object message) { if ((Object)(object)Instance != (Object)null) { ((BaseUnityPlugin)Instance).Logger.LogWarning(message); } else { Debug.LogWarning((object)("[BalrondBetterBuild] " + message)); } } internal static void LogError(object message) { if ((Object)(object)Instance != (Object)null) { ((BaseUnityPlugin)Instance).Logger.LogError(message); } else { Debug.LogError((object)("[BalrondBetterBuild] " + message)); } } private void Awake() { Instance = this; Harmony = harmony; Settings = new BetterBuildConfig(this); RefreshRuntimeFlags(); ConfigSync.AddLockingConfigEntry<bool>(Settings.LockConfiguration); WearNTearAccess.Initialize(((BaseUnityPlugin)this).Logger, Settings); MaterialProfiles.Initialize(Settings); Integrity = new IntegrityService(((BaseUnityPlugin)this).Logger, Settings); SubscribeConfigEvents(); harmony.PatchAll(); LogInfo("BalrondBetterBuild 0.1.0 loaded. Mode=" + RuntimeMode.ToString() + ", diagnostics=" + RuntimeDiagnostics.ToString() + "."); if (RuntimeMode == IntegrityMode.Replace) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Integrity replacement is active with safety arming and a session circuit breaker. Test on a copied world first. Vanilla support cache release is " + (Settings.ReleaseVanillaSupportCache.Value ? "ENABLED." : "disabled."))); } else { LogInfo("Plugin loaded. Integrity runtime will remain dormant until a world is active."); } } private void Update() { if (Integrity == null) { return; } if (!IsWorldRuntimeReady()) { if (worldSessionActive) { EndWorldSession(); } return; } if (!worldSessionActive) { BeginWorldSession(); } Integrity.Tick(Time.realtimeSinceStartup); } internal static void NotifyZNetSceneAwake() { if ((Object)(object)Instance != (Object)null) { Instance.TryBeginWorldSession(); } } private void TryBeginWorldSession() { if (!worldSessionActive && IsWorldRuntimeReady()) { BeginWorldSession(); } } private void BeginWorldSession() { worldSessionActive = true; Integrity.BeginWorldSession(Time.realtimeSinceStartup); if (RuntimeMode != IntegrityMode.Vanilla) { Integrity.RegisterExistingInstances(); } if (InformationLoggingEnabled) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Integrity world session started. Mode=" + RuntimeMode.ToString() + ", discovered=" + WearNTear.GetAllInstances().Count + ".")); } } private void EndWorldSession() { worldSessionActive = false; Integrity.Reset(); } private static bool IsWorldRuntimeReady() { return (Object)(object)ZNetScene.instance != (Object)null && ZDOMan.instance != null && (Object)(object)ZoneSystem.instance != (Object)null; } private void OnDestroy() { UnsubscribeConfigEvents(); if (worldSessionActive && Integrity != null) { EndWorldSession(); } if (Harmony != null) { Harmony.UnpatchSelf(); } if (Integrity != null) { Integrity.Reset(); } Integrity = null; Harmony = null; Instance = null; } private void SubscribeConfigEvents() { Settings.Mode.SettingChanged += OnGraphConfigChanged; Settings.SpatialCellSize.SettingChanged += OnGraphConfigChanged; Settings.ContactPadding.SettingChanged += OnGraphConfigChanged; Settings.MaximumOverlapResults.SettingChanged += OnGraphConfigChanged; Settings.MaximumIslandNodes.SettingChanged += OnGraphConfigChanged; Settings.SolveDebounceMilliseconds.SettingChanged += OnGraphConfigChanged; Settings.MaterialPreset.SettingChanged += OnGraphConfigChanged; Settings.CustomMaxSupportMultiplier.SettingChanged += OnGraphConfigChanged; Settings.CustomMinSupportMultiplier.SettingChanged += OnGraphConfigChanged; Settings.CustomHorizontalLossMultiplier.SettingChanged += OnGraphConfigChanged; Settings.CustomVerticalLossMultiplier.SettingChanged += OnGraphConfigChanged; Settings.WorkBudgetMilliseconds.SettingChanged += OnRuntimeConfigChanged; Settings.ActiveAreaReconcileSeconds.SettingChanged += OnRuntimeConfigChanged; Settings.RequireInitialStableGraphBeforeReplace.SettingChanged += OnRuntimeConfigChanged; Settings.MaximumPooledNodeLists.SettingChanged += OnRuntimeConfigChanged; Settings.MaximumRetainedNodeListCapacity.SettingChanged += OnRuntimeConfigChanged; Settings.MaximumPooledSpatialCellLists.SettingChanged += OnRuntimeConfigChanged; Settings.ApplySupportToZdo.SettingChanged += OnRuntimeConfigChanged; Settings.NetworkWriteEpsilon.SettingChanged += OnRuntimeConfigChanged; Settings.NetworkNormalizedWriteEpsilon.SettingChanged += OnRuntimeConfigChanged; Settings.OwnershipRecheckSeconds.SettingChanged += OnRuntimeConfigChanged; Settings.MaximumSupportZdoWritesPerFrame.SettingChanged += OnRuntimeConfigChanged; Settings.ReleaseVanillaSupportCache.SettingChanged += OnRuntimeConfigChanged; Settings.VanillaCacheReleaseStableSeconds.SettingChanged += OnRuntimeConfigChanged; Settings.VanillaCacheReleaseFallbackCooldownSeconds.SettingChanged += OnRuntimeConfigChanged; Settings.MaximumVanillaCacheReleasesPerFrame.SettingChanged += OnRuntimeConfigChanged; Settings.Diagnostics.SettingChanged += OnDiagnosticConfigChanged; Settings.EnableInformationLogging.SettingChanged += OnDiagnosticConfigChanged; Settings.DetailedTimingDiagnostics.SettingChanged += OnDiagnosticConfigChanged; } private void UnsubscribeConfigEvents() { if (Settings != null) { Settings.Mode.SettingChanged -= OnGraphConfigChanged; Settings.SpatialCellSize.SettingChanged -= OnGraphConfigChanged; Settings.ContactPadding.SettingChanged -= OnGraphConfigChanged; Settings.MaximumOverlapResults.SettingChanged -= OnGraphConfigChanged; Settings.MaximumIslandNodes.SettingChanged -= OnGraphConfigChanged; Settings.SolveDebounceMilliseconds.SettingChanged -= OnGraphConfigChanged; Settings.MaterialPreset.SettingChanged -= OnGraphConfigChanged; Settings.CustomMaxSupportMultiplier.SettingChanged -= OnGraphConfigChanged; Settings.CustomMinSupportMultiplier.SettingChanged -= OnGraphConfigChanged; Settings.CustomHorizontalLossMultiplier.SettingChanged -= OnGraphConfigChanged; Settings.CustomVerticalLossMultiplier.SettingChanged -= OnGraphConfigChanged; Settings.WorkBudgetMilliseconds.SettingChanged -= OnRuntimeConfigChanged; Settings.ActiveAreaReconcileSeconds.SettingChanged -= OnRuntimeConfigChanged; Settings.RequireInitialStableGraphBeforeReplace.SettingChanged -= OnRuntimeConfigChanged; Settings.MaximumPooledNodeLists.SettingChanged -= OnRuntimeConfigChanged; Settings.MaximumRetainedNodeListCapacity.SettingChanged -= OnRuntimeConfigChanged; Settings.MaximumPooledSpatialCellLists.SettingChanged -= OnRuntimeConfigChanged; Settings.ApplySupportToZdo.SettingChanged -= OnRuntimeConfigChanged; Settings.NetworkWriteEpsilon.SettingChanged -= OnRuntimeConfigChanged; Settings.NetworkNormalizedWriteEpsilon.SettingChanged -= OnRuntimeConfigChanged; Settings.OwnershipRecheckSeconds.SettingChanged -= OnRuntimeConfigChanged; Settings.MaximumSupportZdoWritesPerFrame.SettingChanged -= OnRuntimeConfigChanged; Settings.ReleaseVanillaSupportCache.SettingChanged -= OnRuntimeConfigChanged; Settings.VanillaCacheReleaseStableSeconds.SettingChanged -= OnRuntimeConfigChanged; Settings.VanillaCacheReleaseFallbackCooldownSeconds.SettingChanged -= OnRuntimeConfigChanged; Settings.MaximumVanillaCacheReleasesPerFrame.SettingChanged -= OnRuntimeConfigChanged; Settings.Diagnostics.SettingChanged -= OnDiagnosticConfigChanged; Settings.EnableInformationLogging.SettingChanged -= OnDiagnosticConfigChanged; Settings.DetailedTimingDiagnostics.SettingChanged -= OnDiagnosticConfigChanged; } } private void OnGraphConfigChanged(object sender, EventArgs eventArgs) { if (Integrity != null && worldSessionActive) { RefreshRuntimeFlags(); Integrity.MarkRuntimeOptionsDirty(); LogInfo("Integrity configuration changed. Rebuilding graph. Mode=" + RuntimeMode.ToString() + "."); Integrity.BeginWorldSession(Time.realtimeSinceStartup); if (RuntimeMode != IntegrityMode.Vanilla) { Integrity.RegisterExistingInstances(); } } } private void OnRuntimeConfigChanged(object sender, EventArgs eventArgs) { if (Integrity != null) { Integrity.MarkRuntimeOptionsDirty(); } } private void OnDiagnosticConfigChanged(object sender, EventArgs eventArgs) { RefreshRuntimeFlags(); if (Integrity != null) { Integrity.RefreshDiagnosticMode(); } } private void RefreshRuntimeFlags() { if (Settings == null) { RuntimeMode = IntegrityMode.Vanilla; RuntimeDiagnostics = DiagnosticsLevel.Off; InformationLoggingEnabled = false; } else { RuntimeMode = Settings.Mode.Value; RuntimeDiagnostics = Settings.Diagnostics.Value; InformationLoggingEnabled = Settings.EnableInformationLogging.Value; } } } } namespace BalrondBetterBuild.Runtime { internal sealed class BenchmarkRecorder { private struct ComparisonSample { internal readonly float RawDifference; internal readonly float NormalizedDifference; internal readonly float VisualDifference; internal readonly bool StabilityMismatch; internal readonly bool VisualMismatch; internal ComparisonSample(float rawDifference, float normalizedDifference, float visualDifference, bool stabilityMismatch, bool visualMismatch) { RawDifference = rawDifference; NormalizedDifference = normalizedDifference; VisualDifference = visualDifference; StabilityMismatch = stabilityMismatch; VisualMismatch = visualMismatch; } } private sealed class ComparisonAccumulator { private long comparisons; private long stabilityMismatches; private long visualMismatches; private double rawDifferenceSum; private double normalizedDifferenceSum; private double visualDifferenceSum; private float maximumRawDifference; private float maximumNormalizedDifference; private float maximumVisualDifference; internal void Add(ComparisonSample sample) { comparisons++; if (sample.StabilityMismatch) { stabilityMismatches++; } if (sample.VisualMismatch) { visualMismatches++; } rawDifferenceSum += sample.RawDifference; normalizedDifferenceSum += sample.NormalizedDifference; visualDifferenceSum += sample.VisualDifference; maximumRawDifference = Math.Max(maximumRawDifference, sample.RawDifference); maximumNormalizedDifference = Math.Max(maximumNormalizedDifference, sample.NormalizedDifference); maximumVisualDifference = Math.Max(maximumVisualDifference, sample.VisualDifference); } internal ComparisonTotals Snapshot() { return new ComparisonTotals(comparisons, stabilityMismatches, visualMismatches, (comparisons == 0L) ? 0.0 : (rawDifferenceSum / (double)comparisons), maximumRawDifference, (comparisons == 0L) ? 0.0 : (normalizedDifferenceSum / (double)comparisons), maximumNormalizedDifference, (comparisons == 0L) ? 0.0 : (visualDifferenceSum / (double)comparisons), maximumVisualDifference); } internal void Reset() { comparisons = 0L; stabilityMismatches = 0L; visualMismatches = 0L; rawDifferenceSum = 0.0; normalizedDifferenceSum = 0.0; visualDifferenceSum = 0.0; maximumRawDifference = 0f; maximumNormalizedDifference = 0f; maximumVisualDifference = 0f; } } private struct NodeComparison { internal readonly int NodeId; internal readonly string Name; internal readonly MaterialType MaterialType; internal readonly float VanillaSupport; internal readonly float GraphSupport; internal readonly float VanillaNormalized; internal readonly float GraphNormalized; internal readonly float VisualDifference; internal readonly bool StabilityMismatch; internal readonly bool VisualMismatch; internal readonly Vector3 Position; internal readonly int ZoneX; internal readonly int ZoneY; internal readonly float DistanceFromReference; internal readonly bool OutsideActiveArea; internal readonly AnchorKind Anchor; internal readonly int LinkCount; internal float NormalizedDifference => Math.Abs(VanillaNormalized - GraphNormalized); internal float Score { get { float num = Math.Max(NormalizedDifference, VisualDifference); return StabilityMismatch ? (num + 2f) : num; } } internal NodeComparison(int nodeId, string name, MaterialType materialType, float vanillaSupport, float graphSupport, float vanillaNormalized, float graphNormalized, float visualDifference, bool stabilityMismatch, bool visualMismatch, Vector3 position, int zoneX, int zoneY, float distanceFromReference, bool outsideActiveArea, AnchorKind anchor, int linkCount) { //IL_001f: 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_005e: 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) NodeId = nodeId; Name = (string.IsNullOrEmpty(name) ? "WearNTear" : name); MaterialType = materialType; VanillaSupport = vanillaSupport; GraphSupport = graphSupport; VanillaNormalized = vanillaNormalized; GraphNormalized = graphNormalized; VisualDifference = visualDifference; StabilityMismatch = stabilityMismatch; VisualMismatch = visualMismatch; Position = position; ZoneX = zoneX; ZoneY = zoneY; DistanceFromReference = distanceFromReference; OutsideActiveArea = outsideActiveArea; Anchor = anchor; LinkCount = linkCount; } internal bool IsEquivalentTo(NodeComparison other, float epsilon) { //IL_0002: 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_00a5: 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_00b0: Unknown result type (might be due to invalid IL or missing references) return MaterialType == other.MaterialType && Math.Abs(VanillaSupport - other.VanillaSupport) <= epsilon && Math.Abs(GraphSupport - other.GraphSupport) <= epsilon && StabilityMismatch == other.StabilityMismatch && VisualMismatch == other.VisualMismatch && Anchor == other.Anchor && LinkCount == other.LinkCount && ZoneX == other.ZoneX && ZoneY == other.ZoneY && OutsideActiveArea == other.OutsideActiveArea && Vector3.SqrMagnitude(Position - other.Position) <= 0.0001f; } } private sealed class MaterialSummaryAccumulator { private struct MaterialCurrentStats { internal int Nodes; internal int StabilityMismatches; internal int VisualMismatches; internal double NormalizedDifferenceSum; internal double VisualDifferenceSum; } private readonly Dictionary<MaterialType, MaterialCurrentStats> values = new Dictionary<MaterialType, MaterialCurrentStats>(); internal void Add(NodeComparison comparison) { //IL_0008: 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) values.TryGetValue(comparison.MaterialType, out var value); value.Nodes++; value.NormalizedDifferenceSum += comparison.NormalizedDifference; value.VisualDifferenceSum += comparison.VisualDifference; if (comparison.StabilityMismatch) { value.StabilityMismatches++; } if (comparison.VisualMismatch) { value.VisualMismatches++; } values[comparison.MaterialType] = value; } internal string BuildSummary() { //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_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) if (values.Count == 0) { return string.Empty; } List<MaterialType> list = new List<MaterialType>(values.Keys); list.Sort((MaterialType left, MaterialType right) => ((int)left).CompareTo((int)right)); StringBuilder stringBuilder = new StringBuilder(192); for (int num = 0; num < list.Count; num++) { if (num > 0) { stringBuilder.Append(" | "); } MaterialType val = list[num]; MaterialCurrentStats materialCurrentStats = values[val]; stringBuilder.Append(val); stringBuilder.Append(':'); stringBuilder.Append(materialCurrentStats.Nodes); stringBuilder.Append(" n="); stringBuilder.Append((materialCurrentStats.NormalizedDifferenceSum / (double)Math.Max(1, materialCurrentStats.Nodes)).ToString("F3")); stringBuilder.Append(" c="); stringBuilder.Append((materialCurrentStats.VisualDifferenceSum / (double)Math.Max(1, materialCurrentStats.Nodes)).ToString("F3")); stringBuilder.Append(" s="); stringBuilder.Append(materialCurrentStats.StabilityMismatches); stringBuilder.Append(" v="); stringBuilder.Append(materialCurrentStats.VisualMismatches); } return stringBuilder.ToString(); } } private const float Epsilon = 0.0001f; private readonly Dictionary<int, NodeComparison> latestByNode = new Dictionary<int, NodeComparison>(); private readonly ComparisonAccumulator lifetime = new ComparisonAccumulator(); private readonly ComparisonAccumulator window = new ComparisonAccumulator(); internal bool Record(int nodeId, string nodeName, MaterialType materialType, MaterialProfile material, float vanilla, float graph, bool vanillaStable, bool graphStable, float visualMismatchThreshold, float changeEpsilon, Vector3 position, int zoneX, int zoneY, float distanceFromReference, bool outsideActiveArea, AnchorKind anchor, int linkCount) { //IL_007e: 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) float rawDifference = Math.Abs(vanilla - graph); float num = NormalizeSupport(vanilla, material); float num2 = NormalizeSupport(graph, material); GetVisualValue(vanilla, material, out var value, out var blue); GetVisualValue(graph, material, out var value2, out var blue2); float num3 = ((blue != blue2) ? 1f : (blue ? 0f : Math.Abs(value - value2))); bool stabilityMismatch = vanillaStable != graphStable; bool visualMismatch = num3 >= Mathf.Clamp01(visualMismatchThreshold); NodeComparison nodeComparison = new NodeComparison(nodeId, nodeName, materialType, vanilla, graph, num, num2, num3, stabilityMismatch, visualMismatch, position, zoneX, zoneY, distanceFromReference, outsideActiveArea, anchor, linkCount); float epsilon = Mathf.Clamp(changeEpsilon, 1E-05f, 10f); if (latestByNode.TryGetValue(nodeId, out var value3) && value3.IsEquivalentTo(nodeComparison, epsilon)) { return false; } ComparisonSample sample = new ComparisonSample(rawDifference, Math.Abs(num - num2), num3, stabilityMismatch, visualMismatch); lifetime.Add(sample); window.Add(sample); latestByNode[nodeId] = nodeComparison; return true; } internal void RemoveNode(int nodeId) { latestByNode.Remove(nodeId); } internal BenchmarkSnapshot SnapshotAndResetWindow(int topDifferenceCount) { int num = 0; int num2 = 0; MaterialSummaryAccumulator materialSummaryAccumulator = new MaterialSummaryAccumulator(); int num3 = Mathf.Clamp(topDifferenceCount, 0, 20); NodeComparison[] top = ((num3 > 0) ? new NodeComparison[num3] : null); float[] scores = ((num3 > 0) ? new float[num3] : null); int used = 0; foreach (NodeComparison value in latestByNode.Values) { if (value.StabilityMismatch) { num++; } if (value.VisualMismatch) { num2++; } materialSummaryAccumulator.Add(value); if (num3 > 0 && (value.StabilityMismatch || value.VisualMismatch || value.NormalizedDifference > 0.0005f || value.VisualDifference > 0.0005f)) { InsertTop(top, scores, ref used, value, value.Score); } } BenchmarkSnapshot result = new BenchmarkSnapshot(lifetime.Snapshot(), window.Snapshot(), latestByNode.Count, num, num2, materialSummaryAccumulator.BuildSummary(), BuildTopSummary(top, used)); window.Reset(); return result; } internal void Reset() { latestByNode.Clear(); lifetime.Reset(); window.Reset(); } private static void InsertTop(NodeComparison[] top, float[] scores, ref int used, NodeComparison candidate, float score) { int num = top.Length; int num2 = used; for (int i = 0; i < used; i++) { if (score > scores[i]) { num2 = i; break; } } if (num2 < num) { int num3 = Math.Min(used, num - 1); for (int num4 = num3; num4 > num2; num4--) { top[num4] = top[num4 - 1]; scores[num4] = scores[num4 - 1]; } top[num2] = candidate; scores[num2] = score; if (used < num) { used++; } } } private static string BuildTopSummary(NodeComparison[] top, int count) { //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) if (top == null || count <= 0) { return string.Empty; } StringBuilder stringBuilder = new StringBuilder(512); for (int i = 0; i < count; i++) { if (i > 0) { stringBuilder.Append(" | "); } NodeComparison nodeComparison = top[i]; stringBuilder.Append(nodeComparison.Name); stringBuilder.Append('#'); stringBuilder.Append(nodeComparison.NodeId); stringBuilder.Append('['); stringBuilder.Append(nodeComparison.MaterialType); stringBuilder.Append("]:v="); float vanillaSupport = nodeComparison.VanillaSupport; stringBuilder.Append(vanillaSupport.ToString("F1")); stringBuilder.Append(",g="); vanillaSupport = nodeComparison.GraphSupport; stringBuilder.Append(vanillaSupport.ToString("F1")); stringBuilder.Append(",n="); stringBuilder.Append(nodeComparison.NormalizedDifference.ToString("F3")); stringBuilder.Append(",c="); vanillaSupport = nodeComparison.VisualDifference; stringBuilder.Append(vanillaSupport.ToString("F3")); stringBuilder.Append(",a="); stringBuilder.Append(nodeComparison.Anchor); stringBuilder.Append(",e="); stringBuilder.Append(nodeComparison.LinkCount); stringBuilder.Append(",z="); stringBuilder.Append(nodeComparison.ZoneX); stringBuilder.Append('/'); stringBuilder.Append(nodeComparison.ZoneY); stringBuilder.Append(",d="); vanillaSupport = nodeComparison.DistanceFromReference; stringBuilder.Append(vanillaSupport.ToString("F1")); stringBuilder.Append(",out="); stringBuilder.Append(nodeComparison.OutsideActiveArea ? '1' : '0'); stringBuilder.Append(",p="); AppendPosition(stringBuilder, nodeComparison.Position); if (nodeComparison.StabilityMismatch) { stringBuilder.Append(",STABLE!"); } } return stringBuilder.ToString(); } private static void AppendPosition(StringBuilder builder, Vector3 position) { builder.Append('('); builder.Append(position.x.ToString("F1")); builder.Append(','); builder.Append(position.y.ToString("F1")); builder.Append(','); builder.Append(position.z.ToString("F1")); builder.Append(')'); } private static float NormalizeSupport(float support, MaterialProfile material) { float num = material.MaxSupport - material.MinSupport; if (num <= 0.0001f) { return (support >= material.MinSupport) ? 1f : 0f; } return Mathf.Clamp01((support - material.MinSupport) / num); } private static void GetVisualValue(float support, MaterialProfile material, out float value, out bool blue) { blue = support >= material.MaxSupport; if (blue) { value = -1f; return; } float num = material.MaxSupport * 0.5f - material.MinSupport; if (num <= 0.0001f) { value = ((support >= material.MinSupport) ? 1f : 0f); } else { value = Mathf.Clamp01((support - material.MinSupport) / num); } } } internal struct ComparisonTotals { internal long Comparisons; internal long StabilityMismatches; internal long VisualMismatches; internal double AverageRawDifference; internal float MaximumRawDifference; internal double AverageNormalizedDifference; internal float MaximumNormalizedDifference; internal double AverageVisualDifference; internal float MaximumVisualDifference; internal ComparisonTotals(long comparisons, long stabilityMismatches, long visualMismatches, double averageRawDifference, float maximumRawDifference, double averageNormalizedDifference, float maximumNormalizedDifference, double averageVisualDifference, float maximumVisualDifference) { Comparisons = comparisons; StabilityMismatches = stabilityMismatches; VisualMismatches = visualMismatches; AverageRawDifference = averageRawDifference; MaximumRawDifference = maximumRawDifference; AverageNormalizedDifference = averageNormalizedDifference; MaximumNormalizedDifference = maximumNormalizedDifference; AverageVisualDifference = averageVisualDifference; MaximumVisualDifference = maximumVisualDifference; } } internal struct BenchmarkSnapshot { internal ComparisonTotals Lifetime; internal ComparisonTotals Window; internal int UniqueComparedNodes; internal int CurrentStabilityMismatchNodes; internal int CurrentVisualMismatchNodes; internal string MaterialSummary; internal string TopDifferences; internal BenchmarkSnapshot(ComparisonTotals lifetime, ComparisonTotals window, int uniqueComparedNodes, int currentStabilityMismatchNodes, int currentVisualMismatchNodes, string materialSummary, string topDifferences) { Lifetime = lifetime; Window = window; UniqueComparedNodes = uniqueComparedNodes; CurrentStabilityMismatchNodes = currentStabilityMismatchNodes; CurrentVisualMismatchNodes = currentVisualMismatchNodes; MaterialSummary = materialSummary; TopDifferences = topDifferences; } } internal sealed class BoundedListPool<T> { private readonly Stack<List<T>> pool = new Stack<List<T>>(); private int maximumCount; private int maximumRetainedCapacity; private readonly int initialCapacity; private long allocated; private long discarded; internal int Count => pool.Count; internal long Allocated => allocated; internal long Discarded => discarded; internal BoundedListPool(int initialListCapacity, int maximumPooledLists, int maximumListCapacity) { initialCapacity = Math.Max(0, initialListCapacity); SetLimits(maximumPooledLists, maximumListCapacity); } internal void SetLimits(int maximumPooledLists, int maximumListCapacity) { maximumCount = Math.Max(0, maximumPooledLists); maximumRetainedCapacity = Math.Max(initialCapacity, maximumListCapacity); TrimToLimit(); } internal List<T> Rent() { if (pool.Count > 0) { return pool.Pop(); } allocated++; return new List<T>(initialCapacity); } internal void Return(List<T> list) { if (list == null) { return; } list.Clear(); if (maximumCount <= 0 || pool.Count >= maximumCount) { discarded++; return; } if (list.Capacity > maximumRetainedCapacity) { list.Capacity = maximumRetainedCapacity; } pool.Push(list); } internal void Clear() { pool.Clear(); } internal void TrimToCount(int targetCount) { int num = Math.Max(0, Math.Min(targetCount, maximumCount)); while (pool.Count > num) { pool.Pop(); discarded++; } } private void TrimToLimit() { while (pool.Count > maximumCount) { pool.Pop(); discarded++; } } } internal sealed class ContactDetector { private const int InitialOverlapCapacity = 128; private const float HalfPi = (float)Math.PI / 2f; private Collider[] overlapBuffer = (Collider[])(object)new Collider[128]; private readonly int supportMask; private readonly int terrainLayer; private long overlapRetries; private long overlapOverflows; internal long OverlapRetries => overlapRetries; internal long OverlapOverflows => overlapOverflows; internal int OverlapCapacity => overlapBuffer.Length; internal ContactDetector() { supportMask = LayerMask.GetMask(new string[5] { "piece", "Default", "static_solid", "Default_small", "terrain" }); terrainLayer = LayerMask.NameToLayer("terrain"); } internal int QueryCollider(Collider collider, float padding, int configuredMaximum) { //IL_0045: 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_004d: Unknown result type (might be due to invalid IL or missing references) if (!IsStructuralCollider(collider)) { return 0; } BuildProbe(collider, Mathf.Max(0f, padding), out var center, out var rotation, out var halfExtents); int num = Mathf.Clamp(configuredMaximum, 128, 16384); int num2; while (true) { num2 = Physics.OverlapBoxNonAlloc(center, halfExtents, overlapBuffer, rotation, supportMask, (QueryTriggerInteraction)1); if (num2 < overlapBuffer.Length || overlapBuffer.Length >= num) { break; } int num3 = Mathf.Min(num, overlapBuffer.Length * 2); overlapBuffer = (Collider[])(object)new Collider[num3]; overlapRetries++; } if (num2 >= overlapBuffer.Length && overlapBuffer.Length >= num) { overlapOverflows++; } return num2; } internal Collider GetResult(int index) { return (index >= 0 && index < overlapBuffer.Length) ? overlapBuffer[index] : null; } internal void ClearResults(int count) { int num = Mathf.Min(count, overlapBuffer.Length); for (int i = 0; i < num; i++) { overlapBuffer[i] = null; } } internal bool IsTerrain(Collider collider) { return (Object)(object)collider != (Object)null && ((Component)collider).gameObject.layer == terrainLayer; } internal StructuralContact CreateDirectionalContact(IntegrityNode target, IntegrityNode source, Collider sourceCollider) { //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_000a: 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_001d: 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_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: 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_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0052: 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_0070: 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_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0077: 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_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: 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) Vector3 centerOfMass = target.CenterOfMass; float num = Vector3.Distance(centerOfMass, source.CenterOfMass) + 0.1f; float num2 = Vector3.Distance(centerOfMass, source.OriginPosition) + 0.1f; if (!target.ForceCorrectComCalculation && num2 < num) { num = num2; } Vector3 val = FindSupportPoint(centerOfMass, source, sourceCollider); Vector3 relativePoint = val - centerOfMass; Vector3 val2 = ((((Vector3)(ref relativePoint)).sqrMagnitude > 1E-06f) ? ((Vector3)(ref relativePoint)).normalized : Vector3.zero); bool flag = val.y < centerOfMass.y + 0.05f; float directVerticalBlend = 0f; if (flag && val2.y < 0f) { directVerticalBlend = Mathf.Acos(1f - Mathf.Abs(val2.y)) / ((float)Math.PI / 2f); } SupportPointData supportPoint = new SupportPointData(relativePoint, num); return new StructuralContact(num, directVerticalBlend, flag, supportPoint); } private static void BuildProbe(Collider collider, float padding, out Vector3 center, out Quaternion rotation, out Vector3 halfExtents) { //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_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: 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_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_0028: 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_0034: 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_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: 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_0059: 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_0079: 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_0099: 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) BoxCollider val = (BoxCollider)(object)((collider is BoxCollider) ? collider : null); if ((Object)(object)val != (Object)null) { Transform transform = ((Component)val).transform; Vector3 lossyScale = transform.lossyScale; center = transform.position + transform.TransformVector(val.center); rotation = transform.rotation; halfExtents = new Vector3(Mathf.Abs(lossyScale.x * val.size.x) * 0.5f + padding, Mathf.Abs(lossyScale.y * val.size.y) * 0.5f + padding, Mathf.Abs(lossyScale.z * val.size.z) * 0.5f + padding); } else { Bounds bounds = collider.bounds; center = ((Bounds)(ref bounds)).center; rotation = Quaternion.identity; halfExtents = ((Bounds)(ref bounds)).extents + Vector3.one * padding; } } private static Vector3 FindSupportPoint(Vector3 targetCom, IntegrityNode source, Collider sourceCollider) { //IL_002a: 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_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0021: 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_0052: 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) //IL_0059: 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_0068: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) MeshCollider val = (MeshCollider)(object)((sourceCollider is MeshCollider) ? sourceCollider : null); if ((Object)(object)val == (Object)null || val.convex) { return sourceCollider.ClosestPoint(targetCom); } RaycastHit val2 = default(RaycastHit); if (((Collider)val).Raycast(new Ray(targetCom, Vector3.down), ref val2, 10f)) { return ((RaycastHit)(ref val2)).point; } return (targetCom + source.CenterOfMass) * 0.5f; } private static bool IsStructuralCollider(Collider collider) { return (Object)(object)collider != (Object)null && !collider.isTrigger && (Object)(object)collider.attachedRigidbody == (Object)null; } } internal enum AnchorKind : byte { None, Terrain, StaticWorld } internal enum LinkCommitResult : byte { None, ImprovedOnly, RemovedOrWeakened } internal sealed class IntegrityNode { private static readonly Collider[] EmptyColliders = (Collider[])(object)new Collider[0]; internal readonly WearNTear Instance; internal readonly int RuntimeId; internal readonly ZNetView NView; internal readonly List<StructuralLink> Links; internal readonly List<int> Dependents; internal MaterialProfile Material; internal bool CanTransmitSupport; internal bool RequiresSupport; internal bool ForceCorrectComCalculation; internal Collider[] Colliders; internal Bounds RawBounds; internal Bounds QueryBounds; internal Vector3 CenterOfMass; internal Vector3 OriginPosition; internal AnchorKind Anchor; internal float GraphSupport; internal float WorkingSupport; internal bool GraphStable; internal bool IsReady; internal bool IsPrepared; internal bool GeometryDirty; internal bool ContactsDirty; internal bool PrepareQueued; internal bool RefreshQueued; internal bool SolveQueued; internal bool RelaxQueued; internal bool VanillaCacheReleased; internal bool SupportValid; internal bool OwnerSyncQueued; internal bool OwnerSyncEstablished; internal bool LastKnownOwner; internal bool OwnershipKnown; internal float NextOwnershipCheckTime; internal float CacheReleaseEligibleTime; internal float LastVanillaFallbackTime; internal int ActiveListIndex = -1; internal bool IsAlive => (Object)(object)Instance != (Object)null && (Object)(object)((Component)Instance).gameObject != (Object)null; internal bool IsAnchor => Anchor != AnchorKind.None; internal IntegrityNode(WearNTear instance, ZNetView nview, List<StructuralLink> links, List<int> dependents) { //IL_0094: 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_00a1: 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_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) Instance = instance; RuntimeId = ((Object)instance).GetInstanceID(); NView = nview; Material = MaterialProfiles.Get(instance, NView); CanTransmitSupport = WearNTearAccess.CanTransmitSupport(instance); RequiresSupport = WearNTearAccess.RequiresSupport(instance); ForceCorrectComCalculation = WearNTearAccess.ForceCorrectComCalculation(instance); Links = links ?? new List<StructuralLink>(6); Dependents = dependents ?? new List<int>(6); Colliders = EmptyColliders; OriginPosition = ((Component)instance).transform.position; CenterOfMass = WearNTearAccess.GetCenterOfMass(instance, OriginPosition); RawBounds = new Bounds(CenterOfMass, Vector3.one * 0.05f); QueryBounds = RawBounds; GeometryDirty = true; ContactsDirty = true; } internal void ReleaseManagedCaches() { Links.Clear(); Dependents.Clear(); Colliders = EmptyColliders; IsPrepared = false; IsReady = false; SupportValid = false; GeometryDirty = true; ContactsDirty = true; } internal void RefreshStaticProperties() { Material = MaterialProfiles.Get(Instance, NView); CanTransmitSupport = WearNTearAccess.CanTransmitSupport(Instance); RequiresSupport = WearNTearAccess.RequiresSupport(Instance); ForceCorrectComCalculation = WearNTearAccess.ForceCorrectComCalculation(Instance); } internal void PrepareGeometry(float contactPadding) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: 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_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0070: 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_007f: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: 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_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) if (!IsAlive) { Colliders = EmptyColliders; IsPrepared = false; return; } RefreshStaticProperties(); Colliders = WearNTearAccess.GetOrCreateStructuralColliders(Instance); OriginPosition = ((Component)Instance).transform.position; CenterOfMass = WearNTearAccess.GetCenterOfMass(Instance, OriginPosition); bool flag = false; Bounds bounds = default(Bounds); ((Bounds)(ref bounds))..ctor(CenterOfMass, Vector3.one * 0.05f); for (int i = 0; i < Colliders.Length; i++) { Collider val = Colliders[i]; if (IsStructuralCollider(val)) { if (!flag) { bounds = val.bounds; flag = true; } else { ((Bounds)(ref bounds)).Encapsulate(val.bounds); } } } RawBounds = bounds; QueryBounds = bounds; ((Bounds)(ref QueryBounds)).Expand(Mathf.Max(0f, contactPadding) * 2f); IsPrepared = true; GeometryDirty = false; } internal LinkCommitResult ReplaceLinks(List<StructuralLink> pending, AnchorKind pendingAnchor, List<int> removedSources, List<int> addedSources) { removedSources.Clear(); addedSources.Clear(); bool flag = Anchor != AnchorKind.None && pendingAnchor == AnchorKind.None; bool flag2 = Anchor == AnchorKind.None && pendingAnchor != AnchorKind.None; Anchor = pendingAnchor; for (int i = 0; i < Links.Count; i++) { StructuralLink structuralLink = Links[i]; int num = FindLinkIndex(pending, structuralLink.OtherId); if (num < 0) { removedSources.Add(structuralLink.OtherId); flag = true; continue; } StructuralContact contact = pending[num].Contact; if (!structuralLink.Contact.ApproximatelyEquals(contact)) { flag = true; } } for (int j = 0; j < pending.Count; j++) { StructuralLink structuralLink2 = pending[j]; if (FindLinkIndex(Links, structuralLink2.OtherId) < 0) { addedSources.Add(structuralLink2.OtherId); flag2 = true; } } Links.Clear(); for (int k = 0; k < pending.Count; k++) { Links.Add(pending[k]); } ContactsDirty = false; IsReady = false; VanillaCacheReleased = false; if (flag) { return LinkCommitResult.RemovedOrWeakened; } return flag2 ? LinkCommitResult.ImprovedOnly : LinkCommitResult.None; } internal bool AddDependent(int targetId) { for (int i = 0; i < Dependents.Count; i++) { if (Dependents[i] == targetId) { return false; } } Dependents.Add(targetId); return true; } internal bool RemoveDependent(int targetId) { for (int i = 0; i < Dependents.Count; i++) { if (Dependents[i] == targetId) { int index = Dependents.Count - 1; Dependents[i] = Dependents[index]; Dependents.RemoveAt(index); return true; } } return false; } internal bool RemoveLink(int sourceId) { for (int i = 0; i < Links.Count; i++) { if (Links[i].OtherId == sourceId) { int index = Links.Count - 1; Links[i] = Links[index]; Links.RemoveAt(index); IsReady = false; return true; } } return false; } private static int FindLinkIndex(List<StructuralLink> links, int otherId) { for (int i = 0; i < links.Count; i++) { if (links[i].OtherId == otherId) { return i; } } return -1; } private static bool IsStructuralCollider(Collider collider) { return (Object)(object)collider != (Object)null && !collider.isTrigger && (Object)(object)collider.attachedRigidbody == (Object)null; } } internal sealed class IntegrityService { private enum SolvePhase : byte { None, Collect, Initialize, Relax, Commit } private enum ReconcilePhase : byte { None, ScanInstances, PruneNodes } private enum ReconcileReason : byte { None, WorldStart, ZoneChange, PeriodicSafety, LifecycleRequest, RestartRequested } private enum WorkStage : byte { None, Prepare, Refresh, Solve, Reconcile, Maintenance } private struct ColliderOwnerCacheEntry { internal Collider Collider; internal int OwnerId; } private const float SupportEpsilon = 0.001f; private const float VanillaBraceCosine = -0.17364818f; private const float CacheReleaseSweepIntervalSeconds = 5f; private readonly ManualLogSource log; private readonly BetterBuildConfig config; private readonly Dictionary<int, IntegrityNode> nodes = new Dictionary<int, IntegrityNode>(); private readonly Dictionary<int, ColliderOwnerCacheEntry> colliderOwners = new Dictionary<int, ColliderOwnerCacheEntry>(); private readonly Dictionary<int, Collider> staticColliderCache = new Dictionary<int, Collider>(); private readonly BoundedListPool<StructuralLink> linkListPool; private readonly BoundedListPool<int> dependentListPool; private readonly SpatialHash spatialHash; private readonly ContactDetector contactDetector = new ContactDetector(); private readonly Queue<int> prepareQueue = new Queue<int>(); private readonly Queue<int> refreshQueue = new Queue<int>(); private readonly Queue<int> solveQueue = new Queue<int>(); private readonly Queue<int> ownerSyncQueue = new Queue<int>(); private readonly HashSet<int> queryBuffer = new HashSet<int>(); private readonly List<int> removedSourceBuffer = new List<int>(8); private readonly List<int> addedSourceBuffer = new List<int>(8); private readonly List<StructuralLink> pendingLinks = new List<StructuralLink>(8); private int currentRefreshNodeId; private int currentRefreshColliderIndex; private AnchorKind currentPendingAnchor; private bool ownerSweepActive; private int ownerSweepIndex; private float nextOwnershipSweepTime; private bool cacheReleaseSweepActive; private int cacheReleaseSweepIndex; private float nextCacheReleaseSweepTime; private int cacheReleaseBudgetFrame = -1; private int cacheReleasesThisFrame; private SolvePhase solvePhase; private int solveSeedId; private int solveGraphRevision; private int graphRevision; private int solveInitializeIndex; private int solveCommitIndex; private readonly List<int> solveIsland = new List<int>(256); private readonly Queue<int> solveCollectQueue = new Queue<int>(); private readonly HashSet<int> solveVisited = new HashSet<int>(); private readonly Queue<int> relaxationQueue = new Queue<int>(); private ReconcilePhase reconcilePhase; private readonly List<int> activeNodeIds = new List<int>(512); private List<WearNTear> reconcileInstances; private int reconcileInstanceIndex; private int reconcileNodeIndex; private bool reconcileGraphChanged; private bool reconcileRestartRequested; private ReconcileReason reconcileReason; private ReconcileReason reconcileRestartReason; private ReconcileReason lastCompletedReconcileReason; private float nextReconcileTime; private float nextReferenceZoneCheckTime; private bool hasReferenceZone; private Vector2Int lastReferenceZone; private long completedReconciliations; private long zoneChangeReconciliations; private long periodicReconciliations; private long requestedReconciliations; private long reconciledPrunedNodes; private bool replacementArmed; private bool replacementFaulted; private string replacementFaultReason = string.Empty; private long replacementRequests; private long replacementHits; private long replacementMissNotArmed; private long replacementMissNotReady; private long replacementMissOutsideArea; private long replacementMissFaulted; private long replacementInvalidSupport; private long replacementExceptions; private long replacementCircuitTrips; private long windowReplacementRequests; private long windowReplacementHits; private long windowReplacementMissNotArmed; private long windowReplacementMissNotReady; private long windowReplacementMissOutsideArea; private long windowReplacementMissFaulted; private long windowReplacementInvalidSupport; private long windowReplacementExceptions; private long windowReplacementCircuitTrips; private readonly BenchmarkRecorder benchmark = new BenchmarkRecorder(); private readonly PerformanceProfiler profiler = new PerformanceProfiler(); private readonly Stopwatch workWatch = new Stopwatch(); private readonly StringBuilder statsBuilder = new StringBuilder(1024); private bool diagnosticsEnabled; private bool profilingEnabled; private bool detailedStageTimingEnabled; private bool runtimeOptionsDirty; private bool dedicatedServer; private float currentRealtimeSinceStartup; private double cachedWorkBudgetMilliseconds; private float cachedContactPadding; private int cachedMaximumOverlapResults; private int cachedMaximumIslandNodes; private float cachedSolveDebounceSeconds; private float cachedReconcileSeconds; private bool cachedRequireInitialStableGraph; private bool cachedReleaseVanillaCache; private bool cachedApplySupportToZdo; private float cachedNetworkAbsoluteEpsilon; private float cachedNetworkNormalizedEpsilon; private float cachedOwnershipRecheckSeconds; private int cachedMaximumSupportZdoWritesPerFrame; private int cachedMaximumPooledNodeLists; private int cachedMaximumRetainedNodeListCapacity; private int cachedMaximumPooledSpatialCellLists; private float cachedVanillaCacheReleaseStableSeconds; private float cachedVanillaCacheReleaseFallbackCooldownSeconds; private int cachedMaximumVanillaCacheReleasesPerFrame; private int zdoWriteBudgetFrame = -1; private int zdoWritesThisFrame; private long zdoWritesSkippedEpsilon; private long zdoWritesSkippedNotOwner; private long zdoWritesDeferredBudget; private long nodeAllocations; private long nodeRemovals; private long negativeColliderCacheHits; private long negativeColliderCacheMisses; private float nextStatsTime; private float solveNotBefore; private long solvedIslands; private long solvedNodes; private long supportRelaxations; private long zdoWrites; private long vanillaCachesReleased; private double lastWorkMilliseconds; private double maximumWorkMilliseconds; private double windowMaximumWorkMilliseconds; private double windowMaxPrepareMilliseconds; private double windowMaxRefreshMilliseconds; private double windowMaxSolveMilliseconds; private double windowMaxReconcileMilliseconds; private double windowMaxMaintenanceMilliseconds; private double lifetimeMaxPrepareMilliseconds; private double lifetimeMaxRefreshMilliseconds; private double lifetimeMaxSolveMilliseconds; private double lifetimeMaxReconcileMilliseconds; private double lifetimeMaxMaintenanceMilliseconds; private float nextIdleHeartbeatTime; private int lastLoggedNodes = -1; private int lastLoggedEdges = -1; private int lastLoggedTerrainAnchors = -1; private int lastLoggedStaticAnchors = -1; private int lastLoggedStableMismatches = -1; private int lastLoggedVisualMismatches = -1; internal IntegrityService(ManualLogSource logger, BetterBuildConfig settings) { log = logger; config = settings; linkListPool = new BoundedListPool<StructuralLink>(6, 2048, 16); dependentListPool = new BoundedListPool<int>(6, 2048, 16); spatialHash = new SpatialHash(GetSpatialCellSize()); RefreshDiagnosticMode(); RefreshRuntimeOptions(0f); } internal void RefreshDiagnosticMode() { bool flag = profilingEnabled; diagnosticsEnabled = Launch.RuntimeStatisticsEnabled; profilingEnabled = Launch.ProfilingEnabled; detailedStageTimingEnabled = profilingEnabled && config.DetailedTimingDiagnostics.Value; if (flag != profilingEnabled) { profiler.Reset(); } } internal void MarkRuntimeOptionsDirty() { runtimeOptionsDirty = true; } internal void RecordUpdateSupportTiming(bool vanillaPath, long elapsedTicks) { if (profilingEnabled) { profiler.RecordSupportCall(vanillaPath, elapsedTicks); } } internal void RecordWearUpdaterTiming(long elapsedTicks) { if (profilingEnabled) { profiler.RecordWearUpdater(elapsedTicks); } } internal void BeginWorldSession(float realtimeSinceStartup) { Reset(); currentRealtimeSinceStartup = realtimeSinceStartup; dedicatedServer = IsDedicatedServer(); RefreshDiagnosticMode(); RefreshRuntimeOptions(realtimeSinceStartup); float num = Math.Max(0f, config.StatsIntervalSeconds.Value); nextStatsTime = realtimeSinceStartup + num; float num2 = Math.Max(0f, config.IdleHeartbeatSeconds.Value); nextIdleHeartbeatTime = ((num2 > 0f) ? (realtimeSinceStartup + num2) : float.PositiveInfinity); nextReconcileTime = realtimeSinceStartup; nextReferenceZoneCheckTime = realtimeSinceStartup; nextOwnershipSweepTime = realtimeSinceStartup; nextCacheReleaseSweepTime = realtimeSinceStartup + 5f; } internal void RegisterExistingInstances() { RequestActiveAreaReconciliation(immediate: true, ReconcileReason.WorldStart); } internal void Reset() { foreach (IntegrityNode value in nodes.Values) { value.ReleaseManagedCaches(); linkListPool.Return(value.Links); dependentListPool.Return(value.Dependents); } nodes.Clear(); activeNodeIds.Clear(); colliderOwners.Clear(); staticColliderCache.Clear(); spatialHash.Clear(); linkListPool.TrimToCount(0); dependentListPool.TrimToCount(0); spatialHash.TrimPool(0); prepareQueue.Clear(); refreshQueue.Clear(); solveQueue.Clear(); ownerSyncQueue.Clear(); queryBuffer.Clear(); removedSourceBuffer.Clear(); addedSourceBuffer.Clear(); pendingLinks.Clear(); currentRefreshNodeId = 0; currentRefreshColliderIndex = 0; currentPendingAnchor = AnchorKind.None; CancelActiveSolve(); CancelReconciliation(); ownerSweepActive = false; ownerSweepIndex = 0; nextOwnershipSweepTime = 0f; cacheReleaseSweepActive = false; cacheReleaseSweepIndex = 0; nextCacheReleaseSweepTime = 0f; cacheReleaseBudgetFrame = -1; cacheReleasesThisFrame = 0; benchmark.Reset(); profiler.Reset(); graphRevision = 0; solvedIslands = 0L; solvedNodes = 0L; supportRelaxations = 0L; zdoWrites = 0L; vanillaCachesReleased = 0L; zdoWritesSkippedEpsilon = 0L; zdoWritesSkippedNotOwner = 0L; zdoWritesDeferredBudget = 0L; zdoWriteBudgetFrame = -1; zdoWritesThisFrame = 0; nodeAllocations = 0L; nodeRemovals = 0L; negativeColliderCacheHits = 0L; negativeColliderCacheMisses = 0L; lastWorkMilliseconds = 0.0; maximumWorkMilliseconds = 0.0; windowMaximumWorkMilliseconds = 0.0; windowMaxPrepareMilliseconds = 0.0; windowMaxRefreshMilliseconds = 0.0; windowMaxSolveMilliseconds = 0.0; windowMaxReconcileMilliseconds = 0.0; windowMaxMaintenanceMilliseconds = 0.0; lifetimeMaxPrepareMilliseconds = 0.0; lifetimeMaxRefreshMilliseconds = 0.0; lifetimeMaxSolveMilliseconds = 0.0; lifetimeMaxReconcileMilliseconds = 0.0; lifetimeMaxMaintenanceMilliseconds = 0.0; nextStatsTime = 0f; solveNotBefore = 0f; nextReconcileTime = 0f; nextReferenceZoneCheckTime = 0f; hasReferenceZone = false; completedReconciliations = 0L; zoneChangeReconciliations = 0L; periodicReconciliations = 0L; requestedReconciliations = 0L; reconciledPrunedNodes = 0L; reconcileReason = ReconcileReason.None; reconcileRestartReason = ReconcileReason.None; lastCompletedReconcileReason = ReconcileReason.None; replacementArmed = false; replacementFaulted = false; replacementFaultReason = string.Empty; replacementRequests = 0L; replacementHits = 0L; replacementMissNotArmed = 0L; replacementMissNotReady = 0L; replacementMissOutsideArea = 0L; replacementMissFaulted = 0L; replacementInvalidSupport = 0L; replacementExceptions = 0L; replacementCircuitTrips = 0L; windowReplacementRequests = 0L; windowReplacementHits = 0L; windowReplacementMissNotArmed = 0L; windowReplacementMissNotReady = 0L; windowReplacementMissOutsideArea = 0L; windowReplacementMissFaulted = 0L; windowReplacementInvalidSupport = 0L; windowReplacementExceptions = 0L; windowReplacementCircuitTrips = 0L; nextIdleHeartbeatTime = 0f; lastLoggedNodes = -1; lastLoggedEdges = -1; lastLoggedTerrainAnchors = -1; lastLoggedStaticAnchors = -1; lastLoggedStableMismatches = -1; lastLoggedVisualMismatches = -1; } internal void Register(WearNTear instance) { if (Launch.RuntimeMode == IntegrityMode.Vanilla || (Object)(object)instance == (Object)null) { return; } int instanceID = ((Object)instance).GetInstanceID(); if (nodes.TryGetValue(instanceID, out var _) || !ShouldManageInstance(instance, out var nview)) { return; } bool flag = WearNTearAccess.RequiresSupport(instance); bool flag2 = WearNTearAccess.CanTransmitSupport(instance); if (flag || flag2) { IntegrityNode integrityNode = new IntegrityNode(instance, nview, linkListPool.Rent(), dependentListPool.Rent()); integrityNode.GraphSupport = WearNTearAccess.ReadSupport(instance); integrityNode.WorkingSupport = integrityNode.GraphSupport; integrityNode.GraphStable = !integrityNode.RequiresSupport || integrityNode.GraphSupport >= integrityNode.Material.MinSupport; integrityNode.IsReady = false; integrityNode.ActiveListIndex = activeNodeIds.Count; nodes.Add(instanceID, integrityNode); activeNodeIds.Add(instanceID); if (diagnosticsEnabled) { nodeAllocations++; } QueuePrepare(integrityNode); } } internal void Unregister(WearNTear instance) { if (!((Object)(object)instance == (Object)null)) { RemoveNode(((Object)instance).GetInstanceID(), markNearby: true, mutateImmediately: true); } } private bool RemoveNode(int id, bool markNearby, bool mutateImmediately) { //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_0172: Unknown result type (might be due to invalid IL or missing references) if (!nodes.TryGetValue(id, out var value)) { return false; } Bounds queryBounds = value.QueryBounds; bool isPrepared = value.IsPrepared; RemoveColliderMappings(value); for (int i = 0; i < value.Links.Count; i++) { if (nodes.TryGetValue(value.Links[i].OtherId, out var value2)) { value2.RemoveDependent(id); } } for (int j = 0; j < value.Dependents.Count; j++) { if (nodes.TryGetValue(value.Dependents[j], out var value3)) { value3.RemoveLink(id); QueueSolve(value3); } } spatialHash.Remove(id); RemoveFromActiveNodeList(value); nodes.Remove(id); if (diagnosticsEnabled) { nodeRemovals++; } benchmark.RemoveNode(id); if (currentRefreshNodeId == id) { CancelCurrentRefresh(); } if (solvePhase != SolvePhase.None && solveVisited.Contains(id)) { CancelActiveSolve(); } if (markNearby && isPrepared) { MarkNearbyContactsDirty(queryBounds, id); } value.ReleaseManagedCaches(); linkListPool.Return(value.Links); dependentListPool.Return(value.Dependents); if (mutateImmediately) { MutatedGraph(); } else { reconcileGraphChanged = true; } return true; } internal void MarkGeometryDirty(WearNTear instance) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) Register(instance); if (!((Object)(object)instance == (Object)null) && nodes.TryGetValue(((Object)instance).GetInstanceID(), out var value)) { if (value.IsPrepared) { MarkNearbyContactsDirty(value.QueryBounds, value.RuntimeId); } bool flag = !value.GeometryDirty || !value.ContactsDirty || value.IsReady; value.GeometryDirty = true; value.ContactsDirty = true; value.IsReady = false; value.SupportValid = false; value.OwnerSyncEstablished = false; value.NextOwnershipCheckTime = 0f; value.VanillaCacheReleased = false; if (currentRefreshNodeId == value.RuntimeId) { CancelCurrentRefresh(); flag = true; } bool flag2 = QueuePrepare(value); if (flag || flag2) { MutatedGraph(); } } } internal void MarkSupportDirty(WearNTear instance) { Register(instance); if (!((Object)(object)instance == (Object)null) && nodes.TryGetValue(((Object)instance).GetInstanceID(), out var value) && ((value.IsPrepared && !value.GeometryDirty) ? QueueRefresh(value) : QueuePrepare(value))) { MutatedGraph(); } } internal void ForceFullRebuild() { MaterialProfiles.Invalidate(); colliderOwners.Clear(); staticColliderCache.Clear(); spatialHash.Clear(); spatialHash.SetCellSize(GetSpatialCellSize()); prepareQueue.Clear(); refreshQueue.Clear(); solveQueue.Clear(); ownerSyncQueue.Clear(); ownerSweepActive = false; ownerSweepIndex = 0; cacheReleaseSweepActive = false; cacheReleaseSweepIndex = 0; CancelCurrentRefresh(); CancelActiveSolve(); benchmark.Reset(); replacementArmed = false; replacementFaulted = false; replacementFaultReason = string.Empty; foreach (IntegrityNode value in nodes.Values) { value.Links.Clear(); value.Dependents.Clear(); value.IsReady = false; value.IsPrepared = false; value.GeometryDirty = true; value.ContactsDirty = true; value.PrepareQueued = false; value.RefreshQueued = false; value.SolveQueued = false; value.RelaxQueued = false; value.Anchor = AnchorKind.None; value.VanillaCacheReleased = false; value.SupportValid = false; value.OwnerSyncQueued = false; if (value.IsAlive) { QueuePrepare(value); } } MutatedGraph(); if (Launch.InformationLoggingEnabled) { log.LogInfo((object)("Forced integrity graph rebuild for " + nodes.Count + " registered WearNTear instances.")); } } internal bool TryGetCachedSupport(WearNTear instance, out float support) { support = 0f; if (diagnosticsEnabled) { replacementRequests++; windowReplacementRequests++; } if (replacementFaulted) { if (diagnosticsEnabled) { replacementMissFaulted++; windowReplacementMissFaulted++; } return false; } if ((Object)(object)instance == (Object)null) { if (diagnosticsEnabled) { replacementMissOutsideArea++; windowReplacementMissOutsideArea++; } return false; } int instanceID = ((Object)instance).GetInstanceID(); if (!nodes.TryGetValue(instanceID, out var value)) { Register(instance); if (!nodes.TryGetValue(instanceID, out value)) { if (diagnosticsEnabled) { replacementMissOutsideArea++; windowReplacementMissOutsideArea++; } return false; } } if (cachedRequireInitialStableGraph && !replacementArmed) { if (diagnosticsEnabled) { replacementMissNotArmed++; windowReplacementMissNotArmed++; } return false; } if (value == null || !value.IsReady || !value.IsPrepared || value.GeometryDirty || value.ContactsDirty || value.PrepareQueued || value.RefreshQueued || value.SolveQueued) { if (cachedReleaseVanillaCache && value != null) { value.LastVanillaFallbackTime = currentRealtimeSinceStartup; value.VanillaCacheReleased = false; } if (diagnosticsEnabled) { replacementMissNotReady++; windowReplacementMissNotReady++; } return false; } if (!value.SupportValid) { if (diagnosticsEnabled) { replacementInvalidSupport++; windowReplacementInvalidSupport++; } string[] obj = new string[7] { "Invalid graph support for ", ((Object)instance).name, "#", null, null, null, null }; int runtimeId = value.RuntimeId; obj[3] = runtimeId.ToString(); obj[4] = ": "; obj[5] = value.GraphSupport.ToString(); obj[6] = "."; DisableReplacementForSession(string.Concat(obj), null); return false; } support = value.GraphSupport; if (diagnosticsEnabled) { replacementHits++; windowReplacementHits++; } return true; } private void SynchronizeOwnerIfNeeded(IntegrityNode node, bool forceCheck) { if (!cachedApplySupportToZdo || node == null || (Object)(object)node.NView == (Object)null || (!forceCheck && currentRealtimeSinceStartup < node.NextOwnershipCheckTime)) { return; } bool flag = forceCheck || !node.OwnerSyncEstablished; node.NextOwnershipCheckTime = currentRealtimeSinceStartup + cachedOwnershipRecheckSeconds; bool flag2; try { flag2 = node.NView.IsValid() && node.NView.IsOwner(); } catch { flag2 = false; } bool flag3 = node.OwnershipKnown && flag2 != node.LastKnownOwner; node.OwnershipKnown = true; node.LastKnownOwner = flag2; if (!flag2) { node.OwnerSyncEstablished = false; if (diagnosticsEnabled) { zdoWritesSkippedNotOwner++; } } else { if (!flag && !flag3) { return; } ResetZdoWriteBudgetIfNeeded(); bool allowNonCriticalWrite = zdoWritesThisFrame < cachedMaximumSupportZdoWritesPerFrame; ZdoWriteResult zdoWriteResult = WearNTearAccess.WriteSupportToZdo(node.Instance, node.NView, node.GraphSupport, node.Material, cachedNetworkAbsoluteEpsilon, cachedNetworkNormalizedEpsilon, flag3, allowNonCriticalWrite); if (zdoWriteResult == ZdoWriteResult.Written) { zdoWritesThisFrame++; if (diagnosticsEnabled) { zdoWrites++; } } else if (zdoWriteResult == ZdoWriteResult.SkippedEpsilon) { if (diagnosticsEnabled) { zdoWritesSkippedEpsilon++; } } else if (zdoWriteResult == ZdoWriteResult.SkippedNotOwner && diagnosticsEnabled) { zdoWritesSkippedNotOwner++; } else if (zdoWriteResult == ZdoWriteResult.SkippedBudget) { node.NextOwnershipCheckTime = currentRealtimeSinceStartup + 0.05f; nextOwnershipSweepTime = Math.Min(nextOwnershipSweepTime, node.NextOwnershipCheckTime); if (diagnosticsEnabled) { zdoWritesDeferredBudget++; } } node.OwnerSyncEstablished = zdoWriteResult == ZdoWriteResult.Written || zdoWriteResult == ZdoWriteResult.SkippedEpsilon; } } internal void DisableReplacementForSession(string reason, Exception exception) { if (exception != null) { replacementExceptions++; windowReplacementExceptions++; } if (!replacementFaulted) { replacementFaulted = true; replacementArmed = false; replacementCircuitTrips++; windowReplacementCircuitTrips++; replacementFaultReason = (string.IsNullOrEmpty(reason) ? "Unknown replacement failure." : reason); string text = "Replacement circuit breaker opened for this world session. " + replacementFaultReason + " Vanilla integrity remains active until the world is reloaded or the graph is rebuilt."; if (exception == null) { log.LogError((object)text); } else { log.LogError((object)(text + " Exception: " + exception)); } } } internal unsafe void RecordVanillaResult(WearNTear instance, float vanillaSupport) { //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_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_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: 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_00ad: 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_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0348: Unknown result type (might be due to invalid IL or missing references) //IL_0349: Unknown result type (might be due to invalid IL or missing references) //IL_0366: Unknown result type (might be due to invalid IL or missing references) //IL_036b: Unknown result type (might be due to invalid IL or missing references) if (!diagnosticsEnabled || (Object)(object)instance == (Object)null || !nodes.TryGetValue(((Object)instance).GetInstanceID(), out var value) || !value.IsReady) { return; } bool vanillaStable = !value.RequiresSupport || vanillaSupport >= value.Material.MinSupport; float visualMismatchThreshold = Mathf.Clamp01(config.VisualDifferenceThreshold.Value); Vector3 position = ((Component)instance).transform.position; Vector2Int zoneCoordinate = GetZoneCoordinate(position); Vector3 val = (((Object)(object)ZNet.instance == (Object)null) ? position : ZNet.instance.GetReferencePosition()); float distanceFromReference = Vector3.Distance(position, val); bool outsideActiveArea = IsOutsideActiveArea(instance); if (benchmark.Record(value.RuntimeId, ((Object)instance).name, WearNTearAccess.GetMaterialType(instance), value.Material, vanillaSupport, value.GraphSupport, vanillaStable, value.GraphStable, visualMismatchThreshold, config.ComparisonChangeEpsilon.Value, position, ((Vector2Int)(ref zoneCoordinate)).x, ((Vector2Int)(ref zoneCoordinate)).y, distanceFromReference, outsideActiveArea, value.Anchor, value.Links.Count)) { float num = Math.Abs(vanillaSupport - value.GraphSupport); float num2 = Math.Abs(NormalizeSupport(vanillaSupport, value.Material) - NormalizeSupport(value.GraphSupport, value.Material)); if (config.VerboseLogging.Value && (num >= Math.Max(0f, config.DifferenceWarning.Value) || num2 >= Mathf.Clamp01(config.NormalizedDifferenceWarning.Value))) { ManualLogSource obj = log; string[] array = new string[32]; array[0] = "Support difference "; array[1] = ((Object)instance).name; array[2] = "#"; int runtimeId = value.RuntimeId; array[3] = runtimeId.ToString(); array[4] = ": vanilla="; array[5] = vanillaSupport.ToString("F2"); array[6] = ", graph="; array[7] = value.GraphSupport.ToString("F2"); array[8] = ", normalized="; array[9] = num2.ToString("F3"); array[10] = ", stable="; array[11] = vanillaStable.ToString(); array[12] = "/"; array[13] = value.GraphStable.ToString(); array[14] = ", anchor="; array[15] = value.Anchor.ToString(); array[16] = ", edges="; array[17] = value.Links.Count.ToString(); array[18] = ", colliders="; array[19] = value.Colliders.Length.ToString(); array[20] = ", zone="; array[21] = ((Vector2Int)(ref zoneCoordinate)).x.ToString(); array[22] = "/"; array[23] = ((Vector2Int)(ref zoneCoordinate)).y.ToString(); array[24] = ", distance="; array[25] = distanceFromReference.ToString("F1"); array[26] = ", outside="; array[27] = outsideActiveArea.ToString(); array[28] = ", position="; Vector3 val2 = position; array[29] = ((object)(*(Vector3*)(&val2))/*cast due to .constrained prefix*/).ToString(); array[30] = ", material="; array[31] = ((object)WearNTearAccess.GetMaterialType(instance)/*cast due to .constrained prefix*/).ToString(); obj.LogWarning((object)string.Concat(array)); } } } internal void Tick(float realtimeSinceStartup) { currentRealtimeSinceStartup = realtimeSinceStartup; if (runtimeOptionsDirty) { RefreshRuntimeOptions(realtimeSinceStartup); } if (Launch.RuntimeMode == IntegrityMode.Vanilla) { if (diagnosticsEnabled && Launch.InformationLoggingEnabled) { float num = Math.Max(0f, config.StatsIntervalSeconds.Value); if (num > 0f && realtimeSinceStartup >= nextStatsTime) { nextStatsTime = realtimeSinceStartup + num; LogStats(realtimeSinceStartup); } } return; } UpdateActiveAreaSchedule(realtimeSinceStartup); UpdateMaintenanceSchedule(realtimeSinceStartup); if (HasPendingWork()) { double num2 = cachedWorkBudgetMilliseconds; workWatch.Restart(); bool flag = true; while (workWatch.Elapsed.TotalMilliseconds < num2) { WorkStage workStage = WorkStage.None; bool flag2 = prepareQueue.Count > 0 || currentRefreshNodeId != 0 || refreshQueue.Count > 0 || ((solvePhase != SolvePhase.None || solveQueue.Count > 0) && realtimeSinceStartup >= solveNotBefore) || HasPendingMaintenance(); double num3 = (detailedStageTimingEnabled ? workWatch.Elapsed.TotalMilliseconds : 0.0); bool flag3; if (reconcilePhase != ReconcilePhase.None && (flag || !flag2)) { workStage = WorkStage.Reconcile; flag3 = ProcessReconciliationStep(); flag = false; } else if (prepareQueue.Count > 0) { workStage = WorkStage.Prepare; flag3 = ProcessPrepare(); flag = true; } else if (currentRefreshNodeId != 0 || refreshQueue.Count > 0) { workStage = WorkStage.Refresh; flag3 = ProcessRefreshStep(); flag = true; } else if ((solvePhase != SolvePhase.None || solveQueue.Count > 0) && realtimeSinceStartup >= solveNotBefore) { workStage = WorkStage.Solve; flag3 = ProcessSolveStep(); flag = true; } else if (HasPendingMaintenance()) { workStage = WorkStage.Maintenance; flag3 = ProcessMaintenanceStep(); flag = true; } else { if (reconcilePhase == ReconcilePhase.None) { break; } workStage = WorkStage.Reconcile; flag3 = ProcessReconciliationStep(); flag = false; } if (detailedStageTimingEnabled && workStage != WorkStage.None) { RecordStageTiming(workStage, Math.Max(0.0, workWatch.Elapsed.TotalMilliseconds - num3)); } if (!flag3 && !HasPendingWork()) { break; } } workWatch.Stop(); if (diagnosticsEnabled) { lastWorkMilliseconds = workWatch.Elapsed.TotalMilliseconds; maximumWorkMilliseconds = Math.Max(maximumWorkMilliseconds, lastWorkMilliseconds); windowMaximumWorkMilliseconds = Math.Max(windowMaximumWorkMilliseconds, lastWorkMilliseconds); } } else if (diagnosticsEnabled) { lastWorkMilliseconds = 0.0; } if (!replacementArmed && !replacementFaulted && IsGraphSettled()) { if (ValidateGraphForReplacement(out var failure)) { replacementArmed = true; if (Launch.RuntimeMode == IntegrityMode.Replace && Launch.InformationLoggingEnabled) { log.LogInfo((object)("Initial active-area graph is stable. Replacement is now armed for " + nodes.Count + " WearNTear nodes.")); } } else { DisableReplacementForSession(failure, null); } } if (diagnosticsEnabled && Launch.InformationLoggingEnabled) { float num4 = Math.Max(0f, config.StatsIntervalSeconds.Value); if (num4 > 0f && realtimeSinceStartup >= nextStatsTime) { nextStatsTime = realtimeSinceStartup + num4; LogStats(realtimeSinceStartup); } } } private bool ValidateGraphForReplacement(out string failure) { foreach (IntegrityNode value in nodes.Values) { if (value.IsAlive) { if (!value.IsPrepared || !value.IsReady || value.GeometryDirty || value.ContactsDirty || value.PrepareQueued || value.RefreshQueued || value.SolveQueued) { string[] obj = new string[5] { "Graph settled with an unready node: ", ((Object)value.Instance).name, "#", null, null }; int runtimeId = value.RuntimeId; obj[3] = runtimeId.ToString(); obj[4] = "."; failure = string.Concat(obj); return false; } if (!value.SupportValid || !IsFiniteSupport(value.GraphSupport, value.Material)) { string[] obj2 = new string[7] { "Graph settled with invalid support on ", ((Object)value.Instance).name, "#", null, null, null, null }; int runtimeId = value.RuntimeId; obj2[3] = runtimeId.ToString(); obj2[4] = ": "; obj2[5] = value.GraphSupport.ToString(); obj2[6] = "."; failure = string.Concat(obj2); return false; } } } failure = string.Empty; return true; } private void RecordStageTiming(WorkStage stage, double milliseconds) { switch (stage) { case WorkStage.Prepare: windowMaxPrepareMilliseconds = Math.Max(windowMaxPrepareMilliseconds, milliseconds); lifetimeMaxPrepareMilliseconds = Math.Max(lifetimeMaxPrepareMilliseconds, milliseconds); break; case WorkStage.Refresh: windowMaxRefreshMilliseconds = Math.Max(windowMaxRefreshMilliseconds, milliseconds); lifetimeMaxRefreshMilliseconds = Math.Max(lifetimeMaxRefreshMilliseconds, milliseconds); break; case WorkStage.Solve: windowMaxSolveMilliseconds = Math.Max(windowMaxSolveMilliseconds, milliseconds); lifetimeMaxSolveMilliseconds = Math.Max(lifetimeMaxSolveMilliseconds, milliseconds); break; case WorkStage.Reconcile: windowMaxReconcileMilliseconds = Math.Max(windowMaxReconcileMilliseconds, milliseconds); lifetimeMaxReconcileMilliseconds = Math.Max(lifetimeMaxReconcileMilliseconds, milliseconds); break; case WorkStage.Maintenance: windowMaxMaintenanceMilliseconds = Math.Max(windowMaxMaintenanceMilliseconds, milliseconds); lifetimeMaxMaintenanceMilliseconds = Math.Max(lifetimeMaxMaintenanceMilliseconds, milliseconds); break; } } internal void LogStats(float realtimeSinceStartup) { if (!diagnosticsEnabled || !Launch.InformationLoggingEnabled) { return; } RuntimeStats stats = GetStats(); ComparisonTotals lifetime = stats.Benchmark.Lifetime; ComparisonTotals window = stats.Benchmark.Window; IntegrityMode runtimeMode = Launch.RuntimeMode; bool flag = stats.PrepareQueue > 0 || stats.RefreshQueue > 0 || stats.SolveQueue > 0 || stats.SolvePhase != "None" || stats.ReconcilePhase != "None"; bool flag2 = stats.Nodes != lastLoggedNodes || stats.Edges != lastLoggedEdges || stats.TerrainAnchors != lastLoggedTerrainAnchors || stats.StaticAnchors != lastLoggedStaticAnchors || stats.Benchmark.CurrentStabilityMismatchNodes != lastLoggedStableMismatches || stats.Benchmark.CurrentVisualMismatchNodes != lastLoggedVisualMismatches; bool flag3 = runtimeMode == IntegrityMode.Observe && (window.Comparisons > 0 || window.StabilityMismatches > 0 || window.VisualMismatches > 0); bool flag4 = runtimeMode == IntegrityMode.Replace && (stats.WindowReplacementRequests > 0 || stats.WindowReplacementInvalidSupport > 0 || stats.WindowReplacementExceptions > 0 || stats.WindowReplacementCircuitTrips > 0 || stats.ReplacementFaulted); bool flag5 = profilingEnabled && (stats.Profiler.ReplacementLookup.WindowCalls > 0 || stats.Profiler.VanillaSupport.WindowCalls > 0 || stats.Profiler.WearUpdater.WindowCalls > 0); bool flag6 = realtimeSinceStartup >= nextIdleHeartbeatTime; if (config.LogIdleStatistics.Value || flag || flag2 || flag3 || flag4 || flag5 || flag6) { string value = (stats.ReplacementFaulted ? "Faulted" : (stats.ReplacementArmed ? "Armed" : "Warming")); double num = ((stats.ReplacementRequests <= 0) ? 0.0 : (100.0 * (double)stats.ReplacementHits / (double)stats.ReplacementRequests)); statsBuilder.Length = 0; statsBuilder.Append("BetterBuild stats: mode="); statsBuilder.Append(runtimeMode); statsBuilder.Append(", nodes="); statsBuilder.Append(stats.Nodes); statsBuilder.Append(", prepared="); statsBuilder.Append(stats.PreparedNodes); statsBuilder.Append(", ready="); statsBuilder.Append(stats.ReadyNodes); statsBuilder.Append(", comparable="); statsBuilder.Append(stats.ComparableNodes); statsBuilder.Append(", edges="); statsBuilder.Append(stats.Edges); statsBuilder.Append(", anchors="); statsBuilder.Append(stats.TerrainAnchors); statsBuilder.Append('/'); statsBuilder.Append(stats.StaticAnchors); statsBuilder.Append(", queues="); statsBuilder.Append(stats.PrepareQueue); statsBuilder.Append('/'); statsBuilder.Append(stats.RefreshQueue); statsBuilder.Append('/'); statsBuilder.Append(stats.SolveQueue); statsBuilder.Append(", phase="); statsBuilder.Append(stats.SolvePhase); statsBuilder.Append(", reconcile="); statsBuilder.Append(stats.ReconcilePhase); statsBuilder.Append(", reconcileRemaining="); statsBuilder.Append(stats.ReconcileScanRemaining); statsBuilder.Append('/'); statsBuilder.Append(stats.ReconcilePruneRemaining); statsBuilder.Append(", reconciliations="); statsBuilder.Append(stats.Reconciliations); statsBuilder.Append("(zone="); statsBuilder.Append(stats.ZoneChangeReconciliations); statsBuilder.Append(",periodic="); statsBuilder.Append(stats.PeriodicReconciliations); statsBuilder.Append(",requested="); statsBuilder.Append(stats.RequestedReconciliations); statsBuilder.Append(",last="); statsBuilder.Append(stats.LastReconcileReason); statsBuilder.Append(')'); statsBuilder.Append(", pruned="); statsBuilder.Append(stats.ReconciledPrunedNodes); statsBuilder.Append(", replace="); statsBuilder.Append(value); statsBuilder.Append(", islands="); statsBuilder.Append(stats.SolvedIslands); statsBuilder.Append(", solvedNodes="); statsBuilder.Append(stats.SolvedNodes); statsBuilder.Append(", relax="); statsBuilder.Append(stats.SupportRelaxations); statsBuilder.Append(", zdo="); statsBuilder.Append(stats.ZdoWrites); statsBuilder.Append("(eps="); statsBuilder.Append(stats.ZdoWritesSkippedEpsilon); statsBuilder.Append(",notOwner="); statsBuilder.Append(stats.ZdoWritesSkippedNotOwner); statsBuilder.Append(",budget="); statsBuilder.Append(stats.ZdoWritesDeferredBudget); statsBuilder.Append(')'); statsBuilder.Append(", releasedCaches="); statsBuilder.Append(stats.VanillaCachesReleased); statsBuilder.Append(", allocations(nodes/remove/nodeLists/cellLists)="); statsBuilder.Append(stats.NodeAllocations); statsBuilder.Append('/'); statsBuilder.Append(stats.NodeRemovals); statsBuilder.Append('/'); statsBuilder.Append(stats.AllocatedNodeLists); statsBuilder.Append('/'); statsBuilder.Append(stats.SpatialAllocatedLists); statsBuilder.Append(", nodePools(link/dependent/discarded)="); statsBuilder.Append(stats.PooledLinkLists); statsBuilder.Append('/'); statsBuilder.Append(stats.PooledDependentLists); statsBuilder.Append('/'); statsBuilder.Append(stats.DiscardedNodeLists); statsBuilder.Append(", spatial(cells/pool/discarded/owners)="); statsBuilder.Append(stats.SpatialCells); statsBuilder.Append('/'); statsBuilder.Append(stats.SpatialPooledLists); statsBuilder.Append('/'); statsBuilder.Append(stats.SpatialDiscardedLists); statsBuilder.Append('/'); statsBuilder.Append(stats.ColliderOwnerCacheEntries); statsBuilder.Append(", staticCache="); statsBuilder.Append(stats.StaticColliderCacheEntries); statsBuilder.Append("(hit/miss="); statsBuilder.Append(stats.NegativeColliderCacheHits); statsBuilder.Append('/'); statsBuilder.Append(stats.NegativeColliderCacheMisses); statsBuilder.Append(')'); statsBuilder.Append(", graphEst="); statsBuilder.Append(((double)stats.EstimatedGraphBytes / 1024.0).ToString("F1")); statsBuilder.Append("KiB"); statsBuilder.Append(", overlap="); statsBuilder.Append(stats.OverlapRetries); statsBuilder.Append('/'); statsBuilder.Append(stats.OverlapOverflows); statsBuilder.Append(" cap="); statsBuilder.Append(stats.OverlapCapacity); statsBuilder.Append(", work="); statsBuilder.Append(stats.LastWorkMilliseconds.ToString("F3")); statsBuilder.Append("ms, maxWindow="); statsBuilder.Append(stats.WindowMaximumWorkMilliseconds.ToString("F3")); statsBuilder.Append("ms, maxLifetime="); statsBuilder.Append(stats.MaximumWorkMilliseconds.ToString("F3")); statsBuilder.Append("ms, stageMaxWindow(p/r/s/c/m)="); statsBuilder.Append(stats.WindowMaxPrepareMilliseconds.ToString("F3")); statsBuilder.Append('/'); statsBuilder.Append(stats.WindowMaxRefreshMilliseconds.ToString("F3")); statsBuilder.Append('/'); statsBuilder.Append(stats.WindowMaxSolveMilliseconds.ToString("F3")); statsBuilder.Append('/'); statsBuilder.Append(stats.WindowMaxReconcileMilliseconds.ToString("F3")); statsBuilder.Append('/'); statsBuilder.Append(stats.WindowMaxMaintenanceMilliseconds.ToString("F3")); statsBuilder.Append("ms"); switch (runtimeMode) { case IntegrityMode.Replace: { long value2 = stats.WindowReplacementMissNotArmed + stats.WindowReplacementMissNotReady + stats.WindowReplacementMissOutsideArea + stats.WindowReplacementMissFaulted; double num2 = ((stats.WindowReplacementRequests <= 0) ? 0.0 : (100.0 * (double)stats.WindowReplacementHits / (double)stats.WindowReplacementRequests)); statsBuilder.Append(", replaceWindow="); statsBuilder.Append(stats.WindowReplacementRequests); statsBuilder.Append('/'); statsBuilder.Append(stats.WindowReplacementHits); statsBuilder.Append('('); statsBuilder.Append(num2.ToString("F1")); statsBuilder.Append("%), windowMisses="); statsBuilder.Append(value2); statsBuilder.Append("(arm="); statsBuilder.Append(stats.WindowReplacementMissNotArmed); statsBuilder.Append(",ready="); statsBuilder.Append(stats.WindowReplacementMissNotReady); statsBuilder.Append(",outside="); statsBuilder.Append(stats.WindowReplacementMissOutsideArea); statsBuilder.Append(",fault="); statsBuilder.Append(stats.WindowReplacementMissFaulted); statsBuilder.Append("), replaceLifetime="); statsBuilder.Append(stats.ReplacementRequests); statsBuilder.Append('/'); statsBuilder.Append(stats.ReplacementHits); statsBuilder.Append('('); statsBuilder.Append(num.ToString("F1")); statsBuilder.Append("%), invalid="); statsBuilder.Append(stats.ReplacementInvalidSupport); statsBuilder.Append(", exceptions="); statsBuilder.Append(stats.ReplacementExceptions); statsBuilder.Append(", circuitTrips="); statsBuilder.Append(stats.ReplacementCircuitTrips); if (stats.ReplacementFaulted) { statsBuilder.Append(", faultReason="); statsBuilder.Append(stats.ReplacementFaultReason); } break; } case IntegrityMode.Observe: statsBuilder.Append(", comparedUnique="); statsBuilder.Append(stats.Benchmark.UniqueComparedNodes); statsBuilder.Append(", waitingVanilla="); statsBuilder.Append(Math.Max(0, stats.ComparableNodes - stats.Benchmark.UniqueComparedNodes)); statsBuilder.Append(", compareCoverage="); statsBuilder.Append((stats.ComparableNodes <= 0) ? "0.0%" : ((100.0 * (double)stats.Benchmark.UniqueComparedNodes / (double)stats.ComparableNodes).ToString("F1") + "%")); statsBuilder.Append(", currentStableMismatch="); statsBuilder.Append(stats.Benchmark.CurrentStabilityMismatchNodes); statsBuilder.Append(", currentVisualMismatch="); statsBuilder.Append(stats.Benchmark.CurrentVisualMismatchNodes); statsBuilder.Append(", windowChanged="); statsBuilder.Append(window.Comparisons); statsBuilder.Append(", windowStableMismatch="); statsBuilder.Append(window.StabilityMismatches); statsBuilder.Append(", windowVisualMismatch="); statsBuilder.Append(window.VisualMismatches); statsBuilder.Append(", windowAvgNorm="); statsBuilder.Append(window.AverageNormalizedDifference.ToString("F3")); statsBuilder.Append(", windowMaxNorm="); statsBuilder.Append(window.MaximumNormalizedDifference.ToString("F3")); statsBuilder.Append(", lifetimeChanged="); statsBuilder.Append(lifetime.Comparisons); statsBuilder.Append(", lifetimeStableMismatch="); statsBuilder.Append(lifetime.StabilityMismatches); statsBuilder.Append(", lifetimeAvgNorm="); statsBuilder.Append(lifetime.AverageNormalizedDifference.ToString("F3")); statsBuilder.Append(", lifetimeMaxNorm="); statsBuilder.Append(lifetime.MaximumNormalizedDifference.ToString("F3")); break; } if (profilingEnabled) { AppendProfiler(statsBuilder, stats.Profiler); } log.LogInfo((object)statsBuilder.ToString()); if (runtimeMode == IntegrityMode.Observe && config.LogMaterialBreakdown.Value && !string.IsNullOrEmpty(stats.Benchmark.MaterialSummary)) { log.LogInfo((object)("BetterBuild materials: " + stats.Benchmark.MaterialSummary)); } if (runtimeMode == IntegrityMode.Observe && !string.IsNullOrEmpty(stats.Benchmark.TopDifferences)) { log.LogInfo((object)("BetterBuild top differences: " + stats.Benchmark.TopDifferences)); } lastLoggedNodes = stats.Nodes; lastLoggedEdges = stats.Edges; lastLoggedTerrainAnchors = stats.TerrainAnchors; lastLoggedStaticAnchors = stats.StaticAnchors; lastLoggedStableMismatches = stats.Benchmark.CurrentStabilityMismatchNodes; lastLoggedVisualMismatches = stats.Benchmark.CurrentVisualMismatchNodes; float num3 = Math.Max(0f, config.IdleHeartbeatSeconds.Value); nextIdleHeartbeatTime = ((num3 > 0f) ? (realtimeSinceStartup + num3) : float.PositiveInfinity); } ResetDiagnosticWindow(); } private static void AppendProfiler(StringBuilder builder, ProfilerSnapshot snapshot) { builder.Append(", profiler lookup="); AppendTiming(builder, snapshot.ReplacementLookup); builder.Append(", vanillaSupport="); AppendTiming(builder, snapshot.VanillaSupport); builder.Append(", wearUpdater="); AppendTiming(builder, snapshot.WearUpdater); builder.Append(", managed="); builder.Append(((double)snapshot.ManagedBytes / 1048576.0).ToString("F1")); builder.Append("MiB, gc="); builder.Append(snapshot.Gen0Collections); builder.Append('/'); builder.Append(snapshot.Gen1Collections); builder.Append('/'); builder.Append(snapshot.Gen2Collections); } private static void AppendTiming(StringBuilder builder, TimingSnapshot timing) { builder.Append(timing.WindowCalls); builder.Append(" calls/"); builder.Append(timing.WindowMilliseconds.ToString("F3")); builder.Append("ms avg="); builder.Append(timing.WindowAverageMicroseconds.ToString("F2")); builder.Append("us max="); builder.Append((timing.WindowMaximumMilliseconds * 1000.0).ToString("F2")); builder.Append("us"); } private void ResetDiagnosticWindow() { windowMaximumWorkMilliseconds = 0.0; windowMaxPrepareMilliseconds = 0.0; windowMaxRefreshMilliseconds = 0.0; windowMaxSolveMilliseconds = 0.0; windowMaxReconcileMilliseconds = 0.0; windowMaxMaintenanceMilliseconds = 0.0; windowReplacementRequests = 0L; windowReplacementHits = 0L; windowReplacementMissNotArmed = 0L; windowReplacementMissNotReady = 0L; windowReplacementMissOutsideArea = 0L; windowReplacementMissFaulted = 0L; windowReplacementInvalidSupport = 0L; windowReplacementExceptions = 0L; windowReplacementCircuitTrips = 0L; } private void UpdateActiveAreaSchedule(float realtimeSinceStartup) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0077: 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) if (reconcilePhase != ReconcilePhase.None) { return; } bool flag = false; if (!dedicatedServer && realtimeSinceStartup >= nextReferenceZoneCheckTime) { nextReferenceZoneCheckTime = realtimeSinceStartup + 0.25f; if (TryGetReferenceZone(out var zone) && (!hasReferenceZone || !((Vector2Int)(ref zone)).Equals(lastReferenceZone))) { hasReferenceZone = true; lastReferenceZone = zone; flag = true; } } if (flag || realtimeSinceStartup >= nextReconcileTime) { StartReconciliation(flag ? ReconcileReason.ZoneChange : ReconcileReason.PeriodicSafety); } } private void UpdateMaintenanceSchedule(float realtimeSinceStartup) { if (cachedApplySupportToZdo && !ownerSweepActive && realtimeSinceStartup >= nextOwnershipSweepTime) { ownerSweepActive = activeNodeIds.Count > 0; ownerSweepIndex = 0; if (!ownerSweepActive) { nextOwnershipSweepTime = realtimeSinceStartup + cachedOwnershipRecheckSeconds; } } else if (!cachedApplySupportToZdo) { ownerSweepActive = false; ownerSweepIndex = 0; } bool flag = cachedReleaseVanillaCache && Launch.RuntimeMode == IntegrityMode.Replace && replacementArmed && !replacementFaulted; if (flag && !cacheReleaseSweepActive && realtimeSinceStartup >= nextCacheReleaseSweepTime) { cacheReleaseSweepActive = activeNodeIds.Count > 0; cacheReleaseSweepIndex = 0; if (!cacheReleaseSweepActive) { nextCacheReleaseSweepTime = realtimeSinceStartup + 5f; } } else if (!flag) { cacheReleaseSweepActive = false; cacheReleaseSweepIndex = 0; } } private bool HasPendingMaintenance() { return ownerSyncQueue.Count > 0 || ownerSweepActive || cacheReleaseSweepActive; } private bool ProcessMaintenanceStep() { while (ownerSyncQueue.Count > 0) { int key = ownerSyncQueue