Decompiled source of RustyHeathensServerSync v1.0.0

RustyHeathensServerSync.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using HarmonyLib;
using UnityEngine;

[assembly: AssemblyCompany("RustyLaserGaming")]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyTitle("Rusty Heathens ServerSync")]
[assembly: AssemblyDescription("Heathens' Haven desync diagnostics and guarded bounded scheduler. Reviewed for Valheim 1.0.17 / network 40.")]
[assembly: AssemblyProduct("Rusty Heathens ServerSync")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyVersion("1.0.0.0")]
namespace RustyHeathens.ServerSync;

internal static class CompatibilityRules
{
	internal static bool IsSupported(string gameVersion, uint networkVersion)
	{
		if (networkVersion != 40)
		{
			return false;
		}
		if (!(gameVersion == "1.0.16"))
		{
			return gameVersion == "1.0.17";
		}
		return true;
	}
}
internal static class MethodFingerprint
{
	private static readonly Dictionary<ushort, OpCode> Codes = MakeCodes();

	private static Dictionary<ushort, OpCode> MakeCodes()
	{
		Dictionary<ushort, OpCode> dictionary = new Dictionary<ushort, OpCode>();
		FieldInfo[] fields = typeof(OpCodes).GetFields(BindingFlags.Static | BindingFlags.Public);
		foreach (FieldInfo fieldInfo in fields)
		{
			if (!(fieldInfo.FieldType != typeof(OpCode)))
			{
				OpCode value = (OpCode)fieldInfo.GetValue(null);
				dictionary[(ushort)value.Value] = value;
			}
		}
		return dictionary;
	}

	internal static string Raw(MethodInfo method)
	{
		if (method == null || method.GetMethodBody() == null)
		{
			return "missing";
		}
		return Hash(method.GetMethodBody().GetILAsByteArray());
	}

	internal static string Normalized(MethodInfo method)
	{
		if (method == null || method.GetMethodBody() == null)
		{
			return "missing";
		}
		byte[] iLAsByteArray = method.GetMethodBody().GetILAsByteArray();
		StringBuilder stringBuilder = new StringBuilder();
		int num = 0;
		while (num < iLAsByteArray.Length)
		{
			ushort num2 = iLAsByteArray[num++];
			if (num2 == 254)
			{
				Need(iLAsByteArray, num, 1);
				num2 = (ushort)(0xFE00 | iLAsByteArray[num++]);
			}
			if (!Codes.TryGetValue(num2, out var value))
			{
				throw new InvalidOperationException("Unknown IL opcode.");
			}
			stringBuilder.Append(num2.ToString("x4", CultureInfo.InvariantCulture)).Append(':');
			int num3 = 0;
			switch (value.OperandType)
			{
			case OperandType.ShortInlineBrTarget:
			case OperandType.ShortInlineI:
			case OperandType.ShortInlineVar:
				num3 = 1;
				break;
			case OperandType.InlineVar:
				num3 = 2;
				break;
			case OperandType.InlineBrTarget:
			case OperandType.InlineI:
			case OperandType.ShortInlineR:
				num3 = 4;
				break;
			case OperandType.InlineI8:
			case OperandType.InlineR:
				num3 = 8;
				break;
			case OperandType.InlineSwitch:
			{
				Need(iLAsByteArray, num, 4);
				int num4 = BitConverter.ToInt32(iLAsByteArray, num);
				if (num4 < 0 || num4 > 10000)
				{
					throw new InvalidOperationException("Invalid switch.");
				}
				num3 = checked(4 + num4 * 4);
				break;
			}
			case OperandType.InlineField:
			case OperandType.InlineMethod:
			case OperandType.InlineTok:
			case OperandType.InlineType:
			{
				Need(iLAsByteArray, num, 4);
				MemberInfo memberInfo = method.Module.ResolveMember(BitConverter.ToInt32(iLAsByteArray, num));
				Type type = memberInfo as Type;
				if (type != null)
				{
					stringBuilder.Append(type.Name);
				}
				else
				{
					stringBuilder.Append(memberInfo.DeclaringType.Name).Append("::").Append(memberInfo.Name);
				}
				num += 4;
				break;
			}
			case OperandType.InlineString:
				Need(iLAsByteArray, num, 4);
				stringBuilder.Append("string:").Append(method.Module.ResolveString(BitConverter.ToInt32(iLAsByteArray, num)));
				num += 4;
				break;
			default:
				throw new InvalidOperationException("Unsupported IL operand in guard.");
			case OperandType.InlineNone:
				break;
			}
			Need(iLAsByteArray, num, num3);
			for (int i = 0; i < num3; i++)
			{
				stringBuilder.Append(iLAsByteArray[num++].ToString("x2", CultureInfo.InvariantCulture));
			}
			stringBuilder.Append('\n');
		}
		return Hash(Encoding.UTF8.GetBytes(stringBuilder.ToString()));
	}

