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 HeimKit v0.2.0
BepInEx/plugins/HeimKit/HeimKit.dll
Decompiled 4 days 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.Linq.Expressions; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using HeimKit.Configuration; using HeimKit.Core.Diagnostics; using HeimKit.Core.Lifecycle; using HeimKit.Core.Native; using HeimKit.Core.Ownership; using HeimKit.Core.Players; using HeimKit.Core.Players.Models; using HeimKit.Core.Prefabs; using HeimKit.Core.Scheduling; using HeimKit.Core.World; using HeimKit.Features.AFKNightWatch; using HeimKit.Features.AFKNightWatch.Models; using HeimKit.Features.AFKRaidWatch; using HeimKit.Features.AFKRaidWatch.Models; using HeimKit.Features.DoorKeeper; using HeimKit.Features.ForestRenewal; using HeimKit.Features.ForestRenewal.Models; using HeimKit.Features.HeimMender; using HeimKit.Features.HeimMender.Models; using HeimKit.Features.InfiniteTorches; using HeimKit.Features.InfiniteTorches.Models; using HeimKit.Features.SeaSalvage; using HeimKit.Features.SeaSalvage.Models; using HeimKit.Features.SharedMap; using HeimKit.Features.SharedMap.Models; using HeimKit.Features.TameTravel; using HeimKit.Features.TameTravel.Models; using HeimKit.Features.WeatherGuard; using HeimKit.Features.WeatherGuard.Models; using Microsoft.CodeAnalysis; using SoftReferenceableAssets; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("HeimKit")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.2.0.0")] [assembly: AssemblyInformationalVersion("0.2.0")] [assembly: AssemblyProduct("HeimKit")] [assembly: AssemblyTitle("HeimKit")] [assembly: InternalsVisibleTo("HeimKit.Tests")] [assembly: AssemblyVersion("0.2.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace HeimKit { [BepInPlugin("heimkit", "HeimKit", "0.2.0")] [BepInProcess("valheim_server.exe")] public sealed class Plugin : BaseUnityPlugin { private ModuleHost? _host; private PlayerServices? _players; private WorldObjectProvider? _world; private void Awake() { //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) _host = new ModuleHost(((BaseUnityPlugin)this).Logger); DiagnosticLog.StartSession(); DiagnosticLog.Write(((BaseUnityPlugin)this).Logger, "HeimKit", "Starting version 0.2.0 at " + DiagnosticLog.WallClock().ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture) + ". Build configuration: Release.", (LogLevel)16); try { ConfigurationLoader.Load(Paths.ConfigPath, ((BaseUnityPlugin)this).Logger, delegate(ConfigFile val) { _players = new PlayerServices(val, ((BaseUnityPlugin)this).Logger); _world = new WorldObjectProvider(_players.Presence); _host.Register(() => new InfiniteTorches(val, ((BaseUnityPlugin)this).Logger, _players), "InfiniteTorches"); _host.Register(() => new WeatherGuard(val, ((BaseUnityPlugin)this).Logger, _players), "WeatherGuard"); _host.Register(() => new AFKNightWatch(val, ((BaseUnityPlugin)this).Logger, _players), "AFKNightWatch"); _host.Register(() => new AFKRaidWatch(val, ((BaseUnityPlugin)this).Logger, _players), "AFKRaidWatch"); _host.Register(() => new SharedMap(val, ((BaseUnityPlugin)this).Logger, _players), "SharedMap"); _host.Register(() => new DoorKeeper(val, ((BaseUnityPlugin)this).Logger, _players), "DoorKeeper"); _host.Register(() => new ForestRenewal(val, ((BaseUnityPlugin)this).Logger, _players), "ForestRenewal"); _host.Register(() => new SeaSalvage(val, ((BaseUnityPlugin)this).Logger, _players), "SeaSalvage"); _host.Register(() => new TameTravel(val, ((BaseUnityPlugin)this).Logger, _players), "TameTravel"); _host.Register(() => new HeimMender(val, ((BaseUnityPlugin)this).Logger, _players), "HeimMender"); return val; }); } catch (Exception ex) { _players?.Dispose(); _players = null; _host.Dispose(); _world?.Dispose(); _world = null; ManualLogSource logger = ((BaseUnityPlugin)this).Logger; LogTopic config = CoreLogTopics.Config; Exception error = ex; DiagnosticLog.Write(logger, "HeimKit", config, "Modules disabled because configuration setup failed.", default(LogFields), (LogLevel)2, verbose: false, error); return; } _host.Initialize(((object)Version.CurrentVersion/*cast due to .constrained prefix*/).ToString()); } private void Update() { float unscaledTime = Time.unscaledTime; WorldServices.Refresh(); _players?.Tick(unscaledTime); _world?.Tick(unscaledTime); _host?.Tick(unscaledTime); _players?.Events.ReportProcessing(); } private void OnDestroy() { _host?.Dispose(); _host = null; _world?.Dispose(); _world = null; _players?.Dispose(); _players = null; PrefabRegistry.Current.Clear(); } } } namespace HeimKit.Features.WeatherGuard { public sealed class WeatherGuard : IServerModule { private readonly WeatherGuardSettings _settings; private readonly ManualLogSource _logger; private readonly GameVersionCompatibility _compatibility; private readonly string _configPath; private readonly WeatherGuardCoverageRequests _coverageRequests; private readonly WeatherGuardDiagnostics _adminDiagnostics; private WeatherGuardController? _controller; private ZDOMan? _world; private readonly PlayerServices _players; private IDisposable? _presenceRegistration; private bool? _occupied; private readonly PlayerProcessingNotices _processing; private float _coverageNow; private readonly Action _coverageReport; public string Name => "WeatherGuard"; public bool IsActive { get; private set; } private static bool ServerReady => WorldServices.Terrain; public WeatherGuard(ConfigFile config, ManualLogSource logger, PlayerServices players) { _coverageReport = ReportCoverage; _logger = logger; _compatibility = GameVersionCompatibility.Resolve(config, logger); _players = players; _settings = new WeatherGuardSettings(config, logger); _processing = new PlayerProcessingNotices(logger, Name, () => _settings.DebugLogging.Enabled); _configPath = config.ConfigFilePath; _coverageRequests = new WeatherGuardCoverageRequests(Path.GetDirectoryName(_configPath), logger); _adminDiagnostics = new WeatherGuardDiagnostics(logger, debug: false); } public void Initialize(string gameVersion) { Shutdown(); DiagnosticLog.Write(_logger, Name, _settings.Enabled.Value ? "Enabled." : "Disabled.", (LogLevel)16); _settings.DebugLogging.ReportStartup(_logger, Name, _settings.Enabled.Value); WeatherGuardDiagnostics.StartupSettings(_logger, _settings); if (!_settings.Enabled.Value) { return; } if (!_compatibility.Supports(gameVersion)) { DiagnosticLog.Write(_logger, "WeatherGuard", "DISABLED (unsupported Valheim version " + gameVersion + "; required version " + _compatibility.RequiredVersion + "; built-in audited version 1.0.20).", (LogLevel)4); return; } IsActive = true; if (_settings.DebugLogging.Enabled) { DiagnosticLog.Write(_logger, Name, "Waiting for joined players and dedicated-server world", (LogLevel)32); } _presenceRegistration = _players.Events.Subscribe(PresenceChanged, Fail, () => _processing.IsEmptyPaused, () => _processing.IsRunning, () => _processing.IsServerReady); } public void Tick(float now) { if (IsActive && !_settings.Enabled.Value) { Shutdown(); } if (IsActive) { if (ServerReady) { _processing.ServerReady(); } if (_occupied != true) { StopController(); } else { StartController(); _controller?.Tick(now); } } PollCoverage(now); } private void PresenceChanged(bool? occupied) { _occupied = occupied; if (IsActive && occupied != true) { StopController(); if (occupied.HasValue) { _processing.EmptyPaused(); } else { _processing.Unavailable("player presence unavailable"); } } } private void StartController() { _ = ZNet.instance; ZDOMan instance = ZDOMan.instance; if (!WorldServices.Terrain) { StopController(); _processing.Paused("world services unavailable"); return; } if (_world != instance && _controller != null) { StopController(); _processing.Paused("world changed"); } if (_controller == null) { _world = instance; _controller = new WeatherGuardController(this, _logger, _settings.DebugLogging, _settings.DebugLogLevel.Value, _settings.LogWorldCreatedItems.Value, _settings.ProtectRain.Value, _settings.ProtectUnderwater.Value, _settings.ExcludedPrefabs.Value, _players.Presence); _controller.Install(); _processing.Ready(); } } private void StopController() { WeatherGuardController controller = _controller; _controller = null; if (controller != null) { ModuleScheduler.Current.Forget(controller); } _world = null; try { controller?.Dispose(); } finally { WorldObjectProvider.Current?.ReleaseOwner(Name); } } private void PollCoverage(float now) { _coverageNow = now; _coverageRequests.Poll(now, _coverageReport); } private void ReportCoverage() { _adminDiagnostics.Coverage(((_controller != null && _world == ZDOMan.instance && WorldServices.Terrain) ? _controller.Coverage(_coverageNow) : null) ?? new CoverageSnapshot { State = ((!IsActive) ? "module_inactive" : ((_occupied == false) ? "server_empty" : ((!_occupied.HasValue) ? "player_presence_unavailable" : "waiting_for_world"))), RainEnabled = _settings.ProtectRain.Value, UnderwaterEnabled = _settings.ProtectUnderwater.Value }); } internal void Fail(Exception error) { DiagnosticLog.Write(_logger, "WeatherGuard", CoreLogTopics.Lifecycle, "Disabled after controller error; returning pieces to vanilla ownership.", default(LogFields), (LogLevel)2, verbose: false, error); Shutdown(); } public void Shutdown() { IsActive = false; _occupied = null; _processing.Reset(); IDisposable registration = _presenceRegistration; _presenceRegistration = null; ModuleCleanup.Run(_logger, Name, delegate { registration?.Dispose(); }, StopController); } } internal sealed class WeatherGuardController : IDisposable { private readonly WeatherGuard _module; private readonly IPlayerPresence _presence; private readonly ManualLogSource _log; private readonly WeatherGuardDiagnostics _diagnostics; private readonly Action<ZDOID, string?> _confirmedPiece; private readonly bool _protectRain; private readonly bool _protectUnderwater; private readonly HashSet<string> _excludedPrefabs; private float _lastScopeScan = -1f; private bool _scopeLimited; private readonly FieldRef<WearNTear, bool> _rainWet = NativeAccess.Field<WearNTear, bool>("m_rainWet"); private readonly ZDOMan _manager; private readonly WeatherGuardPatches _patches; private readonly List<ZDO> _near = new List<ZDO>(); private readonly List<ZDO> _distant = new List<ZDO>(); private readonly List<ZDO> _scratch = new List<ZDO>(); private readonly List<ZDO> _farScratch = new List<ZDO>(); private readonly HashSet<ZDOID> _nearIds = new HashSet<ZDOID>(); private readonly HashSet<ZDOID> _distantIds = new HashSet<ZDOID>(); private readonly HashSet<ZDOID> _instanceSeen = new HashSet<ZDOID>(); private readonly HashSet<Vector2s> _regions = new HashSet<Vector2s>(); private readonly List<Vector3> _positions = new List<Vector3>(); private readonly Dictionary<ZDOID, ZDO> _protected = new Dictionary<ZDOID, ZDO>(); private readonly Dictionary<Vector2s, bool> _readyContexts = new Dictionary<Vector2s, bool>(); private readonly PrefabCatalog<bool> _contextPrefabs = PrefabRegistry.Current.Catalog<bool>("WeatherGuardController._contextPrefabs"); private readonly List<ZDO> _contextObjects = new List<ZDO>(); private readonly List<ZDOID> _release = new List<ZDOID>(); private readonly Dictionary<string, int> _exclusions = new Dictionary<string, int>(); private readonly Dictionary<string, int> _releaseReasons = new Dictionary<string, int>(); private readonly Dictionary<string, int> _releaseTotals = new Dictionary<string, int>(); private readonly Dictionary<ZDOID, RainEvidence> _rainEvidence = new Dictionary<ZDOID, RainEvidence>(); private readonly HashSet<ZDOID> _managedExposure = new HashSet<ZDOID>(); private readonly HashSet<ZDOID> _eligibleExposure = new HashSet<ZDOID>(); private readonly List<ZDOID> _staleDebug = new List<ZDOID>(); private readonly HashSet<ZDOID> _observedCandidates = new HashSet<ZDOID>(); private readonly Dictionary<ZDOID, string> _candidateReasons = new Dictionary<ZDOID, string>(); private int _rainProbeCursor; private int _exposureProbeCursor; private readonly WeatherGuardExposureTracking _exposure = new WeatherGuardExposureTracking(); private readonly List<ZDO> _eligiblePieces = new List<ZDO>(); private readonly Dictionary<string, int> _playerBiomes = new Dictionary<string, int>(); private bool _candidateScanStarted; private ZDOID _recentPlayerCandidate; private readonly FieldRef<WearNTear, bool> _roof = NativeAccess.Field<WearNTear, bool>("m_haveRoof"); private readonly FieldRef<WearNTear, int> _shield = NativeAccess.Field<WearNTear, int>("m_shieldChangeID"); private readonly FieldRef<WearNTear, float> _rainTimer = NativeAccess.Field<WearNTear, float>("m_rainTimer"); private readonly FieldRef<WearNTear, float> _creationTime = NativeAccess.Field<WearNTear, float>("m_createTime"); private readonly FieldRef<WearNTear, float> _coverTimer = NativeAccess.Field<WearNTear, float>("m_updateCoverTimer"); private readonly Func<WearNTear, float, bool> _shouldUpdate = NativeAccess.Method<Func<WearNTear, float, bool>>(typeof(WearNTear), "ShouldUpdate", new Type[1] { typeof(float) }); private readonly Func<WearNTear, bool> _underWater = NativeAccess.Method<Func<WearNTear, bool>>(typeof(WearNTear), "IsUnderWater", Array.Empty<Type>()); private readonly Func<WearNTear, bool> _canBeRemoved = NativeAccess.Method<Func<WearNTear, bool>>(typeof(WearNTear), "CanBeRemoved", Array.Empty<Type>()); private readonly Func<ZoneSystem, Vector3, bool> _createZones = NativeAccess.Method<Func<ZoneSystem, Vector3, bool>>(typeof(ZoneSystem), "CreateLocalZones", new Type[1] { typeof(Vector3) }); private readonly FieldRef<Piece, long> _creator = NativeAccess.Field<Piece, long>("m_creator"); private readonly FieldRef<Piece, int> _creatorIndex = NativeAccess.Field<Piece, int>("m_creatorPlatformUserIDIndex"); private readonly PrefabCatalog<(string Name, bool Wear, bool Static, bool NoRoofWear, float Health, bool Building, bool Container)> _eligibility = PrefabRegistry.Current.Catalog<(string, bool, bool, bool, float, bool, bool)>("WeatherGuardController._eligibility"); private bool _announced; private int _eligible; private int _waiting; private int _waitingTerrain; private int _waitingObjects; private int _waitingInstance; private long _acquired; private long _released; private long _blockedData; private long _blockedOwner; private long _blockedBroadcast; private long _commands; private long _wearPasses; private long _ownerLosses; private long _weatherGates; private long _wetOpportunities; private long _weatherSuppressedTotal; private long _confirmedPreventions; private readonly Dictionary<string, long> _decisions = new Dictionary<string, long>(); private long _nativeCommands; private long _supportPasses; private int _peers; private int _readyPeers; private int _characterWaits; internal Action<ZDOID, string?> ConfirmedPiece => _confirmedPiece; internal static WeatherGuardController? Active { get; private set; } internal long ServerId => ZDOMan.GetSessionID(); internal bool Running { get { if (Active == this && _module.IsActive && _manager == ZDOMan.instance && (_protectRain || _protectUnderwater)) { return WorldServices.Terrain; } return false; } } public WeatherGuardController(WeatherGuard module, ManualLogSource log, DebugLoggingPolicy debug, DebugLogLevel level, bool logWorldCreated, bool protectRain, bool protectUnderwater, string excludedPrefabs, IPlayerPresence presence) { _confirmedPiece = WeatherDamageSuppressed; _presence = presence; _protectRain = protectRain; _protectUnderwater = protectUnderwater; _excludedPrefabs = WeatherGuardRules.ParseExcludedPrefabs(excludedPrefabs, out var rejected); if (rejected > 0) { DiagnosticLog.Write(log, "WeatherGuard", $"Ignored {rejected} invalid or over-limit prefab exclusions. Review WeatherGuard.ExcludedPrefabs.", (LogLevel)4); } _module = module; _log = log; _diagnostics = new WeatherGuardDiagnostics(log, debug, level, logWorldCreated); _manager = ZDOMan.instance; _patches = new WeatherGuardPatches(); } public void Install() { WorldObjectProvider.CheckLiveInstanceCompatibility(); if (_creator == null || _creatorIndex == null || _rainWet == null || _createZones == null || _roof == null || _shield == null || _rainTimer == null || _coverTimer == null || _creationTime == null || _shouldUpdate == null || _underWater == null || _canBeRemoved == null) { throw new MissingMemberException("WeatherGuard terrain/instance/wear evidence APIs unavailable."); } List<string> list = new List<string>(); foreach (string excludedPrefab in _excludedPrefabs) { if ((Object)(object)PrefabRegistry.Current.Prefab(excludedPrefab) == (Object)null) { list.Add(excludedPrefab); } } if (list.Count > 0) { DiagnosticLog.Write(_log, "WeatherGuard", $"{list.Count} excluded prefab identifiers were not found. Review WeatherGuard.ExcludedPrefabs; matching remains exact.", (LogLevel)4); } Active = this; try { _patches.Install(); } catch { Dispose(); throw; } } internal bool Protects(ZDOID id) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (Running) { return _protected.ContainsKey(id); } return false; } internal void Fail(Exception error) { _module.Fail(error); } internal void OwnerBlocked(ZDO zdo, long requested) { _blockedOwner++; } internal void DataBlocked(int count) { _blockedData += count; } internal void Reassert(ZDOID id, uint revision, ushort ownerRevision) { //IL_0006: 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) if (_protected.TryGetValue(id, out ZDO value) && value.IsValid()) { (uint, ushort) tuple = WeatherGuardRules.ReassertRevisions(value.DataRevision, value.OwnerRevision, revision, ownerRevision); value.DataRevision = tuple.Item1; value.OwnerRevision = tuple.Item2; ZDOMan.instance.ForceSendZDO(id); } } internal void BroadcastBlocked(int count = 1) { _blockedBroadcast += count; } internal void Resend(ZDOID id) { //IL_0006: 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) if (_protected.TryGetValue(id, out ZDO value) && value.IsValid()) { ZDOMan.instance.ForceSendZDO(id); } } internal void CommandRouted() { _commands++; } internal void WearPass() { _wearPasses++; } internal bool SuppressWeather(WearNTear wear, bool native) { if (_protectRain && _protectUnderwater) { return native; } return WeatherGuardRules.SuppressWeatherDamage(native, _protectRain, _protectUnderwater, _rainWet.Invoke(wear), _underWater(wear)); } internal bool WeatherDamageMayApply(WearNTear wear) { int num; if (_canBeRemoved(wear)) { num = ((!ZoneSystem.instance.GetGlobalKey((GlobalKeys)37)) ? 1 : 0); if (num != 0) { goto IL_0057; } } else { num = 0; } if (_diagnostics.StepsEnabled) { _decisions.TryGetValue("native_final_damage_disabled", out var value); _decisions["native_final_damage_disabled"] = value + 1; } goto IL_0057; IL_0057: return (byte)num != 0; } internal string? PiecePrefab(ZDO zdo) { GameObject? obj = PrefabRegistry.Current.Prefab(zdo.GetPrefab()); if (obj == null) { return null; } return ((Object)obj).name; } internal void WeatherDamageSuppressed(ZDOID id, string? prefab = null) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) _confirmedPreventions++; _diagnostics.WeatherDamageSuppressed(id, prefab); } internal void WearConditions(WearNTear wear, float time) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) if (_diagnostics.StepsEnabled) { int num = _shield.Invoke(wear); bool flag = _underWater(wear); string key = ((!_shouldUpdate(wear, time)) ? "waiting_warmup" : (ShieldGenerator.IsInsideShieldCached(((Component)wear).transform.position, ref num) ? "shielded" : ((wear.GetHealthPercentage() <= 0.5f) ? "health_at_or_below_half" : ((!flag && _roof.Invoke(wear)) ? "native_cached_roof_covered" : ((!flag && !EnvMan.IsWet()) ? "native_environment_dry" : ((_rainTimer.Invoke(wear) == 0f) ? "starting_wet_timer" : ((time - _rainTimer.Invoke(wear) <= 60f) ? "waiting_wet_timer" : "native_conditions_met"))))))); _decisions.TryGetValue(key, out var value); _decisions[key] = value + 1; } } internal void WeatherGate(WearNTear wear, bool branchBypassed) { //IL_0058: 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) _weatherGates++; if (branchBypassed) { _weatherSuppressedTotal++; } if (_diagnostics.DebugEnabled) { int num = _shield.Invoke(wear); bool flag = wear.m_noRoofWear && wear.GetHealthPercentage() > 0.5f && !ShieldGenerator.IsInsideShieldCached(((Component)wear).transform.position, ref num) && wear.IsWet(); if (flag) { _wetOpportunities++; } ZDO zDO = ((Component)wear).GetComponent<ZNetView>().GetZDO(); if (flag) { TrackRain(zDO, wear, "eligible"); } if (_rainEvidence.TryGetValue(zDO.m_uid, out RainEvidence value)) { value.ObserveGate(Time.time, flag, branchBypassed); } } } internal WearObservation? BeginWear(WearNTear wear, ZNetView view, bool protectedPiece, float time) { //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Unknown result type (might be due to invalid IL or missing references) if (!_diagnostics.DebugEnabled) { return null; } ZDO zDO = view.GetZDO(); string text = Eligibility(zDO, ZNetScene.instance); if (!protectedPiece && text != "world-created" && text != "eligible") { return null; } if (text == "world-created" && !_diagnostics.LogWorldCreatedItems) { return null; } bool flag = !_roof.Invoke(wear) || _underWater(wear); if (flag) { TrackRain(zDO, wear, text); } if (!_diagnostics.TryWearSample(Time.unscaledTime, ((object)Unsafe.As<ZDOID, ZDOID>(ref zDO.m_uid)/*cast due to .constrained prefix*/).ToString(), protectedPiece, flag)) { return null; } int num = _shield.Invoke(wear); bool flag2 = ShieldGenerator.IsInsideShieldCached(((Component)wear).transform.position, ref num); WearObservation wearObservation = new WearObservation { Identity = Identity(zDO), Protected = protectedPiece, Owner = view.IsOwner(), Warmup = !_shouldUpdate(wear, time), Before = zDO.GetFloat(ZDOVars.s_health, wear.m_health), Fields = new Dictionary<string, object> { ["eligibility"] = text, ["environment_wet"] = EnvMan.IsWet(), ["cached_roof"] = _roof.Invoke(wear), ["shielded"] = flag2, ["underwater"] = _underWater(wear), ["native_health_fraction"] = wear.GetHealthPercentage(), ["removable"] = _canBeRemoved(wear), ["no_building_fall"] = ZoneSystem.instance.GetGlobalKey((GlobalKeys)37) } }; if (_diagnostics.VerboseAfterNormalEnabled) { Dictionary<string, object?> fields = wearObservation.Fields; fields["native_rain_wet"] = _rainWet.Invoke(wear); fields["processor"] = (view.IsOwner() ? "server" : ((zDO.GetOwner() == 0L) ? "none" : "client")); EnvMan instance = EnvMan.instance; fields["server_environment"] = ((instance == null) ? null : instance.GetCurrentEnvironment()?.m_name); GameObject val = default(GameObject); fields["fresh_roof"] = WearNTear.RoofCheck(((Component)wear).transform, ((Component)wear).transform.position, ref val, wear.m_roofCheckOffset); fields["cover_timer_s"] = _coverTimer.Invoke(wear); fields["warmup_remaining_s"] = Math.Max(0f, 30f - (time - _creationTime.Invoke(wear))); fields["maximum_health"] = wear.m_health; fields["native_rain_timer_start_game_s"] = _rainTimer.Invoke(wear); fields["game_time_s"] = time; } return wearObservation; } internal void EndWear(WearNTear wear, WearObservation? observation, Exception? error) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) if (_diagnostics.DebugEnabled) { ZNetView component = ((Component)wear).GetComponent<ZNetView>(); if (_diagnostics.DebugEnabled && (Object)(object)component != (Object)null && component.IsValid() && _rainEvidence.TryGetValue(component.GetZDO().m_uid, out RainEvidence value)) { UpdateRain(component.GetZDO(), wear, value); } if (observation != null) { ZNetView component2 = ((Component)wear).GetComponent<ZNetView>(); float? after = (((Object)(object)component2 != (Object)null && component2.IsValid()) ? new float?(component2.GetZDO().GetFloat(ZDOVars.s_health, wear.m_health)) : ((float?)null)); _diagnostics.Wear(observation, after, error != null, error); } } } internal WearObservation? BeginCommand(WearNTear wear, string method) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) ZNetView component = ((Component)wear).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid() || !Protects(component.GetZDO().m_uid)) { return null; } _nativeCommands++; if (!_diagnostics.ReserveCommand(Time.unscaledTime)) { return null; } ZDO zDO = component.GetZDO(); return new WearObservation { Protected = true, Owner = component.IsOwner(), Identity = Identity(zDO), Fields = new Dictionary<string, object> { ["command"] = method, ["processor"] = (component.IsOwner() ? "server" : "client") }, Before = zDO.GetFloat(ZDOVars.s_health, wear.m_health) }; } internal void EndCommand(WearNTear wear, WearObservation? observation, Exception? error) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) if (_diagnostics.DebugEnabled) { ZNetView component = ((Component)wear).GetComponent<ZNetView>(); if (_diagnostics.DebugEnabled && (Object)(object)component != (Object)null && component.IsValid() && _rainEvidence.TryGetValue(component.GetZDO().m_uid, out RainEvidence value)) { UpdateRain(component.GetZDO(), wear, value); } if (observation != null) { ZNetView component2 = ((Component)wear).GetComponent<ZNetView>(); float? after = (((Object)(object)component2 != (Object)null && component2.IsValid()) ? new float?(component2.GetZDO().GetFloat(ZDOVars.s_health, wear.m_health)) : ((float?)null)); _diagnostics.Command(observation, after, error != null, error); } } } internal void SupportPass(WearNTear wear) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) ZNetView component = ((Component)wear).GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid() && component.IsOwner() && Protects(component.GetZDO().m_uid)) { _supportPasses++; } } private Dictionary<string, object?> Identity(ZDO zdo) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) Dictionary<string, object> obj = new Dictionary<string, object> { ["object"] = ((object)Unsafe.As<ZDOID, ZDOID>(ref zdo.m_uid)/*cast due to .constrained prefix*/).ToString() }; GameObject? obj2 = PrefabRegistry.Current.Prefab(zdo.GetPrefab()); obj["prefab"] = ((obj2 != null) ? ((Object)obj2).name : null); obj["pos"] = zdo.GetPosition(); return obj; } private Dictionary<string, object?> Fields(ZDO zdo, params (string Key, object? Value)[] values) { Dictionary<string, object> dictionary = Identity(zdo); for (int i = 0; i < values.Length; i++) { (string, object) tuple = values[i]; dictionary[tuple.Item1] = tuple.Item2; } return dictionary; } private static string ObservedHealth(ZDO zdo) { float f = zdo.GetFloat(ZDOVars.s_health, float.NaN); if (!float.IsNaN(f)) { return f.ToString(CultureInfo.InvariantCulture); } return "unknown_or_nan"; } private static void Count(Dictionary<string, int> counts, string reason) { counts.TryGetValue(reason, out var value); counts[reason] = value + 1; } private void TrackRain(ZDO zdo, WearNTear wear, string reason) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_004b: 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_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) if ((reason == "world-created" && !_diagnostics.LogWorldCreatedItems) || _rainEvidence.ContainsKey(zdo.m_uid) || (reason != "eligible" && reason != "world-created")) { return; } int num = 0; ZDOID key = ZDOID.None; foreach (KeyValuePair<ZDOID, RainEvidence> item in _rainEvidence) { if (item.Value.Eligibility == reason) { num++; key = item.Key; } } if (num >= 3) { if (reason != "eligible" || zdo.m_uid != _recentPlayerCandidate) { return; } _rainEvidence.Remove(key); } float num2 = zdo.GetFloat(ZDOVars.s_health, wear.m_health); RainEvidence rainEvidence = new RainEvidence { Identity = Identity(zdo), Eligibility = reason, Started = Time.unscaledTime, FirstHealth = num2, MaximumHealth = wear.m_health, Health = num2, MinimumHealth = num2, Owner = zdo.GetOwner(), Protected = Protects(zdo.m_uid), Creator = zdo.GetLong(ZDOVars.s_creator, 0L) }; _rainEvidence.Add(zdo.m_uid, rainEvidence); UpdateRain(zdo, wear, rainEvidence); } private void UpdateRain(ZDO zdo, WearNTear wear, RainEvidence history) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) history.ObserveState(zdo.GetFloat(ZDOVars.s_health, wear.m_health), zdo.GetOwner(), Protects(zdo.m_uid), zdo.GetLong(ZDOVars.s_creator, 0L)); history.ProtectionReason = (history.Protected ? "eligible" : ((history.Eligibility != "eligible") ? history.Eligibility : ((!TerrainReady(zdo, ZoneSystem.instance)) ? "waiting_terrain" : ((!ContextReady(zdo, ZNetScene.instance, ZoneSystem.instance)) ? "waiting_objects" : ((_protected.Count >= 8192) ? "capacity_limit" : "awaiting_acquisition"))))); int num = _shield.Invoke(wear); Dictionary<string, object> obj = new Dictionary<string, object> { ["native_rain_wet"] = _rainWet.Invoke(wear), ["processor"] = ((zdo.GetOwner() == ServerId) ? "server" : ((zdo.GetOwner() == 0L) ? "none" : "client")), ["cached_roof"] = _roof.Invoke(wear), ["cover_timer"] = _coverTimer.Invoke(wear), ["piece_biome"] = Biome(zdo.GetPosition()), ["environment_wet"] = EnvMan.IsWet() }; EnvMan instance = EnvMan.instance; obj["server_environment"] = ((instance == null) ? null : instance.GetCurrentEnvironment()?.m_name); obj["underwater"] = _underWater(wear); obj["shielded"] = ShieldGenerator.IsInsideShieldCached(((Component)wear).transform.position, ref num); obj["health_above_half"] = wear.GetHealthPercentage() > 0.5f; obj["removable"] = _canBeRemoved(wear); obj["no_building_fall"] = ZoneSystem.instance.GetGlobalKey((GlobalKeys)37); obj["warmup"] = !_shouldUpdate(wear, Time.time); obj["warmup_remaining_s"] = Math.Max(0f, 30f - (Time.time - _creationTime.Invoke(wear))); history.Fields = obj; if (history.LastGateTime >= 0f && Time.time - history.LastGateTime > 10f) { history.WetSeconds = 0f; history.LastGateTime = -1f; } } private void RefreshRainEvidence(ZNetScene scene) { //IL_004c: 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_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_028c: Unknown result type (might be due to invalid IL or missing references) //IL_0291: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_035a: Unknown result type (might be due to invalid IL or missing references) //IL_0387: Unknown result type (might be due to invalid IL or missing references) if (!_diagnostics.DebugEnabled) { return; } List<ZDOID> staleDebug = _staleDebug; staleDebug.Clear(); WearNTear wear = default(WearNTear); foreach (KeyValuePair<ZDOID, RainEvidence> pair in _rainEvidence) { ZDO zdo = _manager.GetZDO(pair.Key); if (zdo == null || !zdo.IsValid() || !_nearIds.Contains(pair.Key)) { _diagnostics.Record(Time.unscaledTime, "rain ended", () => (Message: "Rain tracking ended", Fields: new Dictionary<string, object> { ["object"] = ((object)pair.Key/*cast due to .constrained prefix*/).ToString(), ["reason"] = ((zdo == null) ? "missing_world_record" : ((!zdo.IsValid()) ? "invalid_world_record" : "outside_retained_region")), ["last_health"] = pair.Value.Health, ["minimum_health"] = pair.Value.MinimumHealth })); staleDebug.Add(pair.Key); continue; } string currentEligibility = Eligibility(zdo, scene); if (currentEligibility != pair.Value.Eligibility) { _diagnostics.Record(Time.unscaledTime, "rain ended", () => (Message: "Rain tracking role changed", Fields: new Dictionary<string, object> { ["object"] = ((object)pair.Key/*cast due to .constrained prefix*/).ToString(), ["previous_eligibility"] = pair.Value.Eligibility, ["eligibility"] = currentEligibility, ["last_health"] = pair.Value.Health, ["minimum_health"] = pair.Value.MinimumHealth })); staleDebug.Add(pair.Key); continue; } ZNetView val = scene.FindInstance(zdo); if ((Object)(object)val != (Object)null && ((Component)val).TryGetComponent<WearNTear>(ref wear)) { UpdateRain(zdo, wear, pair.Value); continue; } pair.Value.ObserveState(zdo.GetFloat(ZDOVars.s_health, pair.Value.MaximumHealth), zdo.GetOwner(), Protects(zdo.m_uid), zdo.GetLong(ZDOVars.s_creator, 0L)); pair.Value.WetSeconds = 0f; pair.Value.LastGateTime = -1f; pair.Value.ProtectionReason = ((pair.Value.Eligibility == "eligible") ? "waiting_instance" : pair.Value.Eligibility); pair.Value.Fields = new Dictionary<string, object> { ["server_instance"] = false, ["native_conditions"] = null }; } foreach (ZDOID item in staleDebug) { _rainEvidence.Remove(item); } int num = 0; WearNTear val4 = default(WearNTear); GameObject val5 = default(GameObject); for (int num2 = 0; num2 < _near.Count; num2++) { if (num >= 12) { break; } _rainProbeCursor %= _near.Count; ZDO val2 = _near[_rainProbeCursor++]; string text = Eligibility(val2, scene); if (text != "world-created" || !_diagnostics.LogWorldCreatedItems) { continue; } ZNetView val3 = scene.FindInstance(val2); if (!((Object)(object)val3 == (Object)null) && ((Component)val3).TryGetComponent<WearNTear>(ref val4)) { num++; bool flag = WearNTear.RoofCheck(((Component)val4).transform, ((Component)val4).transform.position, ref val5, val4.m_roofCheckOffset); if (!flag) { TrackRain(val2, val4, text); } if (_rainEvidence.TryGetValue(val2.m_uid, out RainEvidence value)) { value.FreshRoof = flag; value.FreshRoofAt = Time.unscaledTime; } } } } private static string Biome(Vector3 position) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) if (WorldGenerator.instance != null) { return ((object)WorldGenerator.instance.GetBiome(position)/*cast due to .constrained prefix*/).ToString(); } return "unknown"; } private void RefreshExposure(ZNetScene scene, float now) { //IL_0039: 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_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) HashSet<ZDOID> managedExposure = _managedExposure; managedExposure.Clear(); _eligibleExposure.Clear(); foreach (ZDO eligiblePiece in _eligiblePieces) { ZNetView val = scene.FindInstance(eligiblePiece); if (Protects(eligiblePiece.m_uid) && (Object)(object)val != (Object)null && val.IsValid() && val.IsOwner()) { managedExposure.Add(eligiblePiece.m_uid); } } foreach (ZDO eligiblePiece2 in _eligiblePieces) { _eligibleExposure.Add(eligiblePiece2.m_uid); } _exposure.Retain(_eligibleExposure, managedExposure); int num = 0; WearNTear val4 = default(WearNTear); GameObject val5 = default(GameObject); for (int i = 0; i < _eligiblePieces.Count; i++) { if (num >= 12) { break; } _exposureProbeCursor %= _eligiblePieces.Count; ZDO val2 = _eligiblePieces[_exposureProbeCursor++]; ZNetView val3 = scene.FindInstance(val2); if (!((Object)(object)val3 == (Object)null) && val3.IsValid() && ContextReady(val2, scene, ZoneSystem.instance) && ((Component)val3).TryGetComponent<WearNTear>(ref val4)) { num++; bool flag = WearNTear.RoofCheck(((Component)val4).transform, ((Component)val4).transform.position, ref val5, val4.m_roofCheckOffset); bool underwater = _underWater(val4); _exposure.Observe(val2.m_uid, flag, underwater, managedExposure.Contains(val2.m_uid), _roof.Invoke(val4), Biome(val2.GetPosition()), now); if (!flag && _diagnostics.DebugEnabled) { TrackRain(val2, val4, "eligible"); } if (_rainEvidence.TryGetValue(val2.m_uid, out RainEvidence value)) { value.FreshRoof = flag; value.FreshRoofAt = now; } } } } public void Tick(float now) { //IL_0351: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_039e: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_03bf: Unknown result type (might be due to invalid IL or missing references) //IL_0429: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_04ca: Unknown result type (might be due to invalid IL or missing references) //IL_04cf: Unknown result type (might be due to invalid IL or missing references) //IL_04d2: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Unknown result type (might be due to invalid IL or missing references) //IL_0277: Unknown result type (might be due to invalid IL or missing references) //IL_0493: Unknown result type (might be due to invalid IL or missing references) //IL_029e: Unknown result type (might be due to invalid IL or missing references) //IL_056b: Unknown result type (might be due to invalid IL or missing references) //IL_0570: Unknown result type (might be due to invalid IL or missing references) //IL_0578: Unknown result type (might be due to invalid IL or missing references) //IL_061c: Unknown result type (might be due to invalid IL or missing references) //IL_0583: Unknown result type (might be due to invalid IL or missing references) //IL_02f0: Unknown result type (might be due to invalid IL or missing references) //IL_05b0: Unknown result type (might be due to invalid IL or missing references) //IL_05b5: Unknown result type (might be due to invalid IL or missing references) //IL_05bd: Unknown result type (might be due to invalid IL or missing references) //IL_06af: Unknown result type (might be due to invalid IL or missing references) //IL_069b: Unknown result type (might be due to invalid IL or missing references) //IL_0654: Unknown result type (might be due to invalid IL or missing references) //IL_0659: Unknown result type (might be due to invalid IL or missing references) //IL_07a2: Unknown result type (might be due to invalid IL or missing references) //IL_06ef: Unknown result type (might be due to invalid IL or missing references) //IL_0717: Unknown result type (might be due to invalid IL or missing references) //IL_071c: Unknown result type (might be due to invalid IL or missing references) //IL_087b: Unknown result type (might be due to invalid IL or missing references) //IL_08dd: Unknown result type (might be due to invalid IL or missing references) _diagnostics.PollPreventionRollup(); if (!ModuleScheduler.Current.Due(this, "processing", now, 1f)) { return; } _eligiblePieces.Clear(); _playerBiomes.Clear(); ZDOMan instance = ZDOMan.instance; ZNetScene instance2 = ZNetScene.instance; ZoneSystem instance3 = ZoneSystem.instance; if (!WorldServices.Terrain) { return; } _near.Clear(); _distant.Clear(); _nearIds.Clear(); _distantIds.Clear(); _regions.Clear(); _positions.Clear(); _readyContexts.Clear(); bool flag = false; _peers = (_readyPeers = (_characterWaits = 0)); _exclusions.Clear(); _releaseReasons.Clear(); for (int i = 0; i < _presence.Peers.Count; i++) { ZNetPeer val = _presence.Peers[i]; _peers++; if (!val.IsReady()) { continue; } _readyPeers++; if (((ZDOID)(ref val.m_characterID)).IsNone()) { _characterWaits++; continue; } ZDO zDO = instance.GetZDO(val.m_characterID); if (zDO == null || !zDO.IsValid() || zDO.GetOwner() != val.m_uid) { _characterWaits++; continue; } Vector3 position = zDO.GetPosition(); if (_diagnostics.StepsEnabled) { Count(_playerBiomes, Biome(position)); } Vector2s zone = ZoneSystem.GetZone(position); if (_regions.Contains(zone)) { continue; } if (_regions.Count >= 8) { flag = true; continue; } _scratch.Clear(); _farScratch.Clear(); WorldObjectProvider.Current.For("WeatherGuard").Query(zone, ZNet.instance.GetSyncedSimulationDistance(), _scratch, _farScratch); if (_near.Count + _distant.Count + _scratch.Count + _farScratch.Count > 32768) { flag = true; continue; } _regions.Add(zone); _positions.Add(position); foreach (ZDO item in _scratch) { if (_nearIds.Add(item.m_uid)) { _near.Add(item); } } foreach (ZDO item2 in _farScratch) { if (_distantIds.Add(item2.m_uid)) { _distant.Add(item2); } } } for (int num = _distant.Count - 1; num >= 0; num--) { if (_nearIds.Contains(_distant[num].m_uid)) { _distant.RemoveAt(num); } } _release.Clear(); foreach (KeyValuePair<ZDOID, ZDO> item3 in _protected) { ZDO zDO2 = instance.GetZDO(item3.Key); string text = ((zDO2 == null || !zDO2.IsValid()) ? "destroyed/invalid" : ((!_nearIds.Contains(item3.Key)) ? "outside retained region" : ((Eligibility(zDO2, instance2) != "eligible") ? Eligibility(zDO2, instance2) : ((!Ready(zDO2, instance2, instance3)) ? "context lost" : "")))); if (text != "") { _release.Add(item3.Key); Count(_releaseReasons, text); Count(_releaseTotals, text); } else if (zDO2.GetOwner() != ServerId) { _ownerLosses++; if (_diagnostics.OptionalEnabled) { RecordOwner(now, zDO2); } ObjectAuthority.Assign(zDO2, ServerId); instance.ForceSendZDO(zDO2.m_uid); } } foreach (ZDOID item4 in _release) { Release(item4); } _eligible = (_waiting = (_waitingTerrain = (_waitingObjects = (_waitingInstance = 0)))); if (_diagnostics.DebugEnabled) { _observedCandidates.IntersectWith(_nearIds); List<ZDOID> staleDebug = _staleDebug; staleDebug.Clear(); foreach (ZDOID key in _candidateReasons.Keys) { if (!_nearIds.Contains(key)) { staleDebug.Add(key); } } foreach (ZDOID item5 in staleDebug) { _candidateReasons.Remove(item5); } } foreach (ZDO item6 in _near) { string text2 = Eligibility(item6, instance2); string value = null; bool flag2 = _diagnostics.DebugEnabled && (!_candidateReasons.TryGetValue(item6.m_uid, out value) || value != text2); if (flag2 && value != null) { if (text2 == "eligible") { _recentPlayerCandidate = item6.m_uid; } if (_diagnostics.OptionalEnabled) { RecordEligibility(now, item6, value, text2); } } if (_diagnostics.DebugEnabled && (text2 != "not a wear piece" || _candidateReasons.ContainsKey(item6.m_uid))) { _candidateReasons[item6.m_uid] = text2; } bool flag3 = false; if (_diagnostics.DebugEnabled && (text2 == "eligible" || text2 == "world-created") && _observedCandidates.Add(item6.m_uid)) { flag3 = true; if (_candidateScanStarted && text2 == "eligible") { _recentPlayerCandidate = item6.m_uid; } if (_diagnostics.OptionalEnabled) { RecordDiscovery(now, item6, text2); } } if (text2 != "eligible") { Count(_exclusions, text2); if (text2 != "not a wear piece" && flag2 && !flag3) { RecordExclusion(now, item6, text2); } continue; } _eligible++; _eligiblePieces.Add(item6); if (_protected.ContainsKey(item6.m_uid)) { continue; } if (_protected.Count >= 8192) { flag = true; continue; } bool flag4 = (Object)(object)instance2.FindInstance(item6) != (Object)null; bool flag5 = TerrainReady(item6, instance3); bool flag6 = flag5 && ContextReady(item6, instance2, instance3); if (!WeatherGuardRules.MayAcquire(flag4, flag5, flag6, withinCapacity: true)) { _waiting++; if (!flag5) { _waitingTerrain++; } if (!flag4) { _waitingInstance++; } if (flag5 && !flag6) { _waitingObjects++; } if (_diagnostics.OptionalEnabled) { RecordContext(now, item6, flag4, flag5, flag6, instance3, instance2); } } else { _protected.Add(item6.m_uid, item6); Piece component = ((Component)instance2.FindInstance(item6)).GetComponent<Piece>(); _creator.Invoke(component) = item6.GetLong(ZDOVars.s_creator, 0L); _creatorIndex.Invoke(component) = item6.GetInt(ZDOVars.s_creatorIndex, -1); ObjectAuthority.Assign(item6, ServerId); instance.ForceSendZDO(item6.m_uid); _acquired++; } } if (_protected.Count > 0 && !_announced) { _announced = true; _diagnostics.InitialAcquisition(_protected.Count); } _diagnostics.CapacityState(flag); _candidateScanStarted |= _near.Count > 0; _lastScopeScan = now; _scopeLimited = flag; if (_diagnostics.StepsEnabled) { RefreshExposure(instance2, now); } RefreshRainEvidence(instance2); if (_diagnostics.SummaryReady(now)) { ReportStatus(now, flag); } } private void RecordOwner(float now, ZDO zdo) { _diagnostics.Record(now, "ownership", () => (Message: "Owner change observed; server ownership reasserted; cause unknown", Fields: Fields(zdo, ("observed_owner", zdo.GetOwner()), ("server_owner", ServerId)))); } private void RecordEligibility(float now, ZDO zdo, string previous, string reason) { _diagnostics.Record(now, "discovery", () => (Message: "Eligibility changed", Fields: Fields(zdo, ("previous_eligibility", previous), ("eligibility", reason)))); } private void RecordDiscovery(float now, ZDO zdo, string reason) { _diagnostics.Record(now, _candidateScanStarted ? "discovery" : "initial discovery", () => (Message: "Structural candidate first observed; creation time unknown", Fields: Fields(zdo, ("eligibility", reason), ("discovery", _candidateScanStarted ? "later_scan" : "initial_scan")))); } private void RecordExclusion(float now, ZDO zdo, string reason) { _diagnostics.Record(now, "eligibility", () => (Message: "Excluded from protection", Fields: Fields(zdo, ("reason", reason), ("stored_health", ObservedHealth(zdo))))); } private void RecordContext(float now, ZDO zdo, bool instanceReady, bool terrainReady, bool objectsReady, ZoneSystem zones, ZNetScene scene) { _diagnostics.Record(now, "context", delegate { Dictionary<string, object> dictionary = Fields(zdo, ("instance_loaded", instanceReady), ("terrain_loaded", terrainReady), ("surrounding_objects_loaded", objectsReady), ("locations_generated", zones.LocationsGenerated)); if (_diagnostics.VerboseAfterNormalEnabled) { foreach (KeyValuePair<string, object> item in ContextBlocker(zdo, scene, zones)) { dictionary[item.Key] = item.Value; } } return (Message: "Waiting for server context", Fields: dictionary); }); } private void ReportStatus(float now, bool limited) { if (!_diagnostics.SummaryReady(now)) { return; } _diagnostics.Report(now, () => new WeatherGuardStatus { RainProtection = _protectRain, UnderwaterProtection = _protectUnderwater, Protected = _protected.Count, Eligible = _eligible, Waiting = _waiting, WaitingTerrain = _waitingTerrain, WaitingInstance = _waitingInstance, WaitingObjects = _waitingObjects, Regions = _regions.Count, Nearby = _near.Count, Distant = _distant.Count, Acquired = _acquired, Released = _released, BlockedData = _blockedData, BlockedOwner = _blockedOwner, BlockedBroadcast = _blockedBroadcast, Commands = _commands, WearPasses = _wearPasses, Limited = limited, Peers = _peers, ReadyPeers = _readyPeers, CharacterWaits = _characterWaits, Exclusions = new Dictionary<string, int>(_exclusions), ReleaseReasons = new Dictionary<string, int>(_releaseReasons), ReleaseTotals = new Dictionary<string, int>(_releaseTotals), OwnerLosses = _ownerLosses, WeatherGates = _weatherGates, WetOpportunities = _wetOpportunities, Decisions = new Dictionary<string, long>(_decisions), WeatherSuppressed = _weatherSuppressedTotal, ConfirmedPreventions = _confirmedPreventions, NativeCommands = _nativeCommands, SupportPasses = _supportPasses }, () => _rainEvidence.Values, ProtectionStatus, delegate { Dictionary<string, object?> dictionary = _exposure.Counts(_eligible, now); dictionary["player_biomes"] = string.Join(",", _playerBiomes.Select<KeyValuePair<string, int>, string>((KeyValuePair<string, int> pair) => pair.Key + ":" + pair.Value)); EnvMan instance = EnvMan.instance; dictionary["server_environment"] = ((instance == null) ? null : instance.GetCurrentEnvironment()?.m_name); dictionary["server_environment_wet"] = EnvMan.IsWet(); dictionary["weather_immune_skipped"] = (_exclusions.TryGetValue("weather immune", out var value) ? value : 0); return dictionary; }); } internal CoverageSnapshot Coverage(float now) { //IL_0167: Unknown result type (might be due to invalid IL or missing references) CoverageSnapshot coverageSnapshot = new CoverageSnapshot { State = ((_regions.Count == 0) ? "no_ready_player_regions" : "ready"), Observed = (_lastScopeScan >= 0f && _regions.Count > 0), ScanAge = ((_lastScopeScan < 0f) ? ((float?)null) : new float?(Math.Max(0f, now - _lastScopeScan))), Regions = _regions.Count, NearbyRecords = _near.Count, DistantRecords = _distant.Count, Limited = _scopeLimited, RainEnabled = _protectRain, UnderwaterEnabled = _protectUnderwater }; if (!coverageSnapshot.Observed) { return coverageSnapshot; } using List<ZDO>.Enumerator enumerator = _near.GetEnumerator(); ZDO current; string text; ZNetView val; bool flag; int num; int num2; bool flag2; bool managed; string waitReason; for (; enumerator.MoveNext(); flag2 = (byte)num2 != 0, managed = flag && flag2 && Protects(current.m_uid) && val.IsOwner(), waitReason = ((num == 0) ? "waiting_terrain" : ((!flag2) ? "waiting_objects" : ((_protected.Count >= 8192) ? "capacity_limit" : "waiting_server_ownership"))), coverageSnapshot.Add(text, managed, flag, waitReason)) { current = enumerator.Current; text = Eligibility(current, ZNetScene.instance); val = ZNetScene.instance.FindInstance(current); flag = (Object)(object)val != (Object)null && val.IsValid(); if (text == "eligible") { num = (TerrainReady(current, ZoneSystem.instance) ? 1 : 0); if (num != 0) { num2 = (ContextReady(current, ZNetScene.instance, ZoneSystem.instance) ? 1 : 0); continue; } } else { num = 0; } num2 = 0; } return coverageSnapshot; } private IEnumerable<ProtectionObservation> ProtectionStatus() { foreach (ZDO item in _near) { string text = Eligibility(item, ZNetScene.instance); if (!(text != "eligible") || !(text != "world-created") || !(text != "excluded_prefab") || !(text != "weather_protection_disabled")) { bool flag = item.GetLong(ZDOVars.s_creator, 0L) == 0; if (!flag || _diagnostics.LogWorldCreatedItems) { bool flag2 = Protects(item.m_uid); string reason = ((text != "eligible") ? text : (flag2 ? "eligible" : (((Object)(object)ZNetScene.instance.FindInstance(item) == (Object)null) ? "waiting_instance" : ((!TerrainReady(item, ZoneSystem.instance)) ? "waiting_terrain" : ((!ContextReady(item, ZNetScene.instance, ZoneSystem.instance)) ? "waiting_objects" : ((_protected.Count >= 8192) ? "capacity_limit" : "awaiting_acquisition")))))); yield return new ProtectionObservation { Identity = Identity(item), Protected = flag2, RainProtection = _protectRain, UnderwaterProtection = _protectUnderwater, Reason = reason, Origin = (flag ? "world_created" : "player_built") }; } } } } private string Eligibility(ZDO zdo, ZNetScene scene) { //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Invalid comparison between Unknown and I4 //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Invalid comparison between Unknown and I4 //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Invalid comparison between Unknown and I4 if (!zdo.IsValid()) { return "invalid world data"; } int prefab = zdo.GetPrefab(); if (!_eligibility.TryGetValue(prefab, out (string, bool, bool, bool, float, bool, bool) value)) { GameObject val = PrefabRegistry.Current.Prefab(prefab); if ((Object)(object)val == (Object)null) { return "missing prefab"; } Piece val2 = PrefabRegistry.Component<Piece>(val); WearNTear val3 = PrefabRegistry.Component<WearNTear>(val); value = (((Object)val).name, (Object)(object)val2 != (Object)null && (Object)(object)val3 != (Object)null, (Object)(object)val3 != (Object)null && val3.m_staticPosition, (Object)(object)val3 != (Object)null && val3.m_noRoofWear, ((Object)(object)val3 != (Object)null) ? val3.m_health : 0f, (Object)(object)val2 != (Object)null && ((int)val2.m_category == 2 || (int)val2.m_category == 3 || (int)val2.m_category == 5), (Object)(object)PrefabRegistry.Component<Container>(val) != (Object)null); if (_eligibility.Count < 4096) { _eligibility[prefab] = value; } } if (!value.Item2) { return "not a wear piece"; } return WeatherGuardRules.SelectionReason(WeatherGuardRules.Exclusion(zdo.GetLong(ZDOVars.s_creator, 0L), zdo.Persistent, value.Item3, value.Item4, zdo.GetFloat(ZDOVars.s_health, value.Item5), value.Item6, value.Item7), value.Item1, _excludedPrefabs, _protectRain, _protectUnderwater); } private Dictionary<string, object?> ContextBlocker(ZDO zdo, ZNetScene scene, ZoneSystem zones) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: 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_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0058: 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_0123: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) Vector2s sector = zdo.GetSector(); for (int i = sector.x - 1; i <= sector.x + 1; i++) { for (int j = sector.y - 1; j <= sector.y + 1; j++) { if (!zones.IsZoneLoaded(new Vector2s(i, j))) { return new Dictionary<string, object> { ["missing_terrain_sector"] = $"{i},{j}" }; } } } List<ZDO> list = new List<ZDO>(); WorldObjectProvider.Current.For("WeatherGuard").Query(sector, new SimulationDistance(1, 0, false), list); foreach (ZDO item in list) { GameObject val = PrefabRegistry.Current.Prefab(item.GetPrefab()); if (val != null && RequiresContext(item, scene) && (Object)(object)scene.FindInstance(item) == (Object)null) { return new Dictionary<string, object> { ["missing_object"] = ((object)Unsafe.As<ZDOID, ZDOID>(ref item.m_uid)/*cast due to .constrained prefix*/).ToString(), ["missing_prefab"] = ((Object)val).name, ["missing_pos"] = item.GetPosition(), ["missing_persistent"] = item.Persistent, ["prefab_colliders"] = PrefabRegistry.Children<Collider>(val, inactive: true).Length, ["prefab_rigidbodies"] = PrefabRegistry.Children<Rigidbody>(val, inactive: true).Length, ["prefab_wear_piece"] = (Object)(object)PrefabRegistry.Component<WearNTear>(val) != (Object)null, ["retained_near"] = _nearIds.Contains(item.m_uid), ["retained_distant"] = _distantIds.Contains(item.m_uid) }; } } return new Dictionary<string, object> { ["missing_dependency"] = "not_found_in_sample" }; } private static bool TerrainReady(ZDO zdo, ZoneSystem zones) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) Vector2s sector = zdo.GetSector(); for (int i = sector.x - 1; i <= sector.x + 1; i++) { for (int j = sector.y - 1; j <= sector.y + 1; j++) { if (!zones.IsZoneLoaded(new Vector2s(i, j))) { return false; } } } return true; } private bool ContextReady(ZDO zdo, ZNetScene scene, ZoneSystem zones) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: 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_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) Vector2s sector = zdo.GetSector(); if (_readyContexts.TryGetValue(sector, out var value)) { return value; } value = TerrainReady(zdo, zones); if (value) { _contextObjects.Clear(); WorldObjectProvider.Current.For("WeatherGuard").Query(sector, new SimulationDistance(1, 0, false), _contextObjects); foreach (ZDO contextObject in _contextObjects) { if (RequiresContext(contextObject, scene) && (Object)(object)scene.FindInstance(contextObject) == (Object)null) { value = false; break; } } } _readyContexts.Add(sector, value); return value; } private bool RequiresContext(ZDO zdo, ZNetScene scene) { int prefab = zdo.GetPrefab(); if (_contextPrefabs.TryGetValue(prefab, out var value)) { return value; } GameObject val = PrefabRegistry.Current.Prefab(prefab); if ((Object)(object)val == (Object)null) { return false; } value = WeatherGuardRules.RequiresContext(PrefabRegistry.Children<Collider>(val, inactive: true).Length, (Object)(object)PrefabRegistry.Component<WearNTear>(val) != (Object)null, (Object)(object)PrefabRegistry.Component<ShieldGenerator>(val) != (Object)null); _contextPrefabs.Add(prefab, value); return value; } private bool Ready(ZDO zdo, ZNetScene scene, ZoneSystem zones) { if ((Object)(object)scene.FindInstance(zdo) != (Object)null) { return ContextReady(zdo, scene, zones); } return false; } internal void LoadTerrain() { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) if (!Running || (Object)(object)ZoneSystem.instance == (Object)null || !ZoneSystem.instance.LocationsGenerated) { return; } float unscaledTime = Time.unscaledTime; if (!ModuleScheduler.Current.Due(this, "terrain", unscaledTime, 0.1f)) { return; } foreach (Vector3 position in _positions) { _createZones(ZoneSystem.instance, position); } } internal void AddInstances(List<ZDO> near, List<ZDO> distant) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) if (!Running) { return; } HashSet<ZDOID> instanceSeen = _instanceSeen; instanceSeen.Clear(); foreach (ZDO item in near) { instanceSeen.Add(item.m_uid); } foreach (ZDO item2 in distant) { instanceSeen.Add(item2.m_uid); } foreach (ZDO item3 in _near) { if (item3.IsValid() && instanceSeen.Add(item3.m_uid)) { near.Add(item3); } } foreach (ZDO item4 in _distant) { if (item4.IsValid() && instanceSeen.Add(item4.m_uid)) { distant.Add(item4); } } WorldObjectProvider.Current.IncludeLiveInstances(near, distant, _positions); } private void Release(ZDOID id) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0017: 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) if (_protected.TryGetValue(id, out ZDO value)) { _protected.Remove(id); if (value.IsValid() && value.GetOwner() == ServerId) { ObjectAuthority.Assign(value, 0L); } if (value.IsValid()) { _manager.ForceSendZDO(id); } _released++; } } public void Dispose() { //IL_00ab: Unknown result type (might be due to invalid IL or missing references) _diagnostics.Dispose(); if (Active == this) { Active = null; } bool flag = true; try { flag = ModuleCleanup.Run(_log, _module.Name, _patches.Dispose); } finally { try { Exception ex = null; int num = 0; foreach (ZDO value in _protected.Values) { try { if (value.IsValid() && _manager == ZDOMan.instance && value.GetOwner() == ServerId) { ObjectAuthority.Assign(value, 0L); _manager.ForceSendZDO(value.m_uid); } } catch (Exception ex2) { flag = false; if (ex == null) { ex = ex2; } num++; } } if (ex != null) { DiagnosticLog.Write(_log, _module.Name, CoreLogTopics.Lifecycle, "Ownership release failed for some pieces; remaining releases attempted.", new(string, object)[1] { ("release_failures", num) }, (LogLevel)2, verbose: false, ex); } } finally { _protected.Clear(); _positions.Clear(); _near.Clear(); _distant.Clear(); _rainEvidence.Clear(); _observedCandidates.Clear(); _contextPrefabs.Clear(); _candidateReasons.Clear(); } } if (!flag) { throw new InvalidOperationException("Controller cleanup did not complete; paused state cannot be confirmed."); } } } public sealed class WeatherGuardCoverageRequests { public const string FileName = "heimkit-weatherguard-coverage.request"; private readonly string _path; private readonly ManualLogSource _logger; private readonly ScheduleToken _nextPoll = new ScheduleToken(); private bool _warned; public WeatherGuardCoverageRequests(string configDirectory, ManualLogSource logger) { _path = Path.Combine(configDirectory, "heimkit-weatherguard-coverage.request"); _logger = logger; } public void Poll(float now, Action report) { if (!_nextPoll.Ready(now)) { return; } _nextPoll.Postpone(now, 1f); try { if (!File.Exists(_path)) { return; } File.Delete(_path); _warned = false; } catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException) { if (!_warned) { _warned = true; DiagnosticLog.Write(_logger, "WeatherGuard", "Could not consume coverage request; correct file access to retry", (LogLevel)4); } return; } try { report(); } catch (Exception error) { DiagnosticLog.Write(_logger, "WeatherGuard", CoreLogTopics.Lifecycle, "Coverage request consumed but report failed; processing state unchanged", default(LogFields), (LogLevel)2, verbose: false, error); } } } internal sealed class WeatherGuardDebugLogLevelValues : AcceptableValueBase { public WeatherGuardDebugLogLevelValues() : base(typeof(DebugLogLevel)) { } public override bool IsValid(object value) { if (value is DebugLogLevel debugLogLevel) { if (debugLogLevel != DebugLogLevel.Medium) { return debugLogLevel == DebugLogLevel.Detailed; } return true; } return false; } public override object Clamp(object value) { if (!((AcceptableValueBase)this).IsValid(value)) { return DebugLogLevel.Detailed; } return value; } public override string ToDescriptionString() { return "# Acceptable values: Medium, Detailed"; } } public sealed class WeatherGuardDiagnostics : FeatureDiagnostics, IDisposable { private readonly ManualLogSource _logger; private readonly HashSet<ZDOID> _prevented = new HashSet<ZDOID>(); private DateTime _windowStart = DiagnosticLog.WallClock(); private long _preventionCount; private ZDOID _singlePiece; private string? _singlePrefab; private readonly Func<bool> _debugEnabled; private readonly DebugLogLevel _level; private readonly HashSet<string> _wearPhases = new HashSet<string>(); public const int MediumSampleLimit = 12; private readonly Dictionary<string, (float Start, HashSet<string> Ids)> _wearStreams = new Dictionary<string, (float, HashSet<string>)>(); private WeatherGuardStatus? _previous; private readonly Dictionary<RainEvidence, (float Health, float Lost, long Bypasses, long Gates)> _reported = new Dictionary<RainEvidence, (float, float, long, long)>(); private float _lastSummary; private bool _capacityLimited; public const int SampleLimit = 6; public const int WearSampleLimit = 3; internal bool LogWorldCreatedItems { get; } private bool Enabled => base.DiagnosticsEnabled; internal bool StepsEnabled => Enabled; internal bool DebugEnabled { get { if (Enabled) { return _level == DebugLogLevel.Detailed; } return false; } } private (float Health, float Lost, long Bypasses, long Gates) Previous(RainEvidence watch) { if (!_reported.TryGetValue(watch, out (float, float, long, long) value)) { return (Health: watch.FirstHealth, Lost: 0f, Bypasses: 0L, Gates: 0L); } return value; } public WeatherGuardDiagnostics(ManualLogSource logger, bool debug, DebugLogLevel level = DebugLogLevel.Detailed, bool logWorldCreated = true) : this(logger, () => debug, level, logWorldCreated) { } public WeatherGuardDiagnostics(ManualLogSource logger, DebugLoggingPolicy policy, DebugLogLevel level, bool logWorldCreated) : this(logger, () => policy.Enabled, level, logWorldCreated) { } private WeatherGuardDiagnostics(ManualLogSource logger, Func<bool> debugEnabled, DebugLogLevel level, bool logWorldCreated) { _logger = logger; _debugEnabled = debugEnabled; ConfigureDiagnostics(debugEnabled, logger, "WeatherGuard"); _level = level; LogWorldCreatedItems = logWorldCreated; } private void Write(LogTopic topic, string result, Dictionary<string, object?> fields, LogLevel level = (LogLevel)32, Exception? error = null) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Invalid comparison between Unknown and I4 //IL_0034: Unknown result type (might be due to invalid IL or missing references) if ((int)level != 32 || base.DiagnosticsEnabled) { LogFields logFields = fields; int num = ((error == null) ? 8 : 5); DiagnosticLog.Write(_logger, "WeatherGuard", topic, result, logFields.Take(num), level, verbose: false, error); if (base.VerboseEnabled && fields.Count > num) { DiagnosticLog.Write(_logger, "WeatherGuard", topic, Subject(fields, "Additional evidence"), logFields.Skip(num), (LogLevel)32, verbose: true); } } } private static string Subject(Dictionary<string, object?> fields, string evidence) { object value; object obj = (fields.TryGetValue("object", out value) ? value : null); object obj2 = (fields.TryGetValue("prefab", out value) ? value : null); if (obj != null) { if (obj2 != null) { return $"{evidence} for {obj2} (piece {obj})."; } return $"{evidence} for piece {obj}."; } return evidence + " for the preceding record."; } public static void StartupSettings(ManualLogSource logger, WeatherGuardSettings settings) { if (settings.DebugLogging.Enabled && settings.DebugLogLevel.Value == DebugLogLevel.Detailed) { if (DiagnosticLog.DebugAvailable(logger, "WeatherGuard")) { DiagnosticLog.Write(logger, "WeatherGuard", CoreLogTopics.Config, "Loaded settings and processing limits.", new LogField[8] { DiagnosticLog.FieldAlways("rain_protection_enabled", settings.ProtectRain.Value), DiagnosticLog.FieldAlways("underwater_protection_enabled", settings.ProtectUnderwater.Value), (Key: "excluded_prefabs", Value: settings.ExcludedPrefabs.Value), (Key: "debug_log_level", Value: settings.DebugLogLevel.Value), DiagnosticLog.FieldAlways("log_world_created_items", settings.LogWorldCreatedItems.Value), (Key: "maximum_regions", Value: 8), (Key: "maximum_objects", Value: 32768), (Key: "maximum_protected", Value: 8192) }, (LogLevel)32); } if (DiagnosticLog.VerboseConfigured && DiagnosticLog.DebugAvailable(logger, "WeatherGuard", verbose: true)) { DiagnosticLog.Write(logger, "WeatherGuard", CoreLogTopics.Config, "Additional evidence for the loaded settings and processing limits.", new(string, object)[6] { ("roof_check_max_age_s", 30), ("roof_probe_limit_per_scan", 12), ("native_wet_timer_threshold_game_s", 60), ("native_weather_damage_percent", 5), ("scope", "eligible_player_built_pieces_in_retained_regions"), ("wetness_source", "server_environment_not_player_local_weather") }, (LogLevel)32, verbose: true); } } } public void CapacityState(bool limited) { if (limited != _capacityLimited) { _capacityLimited = limited; DiagnosticLog.Write(_logger, "WeatherGuard", limited ? "Processing capacity reached. Unmanaged pieces retain vanilla processing; see debug status." : "Processing capacity limit cleared.", (LogLevel)(limited ? 4 : 16)); } } public void WeatherDamageSuppressed(ZDOID id, string? prefab = null) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0049: 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) PollPreventionRollup(); if (!_prevented.Contains(id)) { if (_prevented.Count < 8192) { _prevented.Add(id); } if (_preventionCount++ == 0L) { _singlePiece = id; _singlePrefab = prefab; } } } public void PollPreventionRollup() { DateTime dateTime = DiagnosticLog.WallClock(); if (dateTime < _windowStart) { FlushPreventions(); _windowStart = dateTime; } else if (!(dateTime - _windowStart < TimeSpan.FromMinutes(10.0))) { FlushPreventions(partial: false); long num = (dateTime - _windowStart).Ticks / TimeSpan.FromMinutes(10.0).Ticks; _windowStart = _windowStart.AddTicks(num * TimeSpan.FromMinutes(10.0).Ticks); } } public unsafe void FlushPreventions(bool partial = true) { //IL_00e6: 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_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_002a: 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) if (_preventionCount > 0) { string text; if (_preventionCount == 1) { if (string.IsNullOrEmpty(_singlePrefab)) { ZDOID singlePiece = _singlePiece; text = "piece " + ((object)(*(ZDOID*)(&singlePiece))/*cast due to .constrained prefix*/).ToString(); } else { string? singlePrefab = _singlePrefab; ZDOID singlePiece = _singlePiece; text = singlePrefab + " (piece " + ((object)(*(ZDOID*)(&singlePiece))/*cast due to .constrained prefix*/).ToString() + ")"; } } else { text = _preventionCount + " pieces"; } string text2 = text; string text3 = (partial ? (" since " + _windowStart.ToString("HH:mm", CultureInfo.InvariantCulture)) : " in the last 10 minutes"); DiagnosticLog.Write(_logger, "WeatherGuard", "Prevented weather damage to " + text2 + text3 + ".", (LogLevel)16); } _preventionCount = 0L; _prevented.Clear(); _singlePiece = ZDOID.None; _singlePrefab = null; } public void InitialAcquisition(int protectedCount) { if (Enabled) { Write(WeatherGuardLogTopics.Protection, "Acquired initial protection for eligible pieces.", new Dictionary<string, object> { ["protected"] = protectedCount }, (LogLevel)32); } } private static string Counts(Dictionary<string, int> counts) { return string.Join(",", from p in counts orderby p.Key select $"{p.Key}:{p.Value}"); } private static string ReleaseChanges(Dictionary<string, int> current, Dictionary<string, int> previous) { Dictionary<string, int> dictionary = new Dictionary<string, int>(); foreach (KeyValuePair<string, int> item in current) { previous.TryGetValue(item.Key, out var value); int num = Math.Max(0, item.Value - value); if (num > 0) { dictionary[item.Key] = num; } } return Counts(dictionary); } private static long Delta(long current, long previous) { return Math.Max(0L, current - previous); } public void Report(float now, Func<WeatherGuardStatus> snapshot, Func<IEnumerable<RainEvidence>>? rain = null, Func<IEnumerable<ProtectionObservation>>? protection = null, Func<Dictionary<string, object?>>? exposure = null) { if (!Enabled || !_budget.Reserve(now, "summary", 1, countOmitted: false)) { return; } WeatherGuardStatus weatherGuardStatus = snapshot(); WeatherGuardStatus weatherGuardStatus2 = _previous ?? new WeatherGuardStatus(); Dictionary<string, object> fields = new Dictionary<string, object> { ["eligible"] = weatherGuardStatus.Eligible, ["managed"] = weatherGuardStatus.Protected, ["waiting"] = weatherGuardStatus.Waiting, ["wear_calls"] = Delta(weatherGuardStatus.WearPasses, weatherGuardStatus2.WearPasses), ["native_weather_due"] = Delta(weatherGuardStatus.WeatherGates, weatherGuardStatus2.WeatherGates), ["weather_contributions_removed"] = Delta(weatherGuardStatus.WeatherSuppressed, weatherGuardStatus2.WeatherSuppressed), ["confirmed_preventions"] = Delta(weatherGuardStatus.ConfirmedPreventions, weatherGuardStatus2.ConfirmedPreventions) }; Write(CoreLogTopics.Scope, "Observed the protection path in the last minute.", fields, (LogLevel)32); if (base.VerboseEnabled) { Dictionary<string, object> dictionary = new Dictionary<string, object>(); foreach (KeyValuePair<string, long> decision in weatherGuardStatus.Decisions) { weatherGuardStatus2.Decisions.TryGetValue(decision.Key, out var value); dictionary[decision.Key] = Delta(decision.Value, value); } if (exposure != null) { foreach (KeyValuePair<string, object> item in exposure()) { dictionary[item.Key] = item.Value; } } if (_level == DebugLogLevel.Detailed) { dictionary["waiting_terrain"] = weatherGuardStatus.WaitingTerrain; dictionary["waiting_instance"] = weatherGuardStatus.WaitingInstance; dictionary["waiting_objects"] = weatherGuardStatus.WaitingObjects; dictionary["ready_players"] = weatherGuardStatus.ReadyPeers; dictionary["waiting_character"] = weatherGuardStatus.CharacterWaits; dictionary["exclusions"] = Counts(weatherGuardStatus.Exclusions); dictionary["capacity_limited"] = weatherGuardStatus.Limited; dictionary["omitted_messages"] = _budget.TakeOmitted(); } DiagnosticLog.Write(_logger, "WeatherGuard", CoreLogTopics.Scope, "Observed supporting protection evidence in the last minute.", dictionary, (LogLevel)32, verbose: true); } if (_level == DebugLogLevel.Medium) { _previous = weatherGuardStatus; _lastSummary = now; return; } RainEvidence[] array = rain?.Invoke().Take(6).ToArray() ?? Array.Empty<RainEvidence>(); if (Enabled) { Write(WeatherGuardLogTopics.Protection, "Observed protection and network activity in the last minute.", new Dictionary<string, object> { ["acquired"] = Delta(weatherGuardStatus.Acquired, weatherGuardStatus2.Acquired), ["released"] = Delta(weatherGuardStatus.Released, weatherGuardStatus2.Released), ["release_reasons"] = ReleaseChanges(weatherGuardStatus.ReleaseTotals, weatherGuardStatus2.ReleaseTotals), ["support_passes"] = Delta(weatherGuardStatus.SupportPasses, weatherGuardStatus2.SupportPasses), ["native_commands"] = Delta(weatherGuardStatus.NativeCommands, weatherGuardStatus2.NativeCommands), ["blocked_client_records"] = Delta(weatherGuardStatus.BlockedData, weatherGuardStatus2.BlockedData), ["prevented_transfers"] = Delta(weatherGuardStatus.BlockedOwner, weatherGuardStatus2.BlockedOwner), ["owner_losses"] = Delta(weatherGuardStatus.OwnerLosses, weatherGuardStatus2.OwnerLosses) }, (LogLevel)32); } if (base.VerboseEnabled) { DiagnosticLog.Write(_logger, "WeatherGuard", WeatherGuardLogTopics.Ownership, "Observed supporting ownership and network evidence in the last minute.", new(string, object)[10] { ("interval_s", (_previous == null) ? 0f : Math.Max(0f, now - _lastSummary)), ("blocked_broadcasts", Delta(weatherGuardStatus.BlockedBroadcast, weatherGuardStatus2.BlockedBroadcast)), ("routed_commands", Delta(weatherGuardStatus.Commands, weatherGuardStatus2.Commands)), ("lifetime_release_reasons", Counts(weatherGuardStatus.ReleaseTotals)), ("lifetime_acquired", weatherGuardStatus.Acquired), ("lifetime_released", weatherGuardStatus.Released), ("lifetime_native_weather_due", weatherGuardStatus.WeatherGates), ("regions", weatherGuardStatus.Regions), ("nearby_records", weatherGuardStatus.Nearby), ("distant_records", weatherGuardStatus.Distant) }, (LogLevel)32, verbose: true); } RainEvidence[] array2 = array; foreach (RainEvidence watch in array2) { Rain(now, watch); } _reported.Clear(); array2 = array; foreach (RainEvidence rainEvidence in array2) { _reported[rainEvidence] = (rainEvidence.Health, rainEvidence.HealthLost, rainEvidence.WeatherBypasses, rainEvidence.Gates); } _previous = weatherGuardStatus; _lastSummary = now; } private static bool Flag(Dictionary<string, object?> fields, string key) { bool flag = default(bool); int num; if (fields.TryGetValue(key, out object value)) { if (value is bool) { flag = (bool)value; num = 1; } else { num = 0; } } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } private static string Blockers(Dictionary<string, object?> fields, bool owner, bool warmup) { List<string> list = new List<string>(); if (!owner) { list.Add("not_server_processed"); } if (warmup) { list.Add("warmup"); } if (!fields.ContainsKey("environment_wet")) { list.Add("conditions_unknown"); } else if (!Flag(fields, "environment_wet") && !Flag(fields, "underwater")) { list.Add("server_environment_dry"); } if (Flag(fields, "cached_roof") && !Flag(fields, "underwater")) { list.Add((Flag(fields, "roof_cache_disagrees") || (fields.TryGetValue("fresh_roof", out object value) && value is bool && !(bool)value)) ? "native_roof_cache_disagrees_with_geometry" : "covered"); } if (Flag(fields, "shielded")) { list.Add("shielded"); } if (fields.ContainsKey("health_above_half") && !Flag(fields, "health_above_half")) { list.Add("health_at_or_below_half"); } if (fields.TryGetValue("native_health_fraction", out object value2) && value2 is float num && num <= 0.5f) { list.Add("health_at_or_below_half"); } if (fields.ContainsKey("removable") && !Flag(fields, "removable")) { list.Add("not_removable"); } if (Flag(fields, "no_building_fall")) { list.Add("no_building_fall"); } if (list.Count != 0) { return string.Join(",", list); } return "none"; } private void Rain(float now, RainEvidence watch) { (float, float, long, long) tuple = Previous(watch); if (!(watch.HealthLost <= tuple.Item2) && Enabled) { Dictionary<string, object> fields = new Dictionary<string, object>(watch.Identity) { ["managed"] = watch.Protected, ["health_before"] = tuple.Item1, ["health_after"] = DiagnosticLog.Kept(watch.Health), ["health_lost"] = watch.HealthLost - tuple.Item2, ["weather_cause"] = "unconfirmed" }; Write(WeatherGuardLogTopics.Rain, "Observed health loss since the previous sample; weather cause is unconfirmed.", fields, (LogLevel)32); if (base.VerboseEnabled) { DiagnosticLog.Write(_logger, "WeatherGuard", WeatherGuardLogTopics.Rain, Subject(watch.Identity, "Rain and health evidence since the previous sample"), new(string, object)[6] { ("eligibility", watch.Eligibility), ("health_minimum", watch.MinimumHealth), ("weather_contributions_due", Delta(watch.Gates, tuple.Item4)), ("weather_contributions_removed", Delta(watch.WeatherBypasses, tuple.Item3)), ("lifetime_owner_changes_observed", watch.OwnerChanges), ("lifetime_management_changes_observed", watch.ProtectionChanges) }, (LogLevel)32, verbose: true); } } } public void Sample(float now, Func<string> describe) { Sample(now, "acquisition", describe); } public void Sample(float now, string stream, Func<string> describe) { if (DebugEnabled) { SampleEnabled(now, stream, describe); } } private void SampleEnabled(float now, string stream, Func<string> describe) { Record(now, stream, () => (Message: describe(), Fields: new Dictionary<string, object>())); } public void Record(float now, string stream, Func<(string Message, Dictionary<string, object?> Fields)> describe) { if (!DebugEnabled) { return; } string stream2 = ((stream == "acquisition" || stream == "ownership") ? "protection_samples" : ((stream.Contains("discovery") || stream == "eligibility" || stream == "rain ended") ? "discovery_samples" : "evidence_samples")); LogTopic topic = ((stream == "ownership") ? WeatherGuardLogTopics.Ownership : (stream.StartsWith("rain", StringComparison.Ordinal) ? WeatherGuardLogTopics.Rain : WeatherGuardLogTopics.Protection)); if (_budget.Reserve(now, stream2, 6)) { (string, Dictionary<string, object>) tuple = describe(); Dictionary<string, object> item = tuple.Item2; object value; object value2; object obj = (item.TryGetValue("eligibility", out value) ? value : (item.TryGetValue("reason", out value2) ? value2 : null)); if ((!stream.Contains("discovery") && !(stream == "eligibility")) || obj == null || object.Equals(obj, "eligible") || (LogWorldCreatedItems && object.Equals(obj, "world-created"))) { Write(topic, tuple.Item1, item, (LogLevel)32); } } } public bool ReserveCommand(float now) { if (DebugEnabled) { return _budget.Reserve(now, "native_commands", 6); } return false; } public void Command(WearObservation observation, float? after, bool failed, Exception? error = null) { if (DebugEnabled || failed) { object value; string text = (observation.Fields.TryGetValue("command", out value) ? ((value as string) ?? "") : ""); string text2 = text switch { "RPC_Remove" => "removal handler", "RPC_Repair" => "repair handler", "RPC_Damage" => "damage handler", _ => "receiver", }; Dictionary<string, object> fields = new Dictionary<string, object>(observation.Identity) { ["command"] = text, ["health_before"] = DiagnosticLog.Kept(observation.Before), ["health_after"] = (after.HasValue ? DiagnosticLog.Kept(after.Value) : "unavailable"), ["protection"] = (observation.Protected ? "active" : "unknown"), ["weather_damage"] = "unconfirmed", ["object_available_after"] = after.HasValue }; Write(WeatherGuardLogTopics.Wear, failed ? ("Native " + text2 + " raised an exception.") : ("Native " + text2 + " ran on a protected piece; its health outcome was observed."), fields, (LogLevel)(failed ? 2 : 32), error); if (base.VerboseEnabled) { Dictionary<string, object> dictionary = new Dictionary<string, object>(observation.Fields) { ["action"] = (failed ? "native_command_failed" : "native_command_executed"), ["health_change"] = ((!after.HasValue) ? "unavailable" : ((after.Value < observation.Before) ? "loss_observed" : ((after.Value > observation.Before) ? "increase_observed" : "unchanged"))), ["damage_context"] = "native_command" }; dictionary.Remove("command"); DiagnosticLog.Write(_logger, "WeatherGuard", WeatherGuardLogTopics.Wear, Subject(observation.Identity, "Native command evidence"), dictionary, (LogLevel)32, verbose: true); } } } public bool TryWearSample(float now, string id, bool protectedPiece, bool exposed = false) { if (!DebugEnabled) { return false; } string key = $"{protectedPiece}:{exposed}"; if (!_wearStreams.TryGetValue(key, out (float, HashSet<string>) value) || now < value.Item1 || now - value.Item1 >= 60f) { value = (now, new HashSet<string>()); } if (value.Item2.Count >= 3 || !value.Item2.Add(id)) { return false; } _wearStreams[key] = value; return _budget.Reserve(now, "evidence_samples", 6); } public void Wear(WearObservation observation, float? after, bool failed, Exception? error = null) { if (!DebugEnabled && !failed) { return; } string text = Blockers(observation.Fields, observation.Owner, observation.Warmup); string item = text + ":" + observation.GateReached + ":" + observation.Suppressed; bool flag = after.HasValue && after.Value < observation.Before; if (failed || flag || _wearPhases.Add(item)) { observation.Fields.TryGetValue("eligibility", out object value); Dictionary<string, object> fields = new Dictionary<string, object>(observation.Identity) { ["blockers"] = text, ["protection"] = (observation.Protected ? "active" : (object.Equals(value, "eligible") ? "waiting" : "excluded")), ["health_before"] = DiagnosticLog.Kept(observation.Before), ["health_after"] = (after.HasValue ? DiagnosticLog.Kept(after.Value) : null), ["weather_damage"] = "unconfirmed" }; string result = (failed ? "Native wear calculation failed." : ((!observation.Owner) ? "Wear calculation remained with another owner or was unassigned." : (observation.Warmup ? "Native wear calculation waited for loading warmup." : ((!observation.GateReached) ? "Native weather contribution was not due." : (observation.Suppressed ? "Removed a due native weather contribution; its health outcome was observed." : "Allowed a due native weather contribution; its health outcome was observed."))))); Write(WeatherGuardLogTopics.Wear, result, fields, (LogLevel)(failed ? 2 : 32), error); if (base.VerboseEnabled) { Dictionary<string, object> dictionary = new Dictionary<string, object>(observation.Fields) { ["condition_source"] = "server_instance", ["protection_reason"] = (observation.Protected ? "eligible" : (object.Equals(value, "eligible") ? "not_acquired" : value)), ["action"] = (observation.Suppressed ? "weather_contribution_suppressed" : ((!observation.Owner) ? "left_to_native_owner" : ((!observation.GateReached) ? "weather_contribution_not_due" : "native_weather_contribution_allowed"))), ["health_change"] = ((!after.HasValue) ? "unavailable" : ((after.Value < observation.Before) ? "loss_observed" : ((after.Value > observation.Before) ? "increase_observed" : "unchanged"))), ["damage_source"] = "unobserved", ["managed"] = observation.Protected, ["warmup"] = observation.Warmup, ["native_weather_contribution_due"] = observation.GateReached, ["weather_contribution_suppressed"] = observation.Suppressed }; DiagnosticLog.Write(_logger, "WeatherGuard", WeatherGuardLogTopics.Wear, Subject(observation.Identity, "Native wear evidence"), dictionary, (LogLevel)32, verbose: true); } } } public void Coverage(CoverageSnapshot s) { string text = (s.Observed ? ($"Eligible {s.Eligible}, protected {s.Protected}, waiting {s.Waiting}, skipped {s.Skipped}, unloaded eligible {s.UnloadedEligible}. " + "Skip reasons: " + Counts(s.SkipReasons) + ". Wait reasons: " + Counts(s.WaitReasons) + ". ") : "Eligible, protected, waiting and skipped counts are unknown. "); DiagnosticLog.Write(_logger, "WeatherGuard", "Requested coverage report (" + s.State + "): " + text + $"Scope: retained nearby ready-player regions; observed {s.Observed}; scan age {DiagnosticLog.Value(s.ScanAge)} seconds; " + $"regions {s.Regions}, nearby records {s.NearbyRecords}, distant records unevaluated {s.DistantRecords}; capacity limited {s.Limited}. " + $"Rain protection {s.RainEnabled}; underwater protection {s.UnderwaterEnabled}. " + "The rest of the world is unobserved; weather-damage prevention is not verified.", (LogLevel)16); } public void Dispose() { Reset(); } public void Reset() { FlushPreventions(); _windowStart = DiagnosticLog.WallClock(); _capacityLimited = false; _budget.Reset(); _wearStreams.Clear(); _previous = null; _reported.Clear(); _wearPhases.Clear(); _lastSummary = 0f; } } public sealed class WeatherGuardExposureTracking { public const int MaximumObservationAgeSeconds = 30; public const int ProbeLimitPerScan = 12; private readonly Dictionary<ZDOID, (bool Roof, bool Water, bool Managed, bool CachedRoof, string Biome, float At)> _observed = new Dictionary<ZDOID, (bool, bool, bool, bool, string, float)>(); private readonly List<ZDOID> _remove = new List<ZDOID>(); public void Retain(HashSet<ZDOID> eligible, HashSet<ZDOID> managed) { //IL_0029: 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_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0080: 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_009c: 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) _remove.Clear(); foreach (KeyValuePair<ZDOID, (bool, bool, bool, bool, string, float)> item in _observed) { _remove.Add(item.Key); } foreach (ZDOID item2 in _remove) { if (!eligible.Contains(item2)) { _observed.Remove(item2); continue; } (bool, bool, bool, bool, string, float) value = _observed[item2]; value.Item3 = managed.Contains(item2); _observed[item2] = value; } } public void Observe(ZDOID id, bool roof, bool underwater, bool managed, bool cachedRoof, string biome, float now) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) _observed[id] = (roof, underwater, managed, cachedRoof, biome, now); } public Dictionary<string, object?> Counts(int eligible, float now) { (bool, bool, bool, bool, string, float)[] array = _observed.Values.Where<(bool, bool, bool, bool, string, float)>(((bool Roof, bool Water, bool Managed, bool CachedRoof, string Biome, float At) item) => now >= item.At && now - item.At <= 30f).ToArray(); return new Dictionary<string, object> { ["roof_sample_size"] = array.Length, ["roof_unchecked_or_stale"] = Math.Max(0, eligible - array.Length), ["roof_sample_covered"] = array.Count(((bool Roof, bool Water, bool Managed, bool CachedRoof, string Biome, float At) item) => item.Roof), ["roof_sample_exposed"] = array.Count(((bool Roof, bool Water, bool Managed, bool CachedRoof, string Biome, float At) item) => !item.Roof), ["roof_sample_exposed_managed"] = array.Count(((bool Roof, bool Water, bool Managed, bool CachedRoof, string Biome, float At) item) => !item.Roof && item.Managed), ["roof_sample_exposed_waiting"] = array.Count(((bool Roof, bool Water, bool Managed, bool CachedRoof, string Biome, float At) item) => !item.Roof && !item.Managed), ["roof_sample_underwater"] = array.Count(((bool Roof, bool Water, bool Managed, bool CachedRoof, string Biome, float At) item) => item.Water), ["roof_sample_cache_disagreements"] = array.Count(((bool Roof, bool Water, bool Managed, bool CachedRoof, string Biome, float At) item) => item.Roof != item.CachedRoof), ["roof_sample_biomes"] = string.Join(",", from item in array group item by item.Biome into @group orderby @group.Key select @group.Key + ":" + @group.Count()), ["roof_sample_oldest_check_age_s"] = ((array.Length == 0) ? ((float?)null) : new float?(array.Max(((bool Roof, bool Water, bool Managed, bool CachedRoof, string Biome, float At) item) => now - item.At))) }; } } public static class WeatherGuardLogTopics { public static readonly LogTopic Protection = new LogTopic("protection"); public static readonly LogTopic Ownership = new LogTopic("ownership");