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 TerramizerServer v0.4.7
plugins/TerramizerServer/TerramizerServer.dll
Decompiled 12 hours 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.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("TerramizerServer")] [assembly: AssemblyFileVersion("0.4.7")] [assembly: AssemblyCompany("R4V9N1")] [assembly: AssemblyDescription("Created by R4V9N1")] [assembly: AssemblyProduct("TerramizerServer")] [assembly: AssemblyCopyright("Created by R4V9N1")] [assembly: AssemblyMetadata("Creator", "Created by R4V9N1")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("0.4.7.0")] namespace TerramizerServer; [BepInPlugin("r4v9n1.terramizerserver", "TerramizerServer", "0.4.7")] public sealed class TerramizerServerPlugin : BaseUnityPlugin { private struct PeerMotionSample { public Vector3 Position; public Vector3 Velocity; public float Time; public PeerMotionSample(Vector3 position, Vector3 velocity, float time) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) Position = position; Velocity = velocity; Time = time; } } private struct PeerStreamingState { public bool HasZone; public Vector2i CurrentZone; public Vector2i PredictedZone; public float NextBoostTime; } private delegate void CreateObjectsDelegate(ZNetScene scene, List<ZDO> currentObjects, List<ZDO> distantObjects); private delegate void RemoveObjectsDelegate(ZNetScene scene, List<ZDO> currentObjects, List<ZDO> distantObjects); private delegate bool CreateLocalZonesDelegate(ZoneSystem zoneSystem, Vector3 refPoint); private delegate void WearNTearRemoveRpcDelegate(WearNTear instance, long sender, bool blockDrop); public const string PluginGuid = "r4v9n1.terramizerserver"; public const string PluginName = "TerramizerServer"; public const string PluginVersion = "0.4.7"; public const string CreatorCredit = "Created by R4V9N1"; internal const int VanillaMaxSendQueueBytes = 10240; internal const int VanillaMinFreeSendQueueBytes = 2048; internal const float VanillaPeerSendIntervalSeconds = 0.05f; private static ConfigEntry<bool> _enabled; private static ConfigEntry<bool> _serverOnly; private static ConfigEntry<bool> _dedicatedOnly; private static ConfigEntry<int> _safetyDefaultsVersion; private static ConfigEntry<int> _maxSendQueueBytes; private static ConfigEntry<int> _minFreeSendQueueBytes; private static ConfigEntry<float> _peerSendIntervalSeconds; private static ConfigEntry<bool> _enableServerZoneStreamingBoost; private static ConfigEntry<int> _zoneStreamingBoostExtraRadius; private static ConfigEntry<int> _maxZoneStreamingBoostZdosPerPeer; private static ConfigEntry<float> _zoneStreamingBoostCooldownSeconds; private static ConfigEntry<int> _zoneStreamingBoostMaxQueuePercent; private static ConfigEntry<bool> _zoneStreamingBoostIncludeDistantZdos; private static ConfigEntry<bool> _logZoneStreamingBoosts; private static ConfigEntry<bool> _logDenseSyncs; private static ConfigEntry<int> _denseSyncThreshold; private static ConfigEntry<float> _denseSyncLogIntervalSeconds; private static ConfigEntry<bool> _pauseExtraStreamingDuringDenseSync; private static ConfigEntry<float> _denseSyncPauseSeconds; private static ConfigEntry<int> _extendedZoneRadius; private static ConfigEntry<float> _createDestroyIntervalSeconds; private static ConfigEntry<float> _removeObjectsIntervalSeconds; private static ConfigEntry<bool> _enablePredictiveZoneStreaming; private static ConfigEntry<float> _predictionLookaheadSec; private static ConfigEntry<float> _predictionMinVelocity; private static ConfigEntry<int> _predictionMaxLookaheadZones; private static ConfigEntry<bool> _enableZDOThrottling; private static ConfigEntry<float> _zdoThrottleDistance; private static ConfigEntry<bool> _enablePlayerPriority; private static ConfigEntry<bool> _enablePeerZoneCreation; private static ConfigEntry<float> _peerZoneUpdateIntervalSeconds; private static ConfigEntry<int> _maxPeerZoneCreationsPerPass; private static ConfigEntry<bool> _enableMultiPeerOutsideActiveArea; private static ConfigEntry<bool> _enableServerOwnershipForPersistentZdos; private static ConfigEntry<bool> _allowExperimentalServerOwnershipForPersistentZdos; private static ConfigEntry<bool> _enableHeadlessVisualGuards; private static ConfigEntry<bool> _pauseExtraZoneWorkDuringSleep; private static ConfigEntry<bool> _speedUpSleepFastForward; private static ConfigEntry<float> _sleepFastForwardSeconds; private static ConfigEntry<bool> _skipSleepWorldSave; private static ConfigEntry<bool> _preserveAutosaveTimer; private static ConfigEntry<bool> _logSkippedSleepSaves; private static ConfigEntry<bool> _logSleepOptimizations; private static ConfigEntry<bool> _repairStaleWearNTearRemoveOwnership; private static ConfigEntry<float> _maxRemoveRepairDistance; private static ConfigEntry<bool> _logRemoveOwnershipRepairs; private static ConfigEntry<bool> _repairStaleItemDropOwnership; private static ConfigEntry<bool> _logItemDropOwnershipRepairs; private static ConfigEntry<float> _diagnosticIntervalSec; private static readonly List<ZDO> _nearScratch = new List<ZDO>(); private static readonly List<ZDO> _distantScratch = new List<ZDO>(); private static readonly List<ZDO> _nearFiltered = new List<ZDO>(); private static readonly List<ZDO> _distantFiltered = new List<ZDO>(); private static readonly List<ZDO> _streamBoostNearScratch = new List<ZDO>(); private static readonly List<ZDO> _streamBoostDistantScratch = new List<ZDO>(); private static readonly List<ZDO> _streamBoostCandidates = new List<ZDO>(); private static readonly HashSet<ZDOID> _streamBoostSeenZdos = new HashSet<ZDOID>(); private static readonly HashSet<long> _readyPeerIds = new HashSet<long>(); private static readonly List<long> _stalePeerIds = new List<long>(); private static readonly HashSet<ZDO> _seenZdos = new HashSet<ZDO>(); private static readonly HashSet<ZDOID> _syncSeenZdos = new HashSet<ZDOID>(); private static readonly HashSet<Vector2i> _coverageZones = new HashSet<Vector2i>(); private static readonly HashSet<Vector2i> _ttlRefreshZones = new HashSet<Vector2i>(); private static readonly List<Vector3> _zoneCreationCenters = new List<Vector3>(); private static readonly Dictionary<long, float> _lastDenseSyncLogTimes = new Dictionary<long, float>(); private static readonly Dictionary<Type, FieldInfo> _netPeerFields = new Dictionary<Type, FieldInfo>(); private static readonly Dictionary<long, PeerMotionSample> _peerMotion = new Dictionary<long, PeerMotionSample>(); private static readonly Dictionary<long, PeerStreamingState> _peerStreamingStates = new Dictionary<long, PeerStreamingState>(); private static readonly Dictionary<int, bool> _terrainCompilerPrefabCache = new Dictionary<int, bool>(); private static readonly Dictionary<Type, FieldInfo> _forceSendFields = new Dictionary<Type, FieldInfo>(); private static readonly Dictionary<int, int> _densePrefabCounts = new Dictionary<int, int>(); private static readonly List<KeyValuePair<int, int>> _densePrefabCountsSorted = new List<KeyValuePair<int, int>>(); private static readonly int PlayerPrefabHash = StringExtensionMethods.GetStableHashCode("Player"); private static ManualLogSource _log; private static CreateObjectsDelegate _createObjects; private static RemoveObjectsDelegate _removeObjects; private static CreateLocalZonesDelegate _createLocalZones; private static FieldInfo _routedRpcTargetPeerIdField; private static FieldInfo _routedRpcSenderPeerIdField; private static FieldInfo _routedRpcTargetZdoField; private static FieldInfo _routedRpcMethodHashField; private static FieldInfo _routedRpcParametersField; private static FieldInfo _envManSkipToTimeField; private static FieldInfo _envManTimeSkipSpeedField; private static FieldInfo _gameSaveTimerField; private static FieldInfo _zoneSystemZonesField; private static FieldInfo _zoneDataTtlField; private static FieldInfo _zNetSceneInstancesField; private static readonly List<ZDO> _staleSceneInstanceKeys = new List<ZDO>(); private static long _diagnosticStaleSceneInstancesRemoved; private static WearNTearRemoveRpcDelegate _wearNTearRemoveRpc; private Harmony _harmony; private static float _nextDiagnosticLogTime; private static float _nextPeerZoneCreateTime; private static float _nextCreateDestroyTime; private static float _nextRemoveObjectsTime; private static float _nextWarningLogTime; private static float _nextRemoveRepairWarningTime; private static float _nextSleepPauseLogTime; private static float _nextSleepBedCheckTime; private static float _denseSyncPauseUntil; private static bool _sleepBedPauseActive; private static int _nextZoneCreationCenter; private static long _diagnosticCreateDestroyPasses; private static long _diagnosticZoneCreateAttempts; private static long _diagnosticZoneCreateSuccesses; private static long _diagnosticBoostQueued; private static long _diagnosticBoostBackpressureSkips; private static long _diagnosticSyncDuplicatesRemoved; private static long _diagnosticItemDropOwnershipRepairs; private static long _diagnosticItemDropOwnershipRefreshes; private static long _diagnosticDensePressurePauses; private static long _diagnosticZoneTtlRefreshes; private static int _diagnosticMaxSyncList; private static int _diagnosticPeakSendQueue; private static HashSet<ZDOID> _syncForceSend; private static long _syncReceiverUid; private static Vector3 _syncReceiverRefPos; private static bool _syncPlayerPriority; private void Awake() { //IL_076f: Unknown result type (might be due to invalid IL or missing references) //IL_0779: Expected O, but got Unknown _log = ((BaseUnityPlugin)this).Logger; _enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable TerramizerServer."); _serverOnly = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ServerOnly", true, "Only run this plugin when this game instance is acting as a Valheim server."); _dedicatedOnly = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DedicatedOnly", true, "Only run on the dedicated server process. Keep true for local/single-player testing."); _safetyDefaultsVersion = BindRange("General", "SafetyDefaultsVersion", 0, "Internal migration marker used when safer compatibility defaults change between releases.", 0, 4); _maxSendQueueBytes = BindRange("Streaming", "MaxSendQueueBytes", 16384, "Socket send queue ceiling used by ZDO streaming. Vanilla is 10240. This moderate increase avoids the long interactive-update delays seen with a 24576-byte ceiling in dense areas.", 2048, 262144); _minFreeSendQueueBytes = BindRange("Streaming", "MinFreeSendQueueBytes", 4096, "Minimum free socket queue space required before sending another ZDO packet. Vanilla is 2048.", 512, 131072); _peerSendIntervalSeconds = BindRange("Streaming", "PeerSendIntervalSeconds", 0.05f, "Seconds between ZDO send passes. The default preserves Valheim's cadence while allowing a moderately larger packet budget.", 0.01f, 0.25f); _enableServerZoneStreamingBoost = ((BaseUnityPlugin)this).Config.Bind<bool>("Streaming", "EnableServerZoneStreamingBoost", true, "When a player enters or approaches a new zone, queue nearby server-known ZDOs to that peer first. This improves area load-in without changing ZDO ownership."); _zoneStreamingBoostExtraRadius = BindRange("Streaming", "ZoneStreamingBoostExtraRadius", 0, "Extra zone rings around the player's current and predicted zone to force-send on zone entry. 0 keeps the boost inside vanilla active-area coverage.", 0, 3); _maxZoneStreamingBoostZdosPerPeer = BindRange("Streaming", "MaxZoneStreamingBoostZdosPerPeer", 128, "Maximum ZDOs to force-queue for one peer on a zone-entry streaming boost. A conservative cap prevents bulk objects from delaying ownership and interaction updates.", 0, 5000); _zoneStreamingBoostCooldownSeconds = BindRange("Streaming", "ZoneStreamingBoostCooldownSeconds", 1.5f, "Minimum seconds between zone-entry streaming boosts for the same peer.", 0.1f, 10f); _zoneStreamingBoostMaxQueuePercent = BindRange("Streaming", "ZoneStreamingBoostMaxQueuePercent", 35, "Do not add a zone-entry boost while the peer socket queue is above this percentage of MaxSendQueueBytes. The zone change is retried after the queue drains.", 10, 90); _zoneStreamingBoostIncludeDistantZdos = ((BaseUnityPlugin)this).Config.Bind<bool>("Streaming", "ZoneStreamingBoostIncludeDistantZdos", true, "Also force-queue distant ZDOs if the near-object boost has remaining room."); _logZoneStreamingBoosts = ((BaseUnityPlugin)this).Config.Bind<bool>("Streaming", "LogZoneStreamingBoosts", false, "Log each zone-entry streaming boost with peer name, zone, and queued ZDO count."); _logDenseSyncs = ((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "LogDenseSyncs", true, "Log when a peer has a large pending ZDO sync list."); _denseSyncThreshold = BindRange("Diagnostics", "DenseSyncThreshold", 1000, "Pending ZDO count that triggers a dense-area log line.", 100, 100000); _denseSyncLogIntervalSeconds = BindRange("Diagnostics", "DenseSyncLogIntervalSeconds", 30f, "Minimum seconds between dense-area log lines per peer.", 5f, 600f); _pauseExtraStreamingDuringDenseSync = ((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "PauseExtraStreamingDuringDenseSync", true, "Pause TerramizerServer's extra zone generation and zone-entry boosts while any peer already has at least DenseSyncThreshold pending objects."); _denseSyncPauseSeconds = BindRange("Diagnostics", "DenseSyncPauseSeconds", 2f, "How long to keep extra streaming paused after observing a dense pending sync list. Repeated dense lists extend the pause.", 0.5f, 30f); _extendedZoneRadius = BindRange("WorldObjects", "ExtendedZoneRadius", 0, "Additional zone layers the server preloads around each peer. 0 keeps vanilla radius while still combining all ready peers.", 0, 3); _createDestroyIntervalSeconds = BindRange("WorldObjects", "CreateDestroyIntervalSeconds", 0.1f, "Minimum time between combined multi-peer object create passes. This bounds repeated scans in object-dense bases.", 0.03f, 1f); _removeObjectsIntervalSeconds = BindRange("WorldObjects", "RemoveObjectsIntervalSeconds", 0.5f, "Minimum time between server instance removal scans. Object creation still runs at CreateDestroyIntervalSeconds.", 0.05f, 2f); _enablePredictiveZoneStreaming = ((BaseUnityPlugin)this).Config.Bind<bool>("WorldObjects", "EnablePredictiveZoneStreaming", true, "Bias each peer's active-area center forward along their velocity so the server loads ahead of movement."); _predictionLookaheadSec = BindRange("WorldObjects", "PredictionLookaheadSec", 3f, "Seconds ahead to project each peer before zone checks.", 0.5f, 10f); _predictionMinVelocity = BindRange("WorldObjects", "PredictionMinVelocity", 2f, "Minimum smoothed speed before prediction engages.", 0.5f, 20f); _predictionMaxLookaheadZones = BindRange("WorldObjects", "PredictionMaxLookaheadZones", 9, "Hard cap on prediction distance, in zones.", 1, 25); _enableZDOThrottling = ((BaseUnityPlugin)this).Config.Bind<bool>("WorldObjects", "EnableZDOThrottling", false, "Reduce send priority for far-away default-type ZDOs while preserving Valheim's terrain, solid, prioritized, and player ordering. Disabled by default because distant objects normally fall outside the near sync list."); _zdoThrottleDistance = BindRange("WorldObjects", "ZDOThrottleDistance", 500f, "Distance beyond which ordinary ZDOs are deprioritized during send sorting.", 0f, 1000f); _enablePlayerPriority = ((BaseUnityPlugin)this).Config.Bind<bool>("WorldObjects", "EnablePlayerPriority", true, "Boost player ZDOs ahead of bulk world objects during server send sorting."); _enablePeerZoneCreation = ((BaseUnityPlugin)this).Config.Bind<bool>("ServerSimulation", "EnablePeerZoneCreation", false, "Experimental: instantiate full local zones around every ready peer. Disabled by default because moving around a multi-zone base can repeatedly unload/reload dungeon-bearing edge zones; Valheim still performs its normal peer ghost-zone generation."); _peerZoneUpdateIntervalSeconds = BindRange("ServerSimulation", "PeerZoneUpdateIntervalSeconds", 0.5f, "Seconds between server-side peer zone creation passes. This avoids hundreds of no-op checks per minute after zones are warm.", 0.05f, 2f); _maxPeerZoneCreationsPerPass = BindRange("ServerSimulation", "MaxPeerZoneCreationsPerPass", 1, "Maximum current/predicted peer centers allowed to generate a new zone in one server update pass.", 1, 16); _enableMultiPeerOutsideActiveArea = ((BaseUnityPlugin)this).Config.Bind<bool>("ServerSimulation", "EnableMultiPeerOutsideActiveArea", true, "Treat a point as active when it is inside any ready peer's active area. This helps server-side systems work for split-up players."); _enableServerOwnershipForPersistentZdos = ((BaseUnityPlugin)this).Config.Bind<bool>("ServerSimulation", "EnableServerOwnershipForPersistentZdos", false, "Legacy dangerous option kept only for config migration. TerramizerServer no longer mass-transfers persistent ZDO ownership; use Streaming.EnableServerZoneStreamingBoost instead."); _allowExperimentalServerOwnershipForPersistentZdos = ((BaseUnityPlugin)this).Config.Bind<bool>("ServerSimulation", "AllowExperimentalServerOwnershipForPersistentZdos", false, "Legacy dangerous option kept only for config migration. It is ignored by this build."); _enableHeadlessVisualGuards = ((BaseUnityPlugin)this).Config.Bind<bool>("ServerSimulation", "EnableHeadlessVisualGuards", true, "Skip a few visual/audio-only systems on dedicated servers to avoid pointless headless work and log spam."); _pauseExtraZoneWorkDuringSleep = ((BaseUnityPlugin)this).Config.Bind<bool>("Sleep", "PauseExtraZoneWorkDuringSleep", true, "Temporarily disable TerramizerServer's extra peer-zone warming and zone-entry streaming boost while all connected characters are in bed or the server is skipping time."); _speedUpSleepFastForward = ((BaseUnityPlugin)this).Config.Bind<bool>("Sleep", "SpeedUpSleepFastForward", true, "Tune Valheim's sleep time-skip so the night passes in the configured number of real seconds."); _sleepFastForwardSeconds = BindRange("Sleep", "SleepFastForwardSeconds", 4f, "Target real seconds for the sleep time-skip. Lower is faster, but very low values can make time-based object catch-up spike after waking.", 1f, 60f); _skipSleepWorldSave = ((BaseUnityPlugin)this).Config.Bind<bool>("Sleep", "SkipSleepWorldSave", false, "Skip the extra world save Valheim runs when sleep ends. This is off by default to preserve vanilla durability and save-system compatibility."); _preserveAutosaveTimer = ((BaseUnityPlugin)this).Config.Bind<bool>("Sleep", "PreserveAutosaveTimer", true, "Keep Valheim's regular autosave timer unchanged while skipping the sleep-triggered world save."); _logSkippedSleepSaves = ((BaseUnityPlugin)this).Config.Bind<bool>("Sleep", "LogSkippedSleepSaves", true, "Log when TerramizerServer skips a sleep-triggered world save."); _logSleepOptimizations = ((BaseUnityPlugin)this).Config.Bind<bool>("Sleep", "LogSleepOptimizations", true, "Log when TerramizerServer speeds up sleep or pauses extra zone work for sleep."); _repairStaleWearNTearRemoveOwnership = ((BaseUnityPlugin)this).Config.Bind<bool>("BuildInteractions", "RepairStaleWearNTearRemoveOwnership", true, "Recover legitimate hammer deconstruct RPCs when a build piece is routed to a different, stale, disconnected, or inactive ZDO owner. The requester must be nearby, the piece must be removable, and no-build locations are rejected."); _maxRemoveRepairDistance = BindRange("BuildInteractions", "MaxRemoveRepairDistance", 8f, "Maximum 3D distance from the requesting player's reference position to a build piece before stale-remove ownership repair is refused.", 5f, 16f); _logRemoveOwnershipRepairs = ((BaseUnityPlugin)this).Config.Bind<bool>("BuildInteractions", "LogRemoveOwnershipRepairs", true, "Log when TerramizerServer repairs stale ownership for a build-piece remove RPC."); _repairStaleItemDropOwnership = ((BaseUnityPlugin)this).Config.Bind<bool>("ItemInteractions", "RepairStaleItemDropOwnership", true, "Let the server complete a nearby ItemDrop ownership request when food, pickup, or tame consumption is stuck on another owner route."); _logItemDropOwnershipRepairs = ((BaseUnityPlugin)this).Config.Bind<bool>("ItemInteractions", "LogItemDropOwnershipRepairs", false, "Log each server-assisted ItemDrop ownership transfer. Leave off normally because feeding and pickup can produce many requests."); _diagnosticIntervalSec = BindRange("Diagnostics", "DiagnosticIntervalSec", 60f, "Seconds between optional server status log lines.", 10f, 3600f); ClampConfig(); ApplySafetyMigrations(); _nextDiagnosticLogTime = Time.realtimeSinceStartup + Mathf.Clamp(_diagnosticIntervalSec.Value, 10f, 3600f); _createObjects = AccessTools.MethodDelegate<CreateObjectsDelegate>(AccessTools.Method(typeof(ZNetScene), "CreateObjects", (Type[])null, (Type[])null), (object)null, true); _removeObjects = AccessTools.MethodDelegate<RemoveObjectsDelegate>(AccessTools.Method(typeof(ZNetScene), "RemoveObjects", (Type[])null, (Type[])null), (object)null, true); _createLocalZones = CreateDelegateSafely<CreateLocalZonesDelegate>(typeof(ZoneSystem), "CreateLocalZones"); _wearNTearRemoveRpc = CreateDelegateSafely<WearNTearRemoveRpcDelegate>(typeof(WearNTear), "RPC_Remove"); InitializeRoutedRpcReflection(); InitializeSleepReflection(); InitializeZoneTtlReflection(); InitializeZNetSceneReflection(); _harmony = new Harmony("r4v9n1.terramizerserver"); InstallPatches(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("TerramizerServer 0.4.7 loaded. MaxQueue=" + _maxSendQueueBytes.Value + ", MinFree=" + _minFreeSendQueueBytes.Value + ", PeerInterval=" + _peerSendIntervalSeconds.Value + "s.")); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Created by R4V9N1."); } private ConfigEntry<T> BindRange<T>(string section, string key, T defaultValue, string description, T minimum, T maximum) where T : IComparable { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown return ((BaseUnityPlugin)this).Config.Bind<T>(section, key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<T>(minimum, maximum), Array.Empty<object>())); } private void Update() { if (CanRunOnServer()) { MaybeLogDiagnostics(); } } private void OnDestroy() { if (_harmony != null) { _harmony.UnpatchSelf(); _harmony = null; } } private void InstallPatches() { bool num = HasPlugin("CW_Jesse.BetterNetworking") || HasPlugin("com.Fire.FiresGhettoNetworkMod") || HasPlugin("is.codex.valheim.zdostreamtuner"); bool flag = HasPlugin("MVP.Valheim_Serverside_Simulations"); if (num) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Detected another ZDO networking tuner. TerramizerServer will not replace send-queue constants or the send interval; its correctness and diagnostic patches remain active."); } else { PatchFeature(typeof(ZdoManSendZdosPatch), "ZDO queue limits"); PatchFeature(typeof(ZdoManSendZdoToPeersPatch), "ZDO send interval"); } if (!PatchFeature(typeof(ZdoManCreateSyncListPatch), "ZDO sync-list deduplication and priority") && _enableServerZoneStreamingBoost != null) { _enableServerZoneStreamingBoost.Value = false; ((BaseUnityPlugin)this).Logger.LogError((object)"Disabled server zone streaming boost because sync-list deduplication could not be installed safely."); } PatchFeature(typeof(ZDOManServerSortSendZdosPatch), "server ZDO distance adjustment"); PatchFeature(typeof(EnvManSkipToMorningPatch), "sleep fast-forward"); PatchFeature(typeof(GameSleepStopPatch), "sleep save policy"); PatchFeature(typeof(ZRoutedRpcHandleRoutedRpcPatch), "locally routed ownership recovery"); PatchFeature(typeof(ZRoutedRpcRouteRpcPatch), "forwarded ownership recovery"); PatchFeature(typeof(AudioManUpdateHeadlessPatch), "headless audio guard"); PatchFeature(typeof(ShieldDomeImageEffectAwakeHeadlessPatch), "headless shield initialization guard"); PatchFeature(typeof(ShieldDomeImageEffectGetDomeColorHeadlessPatch), "headless shield guard"); if (flag) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Detected Valheim Serverside Simulations. TerramizerServer's overlapping multi-peer object/zone simulation patches are disabled to avoid double work and ownership conflicts."); return; } PatchFeature(typeof(ZNetSceneRemoveObjectsSafetyPatch), "stale ZNetScene instance sanitation"); PatchFeature(typeof(ZNetSceneCreateDestroyObjectsPatch), "multi-peer object coverage"); PatchFeature(typeof(ZoneSystemUpdatePeerZoneCreationPatch), "bounded peer zone creation"); PatchFeature(typeof(ZNetSceneOutsideActiveAreaPeerPatch), "multi-peer active area"); PatchFeature(typeof(ZdoManReleaseNearbyZdosServerOwnershipPatch), "legacy ownership migration"); } private bool PatchFeature(Type patchType, string featureName) { try { _harmony.CreateClassProcessor(patchType).Patch(); return true; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Disabled " + featureName + " because its Valheim patch no longer matched: " + ex.Message)); return false; } } private static bool HasPlugin(string guid) { if (Chainloader.PluginInfos != null) { return Chainloader.PluginInfos.ContainsKey(guid); } return false; } internal static bool CanRunOnServer() { if (_enabled == null || !_enabled.Value) { return false; } try { ZNet instance = ZNet.instance; if (_dedicatedOnly != null && _dedicatedOnly.Value) { return (Object)(object)instance != (Object)null && instance.IsDedicated(); } if (_serverOnly == null || !_serverOnly.Value) { return true; } return (Object)(object)instance != (Object)null && (instance.IsServer() || instance.IsDedicated()); } catch { return false; } } internal static bool ShouldRunCreateDestroyObjects() { return CanRunOnServer(); } internal static int GetMaxSendQueueBytes() { if (!CanRunOnServer()) { return 10240; } if (_maxSendQueueBytes != null) { return _maxSendQueueBytes.Value; } return 10240; } internal static int GetMinFreeSendQueueBytes() { if (!CanRunOnServer()) { return 2048; } if (_minFreeSendQueueBytes != null) { return _minFreeSendQueueBytes.Value; } return 2048; } internal static float GetPeerSendIntervalSeconds() { if (!CanRunOnServer()) { return 0.05f; } if (_peerSendIntervalSeconds != null) { return _peerSendIntervalSeconds.Value; } return 0.05f; } internal static bool RunCreateDestroyObjects(ZNetScene scene) { //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) if (!ShouldRunCreateDestroyObjects()) { return true; } bool flag = false; try { ZNet instance = ZNet.instance; ZoneSystem instance2 = ZoneSystem.instance; ZDOMan instance3 = ZDOMan.instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance2 == (Object)null || instance3 == null) { return true; } if (ShouldPauseExtraZoneWorkForSleep()) { return true; } float realtimeSinceStartup = Time.realtimeSinceStartup; float num = ((_createDestroyIntervalSeconds == null) ? 0.1f : Mathf.Clamp(_createDestroyIntervalSeconds.Value, 0.03f, 1f)); if (realtimeSinceStartup < _nextCreateDestroyTime) { return false; } _nextCreateDestroyTime = realtimeSinceStartup + num; List<ZNetPeer> connectedPeers = instance.GetConnectedPeers(); if (connectedPeers == null || connectedPeers.Count == 0) { return true; } int num2 = Mathf.Clamp(_extendedZoneRadius.Value, 0, 3); int num3 = Math.Max(1, instance2.m_activeArea + num2); int num4 = Math.Max(num3, instance2.m_activeDistantArea + num2); _nearScratch.Clear(); _distantScratch.Clear(); _coverageZones.Clear(); bool flag2 = false; for (int i = 0; i < connectedPeers.Count; i++) { ZNetPeer val = connectedPeers[i]; if (val != null && val.IsReady()) { flag2 = true; Vector2i zone = ZoneSystem.GetZone(val.GetRefPos()); Vector2i zone2 = ZoneSystem.GetZone(GetPredictedRefPos(val)); if (_coverageZones.Add(zone)) { instance3.FindSectorObjects(zone, num3, num4, _nearScratch, _distantScratch); } if (_coverageZones.Add(zone2)) { instance3.FindSectorObjects(zone2, num3, num4, _nearScratch, _distantScratch); } } } if (!flag2) { return true; } _seenZdos.Clear(); FilterAndDedupeZdos(_nearScratch, _nearFiltered); FilterAndDedupeZdos(_distantScratch, _distantFiltered); if (_createObjects != null) { _createObjects(scene, _nearFiltered, _distantFiltered); } float num5 = ((_removeObjectsIntervalSeconds == null) ? 0.5f : Mathf.Clamp(_removeObjectsIntervalSeconds.Value, num, 2f)); if (_removeObjects != null && realtimeSinceStartup >= _nextRemoveObjectsTime) { _nextRemoveObjectsTime = realtimeSinceStartup + num5; flag = true; RepairStaleSceneInstances(scene); _removeObjects(scene, _nearFiltered, _distantFiltered); flag = false; } _diagnosticCreateDestroyPasses++; return false; } catch (Exception ex) { if (_log != null) { if (flag) { _log.LogWarning((object)("TerramizerServer RemoveObjects pass failed; suppressing vanilla retry for this frame: " + ex.Message)); } else { _log.LogWarning((object)("TerramizerServer CreateDestroyObjects fell back to vanilla: " + ex.Message)); } } return !flag; } } internal static void SortZdosForServer(List<ZDO> toSync, Vector3 refPos) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) if (!CanRunOnServer() || toSync == null || toSync.Count == 0) { return; } float num = ((_enableZDOThrottling != null && _enableZDOThrottling.Value) ? Mathf.Max(0f, _zdoThrottleDistance.Value) : 0f); float num2 = num * num; for (int i = 0; i < toSync.Count; i++) { ZDO val = toSync[i]; if (val != null && val.IsValid() && !(num2 <= 0f) && (int)val.Type == 0) { Vector3 position = val.GetPosition(); float num3 = position.x - refPos.x; float num4 = position.z - refPos.z; if (num3 * num3 + num4 * num4 > num2) { val.m_tempSortValue += 500f; } } } } internal static void PostProcessSyncList(object zdoPeer, List<ZDO> toSync) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) if (!CanRunOnServer() || zdoPeer == null || toSync == null) { return; } ZNetPeer netPeer = GetNetPeer(zdoPeer); HashSet<ZDOID> forceSendSet = GetForceSendSet(zdoPeer); _syncSeenZdos.Clear(); int num = 0; int count = toSync.Count; for (int i = 0; i < count; i++) { ZDO val = toSync[i]; if (val != null && val.IsValid() && !((ZDOID)(ref val.m_uid)).IsNone() && _syncSeenZdos.Add(val.m_uid)) { toSync[num++] = val; } } if (num < count) { toSync.RemoveRange(num, count - num); _diagnosticSyncDuplicatesRemoved += count - num; } _syncForceSend = forceSendSet; _syncReceiverUid = netPeer?.m_uid ?? 0; _syncReceiverRefPos = ((netPeer == null) ? Vector3.zero : netPeer.GetRefPos()); _syncPlayerPriority = _enablePlayerPriority != null && _enablePlayerPriority.Value; try { toSync.Sort(CompareFinalSyncZdos); } finally { _syncForceSend = null; } _diagnosticMaxSyncList = Math.Max(_diagnosticMaxSyncList, toSync.Count); if (netPeer != null && netPeer.m_socket != null) { _diagnosticPeakSendQueue = Math.Max(_diagnosticPeakSendQueue, netPeer.m_socket.GetSendQueueSize()); } if (_pauseExtraStreamingDuringDenseSync != null && _pauseExtraStreamingDuringDenseSync.Value && _denseSyncThreshold != null && toSync.Count >= _denseSyncThreshold.Value) { float num2 = ((_denseSyncPauseSeconds == null) ? 2f : Mathf.Clamp(_denseSyncPauseSeconds.Value, 0.5f, 30f)); _denseSyncPauseUntil = Math.Max(_denseSyncPauseUntil, Time.realtimeSinceStartup + num2); } MaybeLogDenseSync(zdoPeer, toSync); } private static int CompareFinalSyncZdos(ZDO left, ZDO right) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Invalid comparison between Unknown and I4 //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Invalid comparison between Unknown and I4 //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Expected I4, but got Unknown //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Expected I4, but got Unknown //IL_00f2: 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) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) bool flag = _syncForceSend != null && _syncForceSend.Contains(left.m_uid); bool flag2 = _syncForceSend != null && _syncForceSend.Contains(right.m_uid); if (flag != flag2) { if (!flag) { return 1; } return -1; } if (_syncPlayerPriority) { int playerPrefabHash = GetPlayerPrefabHash(); bool flag3 = left.GetPrefab() == playerPrefabHash; bool flag4 = right.GetPrefab() == playerPrefabHash; if (flag3 != flag4) { if (!flag3) { return 1; } return -1; } } bool flag5 = (int)left.Type == 1 && left.HasOwner() && left.GetOwner() != _syncReceiverUid; bool flag6 = (int)right.Type == 1 && right.HasOwner() && right.GetOwner() != _syncReceiverUid; if (flag5 != flag6) { if (!flag5) { return 1; } return -1; } if (left.Type != right.Type) { return ((int)right.Type).CompareTo((int)left.Type); } if (flag) { Vector3 val = left.GetPosition() - _syncReceiverRefPos; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; val = right.GetPosition() - _syncReceiverRefPos; float sqrMagnitude2 = ((Vector3)(ref val)).sqrMagnitude; return Utils.CompareFloats(sqrMagnitude, sqrMagnitude2); } return Utils.CompareFloats(left.m_tempSortValue, right.m_tempSortValue); } internal static void RunPeerZoneCreation(ZoneSystem zoneSystem) { //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_016f: 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_0232: Unknown result type (might be due to invalid IL or missing references) if (!CanRunOnServer() || (Object)(object)zoneSystem == (Object)null) { return; } float realtimeSinceStartup = Time.realtimeSinceStartup; float num = ((_peerZoneUpdateIntervalSeconds == null) ? 0.5f : Mathf.Clamp(_peerZoneUpdateIntervalSeconds.Value, 0.05f, 2f)); if (realtimeSinceStartup < _nextPeerZoneCreateTime) { return; } _nextPeerZoneCreateTime = realtimeSinceStartup + num; RefreshLoadedPeerZoneTtls(zoneSystem); if (ShouldPauseExtraZoneWorkForSleep()) { return; } if (_pauseExtraStreamingDuringDenseSync != null && _pauseExtraStreamingDuringDenseSync.Value && realtimeSinceStartup < _denseSyncPauseUntil) { _diagnosticDensePressurePauses++; return; } bool flag = _enablePeerZoneCreation != null && _enablePeerZoneCreation.Value && _createLocalZones != null; bool flag2 = IsZoneStreamingBoostEnabled(); if (!flag && !flag2) { return; } try { ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null || !instance.IsServer()) { return; } ZDOMan instance2 = ZDOMan.instance; if (instance2 == null) { flag2 = false; } List<ZNetPeer> connectedPeers = instance.GetConnectedPeers(); if (connectedPeers == null) { return; } _readyPeerIds.Clear(); _coverageZones.Clear(); _zoneCreationCenters.Clear(); for (int i = 0; i < connectedPeers.Count; i++) { ZNetPeer val = connectedPeers[i]; if (val == null || !val.IsReady()) { continue; } _readyPeerIds.Add(val.m_uid); Vector3 refPos = val.GetRefPos(); Vector3 predictedRefPos = GetPredictedRefPos(val); if (flag) { if (_coverageZones.Add(ZoneSystem.GetZone(refPos))) { _zoneCreationCenters.Add(refPos); } if (_coverageZones.Add(ZoneSystem.GetZone(predictedRefPos))) { _zoneCreationCenters.Add(predictedRefPos); } } if (flag2) { MaybeBoostPeerZoneStreaming(instance2, zoneSystem, val, predictedRefPos); } } if (flag && _zoneCreationCenters.Count > 0) { int num2 = ((_maxPeerZoneCreationsPerPass == null) ? 1 : Mathf.Clamp(_maxPeerZoneCreationsPerPass.Value, 1, 16)); int num3 = _nextZoneCreationCenter % _zoneCreationCenters.Count; int num4 = 0; for (int j = 0; j < _zoneCreationCenters.Count; j++) { if (num4 >= num2) { break; } int index = (num3 + j) % _zoneCreationCenters.Count; _diagnosticZoneCreateAttempts++; if (_createLocalZones(zoneSystem, _zoneCreationCenters[index])) { num4++; _diagnosticZoneCreateSuccesses++; } } _nextZoneCreationCenter = (num3 + 1) % _zoneCreationCenters.Count; } PrunePeerTracking(_readyPeerIds); } catch (Exception ex) { LogWarningThrottled("Peer zone creation skipped after an error: " + ex.Message); } } internal static bool TryMultiPeerOutsideActiveArea(Vector3 point, ref bool result) { //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) if (!CanRunOnServer() || _enableMultiPeerOutsideActiveArea == null || !_enableMultiPeerOutsideActiveArea.Value) { return true; } if (ShouldPauseExtraZoneWorkForSleep()) { return true; } try { ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null || !instance.IsServer()) { return true; } List<ZNetPeer> connectedPeers = instance.GetConnectedPeers(); if (connectedPeers == null || connectedPeers.Count == 0) { return true; } ZoneSystem instance2 = ZoneSystem.instance; if ((Object)(object)instance2 == (Object)null) { return true; } bool flag = false; for (int i = 0; i < connectedPeers.Count; i++) { ZNetPeer val = connectedPeers[i]; if (val != null && val.IsReady()) { flag = true; int num = Math.Max(1, instance2.m_activeArea); Vector2i zone = ZoneSystem.GetZone(val.GetRefPos()); if (!ZNetScene.OutsideActiveArea(point, zone, num)) { result = false; return false; } Vector2i zone2 = ZoneSystem.GetZone(GetPredictedRefPos(val)); if (!(zone2 == zone) && !ZNetScene.OutsideActiveArea(point, zone2, num)) { result = false; return false; } } } if (!flag) { return true; } result = true; return false; } catch (Exception ex) { LogWarningThrottled("Multi-peer active-area check fell back to vanilla: " + ex.Message); return true; } } internal static void RunServerOwnershipForPersistentZdos(ZDOMan zdoMan, Vector3 refPosition) { if (_enableServerOwnershipForPersistentZdos != null && _enableServerOwnershipForPersistentZdos.Value) { _enableServerOwnershipForPersistentZdos.Value = false; if (_log != null) { _log.LogWarning((object)"Disabled legacy persistent-ZDO server ownership. TerramizerServer now uses server-side streaming boosts instead of mass ownership transfer."); } } } private static bool IsZoneStreamingBoostEnabled() { if (_enableServerZoneStreamingBoost != null && _enableServerZoneStreamingBoost.Value) { return !ShouldPauseExtraZoneWorkForSleep(); } return false; } internal static void TuneSleepFastForward(EnvMan envMan) { if (!CanRunOnServer() || _speedUpSleepFastForward == null || !_speedUpSleepFastForward.Value || (Object)(object)envMan == (Object)null || !envMan.IsTimeSkipping()) { return; } try { ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null || !instance.IsServer()) { return; } if (_envManSkipToTimeField == null || _envManTimeSkipSpeedField == null) { LogWarningThrottled("Sleep fast-forward tuning is unavailable because EnvMan sleep fields could not be found."); return; } double num = (double)_envManSkipToTimeField.GetValue(envMan) - instance.GetTimeSeconds(); if (!(num <= 0.0)) { float num2 = ((_sleepFastForwardSeconds == null) ? 4f : Mathf.Clamp(_sleepFastForwardSeconds.Value, 1f, 60f)); double num3 = num / (double)num2; _envManTimeSkipSpeedField.SetValue(envMan, num3); if (_logSleepOptimizations != null && _logSleepOptimizations.Value && _log != null) { _log.LogInfo((object)("Sleep fast-forward tuned to about " + num2.ToString("0.##") + " real second(s).")); } } } catch (Exception ex) { LogWarningThrottled("Sleep fast-forward tuning failed: " + ex.Message); } } internal static void SavePlayerProfileFromSleep(Game game, bool setLogoutPoint) { if ((Object)(object)game == (Object)null) { return; } bool flag = ShouldSkipSleepWorldSave() && _preserveAutosaveTimer != null && _preserveAutosaveTimer.Value && _gameSaveTimerField != null; float num = 0f; if (flag) { try { num = (float)_gameSaveTimerField.GetValue(game); } catch (Exception ex) { flag = false; LogWarningThrottled("Could not read Game.m_saveTimer before sleep save: " + ex.Message); } } game.SavePlayerProfile(setLogoutPoint); if (!flag) { return; } try { _gameSaveTimerField.SetValue(game, num); } catch (Exception ex2) { LogWarningThrottled("Could not restore Game.m_saveTimer after sleep save: " + ex2.Message); } } internal static void SaveWorldFromSleep(ZNet znet, bool sync, bool saveOtherPlayerProfiles, bool waitForNextFrame) { if (!ShouldSkipSleepWorldSave()) { if ((Object)(object)znet != (Object)null) { znet.Save(sync, saveOtherPlayerProfiles, waitForNextFrame); } } else if (_logSkippedSleepSaves != null && _logSkippedSleepSaves.Value && _log != null) { _log.LogInfo((object)"Skipped sleep-triggered world save. The regular autosave schedule is unchanged."); } } private static bool ShouldSkipSleepWorldSave() { if (CanRunOnServer() && _skipSleepWorldSave != null) { return _skipSleepWorldSave.Value; } return false; } private unsafe static void MaybeBoostPeerZoneStreaming(ZDOMan zdoMan, ZoneSystem zoneSystem, ZNetPeer peer, Vector3 predictedRefPos) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: 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_002e: 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_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0133: 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_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) if (zdoMan == null || (Object)(object)zoneSystem == (Object)null || peer == null || !peer.IsReady()) { return; } long uid = peer.m_uid; Vector3 refPos = peer.GetRefPos(); Vector2i zone = ZoneSystem.GetZone(refPos); Vector2i zone2 = ZoneSystem.GetZone(predictedRefPos); float realtimeSinceStartup = Time.realtimeSinceStartup; PeerStreamingState value; bool flag = _peerStreamingStates.TryGetValue(uid, out value) && value.HasZone; if (realtimeSinceStartup < value.NextBoostTime || (flag && value.CurrentZone == zone && value.PredictedZone == zone2)) { return; } int num = Math.Max(1, GetMaxSendQueueBytes()); int num2 = ((_zoneStreamingBoostMaxQueuePercent == null) ? 35 : Mathf.Clamp(_zoneStreamingBoostMaxQueuePercent.Value, 10, 90)); int num3 = ((peer.m_socket != null) ? peer.m_socket.GetSendQueueSize() : 0); _diagnosticPeakSendQueue = Math.Max(_diagnosticPeakSendQueue, num3); if ((long)num3 * 100L >= (long)num * (long)num2) { value.NextBoostTime = realtimeSinceStartup + 0.25f; _peerStreamingStates[uid] = value; _diagnosticBoostBackpressureSkips++; return; } int num4 = QueueZoneStreamingBoost(zdoMan, zoneSystem, peer, zone, zone2, refPos); value.HasZone = true; value.CurrentZone = zone; value.PredictedZone = zone2; value.NextBoostTime = realtimeSinceStartup + ((_zoneStreamingBoostCooldownSeconds == null) ? 1.5f : Mathf.Clamp(_zoneStreamingBoostCooldownSeconds.Value, 0.1f, 10f)); _peerStreamingStates[uid] = value; _diagnosticBoostQueued += num4; if (num4 > 0 && _logZoneStreamingBoosts != null && _logZoneStreamingBoosts.Value && _log != null) { string text = (string.IsNullOrEmpty(peer.m_playerName) ? "unknown peer" : peer.m_playerName); ManualLogSource log = _log; string[] obj = new string[7] { "Queued ", num4.ToString(), " server-side ZDO streaming boost object(s) for ", text, " at zone ", null, null }; Vector2i val = zone; obj[5] = ((object)(*(Vector2i*)(&val))/*cast due to .constrained prefix*/).ToString(); obj[6] = "."; log.LogInfo((object)string.Concat(obj)); } } private static int QueueZoneStreamingBoost(ZDOMan zdoMan, ZoneSystem zoneSystem, ZNetPeer peer, Vector2i currentZone, Vector2i predictedZone, Vector3 refPos) { //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) int num = ((_maxZoneStreamingBoostZdosPerPeer == null) ? 128 : Mathf.Clamp(_maxZoneStreamingBoostZdosPerPeer.Value, 0, 5000)); if (num <= 0) { return 0; } int num2 = ((_zoneStreamingBoostExtraRadius != null) ? Mathf.Clamp(_zoneStreamingBoostExtraRadius.Value, 0, 3) : 0); int num3 = Math.Max(1, zoneSystem.m_activeArea + num2); int num4 = ((_zoneStreamingBoostIncludeDistantZdos != null && _zoneStreamingBoostIncludeDistantZdos.Value) ? Math.Max(0, zoneSystem.m_activeDistantArea) : 0); _streamBoostNearScratch.Clear(); _streamBoostDistantScratch.Clear(); _streamBoostCandidates.Clear(); _streamBoostSeenZdos.Clear(); zdoMan.FindSectorObjects(currentZone, num3, num4, _streamBoostNearScratch, _streamBoostDistantScratch); if (!(predictedZone == currentZone)) { zdoMan.FindSectorObjects(predictedZone, num3, num4, _streamBoostNearScratch, _streamBoostDistantScratch); } AddStreamingBoostCandidates(_streamBoostNearScratch, refPos, near: true); if (_zoneStreamingBoostIncludeDistantZdos != null && _zoneStreamingBoostIncludeDistantZdos.Value && _streamBoostCandidates.Count < num) { AddStreamingBoostCandidates(_streamBoostDistantScratch, refPos, near: false); } _streamBoostCandidates.Sort(CompareStreamingBoostZdos); int num5 = 0; for (int i = 0; i < _streamBoostCandidates.Count; i++) { if (num5 >= num) { break; } ZDO val = _streamBoostCandidates[i]; if (val != null && val.IsValid() && !((ZDOID)(ref val.m_uid)).IsNone()) { zdoMan.ForceSendZDO(peer.m_uid, val.m_uid); num5++; } } _streamBoostNearScratch.Clear(); _streamBoostDistantScratch.Clear(); _streamBoostCandidates.Clear(); _streamBoostSeenZdos.Clear(); return num5; } private static void AddStreamingBoostCandidates(List<ZDO> source, Vector3 refPos, bool near) { //IL_0034: 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 (source == null) { return; } ZNetScene instance = ZNetScene.instance; for (int i = 0; i < source.Count; i++) { ZDO val = source[i]; if (val != null && val.IsValid() && !((ZDOID)(ref val.m_uid)).IsNone() && _streamBoostSeenZdos.Add(val.m_uid) && (!((Object)(object)instance != (Object)null) || instance.HasPrefab(val.GetPrefab())) && !ShouldDelayTerrainCompilerZdo(val, instance)) { val.m_tempSortValue = GetStreamingBoostSortValue(val, refPos, near); _streamBoostCandidates.Add(val); } } } private static float GetStreamingBoostSortValue(ZDO zdo, Vector3 refPos, bool near) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) Vector3 position = zdo.GetPosition(); float num = position.x - refPos.x; float num2 = position.z - refPos.z; float num3 = num * num + num2 * num2; if (!near) { num3 += 1000000f; } return num3; } private static int CompareStreamingBoostZdos(ZDO left, ZDO right) { int num = GetStreamingBoostTypeRank(left).CompareTo(GetStreamingBoostTypeRank(right)); if (num != 0) { return num; } return Utils.CompareFloats(left.m_tempSortValue, right.m_tempSortValue); } private static int GetStreamingBoostTypeRank(ZDO zdo) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Invalid comparison between Unknown and I4 //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Invalid comparison between Unknown and I4 //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Invalid comparison between Unknown and I4 if (_enablePlayerPriority != null && _enablePlayerPriority.Value && zdo.GetPrefab() == GetPlayerPrefabHash()) { return 0; } if ((int)zdo.Type == 3) { return 1; } if ((int)zdo.Type == 2) { return 2; } if ((int)zdo.Type == 1) { return 3; } return 4; } internal static bool TryHandleRoutedOwnershipRpc(object routedRpcData) { if (!CanRunOnServer() || routedRpcData == null || !HasRoutedRpcReflection()) { return false; } try { int num = (int)_routedRpcMethodHashField.GetValue(routedRpcData); if (num == StringExtensionMethods.GetStableHashCode("RPC_Remove")) { return TryHandleStaleWearNTearRemoveRpc(routedRpcData); } if (num == StringExtensionMethods.GetStableHashCode("RPC_RequestOwn")) { return TryHandleItemDropOwnershipRequest(routedRpcData); } } catch (Exception ex) { LogRemoveRepairWarning("Routed ownership repair inspection failed: " + ex.Message); } return false; } private unsafe static bool TryHandleItemDropOwnershipRequest(object routedRpcData) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_0137: 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_018f: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_024c: Unknown result type (might be due to invalid IL or missing references) if (_repairStaleItemDropOwnership == null || !_repairStaleItemDropOwnership.Value) { return false; } ZDOID val = (ZDOID)_routedRpcTargetZdoField.GetValue(routedRpcData); long num = (long)_routedRpcSenderPeerIdField.GetValue(routedRpcData); if (((ZDOID)(ref val)).IsNone() || num == 0L) { return false; } ZNet instance = ZNet.instance; ZDOMan instance2 = ZDOMan.instance; ZNetScene instance3 = ZNetScene.instance; if ((Object)(object)instance == (Object)null || instance2 == null || (Object)(object)instance3 == (Object)null || !instance.IsServer()) { return false; } ZDO zDO = instance2.GetZDO(val); if (zDO == null || !zDO.IsValid()) { return false; } bool flag = num == ZNet.GetUID(); ZNetPeer val2 = (flag ? null : instance.GetPeer(num)); if (!flag && (val2 == null || !val2.IsReady() || !IsPeerActiveNearZdo(val2, zDO))) { return false; } GameObject prefab = instance3.GetPrefab(zDO.GetPrefab()); if ((Object)(object)prefab == (Object)null || (Object)(object)prefab.GetComponentInChildren<ItemDrop>(true) == (Object)null) { return false; } if (flag) { ZNetView val3 = instance3.FindInstance(zDO); if ((Object)(object)val3 == (Object)null || (Object)(object)((Component)val3).GetComponent<ItemDrop>() == (Object)null) { return false; } } long owner = zDO.GetOwner(); if (owner == num) { if (flag) { return false; } instance2.ForceSendZDO(num, val); _routedRpcTargetPeerIdField.SetValue(routedRpcData, ZNet.GetUID()); _diagnosticItemDropOwnershipRefreshes++; if (_logItemDropOwnershipRepairs != null && _logItemDropOwnershipRepairs.Value && _log != null) { ManualLogSource log = _log; string[] obj = new string[5] { "Re-sent authoritative ItemDrop ownership for ZDO ", null, null, null, null }; ZDOID val4 = val; obj[1] = ((object)(*(ZDOID*)(&val4))/*cast due to .constrained prefix*/).ToString(); obj[2] = " to recorded owner "; obj[3] = num.ToString(); obj[4] = "."; log.LogInfo((object)string.Concat(obj)); } return true; } zDO.SetOwner(num); if (!flag) { instance2.ForceSendZDO(num, val); } _routedRpcTargetPeerIdField.SetValue(routedRpcData, ZNet.GetUID()); _diagnosticItemDropOwnershipRepairs++; if (_logItemDropOwnershipRepairs != null && _logItemDropOwnershipRepairs.Value && _log != null) { string text = (flag ? "server simulation" : ("nearby peer " + num)); ManualLogSource log2 = _log; string[] obj2 = new string[7] { "Transferred ItemDrop ZDO ", null, null, null, null, null, null }; ZDOID val4 = val; obj2[1] = ((object)(*(ZDOID*)(&val4))/*cast due to .constrained prefix*/).ToString(); obj2[2] = " from owner "; obj2[3] = owner.ToString(); obj2[4] = " to "; obj2[5] = text; obj2[6] = "."; log2.LogInfo((object)string.Concat(obj2)); } return true; } internal unsafe static bool TryHandleStaleWearNTearRemoveRpc(object routedRpcData) { //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_02cc: Unknown result type (might be due to invalid IL or missing references) //IL_02cd: Unknown result type (might be due to invalid IL or missing references) if (!CanRunOnServer() || _repairStaleWearNTearRemoveOwnership == null || !_repairStaleWearNTearRemoveOwnership.Value || routedRpcData == null) { return false; } if (!HasRoutedRpcReflection()) { LogRemoveRepairWarning("Stale remove ownership repair is unavailable because Valheim's routed-RPC fields could not be found."); return false; } if (_routedRpcParametersField == null || _wearNTearRemoveRpc == null) { LogRemoveRepairWarning("Stale remove ownership repair is unavailable because Valheim's WearNTear remove handler could not be bound safely."); return false; } try { if ((int)_routedRpcMethodHashField.GetValue(routedRpcData) != StringExtensionMethods.GetStableHashCode("RPC_Remove")) { return false; } ZDOID val = (ZDOID)_routedRpcTargetZdoField.GetValue(routedRpcData); if (((ZDOID)(ref val)).IsNone()) { return false; } ZDOMan instance = ZDOMan.instance; ZNetScene instance2 = ZNetScene.instance; ZNet instance3 = ZNet.instance; if (instance == null || (Object)(object)instance2 == (Object)null || (Object)(object)instance3 == (Object)null || !instance3.IsServer()) { return false; } ZDO zDO = instance.GetZDO(val); if (zDO == null || !zDO.IsValid()) { return false; } long num = (long)_routedRpcSenderPeerIdField.GetValue(routedRpcData); if (!IsRemoveRequesterCloseEnough(instance3, num, zDO.GetPosition())) { return false; } if (Location.IsInsideNoBuildLocation(zDO.GetPosition())) { return false; } ZNetView val2 = instance2.FindInstance(zDO); if ((Object)(object)val2 == (Object)null) { val2 = TryCreateServerInstanceForRemove(instance2, zDO); if ((Object)(object)val2 == (Object)null) { ZDOID val3 = val; LogRemoveRepairWarning("Could not handle build-piece remove on the server because there is no active instance for ZDO " + ((object)(*(ZDOID*)(&val3))/*cast due to .constrained prefix*/).ToString() + "."); return false; } } WearNTear component = ((Component)val2).GetComponent<WearNTear>(); if ((Object)(object)component == (Object)null) { return false; } Piece component2 = ((Component)val2).GetComponent<Piece>(); if ((Object)(object)component2 != (Object)null && !component2.CanBeRemoved()) { return false; } long targetPeerId = (long)_routedRpcTargetPeerIdField.GetValue(routedRpcData); long owner = zDO.GetOwner(); long uID = ZNet.GetUID(); if (!ShouldServerHandleRemoveRpc(instance3, zDO, owner, targetPeerId, uID, num)) { return false; } zDO.SetOwner(uID); object? value = _routedRpcParametersField.GetValue(routedRpcData); ZPackage val4 = (ZPackage)((value is ZPackage) ? value : null); if (val4 == null || _wearNTearRemoveRpc == null) { zDO.SetOwner(owner); return false; } int pos = val4.GetPos(); bool blockDrop; try { val4.SetPos(0); blockDrop = val4.ReadBool(); } finally { val4.SetPos(pos); } try { _wearNTearRemoveRpc(component, num, blockDrop); } catch { if (zDO.IsValid()) { zDO.SetOwner(owner); } throw; } if (zDO.IsValid()) { zDO.SetOwner(owner); return false; } if (_logRemoveOwnershipRepairs != null && _logRemoveOwnershipRepairs.Value && _log != null) { ManualLogSource log = _log; string[] obj2 = new string[5] { "Handled build-piece remove on server for ZDO ", null, null, null, null }; ZDOID val3 = val; obj2[1] = ((object)(*(ZDOID*)(&val3))/*cast due to .constrained prefix*/).ToString(); obj2[2] = " after temporarily moving ownership from "; obj2[3] = owner.ToString(); obj2[4] = " to server."; log.LogInfo((object)string.Concat(obj2)); } _routedRpcTargetPeerIdField.SetValue(routedRpcData, uID); return true; } catch (Exception innerException) { while (innerException.InnerException != null) { innerException = innerException.InnerException; } LogRemoveRepairWarning("Stale build-piece remove ownership repair failed in " + innerException.GetType().Name + ": " + innerException.Message); return false; } } private static void ApplySafetyMigrations() { if (_enablePeerZoneCreation != null && _enablePeerZoneCreation.Value) { _enablePeerZoneCreation.Value = false; if (_log != null) { _log.LogWarning((object)"Disabled experimental peer zone creation because it can repeatedly reload dungeon-bearing zones. Normal Valheim ghost-zone generation remains active."); } } if (_enableServerOwnershipForPersistentZdos != null && _enableServerOwnershipForPersistentZdos.Value) { _enableServerOwnershipForPersistentZdos.Value = false; if (_log != null) { _log.LogWarning((object)"Disabled legacy persistent-ZDO server ownership. Use Streaming.EnableServerZoneStreamingBoost for faster area data without server ownership transfer."); } } if (_safetyDefaultsVersion != null && _safetyDefaultsVersion.Value < 1) { if (_enableZDOThrottling != null) { _enableZDOThrottling.Value = false; } if (_skipSleepWorldSave != null) { _skipSleepWorldSave.Value = false; } _safetyDefaultsVersion.Value = 1; if (_log != null) { _log.LogWarning((object)"Applied 0.4 safety migration: disabled ZDO throttling and sleep-save skipping."); } } if (_safetyDefaultsVersion != null && _safetyDefaultsVersion.Value < 2) { if (_repairStaleWearNTearRemoveOwnership != null) { _repairStaleWearNTearRemoveOwnership.Value = true; } _safetyDefaultsVersion.Value = 2; if (_log != null) { _log.LogWarning((object)"Applied 0.4.2 ownership-route migration: enabled narrow build-piece remove recovery so non-owner players are not dependent on another client's ownership route."); } } if (_safetyDefaultsVersion != null && _safetyDefaultsVersion.Value < 3) { _maxSendQueueBytes.Value = 16384; _peerSendIntervalSeconds.Value = 0.05f; _zoneStreamingBoostExtraRadius.Value = 0; _maxZoneStreamingBoostZdosPerPeer.Value = 128; _zoneStreamingBoostCooldownSeconds.Value = 1.5f; _extendedZoneRadius.Value = 0; _createDestroyIntervalSeconds.Value = 0.1f; _removeObjectsIntervalSeconds.Value = 0.5f; _peerZoneUpdateIntervalSeconds.Value = 0.5f; _maxPeerZoneCreationsPerPass.Value = 1; if (_repairStaleItemDropOwnership != null) { _repairStaleItemDropOwnership.Value = true; } _safetyDefaultsVersion.Value = 3; if (_log != null) { _log.LogWarning((object)"Applied 0.4.3 dense-world migration: reduced bulk streaming and zone-scan pressure, and enabled nearby ItemDrop ownership-request recovery."); } } if (_safetyDefaultsVersion != null && _safetyDefaultsVersion.Value < 4) { if (_enablePeerZoneCreation != null) { _enablePeerZoneCreation.Value = false; } _safetyDefaultsVersion.Value = 4; if (_log != null) { _log.LogWarning((object)"Applied 0.4.6 zone-loading migration: disabled experimental full local peer-zone instantiation. Valheim's normal peer ghost-zone generation remains enabled."); } } } internal static bool ShouldSkipHeadlessVisualSystems() { if (_enabled == null || !_enabled.Value || _enableHeadlessVisualGuards == null || !_enableHeadlessVisualGuards.Value) { return false; } try { if (Application.isBatchMode) { return true; } if (!CanRunOnServer()) { return false; } ZNet instance = ZNet.instance; return (Object)(object)instance != (Object)null && instance.IsDedicated(); } catch { return false; } } private static bool ShouldPauseExtraZoneWorkForSleep() { if (_pauseExtraZoneWorkDuringSleep == null || !_pauseExtraZoneWorkDuringSleep.Value) { return false; } try { EnvMan instance = EnvMan.instance; if ((Object)(object)instance != (Object)null && instance.IsTimeSkipping()) { LogSleepPause(); return true; } float realtimeSinceStartup = Time.realtimeSinceStartup; if (realtimeSinceStartup >= _nextSleepBedCheckTime) { _nextSleepBedCheckTime = realtimeSinceStartup + 0.2f; _sleepBedPauseActive = AreAllCharactersInBed(); } if (_sleepBedPauseActive) { LogSleepPause(); return true; } } catch { return false; } return false; } private static bool AreAllCharactersInBed() { ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null || !instance.IsServer()) { return false; } List<ZDO> allCharacterZDOS = instance.GetAllCharacterZDOS(); if (allCharacterZDOS == null || allCharacterZDOS.Count == 0) { return false; } bool result = false; for (int i = 0; i < allCharacterZDOS.Count; i++) { ZDO val = allCharacterZDOS[i]; if (val != null && val.IsValid()) { result = true; if (!val.GetBool(ZDOVars.s_inBed, false)) { return false; } } } return result; } private static void LogSleepPause() { if (_log != null && _logSleepOptimizations != null && _logSleepOptimizations.Value) { float realtimeSinceStartup = Time.realtimeSinceStartup; if (!(realtimeSinceStartup < _nextSleepPauseLogTime)) { _nextSleepPauseLogTime = realtimeSinceStartup + 30f; _log.LogInfo((object)"Paused extra zone warming while players are sleeping."); } } } private static bool ShouldServerHandleRemoveRpc(ZNet znet, ZDO zdo, long owner, long targetPeerId, long serverUid, long senderPeerId) { if ((Object)(object)znet == (Object)null || zdo == null) { return false; } if (owner == 0L || owner == serverUid || targetPeerId == 0L || targetPeerId == serverUid) { return true; } if (senderPeerId != 0L && senderPeerId != owner) { return true; } ZNetPeer peer = znet.GetPeer(targetPeerId); if (peer == null || !peer.IsReady()) { return true; } return !IsPeerActiveNearZdo(peer, zdo); } private unsafe static ZNetView TryCreateServerInstanceForRemove(ZNetScene scene, ZDO zdo) { //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)scene == (Object)null || zdo == null || _createObjects == null) { return null; } try { List<ZDO> list = new List<ZDO>(1); List<ZDO> distantObjects = new List<ZDO>(0); list.Add(zdo); _createObjects(scene, list, distantObjects); ZNetView obj = scene.FindInstance(zdo); if ((Object)(object)obj != (Object)null && _logRemoveOwnershipRepairs != null && _logRemoveOwnershipRepairs.Value && _log != null) { ManualLogSource log = _log; ZDOID uid = zdo.m_uid; log.LogInfo((object)("Created missing server instance for build-piece remove ZDO " + ((object)(*(ZDOID*)(&uid))/*cast due to .constrained prefix*/).ToString() + ".")); } return obj; } catch (Exception ex) { LogRemoveRepairWarning("Could not create missing server instance for build-piece remove: " + ex.Message); return null; } } private static bool IsRemoveRequesterCloseEnough(ZNet znet, long senderPeerId, Vector3 zdoPosition) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005b: 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) if ((Object)(object)znet == (Object)null) { return false; } long uID = ZNet.GetUID(); if (senderPeerId == uID) { return true; } ZNetPeer peer = znet.GetPeer(senderPeerId); if (peer == null || !peer.IsReady()) { return false; } float num = ((_maxRemoveRepairDistance == null) ? 8f : Mathf.Clamp(_maxRemoveRepairDistance.Value, 5f, 16f)); Vector3 val = peer.GetRefPos() - zdoPosition; return ((Vector3)(ref val)).sqrMagnitude <= num * num; } private static bool IsPeerActiveNearZdo(ZNetPeer peer, ZDO zdo) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (peer == null || zdo == null) { return false; } ZoneSystem instance = ZoneSystem.instance; int num = (((Object)(object)instance == (Object)null) ? 2 : Math.Max(1, instance.m_activeArea)); return ZNetScene.InActiveArea(zdo.GetSector(), ZoneSystem.GetZone(peer.GetRefPos()), num); } private static void InitializeZNetSceneReflection() { _zNetSceneInstancesField = AccessTools.Field(typeof(ZNetScene), "m_instances"); if (_zNetSceneInstancesField == null && _log != null) { _log.LogWarning((object)"Could not bind ZNetScene.m_instances; stale scene-instance sanitation will be unavailable."); } } internal static int RepairStaleSceneInstances(ZNetScene scene) { if ((Object)(object)scene == (Object)null || _zNetSceneInstancesField == null) { return 0; } if (!(_zNetSceneInstancesField.GetValue(scene) is Dictionary<ZDO, ZNetView> { Count: not 0 } dictionary)) { return 0; } _staleSceneInstanceKeys.Clear(); foreach (KeyValuePair<ZDO, ZNetView> item in dictionary) { ZDO key = item.Key; ZNetView value = item.Value; ZDO val = null; if ((Object)(object)value != (Object)null) { try { val = value.GetZDO(); } catch { } } if (key == null || !key.IsValid() || (Object)(object)value == (Object)null || val == null || val != key) { _staleSceneInstanceKeys.Add(key); } } int num = 0; for (int i = 0; i < _staleSceneInstanceKeys.Count; i++) { ZDO val2 = _staleSceneInstanceKeys[i]; if (val2 == null || !dictionary.TryGetValue(val2, out var value2) || !dictionary.Remove(val2)) { continue; } num++; if (!((Object)(object)value2 != (Object)null)) { continue; } try { if (value2.GetZDO() == null) { Object.Destroy((Object)(object)((Component)value2).gameObject); } } catch { } } if (num > 0) { _diagnosticStaleSceneInstancesRemoved += num; if (_log != null) { _log.LogWarning((object)("Removed " + num + " stale ZNetScene instance registration(s) before RemoveObjects.")); } } _staleSceneInstanceKeys.Clear(); return num; } private static void InitializeRoutedRpcReflection() { MethodInfo methodInfo = AccessTools.Method(typeof(ZRoutedRpc), "RouteRPC", (Type[])null, (Type[])null); Type type = null; if (methodInfo != null) { ParameterInfo[] parameters = methodInfo.GetParameters(); if (parameters.Length == 1) { type = parameters[0].ParameterType; } } if (!(type == null)) { _routedRpcTargetPeerIdField = AccessTools.Field(type, "m_targetPeerID"); _routedRpcSenderPeerIdField = AccessTools.Field(type, "m_senderPeerID"); _routedRpcTargetZdoField = AccessTools.Field(type, "m_targetZDO"); _routedRpcMethodHashField = AccessTools.Field(type, "m_methodHash"); _routedRpcParametersField = AccessTools.Field(type, "m_parameters"); } } private static void InitializeSleepReflection() { _envManSkipToTimeField = AccessTools.Field(typeof(EnvMan), "m_skipToTime"); _envManTimeSkipSpeedField = AccessTools.Field(typeof(EnvMan), "m_timeSkipSpeed"); _gameSaveTimerField = AccessTools.Field(typeof(Game), "m_saveTimer"); } private static void InitializeZoneTtlReflection() { _zoneSystemZonesField = AccessTools.Field(typeof(ZoneSystem), "m_zones"); if (_zoneSystemZonesField != null) { Type[] genericArguments = _zoneSystemZonesField.FieldType.GetGenericArguments(); if (genericArguments.Length == 2) { _zoneDataTtlField = AccessTools.Field(genericArguments[1], "m_ttl"); } } if ((_zoneSystemZonesField == null || _zoneDataTtlField == null) && _enablePeerZoneCreation != null && _enablePeerZoneCreation.Value) { _enablePeerZoneCreation.Value = false; if (_log != null) { _log.LogError((object)"Disabled peer zone creation because Valheim's zone TTL fields could not be found safely."); } } } private static void RefreshLoadedPeerZoneTtls(ZoneSystem zoneSystem) { //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: 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_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)zoneSystem == (Object)null || _enablePeerZoneCreation == null || !_enablePeerZoneCreation.Value || _zoneSystemZonesField == null || _zoneDataTtlField == null) { return; } IDictionary dictionary = _zoneSystemZonesField.GetValue(zoneSystem) as IDictionary; ZNet instance = ZNet.instance; if (dictionary == null || (Object)(object)instance == (Object)null || !instance.IsServer()) { return; } List<ZNetPeer> connectedPeers = instance.GetConnectedPeers(); if (connectedPeers == null) { return; } _ttlRefreshZones.Clear(); int radius = Math.Max(1, zoneSystem.m_activeArea); for (int i = 0; i < connectedPeers.Count; i++) { ZNetPeer val = connectedPeers[i]; if (val != null && val.IsReady()) { Vector2i zone = ZoneSystem.GetZone(val.GetRefPos()); AddZoneSquare(_ttlRefreshZones, zone, radius); Vector2i zone2 = ZoneSystem.GetZone(GetPredictedRefPos(val)); if (!(zone2 == zone)) { AddZoneSquare(_ttlRefreshZones, zone2, radius); } } } foreach (Vector2i ttlRefreshZone in _ttlRefreshZones) { if (dictionary.Contains(ttlRefreshZone)) { object obj = dictionary[ttlRefreshZone]; if (obj != null) { _zoneDataTtlField.SetValue(obj, 0f); _diagnosticZoneTtlRefreshes++; } } } } private static void AddZoneSquare(HashSet<Vector2i> zones, Vector2i center, int radius) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) for (int i = center.y - radius; i <= center.y + radius; i++) { for (int j = center.x - radius; j <= center.x + radius; j++) { zones.Add(new Vector2i(j, i)); } } } private static bool HasRoutedRpcReflection() { if (_routedRpcTargetPeerIdField != null && _routedRpcSenderPeerIdField != null && _routedRpcTargetZdoField != null) { return _routedRpcMethodHashField != null; } return false; } private static void LogRemoveRepairWarning(string message) { if (_log != null && !(Time.realtimeSinceStartup < _nextRemoveRepairWarningTime)) { _nextRemoveRepairWarningTime = Time.realtimeSinceStartup + 30f; _log.LogWarning((object)message); } } private static void ClampConfig() { ClampInt(_maxSendQueueBytes, 2048, 262144); ClampInt(_minFreeSendQueueBytes, 512, 131072); ClampFloat(_peerSendIntervalSeconds, 0.01f, 0.25f); ClampInt(_zoneStreamingBoostExtraRadius, 0, 3); ClampInt(_maxZoneStreamingBoostZdosPerPeer, 0, 5000); ClampFloat(_zoneStreamingBoostCooldownSeconds, 0.1f, 10f); ClampInt(_zoneStreamingBoostMaxQueuePercent, 10, 90); ClampInt(_denseSyncThreshold, 100, 100000); ClampFloat(_denseSyncLogIntervalSeconds, 5f, 600f); ClampFloat(_denseSyncPauseSeconds, 0.5f, 30f); ClampInt(_extendedZoneRadius, 0, 3); ClampFloat(_createDestroyIntervalSeconds, 0.03f, 1f); ClampFloat(_removeObjectsIntervalSeconds, 0.05f, 2f); ClampFloat(_predictionLookaheadSec, 0.5f, 10f); ClampFloat(_predictionMinVelocity, 0.5f, 20f); ClampInt(_predictionMaxLookaheadZones, 1, 25); ClampFloat(_zdoThrottleDistance, 0f, 1000f); ClampFloat(_peerZoneUpdateIntervalSeconds, 0.05f, 2f); ClampInt(_maxPeerZoneCreationsPerPass, 1, 16); ClampFloat(_sleepFastForwardSeconds, 1f, 60f); ClampFloat(_maxRemoveRepairDistance, 5f, 16f); ClampFloat(_diagnosticIntervalSec, 10f, 3600f); if (_minFreeSendQueueBytes != null && _maxSendQueueBytes != null && _minFreeSendQueueBytes.Value > _maxSendQueueBytes.Value) { _minFreeSendQueueBytes.Value = _maxSendQueueBytes.Value; } } private static bool ClampInt(ConfigEntry<int> entry, int min, int max) { if (entry.Value < min) { entry.Value = min; return true; } if (entry.Value > max) { entry.Value = max; return true; } return false; } private static bool ClampFloat(ConfigEntry<float> entry, float min, float max) { if (entry.Value < min) { entry.Value = min; return true; } if (entry.Value > max) { entry.Value = max; return true; } return false; } private static int GetPlayerPrefabHash() { return PlayerPrefabHash; } internal static void MaybeLogDenseSync(object zdoPeer, List<ZDO> toSync) { if (CanRunOnServer() && _log != null && _logDenseSyncs != null && _logDenseSyncs.Value && zdoPeer != null && toSync != null && toSync.Count >= _denseSyncThreshold.Value) { ZNetPeer netPeer = GetNetPeer(zdoPeer); long key = netPeer?.m_uid ?? 0; float realtimeSinceStartup = Time.realtimeSinceStartup; if (!_lastDenseSyncLogTimes.TryGetValue(key, out var value) || !(realtimeSinceStartup - value < _denseSyncLogIntervalSeconds.Value)) { _lastDenseSyncLogTimes[key] = realtimeSinceStartup; string text = ((netPeer == null || string.IsNullOrEmpty(netPeer.m_playerName)) ? "unknown peer" : netPeer.m_playerName); string text2 = DescribeDenseSyncPrefabs(toSync); _log.LogInfo((object)("Dense ZDO sync for " + text + ": " + toSync.Count + " pending object(s)" + text2 + ". If this stays high, the area itself is probably too object-heavy for smooth client loading.")); } } } private static string DescribeDenseSyncPrefabs(List<ZDO> toSync) { _densePrefabCounts.Clear(); _densePrefabCountsSorted.Clear(); for (int i = 0; i < toSync.Count; i++) { ZDO val = toSync[i]; if (val != null && val.IsValid()) { int prefab = val.GetPrefab(); _densePrefabCounts.TryGetValue(prefab, out var value); _densePrefabCounts[prefab] = value + 1; } } foreach (KeyValuePair<int, int> densePrefabCount in _densePrefabCounts) { _densePrefabCountsSorted.Add(densePrefabCount); } _densePrefabCountsSorted.Sort((KeyValuePair<int, int> left, KeyValuePair<int, int> right) => right.Value.CompareTo(left.Value)); int num = Math.Min(5, _densePrefabCountsSorted.Count); if (num == 0) { return string.Empty; } ZNetScene instance = ZNetScene.instance; StringBuilder stringBuilder = new StringBuilder("; top pending prefabs: "); for (int num2 = 0; num2 < num; num2++) { if (num2 > 0) { stringBuilder.Append(", "); } KeyValuePair<int, int> keyValuePair = _densePrefabCountsSorted[num2]; GameObject val2 = (((Object)(object)instance == (Object)null) ? null : instance.GetPrefab(keyValuePair.Key)); stringBuilder.Append(((Object)(object)val2 == (Object)null) ? ("hash:" + keyValuePair.Key) : ((Object)val2).name); stringBuilder.Append('='); stringBuilder.Append(keyValuePair.Value); } return stringBuilder.ToString(); } private static Vector3 GetPredictedRefPos(ZNetPeer peer) { //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_001a: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0152: 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_015c: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) Vector3 refPos = peer.GetRefPos(); if (_enablePredictiveZoneStreaming == null || !_enablePredictiveZoneStreaming.Value) { return refPos; } float realtimeSinceStartup = Time.realtimeSinceStartup; long uid = peer.m_uid; if (!_peerMotion.TryGetValue(uid, out var value)) { value = new PeerMotionSample(refPos, Vector3.zero, realtimeSinceStartup); _peerMotion[uid] = value; return refPos; } float num = realtimeSinceStartup - value.Time; if (num >= 0.25f) { Vector3 val = refPos - value.Position; val.y = 0f; if (num > 2f || ((Vector3)(ref val)).sqrMagnitude > 16384f) { value.Velocity = Vector3.zero; } else if (((Vector3)(ref val)).sqrMagnitude < 0.01f) { value.Velocity = Vector3.zero; } else { Vector3 val2 = val / Mathf.Max(num, 0.05f); value.Velocity = Vector3.Lerp(value.Velocity, val2, 0.5f); } value.Position = refPos; value.Time = realtimeSinceStartup; _peerMotion[uid] = value; } float num2 = Mathf.Max(0f, _predictionMinVelocity.Value); if (((Vector3)(ref value.Velocity)).magnitude < num2) { return refPos; } Vector3 predicted = refPos + value.Velocity * Mathf.Max(0.5f, _predictionLookaheadSec.Value); return ClampForwardOffsetToMaxZones(refPos, predicted, Mathf.Max(1, _predictionMaxLookaheadZones.Value)); } private static void PrunePeerTracking(HashSet<long> readyPeerIds) { if (readyPeerIds == null) { return; } _stalePeerIds.Clear(); foreach (long key in _peerStreamingStates.Keys) { if (!readyPeerIds.Contains(key)) { _stalePeerIds.Add(key); } } for (int i = 0; i < _stalePeerIds.Count; i++) { _peerStreamingStates.Remove(_stalePeerIds[i]); } _stalePeerIds.Clear(); foreach (long key2 in _peerMotion.Keys) { if (!readyPeerIds.Contains(key2)) { _stalePeerIds.Add(key2); } } for (int j = 0; j < _stalePeerIds.Count; j++) { _peerMotion.Remove(_stalePeerIds[j]); } _stalePeerIds.Clear(); foreach (long key3 in _lastDenseSyncLogTimes.Keys) { if (!readyPeerIds.Contains(key3)) { _stalePeerIds.Add(key3); } } for (int k = 0; k < _stalePeerIds.Count; k++) { _lastDenseSyncLogTimes.Remove(_stalePeerIds[k]); } _stalePeerIds.Clear(); } private static Vector3 ClampForwardOffsetToMaxZones(Vector3 origin, Vector3 predicted, int maxZones) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_004f: 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_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005b: 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_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) Vector3 val = predicted - origin; val.y = 0f; float num = (float)maxZones * 64f; if (((Vector3)(ref val)).magnitude <= num) { return new Vector3(origin.x + val.x, predicted.y, origin.z + val.z); } Vector3 val2 = ((Vector3)(ref val)).normalized * num; return new Vector3(origin.x + val2.x, predicted.y, origin.z + val2.z); } private static ZNetPeer GetNetPeer(object zdoPeer) { Type type = zdoPeer.GetType(); if (!_netPeerFields.TryGetValue(type, out var value)) { value = AccessTools.Field(type, "m_peer"); _netPeerFields[type] = value; } if (!(value == null)) { object? value2 = value.GetValue(zdoPeer); return (ZNetPeer)((value2 is ZNetPeer) ? value2 : null); } return null; } private static HashSet<ZDOID> GetForceSendSet(object zdoPeer) { Type type = zdoPeer.GetType(); if (!_forceSendFields.TryGetValue(type, out var value)) { value = AccessTools.Field(type, "m_forceSend"); _forceSendFields[type] = value; } if (!(value == null)) { return value.GetValue(zdoPeer) as HashSet<ZDOID>; } return null; } private static void FilterAndDedupeZdos(List<ZDO> source, List<ZDO> destination) { destination.Clear(); ZNetScene instance = ZNetScene.instance; for (int i = 0; i < source.Count; i++) { ZDO val = source[i]; if (val != null && val.IsValid() && !((ZDOID)(ref val.m_uid)).IsNone() && (!((Object)(object)instance != (Object)null) || instance.HasPrefab(val.GetPrefab())) && !ShouldDelayTerrainCompilerZdo(val, instance) && _seenZdos.Add(val)) { destination.Add(val); } } } private static bool ShouldDelayTerrainCompilerZdo(ZDO zdo, ZNetScene scene) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) if (zdo == null || (Object)(object)scene == (Object)null || !IsTerrainCompilerPrefab(scene, zdo.GetPrefab())) { return false; } try { return (Object)(object)Heightmap.FindHeightmap(zdo.GetPosition()) == (Object)null; } catch { return true; } } private static bool IsTerrainCompilerPrefab(ZNetScene scene, int prefabHash) { if (_terrainCompilerPrefabCache.TryGetValue(prefabHash, out var value)) { return value; } bool flag = false; try { GameObject val = (((Object)(object)scene == (Object)null) ? null : scene.GetPrefab(prefabHash)); if ((Object)(object)val != (Object)null) { flag = (Object)(object)val.GetComponent<TerrainComp>() != (Object)null || (Object)(object)val.GetComponentInChildren<TerrainComp>(true) != (Object)null; } } catch { flag = false; } _terrainCompilerPrefabCache[prefabHash] = flag; return flag; } private static void MaybeLogDiagnostics() { if (_log != null && !(Time.realtimeSinceStartup < _nextDiagnosticLogTime)) { _nextDiagnosticLogTime = Time.realtimeSinceStartup + Mathf.Clamp(_diagnosticIntervalSec.Value, 10f, 3600f); _log.LogInfo((object)("TerramizerServer status: create/destroy passes=" + _diagnosticCreateDestroyPasses + ", last candidates=" + _nearFiltered.Count + " near/" + _distantFiltered.Count + " distant, zone creates=" + _diagnosticZoneCreateSuccesses + "/" + _diagnosticZoneCreateAttempts + ", boost queued=" + _diagnosticBoostQueued + ", boost backpressure skips=" + _diagnosticBoostBackpressureSkips + ", item ownership transfers=" + _diagnosticItemDropOwnershipRepairs + ", item ownership refreshes=" + _diagnosticItemDropOwnershipRefreshes + ", stale scene registrations removed=" + _diagnosticStaleSceneInstancesRemoved + ", dense-pressure pauses=" + _diagnosticDensePressurePauses + ", zone TTL refreshes=" + _diagnosticZoneTtlRefreshes + ", sync duplicates removed=" + _diagnosticSyncDuplicatesRemoved + ", max sync list=" + _diagnosticMaxSyncList + ", peak socket queue=" + _diagnosticPeakSendQueue + " bytes.")); _diagnosticCreateDestroyPasses = 0L; _diagnosticZoneCreateAttempts = 0L; _diagnosticZoneCreateSuccesses = 0L; _diagnosticBoostQueued = 0L; _diagnosticBoostBackpressureSkips = 0L; _diagnosticItemDropOwnershipRepairs = 0L; _diagnosticItemDropOwnershipRefreshes = 0L; _diagnosticStaleSceneInstancesRemoved = 0L; _diagnosticDensePressurePauses = 0L; _diagnosticZoneTtlRefreshes = 0L; _diagnosticSyncDuplicatesRemoved = 0L; _diagnosticMaxSyncList = 0; _diagnosticPeakSendQueue = 0; } } private static T CreateDelegateSafely<T>(Type type, string methodName) where T : Delegate { try { MethodInfo methodInfo = AccessTools.Method(type, methodName, (Type[])null, (Type[])null); if (methodInfo == null) { LogWarningThrottled("Could not find " + type.Name + "." + methodName + "; related server-simulation feature will stay inactive."); return null; } return AccessTools.MethodDelegate<T>(methodInfo, (object)null, true); } catch (Exception ex) { LogWarningThrottled("Could not bind " + type.Name + "." + methodName + ": " + ex.Message); return null; } } private static void LogWarningThrottled(string message) { if (_log != null) { float realtimeSinceStartup = Time.realtimeSinceStartup; if (!(realtimeSinceStartup < _nextWarningLogTime)) { _nextWarningLogTime = realtimeSinceStartup + 30f; _log.LogWarning((object)message); } } } internal static void LogPatchMismatch(string feature, string details) { if (_log != null) { _log.LogError((object)("Left " + feature + " at vanilla behavior because the expected IL pattern was not found (" + details + "). This usually means Valheim changed; update TerramizerServer before forcing the feature.")); } } } [HarmonyPatch(typeof(ZDOMan), "SendZDOs")] internal static class ZdoManSendZdosPatch { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Expected O, but got Unknown //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Expected O, but got Unknown List<CodeInstruction> list = new List<CodeInstruction>(instructions); MethodInfo methodInfo = AccessTools.Method(typeof(TerramizerServerPlugin), "GetMaxSendQueueBytes", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(TerramizerServerPlugin), "GetMinFreeSendQueueBytes", (Type[])null, (Type[])null); int num = 0; int num2 = 0; for (int i = 0; i < list.Count; i++) { CodeInstruction val = list[i]; if (val.opcode == OpCodes.Ldc_I4 && val.operand is int) { int num3 = (int)val.operand; num += ((num3 == 10240) ? 1 : 0); num2 += ((num3 == 2048) ? 1 : 0); } } if (methodInfo == null || methodInfo2 == null || num != 2 || num2 != 1) { TerramizerServerPlugin.LogPatchMismatch("ZDO queue limits", "max=" + num + ", min=" + num2); return list; } List<CodeInstruction> list2 = new List<CodeInstruction>(list.Count); foreach (CodeInstruction item in list) { if (item.opcode == OpCodes.Ldc_I4 && item.operand is int) { switch ((int)item.operand) { case 10240: list2.Add(CopyLabelsAndBlocks(item, new CodeInstruction(OpCodes.Call, (object)methodInfo))); continue; case 2048: list2.Add(CopyLabelsAndBlocks(item, new CodeInstruction(OpCodes.Call, (object)methodInfo2))); continue; } } list2.Add(item); } return list2; } private static CodeInstruction CopyLabelsAndBlocks(CodeInstruction source, CodeInstruction target) { target.labels.AddRange(source.labels); target.blocks.AddRange(source.blocks); return target; } } [HarmonyPatch(typeof(ZDOMan), "SendZDOToPeers2")] internal static class ZdoManSendZdoToPeersPatch { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Expected O, but got Unknown List<CodeInstruction> list = new List<CodeInstruction>(instructions); MethodInfo methodInfo = AccessTools.Method(typeof(TerramizerServerPlugin), "GetPeerSendIntervalSeconds", (Type[])null, (Type[])null); int num = 0; for (int i = 0; i < list.Count; i++) { CodeInstruction val = list[i]; if (val.opcode == OpCodes.Ldc_R4 && val.operand is float && Math.Abs((float)val.operand - 0.05f) < 0.0001f) { num++; } } if (methodInfo == null || num != 1) { TerramizerServerPlugin.LogPatchMismatch("ZDO send interval", "matches=" + num); return list; } List<CodeInstruction> list2 = new List<CodeInstruction>(list.Count); foreach (CodeInstruction item in list) { if (item.opcode == OpCodes.Ldc_R4 && item.operand is float && Math.Abs((float)item.operand - 0.05f) < 0.0001f) { list2.Add(CopyLabelsAndBlocks(item, new CodeInstruction(OpCodes.Call, (object)methodInfo))); } else { list2.Add(item); } } return list2; } private static CodeInstruction CopyLabelsAndBlocks(CodeInstruction source, CodeInstruction target) { target.labels.AddRange(source.labels); target.blocks.AddRange(source.blocks); return target; } } [HarmonyPatch(typeof(ZDOMan), "CreateSyncList")] internal static class ZdoManCreateSyncListPatch { private static void Postfix(object __0, List<ZDO> __1) { TerramizerServerPlugin.PostProcessSyncList(__0, __1); } } [HarmonyPatch(typeof(EnvMan), "SkipToMorning")] internal static class EnvManSkipToMorningPatch { [HarmonyPriority(0)] private static void Postfix(EnvMan __instance) { TerramizerServerPlugin.TuneSleepFastForward(__instance); } } [HarmonyPatch(typeof(Game), "SleepStop")] internal static class GameSleepStopPatch { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Exp