	private static void Need(byte[] bytes, int offset, int size)
	{
		if (size < 0 || offset < 0 || offset > bytes.Length - size)
		{
			throw new InvalidOperationException("Truncated IL method.");
		}
	}

	private static string Hash(byte[] bytes)
	{
		using SHA256 sHA = SHA256.Create();
		byte[] array = sHA.ComputeHash(bytes);
		return BitConverter.ToString(array).Replace("-", "").ToLowerInvariant();
	}
}
public enum SyncMode
{
	Observe,
	BoundedScheduler
}
[BepInPlugin("com.rustylasergaming.serversync", "Rusty Heathens ServerSync", "1.0.0")]
public sealed class Plugin : BaseUnityPlugin
{
	internal sealed class PeerStats
	{
		internal string Label;

		internal readonly RunningStats SendDuration = new RunningStats();

		internal int QueuePeak;

		internal int LastQueue;

		internal long QueueLimitedAttempts;

		internal long CallsWithoutData;

		internal int PingMs;

		internal float QualityLocal;

		internal float QualityRemote;

		internal float OutBytesSec;

		internal float InBytesSec;

		internal string Transport;

		internal bool TransportStatsAvailable;

		internal bool TransportStatsUnsupportedLogged;

		internal long LastCycleStart;

		internal readonly RunningStats VisitGap = new RunningStats();
	}

	public const string PluginId = "com.rustylasergaming.serversync";

	public const string PluginName = "Rusty Heathens ServerSync";

	public const string PluginVersion = "1.0.0";

	internal static Plugin Current;

	private ConfigEntry<SyncMode> mode;

	private ConfigEntry<bool> diagnostics;

	private ConfigEntry<int> reportSeconds;

	private ConfigEntry<int> maxCalls;

	private ConfigEntry<float> budgetMs;

	private ConfigEntry<float> maxFrameMs;

	private ConfigEntry<float> saveCooldownSeconds;

	private Harmony harmony;

	private bool bindingsReady;

	private bool schedulerCompatible;

	private bool schedulerFaulted;

	private bool overlappingPatches;

	private bool otherNetworkPlugin;

	private bool diagnosticFaulted;

	private bool isServer;

	private bool isDedicated;

	private ZNet lastNet;

	private double nextReport;

	private double nextPeerSample;

	private double nextConflictCheck;

	private double lastSave = -1000000.0;

	private int nextLabel = 1;

	private long extraCalls;

	private long reportSerial;

	private string lastEffectiveState = "";

	[ThreadStatic]
	internal static bool ExtraInvocation;

	private readonly RunningStats frames = new RunningStats();

	private readonly RunningStats cycles = new RunningStats();

	private readonly RunningStats saveDispatch = new RunningStats();

	private readonly Dictionary<ZNetPeer, PeerStats> peers = new Dictionary<ZNetPeer, PeerStats>();

	private static readonly object[] ZeroDt = new object[1] { 0f };

	internal static readonly BindingFlags InstanceFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

	internal static MethodInfo SendCycle;

	internal static MethodInfo SendOne;

	internal static MethodInfo SaveWorld;

	internal static FieldInfo NextPeer;

	internal static FieldInfo ZdoPeers;

	internal static FieldInfo WrappedPeer;

	internal static double Now => (double)Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency;

	internal bool Measuring
	{
		get
		{
			if (bindingsReady && diagnostics.Value)
			{
				return !diagnosticFaulted;
			}
			return false;
		}
	}

	private bool ExtraEnabled
	{
		get
		{
			if (bindingsReady && schedulerCompatible && !schedulerFaulted && !overlappingPatches && !otherNetworkPlugin && isServer && isDedicated)
			{
				return mode.Value == SyncMode.BoundedScheduler;
			}
			return false;
		}
	}

	private void Awake()
	{
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0078: Expected O, but got Unknown
		//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ab: Expected O, but got Unknown
		//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ea: Expected O, but got Unknown
		//IL_011f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0129: Expected O, but got Unknown
		//IL_015e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0168: Expected O, but got Unknown
		//IL_0172: Unknown result type (might be due to invalid IL or missing references)
		//IL_0177: Unknown result type (might be due to invalid IL or missing references)
		//IL_0217: Unknown result type (might be due to invalid IL or missing references)
		//IL_0221: Expected O, but got Unknown
		Current = this;
		mode = ((BaseUnityPlugin)this).Config.Bind<SyncMode>("General", "Mode", SyncMode.Observe, "Observe changes no sending decisions. BoundedScheduler is an UNVALIDATED dedicated-server experiment. Restart after editing.");
		diagnostics = ((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "Enabled", true, "Record bounded summary lines in BepInEx/LogOutput.log. No player names, account IDs or IPs are emitted by this plugin.");
		reportSeconds = ((BaseUnityPlugin)this).Config.Bind<int>("Diagnostics", "ReportIntervalSeconds", 10, new ConfigDescription("Summary interval, seconds.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(5, 120), new object[0]));
		maxCalls = ((BaseUnityPlugin)this).Config.Bind<int>("Scheduler", "MaxNativeCallsPerUpdate", 2, new ConfigDescription("Includes the original call. Never starts another round in the same update. Ignored in Observe.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 3), new object[0]));
		budgetMs = ((BaseUnityPlugin)this).Config.Bind<float>("Scheduler", "StartBudgetMilliseconds", 2f, new ConfigDescription("Do not START another native call after this elapsed budget. A native call can overrun it; it cannot be interrupted.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 5f), new object[0]));
		maxFrameMs = ((BaseUnityPlugin)this).Config.Bind<float>("Scheduler", "SkipExtraCallsAboveFrameMilliseconds", 100f, new ConfigDescription("Do not add work on an already slow frame.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(20f, 500f), new object[0]));
		saveCooldownSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Scheduler", "PauseAfterSaveDispatchSeconds", 2f, new ConfigDescription("Pause additional work briefly after SaveWorld returns. This is not whole-save timing.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 30f), new object[0]));
		try
		{
			BindNativeMethods();
			string text = ((object)Version.CurrentVersion/*cast due to .constrained prefix*/).ToString();
			uint num = ReadRuntimeNetworkVersion();
			if (!CompatibilityRules.IsSupported(text, num))
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[RHSS] Unsupported game/network version. No native hooks installed. game=" + text + " network=" + num + ". Reviewed targets: 1.0.16/40 and 1.0.17/40."));
				return;
			}
			schedulerCompatible = Match(SendCycle, "dd2e102940bf06a36ab8cf0e96f7937fb610e50437af8b9610429bb7bc0736d0", "caadd5a991c3b2bc979b726f4e82d634b0606d71097724c36d992055083985d3") && Match(SendOne, "35b3b63e6528c9d38f220578bd4e3f86cddb6c694de50eb32e8edfef56c1a8a5", "5238fd12d2398c6e5e1c859bc0e488f53497a5c8238e64903215d060621d542d");
			harmony = new Harmony("com.rustylasergaming.serversync");
			Patch(SendCycle, typeof(CycleHooks));
			Patch(SendOne, typeof(SendHooks));
			if (SaveWorld != null)
			{
				Patch(SaveWorld, typeof(SaveHooks));
			}
			bindingsReady = true;
			CheckConflicts();
			((BaseUnityPlugin)this).Logger.LogInfo((object)string.Concat("[RHSS] 1.0.0 loaded. game=", text, " network=", num, " configured_mode=", mode.Value, " native_scheduler_guard=", schedulerCompatible, " compat=reviewed-1.0.16-1.0.17 mod_admission_enforcement=NOT_IMPLEMENTED. No queue limits, ownership, inventories or save contents are modified."));
			if (!schedulerCompatible)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"[RHSS] Native method fingerprint differs. Additional scheduling is disabled; diagnostics only.");
			}
		}
		catch (Exception ex)
		{
			bindingsReady = false;
			schedulerFaulted = true;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			((BaseUnityPlugin)this).Logger.LogError((object)("[RHSS] Initialization failed; this plugin's hooks were removed. " + ex));
		}
	}

	private static uint ReadRuntimeNetworkVersion()
	{
		FieldInfo field = typeof(Version).GetField("c_networkVersion", BindingFlags.Static | BindingFlags.Public);
		if (field == null)
		{
			throw new InvalidOperationException("Version.c_networkVersion was not found.");
		}
		object value = (field.IsLiteral ? field.GetRawConstantValue() : field.GetValue(null));
		return Convert.ToUInt32(value, CultureInfo.InvariantCulture);
	}

	private static void BindNativeMethods()
	{
		SendCycle = typeof(ZDOMan).GetMethod("SendZDOToPeers2", InstanceFlags, null, new Type[1] { typeof(float) }, null);
		NextPeer = typeof(ZDOMan).GetField("m_nextSendPeer", InstanceFlags);
		ZdoPeers = typeof(ZDOMan).GetField("m_peers", InstanceFlags);
		SendOne = null;
		MethodInfo[] methods = typeof(ZDOMan).GetMethods(InstanceFlags);
		foreach (MethodInfo methodInfo in methods)
		{
			ParameterInfo[] parameters = methodInfo.GetParameters();
			if (methodInfo.Name == "SendZDOs" && methodInfo.ReturnType == typeof(bool) && parameters.Length == 2 && parameters[1].ParameterType == typeof(bool))
			{
				if (SendOne != null)
				{
					throw new InvalidOperationException("Ambiguous SendZDOs signature.");
				}
				SendOne = methodInfo;
				WrappedPeer = parameters[0].ParameterType.GetField("m_peer", InstanceFlags);
			}
		}
		SaveWorld = typeof(ZNet).GetMethod("SaveWorld", InstanceFlags, null, new Type[1] { typeof(bool) }, null);
		if (SendCycle == null || SendCycle.ReturnType != typeof(void) || NextPeer == null || NextPeer.FieldType != typeof(int) || ZdoPeers == null || SendOne == null || WrappedPeer == null || WrappedPeer.FieldType != typeof(ZNetPeer))
		{
			throw new InvalidOperationException("Required reviewed network method/field signatures were not found.");
		}
	}

	private static bool Match(MethodInfo method, string raw, string normalized)
	{
		try
		{
			return MethodFingerprint.Raw(method) == raw || MethodFingerprint.Normalized(method) == normalized;
		}
		catch
		{
			return false;
		}
	}

	private void Patch(MethodInfo method, Type hooks)
	{
		//IL_000e: 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_0027: Expected O, but got Unknown
		//IL_0027: Expected O, but got Unknown
		harmony.Patch((MethodBase)method, new HarmonyMethod(hooks, "Prefix", (Type[])null), new HarmonyMethod(hooks, "Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
	}

	internal static double Elapsed(long start)
	{
		return 1000.0 * (double)(Stopwatch.GetTimestamp() - start) / (double)Stopwatch.Frequency;
	}

	private string EffectiveState()
	{
		if (!bindingsReady)
		{
			return "inactive";
		}
		if (mode.Value == SyncMode.Observe)
		{
			return "observe";
		}
		if (!isServer || !isDedicated)
		{
			return "observe:not-dedicated-server";
		}
		if (!schedulerCompatible)
		{
			return "observe:method-guard-failed";
		}
		if (schedulerFaulted)
		{
			return "observe:scheduler-fault";
		}
		if (overlappingPatches || otherNetworkPlugin)
		{
			return "observe:network-overlap";
		}
		return "bounded-scheduler:experimental";
	}

	private void Update()
	{
		if (!bindingsReady)
		{
			return;
		}
		try
		{
			ZNet instance = ZNet.instance;
			if ((Object)(object)instance != (Object)(object)lastNet)
			{
				lastNet = instance;
				peers.Clear();
				nextLabel = 1;
				frames.Reset();
				cycles.Reset();
				saveDispatch.Reset();
				extraCalls = 0L;
				lastSave = -1000000.0;
				nextReport = Now + (double)reportSeconds.Value;
			}
			isServer = (Object)(object)instance != (Object)null && instance.IsServer();
			isDedicated = (Object)(object)instance != (Object)null && instance.IsDedicated();
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			if (Measuring)
			{
				frames.Add((double)Time.unscaledDeltaTime * 1000.0);
			}
			double now = Now;
			if (now >= nextConflictCheck)
			{
				nextConflictCheck = now + 1.0;
				CheckConflicts();
			}
			string text = EffectiveState();
			if (text != lastEffectiveState)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("[RHSS] effective_mode=" + text));
				lastEffectiveState = text;
			}
			if (Measuring)
			{
				if (now >= nextPeerSample)
				{
					nextPeerSample = now + 1.0;
					SamplePeers(instance);
				}
				if (now >= nextReport)
				{
					nextReport = now + (double)reportSeconds.Value;
					Report(instance);
				}
			}
		}
		catch (Exception ex)
		{
			DiagnosticFault(ex);
		}
	}

	private void CheckConflicts()
	{
		bool flag = ForeignOwner(SendCycle) || ForeignOwner(SendOne);
		bool flag2 = false;
		foreach (PluginInfo value in Chainloader.PluginInfos.Values)
		{
			if (!(value.Metadata.GUID == "com.rustylasergaming.serversync"))
			{
				string text = (value.Metadata.GUID + " " + value.Metadata.Name).ToLowerInvariant();
				if (text.Contains("ghettonetwork") || text.Contains("vbnettweaks") || text.Contains("valheimplus") || value.Metadata.Name.Equals("Network", StringComparison.OrdinalIgnoreCase))
				{
					flag2 = true;
					break;
				}
			}
		}
		if ((!overlappingPatches && flag) || (!otherNetworkPlugin && flag2))
		{
			List<string> list = new List<string>();
			AddForeignOwners(SendCycle, list);
			AddForeignOwners(SendOne, list);
			((BaseUnityPlugin)this).Logger.LogWarning((object)("[RHSS] Networking overlap detected. Additional scheduling is disabled. Existing mods were not removed. owners=" + ((list.Count == 0) ? "name-detected-network-plugin" : string.Join(",", list.ToArray()))));
		}
		overlappingPatches = flag;
		otherNetworkPlugin = flag2;
	}

	private static bool ForeignOwner(MethodBase method)
	{
		if (method == null)
		{
			return true;
		}
		Patches patchInfo = Harmony.GetPatchInfo(method);
		if (patchInfo == null)
		{
			return false;
		}
		foreach (string owner in patchInfo.Owners)
		{
			if (owner != "com.rustylasergaming.serversync")
			{
				return true;
			}
		}
		return false;
	}

	private static void AddForeignOwners(MethodBase method, List<string> owners)
	{
		if (method == null)
		{
			return;
		}
		Patches patchInfo = Harmony.GetPatchInfo(method);
		if (patchInfo == null)
		{
			return;
		}
		foreach (string owner in patchInfo.Owners)
		{
			if (!(owner == "com.rustylasergaming.serversync") && !owners.Contains(owner))
			{
				owners.Add(owner);
			}
		}
	}

	internal void AfterNativeCycle(ZDOMan instance, long start)
	{
		if (start == 0 || ExtraInvocation)
		{
			return;
		}
		double value = Elapsed(start);
		if (Measuring)
		{
			cycles.Add(value);
		}
		if (!ExtraEnabled)
		{
			return;
		}
		int num = 1;
		while (true)
		{
			int nextPeer;
			int peerCount;
			try
			{
				nextPeer = (int)NextPeer.GetValue(instance);
				peerCount = ((ZdoPeers.GetValue(instance) is IList list) ? list.Count : 0);
			}
			catch (Exception ex)
			{
				schedulerFaulted = true;
				((BaseUnityPlugin)this).Logger.LogError((object)("[RHSS] Scheduler field access failed; disabled until restart. " + ex));
				break;
			}
			if (!SchedulingRules.MayStep(nextPeer, peerCount, num, maxCalls.Value, Elapsed(start), budgetMs.Value, (double)Time.unscaledDeltaTime * 1000.0, maxFrameMs.Value, Now - lastSave < (double)saveCooldownSeconds.Value, ExtraEnabled, schedulerCompatible))
			{
				break;
			}
			ExtraInvocation = true;
			try
			{
				SendCycle.Invoke(instance, ZeroDt);
				extraCalls++;
				num++;
			}
			catch (Exception ex2)
			{
				schedulerFaulted = true;
				((BaseUnityPlugin)this).Logger.LogError((object)("[RHSS] Extra native call failed; optimization disabled until restart. " + ex2));
				throw;
			}
			finally
			{
				ExtraInvocation = false;
			}
		}
	}

	internal PeerStats GetStats(object wrapped)
	{
		if (!Measuring || wrapped == null)
		{
			return null;
		}
		object? value = WrappedPeer.GetValue(wrapped);
		ZNetPeer peer = (ZNetPeer)((value is ZNetPeer) ? value : null);
		return GetStats(peer);
	}

	private PeerStats GetStats(ZNetPeer peer)
	{
		if (peer == null)
		{
			return null;
		}
		if (!peers.TryGetValue(peer, out var value))
		{
			if (peers.Count >= 128)
			{
				return null;
			}
			value = new PeerStats();
			value.Label = "peer" + nextLabel++;
			value.Transport = ((peer.m_socket == null) ? "unknown" : ((object)peer.m_socket).GetType().Name);
			peers.Add(peer, value);
		}
		return value;
	}

	internal void SendStarting(object wrapped, ref SendState state)
	{
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: Expected O, but got Unknown
		if (!Measuring)
		{
			return;
		}
		try
		{
			PeerStats stats = GetStats(wrapped);
			if (stats != null)
			{
				ZNetPeer val = (ZNetPeer)WrappedPeer.GetValue(wrapped);
				int num = (stats.LastQueue = val.m_socket.GetSendQueueSize());
				if (num > stats.QueuePeak)
				{
					stats.QueuePeak = num;
				}
				if (num > 8192)
				{
					stats.QueueLimitedAttempts++;
				}
				long timestamp = Stopwatch.GetTimestamp();
				if (stats.LastCycleStart != 0)
				{
					stats.VisitGap.Add(1000.0 * (double)(timestamp - stats.LastCycleStart) / (double)Stopwatch.Frequency);
				}
				stats.LastCycleStart = timestamp;
				state.Stats = stats;
				state.Start = timestamp;
			}
		}
		catch (Exception ex)
		{
			DiagnosticFault(ex);
		}
	}

	internal void SendFinished(SendState state, bool sent)
	{
		if (Measuring && state.Start != 0 && state.Stats != null)
		{
			state.Stats.SendDuration.Add(Elapsed(state.Start));
			if (!sent)
			{
				state.Stats.CallsWithoutData++;
			}
		}
	}

	internal void SaveFinished(long start)
	{
		lastSave = Now;
		if (Measuring && start != 0)
		{
			saveDispatch.Add(Elapsed(start));
		}
	}

	private void SamplePeers(ZNet net)
	{
		List<ZNetPeer> list = net.GetPeers();
		List<ZNetPeer> list2 = new List<ZNetPeer>();
		foreach (ZNetPeer key in peers.Keys)
		{
			if (!list.Contains(key))
			{
				list2.Add(key);
			}
		}
		foreach (ZNetPeer item in list2)
		{
			peers.Remove(item);
		}
		foreach (ZNetPeer item2 in list)
		{
			if (item2 == null || item2.m_socket == null || !item2.IsReady())
			{
				continue;
			}
			PeerStats stats = GetStats(item2);
			if (stats == null)
			{
				continue;
			}
			stats.LastQueue = item2.m_socket.GetSendQueueSize();
			if (stats.LastQueue > stats.QueuePeak)
			{
				stats.QueuePeak = stats.LastQueue;
			}
			stats.TransportStatsAvailable = false;
			if (!(stats.Transport == "ZSteamSocket"))
			{
				continue;
			}
			try
			{
				item2.m_socket.GetConnectionQuality(ref stats.QualityLocal, ref stats.QualityRemote, ref stats.PingMs, ref stats.OutBytesSec, ref stats.InBytesSec);
				stats.TransportStatsAvailable = stats.PingMs > 0 || stats.QualityLocal > 0f || stats.QualityRemote > 0f;
			}
			catch (InvalidOperationException ex)
			{
				stats.TransportStatsAvailable = false;
				stats.PingMs = 0;
				stats.QualityLocal = 0f;
				stats.QualityRemote = 0f;
				stats.OutBytesSec = 0f;
				stats.InBytesSec = 0f;
				if (!stats.TransportStatsUnsupportedLogged)
				{
					stats.TransportStatsUnsupportedLogged = true;
					((BaseUnityPlugin)this).Logger.LogWarning((object)("[RHSS] Steam transport quality counters are unavailable on this dedicated server; continuing with queue/frame/native-cycle diagnostics. " + ex.Message));
				}
			}
		}
	}

	private void Report(ZNet net)
	{
		reportSerial++;
		int num = ((!isServer && ZDOMan.instance != null) ? ZDOMan.instance.GetClientChangeQueue() : (-1));
		((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format(CultureInfo.InvariantCulture, "[RHSS] sample={0} role={1} mode={2} peers={3} frame_avg_ms={4:F2} frame_max_ms={5:F2} native_cycle_calls={6} native_cycle_avg_ms={7:F3} native_cycle_max_ms={8:F3} extra_native_calls={9} save_dispatch_calls={10} save_dispatch_max_ms={11:F2} local_change_queue={12}", reportSerial, isServer ? "server" : "client", EffectiveState(), peers.Count, frames.Mean, frames.Max, cycles.Count, cycles.Mean, cycles.Max, extraCalls, saveDispatch.Count, saveDispatch.Max, num));
		foreach (PeerStats value in peers.Values)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format(CultureInfo.InvariantCulture, "[RHSS] sample={0} {1} transport={2} queue_now_bytes={3} queue_peak_observed_bytes={4} queue_limited_attempts={5} native_send_calls={6} native_send_avg_ms={7:F3} native_send_max_ms={8:F3} visit_gap_avg_ms={9:F2} visit_gap_max_ms={10:F2} calls_without_data={11} transport_stats_available={12} ping_ms={13} quality_local={14:F3} quality_remote={15:F3} out_bytes_sec={16:F0} in_bytes_sec={17:F0}", reportSerial, value.Label, value.Transport, value.LastQueue, value.QueuePeak, value.QueueLimitedAttempts, value.SendDuration.Count, value.SendDuration.Mean, value.SendDuration.Max, value.VisitGap.Mean, value.VisitGap.Max, value.CallsWithoutData, value.TransportStatsAvailable, value.PingMs, value.QualityLocal, value.QualityRemote, value.OutBytesSec, value.InBytesSec));
			value.SendDuration.Reset();
			value.VisitGap.Reset();
			value.QueuePeak = Math.Max(0, value.LastQueue);
			value.QueueLimitedAttempts = 0L;
			value.CallsWithoutData = 0L;
		}
		frames.Reset();
		cycles.Reset();
		saveDispatch.Reset();
		extraCalls = 0L;
	}

	private void DiagnosticFault(Exception ex)
	{
		if (!diagnosticFaulted)
		{
			diagnosticFaulted = true;
			schedulerFaulted = true;
			((BaseUnityPlugin)this).Logger.LogError((object)("[RHSS] Diagnostic failure; sampling and optimization disabled until restart. " + ex));
		}
	}

	private void OnDestroy()
	{
		bindingsReady = false;
		if (harmony != null)
		{
			harmony.UnpatchSelf();
		}
		if ((Object)(object)Current == (Object)(object)this)
		{
			Current = null;
		}
	}
}
internal struct SendState
{
	internal long Start;

	internal Plugin.PeerStats Stats;
}
internal static class CycleHooks
{
	public static void Prefix(ref long __state)
	{
		__state = ((Plugin.ExtraInvocation || (Object)(object)Plugin.Current == (Object)null) ? 0 : Stopwatch.GetTimestamp());
	}

	public static void Postfix(ZDOMan __instance, long __state)
	{
		if ((Object)(object)Plugin.Current != (Object)null)
		{
			Plugin.Current.AfterNativeCycle(__instance, __state);
		}
	}
}
internal static class SendHooks
{
	public static void Prefix(object __0, ref SendState __state)
	{
		__state = default(SendState);
		if ((Object)(object)Plugin.Current != (Object)null)
		{
			Plugin.Current.SendStarting(__0, ref __state);
		}
	}

	public static void Postfix(SendState __state, bool __result)
	{
		if ((Object)(object)Plugin.Current != (Object)null)
		{
			Plugin.Current.SendFinished(__state, __result);
		}
	}
}
internal static class SaveHooks
{
	public static void Prefix(ref long __state)
	{
		__state = Stopwatch.GetTimestamp();
	}

	public static void Postfix(long __state)
	{
		if ((Object)(object)Plugin.Current != (Object)null)
		{
			Plugin.Current.SaveFinished(__state);
		}
	}
}
internal static class SchedulingRules
{
	internal static bool MayStep(int nextPeer, int peerCount, int callsThisUpdate, int maxCalls, double elapsedMs, double budgetMs, double frameMs, double maxFrameMs, bool savingRecently, bool enabled, bool compatible)
	{
		if (!enabled || !compatible || savingRecently)
		{
			return false;
		}
		if (peerCount < 2 || nextPeer < 0 || nextPeer >= peerCount)
		{
			return false;
		}
		if (maxCalls < 1 || maxCalls > 3 || callsThisUpdate >= maxCalls)
		{
			return false;
		}
		if (!Finite(elapsedMs) || !Finite(budgetMs) || !Finite(frameMs) || !Finite(maxFrameMs))
		{
			return false;
		}
		if (elapsedMs < 0.0 || budgetMs <= 0.0 || budgetMs > 5.0 || elapsedMs >= budgetMs)
		{
			return false;
		}
		if (frameMs >= 0.0 && maxFrameMs > 0.0)
		{
			return frameMs <= maxFrameMs;
		}
		return false;
	}

	private static bool Finite(double value)
	{
		if (!double.IsNaN(value))
		{
			return !double.IsInfinity(value);
		}
		return false;
	}
}
internal sealed class RunningStats
{
	internal long Count;

	internal double Sum;

	internal double Max;

	internal double Mean
	{
		get
		{
			if (Count != 0)
			{
				return Sum / (double)Count;
			}
			return 0.0;
		}
	}

	internal void Add(double value)
	{
		if (!double.IsNaN(value) && !double.IsInfinity(value) && !(value < 0.0))
		{
			Count++;
			Sum += value;
			if (value > Max)
			{
				Max = value;
			}
		}
	}

	internal void Reset()
	{
		Count = 0L;
		Sum = 0.0;
		Max = 0.0;
	}
}