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 RunicWorldEngine v1.2.4
plugins/RunicWorldEngine/RunicWorldEngine.dll
Decompiled a week agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Serialization.Json; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using System.Threading; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Mono.Cecil; using Mono.Cecil.Cil; using Mono.Collections.Generic; using PartyCSharpSDK; using PlayFab.Party; using Runic.Localization; using RunicWorldEngine.Contracts; using RunicWorldEngine.Core; using RunicWorldEngine.Integration; using Steamworks; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("Runic World Engine")] [assembly: AssemblyDescription("Bounded Valheim world-state observability and safe save smoothing")] [assembly: AssemblyCompany("Chazman")] [assembly: AssemblyProduct("Runic World Engine")] [assembly: AssemblyFileVersion("1.2.3.0")] [assembly: AssemblyInformationalVersion("1.2.3")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyVersion("1.2.3.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace Runic.Localization { internal sealed class LanguageCatalog { private readonly Dictionary<string, string> _english; private Dictionary<string, string> _selected = new Dictionary<string, string>(); private readonly Func<string, string> _read; private string _language; internal LanguageCatalog(string english, Func<string, string> read) { _english = Parse(english); _read = read; } internal static Dictionary<string, string> Parse(string json) { if (string.IsNullOrWhiteSpace(json)) { return new Dictionary<string, string>(); } if (json.Length > 2097152) { throw new InvalidDataException("Language file exceeds 2 MiB."); } DataContractJsonSerializer dataContractJsonSerializer = new DataContractJsonSerializer(typeof(Dictionary<string, string>), new DataContractJsonSerializerSettings { UseSimpleDictionaryFormat = true }); using MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(json.TrimStart('\ufeff'))); return ((Dictionary<string, string>)dataContractJsonSerializer.ReadObject(stream)) ?? new Dictionary<string, string>(); } internal void Select(string language) { language = (string.IsNullOrWhiteSpace(language) ? "English" : language); if (string.Equals(language, _language, StringComparison.Ordinal)) { return; } _language = language; _selected = new Dictionary<string, string>(); if (language.IndexOfAny(new char[4] { '/', '\\', ':', '\0' }) >= 0 || language == "." || language == "..") { return; } try { _selected = Parse(_read(language)); } catch (Exception) { } } internal string Get(string key) { _english.TryGetValue(key, out var value); if (_selected.TryGetValue(key, out var value2) && !string.IsNullOrWhiteSpace(value2) && (value == null || SameFields(value, value2))) { return value2; } return value ?? key; } internal string English(string key) { if (!_english.TryGetValue(key, out var value)) { return key; } return value; } internal string TranslateEnglish(string text) { foreach (KeyValuePair<string, string> item in _english) { if (item.Value == text) { return Get(item.Key); } } return text; } internal string Format(string key, params object[] args) { _english.TryGetValue(key, out var value); string text = Get(key); if (value != null && !SameFields(value, text)) { text = value; } try { return string.Format(CultureInfo.CurrentCulture, text, args); } catch (FormatException) { try { return string.Format(CultureInfo.CurrentCulture, value ?? key, args); } catch (FormatException) { return value ?? key; } } } private static bool SameFields(string a, string b) { try { return Fields(a).SetEquals(Fields(b)); } catch (FormatException) { return false; } } private static HashSet<int> Fields(string text) { HashSet<int> hashSet = new HashSet<int>(); for (int i = 0; i < text.Length; i++) { if (text[i] == '}') { if (i + 1 >= text.Length || text[i + 1] != '}') { throw new FormatException(); } i++; } else { if (text[i] != '{') { continue; } if (i + 1 < text.Length && text[i + 1] == '{') { i++; continue; } int num = ++i; for (; i < text.Length && char.IsDigit(text[i]); i++) { } if (num == i || !int.TryParse(text.Substring(num, i - num), out var result)) { throw new FormatException(); } hashSet.Add(result); for (; i < text.Length && text[i] != '}'; i++) { if (text[i] == '{') { throw new FormatException(); } } if (i == text.Length) { throw new FormatException(); } } } return hashSet; } } internal static class RunicText { private static readonly Assembly Owner = typeof(RunicText).Assembly; private static readonly string Module = Owner.GetName().Name; private static readonly LanguageCatalog Catalog = Create(); private static LanguageCatalog Create() { using Stream stream = Owner.GetManifestResourceStream("Runic.Localization.English.json"); using StreamReader streamReader = ((stream == null) ? null : new StreamReader(stream)); return new LanguageCatalog(streamReader?.ReadToEnd() ?? "{}", ReadLanguage); } private static string ReadLanguage(string language) { string path = Path.Combine(Path.Combine(Path.GetDirectoryName(Owner.Location), "Translations", Module), language + ".json"); if (!File.Exists(path)) { return null; } return File.ReadAllText(path); } private static void SelectLanguage() { string language = "English"; try { Localization instance = Localization.instance; language = ((instance != null) ? instance.GetSelectedLanguage() : null) ?? "English"; } catch { } Catalog.Select(language); } internal static string Get(string key) { SelectLanguage(); return Catalog.Get(key); } internal static string English(string key) { return Catalog.English(key); } internal static string TranslateEnglish(string text) { SelectLanguage(); return Catalog.TranslateEnglish(text); } internal static string Format(string key, params object[] args) { SelectLanguage(); return Catalog.Format(key, args); } } } namespace RunicWorldEngine { internal static class WorldEngineConfig { internal static ConfigEntry<bool> OverridePlayerCap; internal static ConfigEntry<bool> HealthEnabled; internal static ConfigEntry<bool> HealthWarnings; internal static ConfigEntry<bool> LogPeerDetails; internal static ConfigEntry<int> MaximumPlayers; internal static ConfigEntry<int> QueueWarningMessages; internal static ConfigEntry<float> RttWarningMilliseconds; internal static ConfigEntry<float> BacklogWarningKiB; internal static ConfigEntry<float> StarvationSeconds; internal static ConfigEntry<float> HeartbeatWarningSeconds; internal static ConfigEntry<float> FrameWarningMilliseconds; internal static ConfigEntry<float> OwnershipWarningPerSecond; internal static ConfigEntry<float> WarningHoldSeconds; internal static ConfigEntry<float> WarningCooldownSeconds; internal static ConfigEntry<bool> Enabled { get; private set; } internal static ConfigEntry<bool> LogPeriodicSummary { get; private set; } internal static ConfigEntry<float> SummaryIntervalSeconds { get; private set; } internal static ConfigEntry<bool> SmoothWorldSaves { get; private set; } internal static ConfigEntry<float> SaveFrameBudgetMilliseconds { get; private set; } internal static ConfigEntry<float> MaximumSaveDeferralSeconds { get; private set; } internal static void Bind(ConfigFile config) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Expected O, but got Unknown //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Expected O, but got Unknown //IL_02be: Unknown result type (might be due to invalid IL or missing references) //IL_02c8: Expected O, but got Unknown //IL_02fb: Unknown result type (might be due to invalid IL or missing references) //IL_0305: Expected O, but got Unknown OverridePlayerCap = config.Bind<bool>("Player Capacity", "Enabled", false, RunicText.Get("text_f99a4834649c")); MaximumPlayers = config.Bind<int>("Player Capacity", "MaximumPlayers", 10, new ConfigDescription(RunicText.Get("text_c1c6835d0205"), (AcceptableValueBase)(object)new AcceptableValueRange<int>(2, 64), Array.Empty<object>())); HealthEnabled = config.Bind<bool>("Server Health", "Enabled", true, RunicText.Get("text_00308931ac1d")); HealthWarnings = config.Bind<bool>("Server Health", "Warnings", true, RunicText.Get("text_651d517dc40d")); LogPeerDetails = config.Bind<bool>("Diagnostics", "LogPeerDetails", false, RunicText.Get("text_42308444810e")); RttWarningMilliseconds = Threshold(config, "RttWarningMilliseconds", 500f, 50f, 10000f); BacklogWarningKiB = Threshold(config, "BacklogWarningKiB", 256f, 1f, 65536f); QueueWarningMessages = config.Bind<int>("Server Health", "QueueWarningMessages", 1000, new ConfigDescription(RunicText.Get("text_26b4a8c272de"), (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100000), Array.Empty<object>())); StarvationSeconds = Threshold(config, "StarvationSeconds", 10f, 2f, 120f); HeartbeatWarningSeconds = Threshold(config, "HeartbeatWarningSeconds", 5f, 2f, 25f); FrameWarningMilliseconds = Threshold(config, "FrameWarningMilliseconds", 50f, 16f, 1000f); OwnershipWarningPerSecond = Threshold(config, "OwnershipWarningPerSecond", 100f, 1f, 100000f); WarningHoldSeconds = Threshold(config, "WarningHoldSeconds", 5f, 1f, 60f); WarningCooldownSeconds = Threshold(config, "WarningCooldownSeconds", 60f, 10f, 600f); Enabled = config.Bind<bool>("General", "Enabled", true, RunicText.Get("text_9c9d086955ae")); LogPeriodicSummary = config.Bind<bool>("Diagnostics", "LogPeriodicSummary", false, RunicText.Get("text_4902dc8c1cb9")); SummaryIntervalSeconds = config.Bind<float>("Diagnostics", "SummaryIntervalSeconds", 30f, new ConfigDescription(RunicText.Get("text_5c17b1f1dcb6"), (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 600f), Array.Empty<object>())); SmoothWorldSaves = config.Bind<bool>("Save Smoothing", "Enabled", true, RunicText.Get("text_062cf05eea1f") + RunicText.Get("text_92cbf9361d05")); SaveFrameBudgetMilliseconds = config.Bind<float>("Save Smoothing", "FrameBudgetMilliseconds", 24f, new ConfigDescription(RunicText.Get("text_b7bcb46277a4"), (AcceptableValueBase)(object)new AcceptableValueRange<float>(8f, 100f), Array.Empty<object>())); MaximumSaveDeferralSeconds = config.Bind<float>("Save Smoothing", "MaximumDeferralSeconds", 5f, new ConfigDescription(RunicText.Get("text_d2a955847a6c"), (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 30f), Array.Empty<object>())); } private static ConfigEntry<float> Threshold(ConfigFile config, string name, float initial, float minimum, float maximum) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown return config.Bind<float>("Server Health", name, initial, new ConfigDescription(RunicText.Get("text_b5d5241509a4") + name + RunicText.Get("text_af43bb1eed0a"), (AcceptableValueBase)(object)new AcceptableValueRange<float>(minimum, maximum), Array.Empty<object>())); } } [BepInPlugin("chazman.RunicWorldEngine", "Runic World Engine", "1.2.3")] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "chazman.RunicWorldEngine"; public const string Name = "Runic World Engine"; public const string Version = "1.2.3"; private Harmony _harmony; private float _nextSummaryAt; internal static ManualLogSource Log { get; private set; } private void Awake() { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; WorldEngineConfig.Bind(((BaseUnityPlugin)this).Config); ConfigEntry<bool> enabled = WorldEngineConfig.Enabled; if (enabled != null && !enabled.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Runic World Engine is disabled; no Harmony patches or observatory state were created."); return; } try { _harmony = new Harmony("chazman.RunicWorldEngine"); ObservatoryRuntime.Verify(); _harmony.PatchAll(typeof(Plugin).Assembly); CapacityRuntime.Initialize(); HealthRuntime.Initialize(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Runic World Engine v1.2.3 ready: world/network diagnostics and save smoothing. Capacity: " + CapacityRuntime.Status + ". Unknown data is preserved; compaction and sync changes are off.")); } catch (Exception ex) { Shutdown(); ((BaseUnityPlugin)this).Logger.LogError((object)("Runic World Engine failed closed; Valheim world handling remains unchanged. " + ex)); } } private void Update() { SaveSmoothingRuntime.Tick(); HealthRuntime.Tick(); ConfigEntry<bool> enabled = WorldEngineConfig.Enabled; if (enabled == null || !enabled.Value) { return; } ConfigEntry<bool> logPeriodicSummary = WorldEngineConfig.LogPeriodicSummary; if (logPeriodicSummary == null || !logPeriodicSummary.Value) { return; } float unscaledTime = Time.unscaledTime; if (unscaledTime < _nextSummaryAt) { return; } _nextSummaryAt = unscaledTime + Mathf.Clamp(WorldEngineConfig.SummaryIntervalSeconds.Value, 5f, 600f); ZdoObservatorySnapshot current = ObservatoryRuntime.Current; ((BaseUnityPlugin)this).Logger.LogInfo((object)($"World sample #{current.Sequence}: objects={current.TotalObjects}, peers={current.ConnectedPeers}, " + $"created={current.CreatedSincePreviousSample}, destroyed={current.DestroyedSincePreviousSample}, " + $"sent/s={current.SentLastSecond}, received/s={current.ReceivedLastSecond}, " + $"save={current.LastSaveMilliseconds:F1}ms, load={current.LastLoadMilliseconds:F1}ms.")); int num = 0; foreach (string item in HealthRuntime.Report()) { if (WorldEngineConfig.LogPeerDetails.Value || num < 3) { ((BaseUnityPlugin)this).Logger.LogInfo((object)item); } num++; } } private void OnDestroy() { Shutdown(); } private void Shutdown() { try { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } catch { } _harmony = null; CapacityRuntime.Reset(); HealthRuntime.Reset(); ObservatoryRuntime.Reset(); SaveSmoothingRuntime.Reset(); } } } namespace RunicWorldEngine.Integration { internal static class CapacityRuntime { private const string Owner = "chazman.RunicWorldEngine.capacity"; private static readonly Dictionary<MethodBase, CapacityAudit.Site> Targets = new Dictionary<MethodBase, CapacityAudit.Site>(); private static Harmony _harmony; private static bool _requested; private static bool _valid; private static bool _dedicated; internal static int PlayerLimit { get; private set; } = 10; internal static bool ValidatedOverride { get { if (_requested) { return _valid; } return false; } } internal static string Status { get; private set; } = "vanilla capacity (override disabled)"; internal static void Initialize() { //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Expected O, but got Unknown //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Expected O, but got Unknown _requested = WorldEngineConfig.OverridePlayerCap.Value; if (!_requested) { return; } try { int value = WorldEngineConfig.MaximumPlayers.Value; CapacityAudit.Limit(value, _dedicated, transport: true); AssemblyDefinition val = AssemblyDefinition.ReadAssembly(typeof(ZNet).Assembly.Location); try { _dedicated = CapacityAudit.IsDedicated(val); byte[] image = File.ReadAllBytes(typeof(ZNet).Assembly.Location); CapacityAudit.Site[] array = CapacityAudit.Validate(val, _dedicated); foreach (CapacityAudit.Site site in array) { MethodBase methodBase = typeof(ZNet).Module.ResolveMethod(site.Token); byte[] array2 = methodBase.GetMethodBody()?.GetILAsByteArray(); if (array2 == null || !array2.SequenceEqual(CapacityAudit.MethodCode(image, site.Rva))) { throw new InvalidOperationException("Loaded/preloader-modified capacity body differs from audit: " + methodBase.Name); } RejectForeignPatches(methodBase); Targets.Add(methodBase, site); } } finally { ((IDisposable)val)?.Dispose(); } PlayerLimit = value; _harmony = new Harmony("chazman.RunicWorldEngine.capacity"); foreach (MethodBase key in Targets.Keys) { _harmony.Patch(key, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(CapacityRuntime), "Transpile", (Type[])null) { priority = 0 }, (HarmonyMethod)null, (HarmonyMethod)null); } _valid = true; if (!CheckIntegrity()) { throw new InvalidOperationException(Status); } Status = RunicText.Format("text_ac591cf388f4", Targets.Count, Targets.Count, PlayerLimit, CapacityAudit.Limit(PlayerLimit, _dedicated, transport: true)); Plugin.Log.LogInfo((object)("Capacity: " + Status)); } catch (Exception ex) { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } _harmony = null; _valid = false; PlayerLimit = 10; Status = RunicText.Get("text_b80e6b9c2dd3") + ex.Message; Plugin.Log.LogError((object)Status); } } internal static bool CheckIntegrity() { if (!_requested) { return true; } if (!_valid) { return false; } try { foreach (MethodBase key in Targets.Keys) { RejectForeignPatches(key); Patches patchInfo = Harmony.GetPatchInfo(key); if (patchInfo == null || patchInfo.Transpilers.Count((Patch p) => p.owner == "chazman.RunicWorldEngine.capacity") != 1) { throw new InvalidOperationException("Capacity patch missing: " + key.Name); } } return true; } catch (Exception ex) { _valid = false; Status = RunicText.Get("text_c175aa0f5106") + ex.Message; Plugin.Log.LogError((object)Status); return false; } } private static void RejectForeignPatches(MethodBase target) { Patches patchInfo = Harmony.GetPatchInfo(target); if (patchInfo != null && patchInfo.Transpilers.Any((Patch p) => p.owner != "chazman.RunicWorldEngine.capacity")) { throw new InvalidOperationException("Conflicting capacity/body transpiler on " + target.DeclaringType.Name + "." + target.Name); } } internal static IEnumerable<CodeInstruction> Transpile(IEnumerable<CodeInstruction> instructions, MethodBase original) { return CapacityRewrite.Apply(instructions, Targets[original], PlayerLimit, _dedicated); } internal static void Reset() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } _harmony = null; Targets.Clear(); _requested = (_valid = false); PlayerLimit = 10; Status = RunicText.Get("text_29e297337e69"); } } [HarmonyPatch(typeof(ZNet), "OpenServer")] internal static class CapacityHostGuard { private static bool Prefix() { return CapacityRuntime.CheckIntegrity(); } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] internal static class CapacityAdmissionGuard { private static bool Prefix(ZNet __instance, ZRpc __0) { if (!__instance.IsServer() || CapacityRuntime.CheckIntegrity()) { return true; } __0.Invoke("Error", new object[1] { 9 }); return false; } } [HarmonyPatch(typeof(ZDOMan), "CreateNewZDO", new Type[] { typeof(ZDOID), typeof(Vector3), typeof(int) })] internal static class ZdoCreatedPatch { private static void Postfix(ZDO __result) { ObservatoryRuntime.MarkCreated(__result); } } [HarmonyPatch(typeof(ZDOMan), "HandleDestroyedZDO", new Type[] { typeof(ZDOID) })] internal static class ZdoDestroyedPatch { private static void Prefix(ZDOMan __instance, ZDOID __0, ref bool __state) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) __state = ObservatoryRuntime.Exists(__instance, __0); } private static void Postfix(ZDOMan __instance, ZDOID __0, bool __state) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) ObservatoryRuntime.MarkDestroyed(__state, __instance, __0); } } [HarmonyPatch(typeof(ZDOMan), "UpdateStats", new Type[] { typeof(float) })] internal static class ZdoStatsPatch { private static void Postfix(ZDOMan __instance) { ObservatoryRuntime.Capture(__instance); } } [HarmonyPatch(typeof(ZDOMan), "SaveChunks", new Type[] { typeof(string), typeof(FileSource) })] internal static class ZdoChunkSaveTimingPatch { private static void Prefix(ref long __state) { __state = ObservatoryRuntime.BeginTimedOperation(); } private static Exception Finalizer(long __state, Exception __exception) { ObservatoryRuntime.EndSave(__state); return __exception; } } [HarmonyPatch(typeof(ZDOMan), "LoadChunks", new Type[] { typeof(string), typeof(FileSource), typeof(World) })] internal static class ZdoChunkLoadTimingPatch { private static void Prefix(ref long __state) { __state = ObservatoryRuntime.BeginTimedOperation(); } private static Exception Finalizer(long __state, Exception __exception) { ObservatoryRuntime.EndLoad(__state); return __exception; } } [HarmonyPatch(typeof(ZDOMan), "Load", new Type[] { typeof(BinaryReader), typeof(World) })] internal static class ZdoLegacyLoadTimingPatch { private static void Prefix(ref long __state) { __state = ObservatoryRuntime.BeginTimedOperation(); } private static Exception Finalizer(long __state, Exception __exception) { ObservatoryRuntime.EndLoad(__state); return __exception; } } internal static class HealthRuntime { private sealed class PeerState { internal double LastProgress; internal double Joined; internal int Sends; } [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static ConsoleEvent <>9__30_0; public static Func<ZNetPeer, bool> <>9__33_0; public static Func<char, char> <>9__38_0; internal void <Initialize>b__30_0(ConsoleEventArgs args) { foreach (string item in Report()) { args.Context.AddString(item); } } internal bool <Sample>b__33_0(ZNetPeer p) { return p.IsReady(); } internal char <SafeName>b__38_0(char c) { if (!char.IsControl(c) && c != '<' && c != '>') { return c; } return '_'; } } private const int MaximumPeers = 128; private static readonly Dictionary<ZNetPeer, PeerState> Peers = new Dictionary<ZNetPeer, PeerState>(); private static readonly Dictionary<string, WarningLatch> Warnings = new Dictionary<string, WarningLatch>(); private static readonly TransferCounter<ZDOID> Transfers = new TransferCounter<ZDOID>(1024); private static readonly FieldInfo ManagerPeers = AccessTools.Field(typeof(ZDOMan), "m_peers"); private static readonly Type PeerType = AccessTools.Inner(typeof(ZDOMan), "ZDOPeer"); private static readonly FieldInfo NetworkPeer = AccessTools.Field(PeerType, "m_peer"); private static readonly FieldInfo ForceSend = AccessTools.Field(PeerType, "m_forceSend"); private static readonly FieldInfo InvalidSector = AccessTools.Field(PeerType, "m_invalidSector"); private static object _session; private static double _nextSample; private static double _lastSample; private static double _frameTotal; private static double _framePeak; private static int _frameCount; private static int _mainThread; private static bool _initialized; internal static bool Active { get; private set; } internal static bool CanObserve { get { if (Active) { return Thread.CurrentThread.ManagedThreadId == _mainThread; } return false; } } internal static string[] Lines { get; private set; } = new string[1] { "Health: no active session sampled." }; private static double Now => (double)Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; internal static void Initialize() { //IL_0048: 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_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown _mainThread = Thread.CurrentThread.ManagedThreadId; _initialized = true; object obj = <>c.<>9__30_0; if (obj == null) { ConsoleEvent val = delegate(ConsoleEventArgs args) { foreach (string item in Report()) { args.Context.AddString(item); } }; <>c.<>9__30_0 = val; obj = (object)val; } new ConsoleCommand("runicworld_status", "Show this process's sampled player capacity and network health (read-only).", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } internal static IEnumerable<string> Report() { yield return "Runic World Engine: " + CapacityRuntime.Status; string[] lines = Lines; for (int i = 0; i < lines.Length; i++) { yield return lines[i]; } } internal static void Tick() { if (!_initialized) { return; } ZNet instance = ZNet.instance; Active = WorldEngineConfig.Enabled.Value && WorldEngineConfig.HealthEnabled.Value && (Object)(object)instance != (Object)null && ZDOMan.instance != null; object obj = (Active ? instance : null); if (obj != _session) { ClearSession(); _session = obj; } if (!Active) { return; } double now = Now; double num = (double)Time.unscaledDeltaTime * 1000.0; if (num >= 0.0 && !double.IsNaN(num) && !double.IsInfinity(num)) { _frameTotal += num; _framePeak = Math.Max(_framePeak, num); _frameCount++; } if (now < _nextSample) { return; } _nextSample = now + 1.0; try { Sample(instance, now); } catch (Exception ex) { Lines = new string[1] { "Health sample unavailable: " + ex.GetType().Name + "; no world data changed." }; Warn("sampling", condition: true, now, "Health sampling unavailable: " + ex.GetType().Name, instance.IsServer()); } } private static void Sample(ZNet network, double now) { bool flag = network.IsServer(); if (flag) { CapacityRuntime.CheckIntegrity(); } double num = ((_lastSample > 0.0) ? (now - _lastSample) : 1.0); _lastSample = now; double num2 = ((_frameCount > 0) ? (_frameTotal / (double)_frameCount) : 0.0); double framePeak = _framePeak; _frameTotal = (_framePeak = 0.0); _frameCount = 0; List<ZNetPeer> peers = network.GetPeers(); int num3 = peers.Take(128).Count((ZNetPeer p) => p.IsReady()); int nrOfPlayers = network.GetNrOfPlayers(); List<string> list = new List<string>(131); list.Add(string.Format("Health ({0}): players={1}, ready remote peers={2}, connections={3}; frame mean/peak={4:F1}/{5:F1}ms.", flag ? "server" : "local client; not remote-server telemetry", nrOfPlayers, num3, peers.Count, num2, framePeak)); list.Add($"Ownership / {num:F1}s: assigned={Transfers.Assigned}, released={Transfers.Released}, transferred={Transfers.Transferred}, rapid repeated transfers={Transfers.RapidTransfers} (10s window; up to 1024 tracked IDs)."); List<string> list2 = list; IList list3 = ManagerPeers.GetValue(ZDOMan.instance) as IList; Dictionary<ZNetPeer, (int, int)> dictionary = new Dictionary<ZNetPeer, (int, int)>(); if (list3 == null) { throw new MissingFieldException("ZDOMan.m_peers"); } for (int num4 = 0; num4 < Math.Min(128, list3.Count); num4++) { object obj = list3[num4]; object? value = NetworkPeer.GetValue(obj); ZNetPeer val = (ZNetPeer)((value is ZNetPeer) ? value : null); if (val != null) { dictionary[val] = (((HashSet<ZDOID>)ForceSend.GetValue(obj)).Count, ((HashSet<ZDOID>)InvalidSector.GetValue(obj)).Count); } } bool flag2 = false; bool flag3 = false; bool flag4 = false; bool flag5 = false; bool flag6 = false; bool flag7 = false; HashSet<ZNetPeer> live = new HashSet<ZNetPeer>(peers.Take(128)); ZNetPeer[] array = Peers.Keys.Where((ZNetPeer p) => !live.Contains(p)).ToArray(); foreach (ZNetPeer key in array) { Peers.Remove(key); } for (int num6 = 0; num6 < Math.Min(128, peers.Count); num6++) { ZNetPeer val2 = peers[num6]; if (val2.IsReady()) { if (!Peers.TryGetValue(val2, out var value2)) { Dictionary<ZNetPeer, PeerState> peers2 = Peers; PeerState obj2 = new PeerState { Joined = now, LastProgress = now }; value2 = obj2; peers2[val2] = obj2; } TransportSample transportSample = TransportSampler.Read(val2.m_socket, now); dictionary.TryGetValue(val2, out var value3); double num7 = val2.m_rpc.GetTimeSinceLastPing(); double num8 = now - value2.LastProgress; bool flag8 = now - value2.Joined >= 15.0; bool valueOrDefault = transportSample.SendWindowPressure == true; bool flag9 = flag8 && (value3.Item1 + value3.Item2 > 0 || valueOrDefault) && num8 >= (double)WorldEngineConfig.StarvationSeconds.Value; flag7 = flag7 || (flag8 && valueOrDefault); flag2 |= flag8 && transportSample.Rtt >= (double)WorldEngineConfig.RttWarningMilliseconds.Value; flag3 |= flag8 && (transportSample.PendingBytes.GetValueOrDefault() + transportSample.InFlightBytes.GetValueOrDefault() >= (double)WorldEngineConfig.BacklogWarningKiB.Value * 1024.0 || transportSample.SendMessages >= WorldEngineConfig.QueueWarningMessages.Value || transportSample.ReceiveMessages >= WorldEngineConfig.QueueWarningMessages.Value || transportSample.OutOfOrder >= WorldEngineConfig.QueueWarningMessages.Value || value3.Item1 + value3.Item2 >= WorldEngineConfig.QueueWarningMessages.Value); flag4 = flag4 || flag9; flag5 |= flag8 && num7 >= (double)WorldEngineConfig.HeartbeatWarningSeconds.Value; flag6 |= transportSample.Error != null || !transportSample.Rtt.HasValue; list2.Add(string.Format("Peer {0} '{1}' [{2}]: RTT={3}ms; send/recv={4}/{5} B/s; queued={6}B, in-flight={7}B; app send/recv queues={8}/{9} messages, out-of-order={10}; send-window pressure={11}; priority/invalid ZDOs={12}/{13}; ZDO sends={14}, last progress={15:F1}s ago; heartbeat age={16:F1}s; {17}{18}.", val2.m_uid, SafeName(val2.m_playerName), transportSample.Kind, Metric(transportSample.Rtt), Metric(transportSample.Sent), Metric(transportSample.Received), Metric(transportSample.PendingBytes), Metric(transportSample.InFlightBytes), Metric(transportSample.SendMessages), Metric(transportSample.ReceiveMessages), Metric(transportSample.OutOfOrder), (!transportSample.SendWindowPressure.HasValue) ? "n/a" : (valueOrDefault ? "yes" : "no"), value3.Item1, value3.Item2, value2.Sends, num8, num7, flag9 ? "POSSIBLE STARVATION" : "no starvation indicator", (transportSample.Error == null) ? "" : ("; sample error=" + transportSample.Error))); value2.Sends = 0; } } if (peers.Count > 128 || list3.Count > 128) { list2.Add("Peer detail and ready-peer count truncated at 128; aggregate connection count remains complete."); } Warn("capacity", flag && CapacityRuntime.ValidatedOverride && (double)nrOfPlayers >= Math.Ceiling((double)CapacityRuntime.PlayerLimit * 0.9), now, "Player count is at or above 90% of the validated cap.", flag); Warn("frames", num2 >= (double)WorldEngineConfig.FrameWarningMilliseconds.Value, now, $"Sustained slow server frames: mean {num2:F1}ms.", flag); Warn("latency", flag2, now, "One or more peers have sustained high RTT; inspect runicworld_status/peer summaries.", flag); Warn("backlog", flag3, now, "Sustained queued/unacknowledged traffic or priority ZDO backlog; inspect peer summaries.", flag); Warn("send-window", flag7, now, "Sustained pressure near Valheim's ZDO send-window limit; synchronization may be throttled.", flag); Warn("starvation", flag4, now, "Possible synchronization starvation: priority/invalid ZDO work or send-window pressure without successful ZDO sends.", flag); Warn("heartbeat", flag5, now, "One or more peer heartbeat replies are overdue; disconnect risk is rising.", flag); Warn("ownership", (double)Transfers.RapidTransfers / num >= (double)WorldEngineConfig.OwnershipWarningPerSecond.Value, now, "Sustained rapid ownership transfers; inspect server load and peer movement.", flag); Warn("sampling", condition: false, now, "Health sampling restored.", flag); if (flag6) { list2.Add("n/a means unavailable/uninitialized, not zero. Heartbeat age is not RTT. Priority ZDO counts are not the full unsent world backlog."); } Lines = list2.ToArray(); Transfers.ResetInterval(); } private static void Warn(string key, bool condition, double now, string message, bool server) { if (!server || !WorldEngineConfig.HealthWarnings.Value) { Warnings.Clear(); return; } if (!Warnings.TryGetValue(key, out var value)) { value = (Warnings[key] = new WarningLatch()); } switch (value.Observe(condition, now, WorldEngineConfig.WarningHoldSeconds.Value, WorldEngineConfig.WarningCooldownSeconds.Value)) { case 1: Plugin.Log.LogWarning((object)("Server health [" + key + "]: " + message)); break; case -1: Plugin.Log.LogInfo((object)("Server health [" + key + "]: recovered below warning threshold.")); break; } } internal static void RecordProgress(object zdoPeer, bool sent) { if (!sent || !Active || Thread.CurrentThread.ManagedThreadId != _mainThread) { return; } try { object? value = NetworkPeer.GetValue(zdoPeer); ZNetPeer val = (ZNetPeer)((value is ZNetPeer) ? value : null); if (val != null && Peers.TryGetValue(val, out var value2)) { value2.LastProgress = Now; value2.Sends++; } } catch { } } internal static void RecordTransfer(ZDO zdo, long before) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) if (!Active || Thread.CurrentThread.ManagedThreadId != _mainThread) { return; } try { Transfers.Record(zdo.m_uid, before, zdo.GetOwner(), Now); } catch { } } private static string Metric(double? value) { if (!value.HasValue) { return "n/a"; } return value.Value.ToString("F0", CultureInfo.InvariantCulture); } private static string SafeName(string name) { return new string((from c in (name ?? "unnamed").Take(48) select (!char.IsControl(c) && c != '<' && c != '>') ? c : '_').ToArray()); } private static void ClearSession() { Peers.Clear(); Warnings.Clear(); Transfers.Clear(); PayloadObservation.Reset(); _lastSample = (_nextSample = (_frameTotal = (_framePeak = 0.0))); _frameCount = 0; Lines = new string[1] { "Health: no active session sampled." }; } internal static void Reset() { Active = (_initialized = false); _session = null; ClearSession(); } } [HarmonyPatch(typeof(ZDO), "SetOwnerInternal", new Type[] { typeof(long) })] internal static class TransferObservationPatch { private static void Prefix(ZDO __instance, out long? __state) { __state = null; if (!HealthRuntime.CanObserve) { return; } try { __state = __instance.GetOwner(); } catch { } } private static void Postfix(ZDO __instance, long? __state) { if (__state.HasValue) { HealthRuntime.RecordTransfer(__instance, __state.Value); } } } [HarmonyPatch(typeof(ZDOMan), "SendZDOs")] internal static class SendProgressObservationPatch { private static void Postfix(object __0, bool __result) { HealthRuntime.RecordProgress(__0, __result); } } internal static class ObservatoryRuntime { private static readonly FieldInfo ObjectsField = AccessTools.Field(typeof(ZDOMan), "m_objectsByID"); private static readonly FieldInfo PeersField = AccessTools.Field(typeof(ZDOMan), "m_peers"); private static readonly FieldInfo SentField = AccessTools.Field(typeof(ZDOMan), "m_zdosSentLastSec"); private static readonly FieldInfo ReceivedField = AccessTools.Field(typeof(ZDOMan), "m_zdosRecvLastSec"); private static readonly ObservatoryCounter Counter = new ObservatoryCounter(); private static long _nextCaptureTimestamp; private static bool _verified; internal static ZdoObservatorySnapshot Current => Counter.Current; internal static void Verify() { bool flag = PeersField != null && !PeersField.IsStatic && PeersField.FieldType.IsGenericType && PeersField.FieldType.GetGenericTypeDefinition() == typeof(List<>) && PeersField.FieldType.GetGenericArguments().Length == 1 && PeersField.FieldType.GetGenericArguments()[0].DeclaringType == typeof(ZDOMan) && PeersField.FieldType.GetGenericArguments()[0].Name == "ZDOPeer"; if (ObjectsField == null || ObjectsField.IsStatic || ObjectsField.FieldType != typeof(Dictionary<ZDOID, ZDO>) || !flag || SentField == null || SentField.IsStatic || SentField.FieldType != typeof(int) || ReceivedField == null || ReceivedField.IsStatic || ReceivedField.FieldType != typeof(int)) { throw new MissingMemberException("ZDOMan observatory fields do not match the audited Valheim 1.0 contract."); } _verified = true; } internal static void MarkCreated(ZDO created) { if (_verified) { ConfigEntry<bool> enabled = WorldEngineConfig.Enabled; if (enabled != null && enabled.Value && created != null) { Counter.MarkCreated(); } } } internal static bool Exists(ZDOMan manager, ZDOID id) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) if (_verified) { ConfigEntry<bool> enabled = WorldEngineConfig.Enabled; if (enabled != null && enabled.Value && manager != null) { try { return ObjectsField.GetValue(manager) is Dictionary<ZDOID, ZDO> dictionary && dictionary.ContainsKey(id); } catch { return false; } } } return false; } internal static void MarkDestroyed(bool existedBefore, ZDOMan manager, ZDOID id) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) if (_verified && existedBefore && !Exists(manager, id)) { Counter.MarkDestroyed(); } } internal static void Capture(ZDOMan manager) { if (!_verified || manager == null) { return; } ConfigEntry<bool> enabled = WorldEngineConfig.Enabled; if (enabled == null || !enabled.Value) { return; } try { long timestamp = Stopwatch.GetTimestamp(); if (timestamp >= _nextCaptureTimestamp) { _nextCaptureTimestamp = ((timestamp > long.MaxValue - Stopwatch.Frequency) ? long.MaxValue : (timestamp + Stopwatch.Frequency)); int totalObjects = ((ObjectsField.GetValue(manager) is Dictionary<ZDOID, ZDO> dictionary) ? dictionary.Count : 0); int connectedPeers = ((PeersField.GetValue(manager) is ICollection collection) ? collection.Count : 0); int sentLastSecond = Convert.ToInt32(SentField.GetValue(manager)); int receivedLastSecond = Convert.ToInt32(ReceivedField.GetValue(manager)); Counter.Capture(DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), totalObjects, connectedPeers, sentLastSecond, receivedLastSecond); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("World observatory sample failed closed: " + ex.Message)); } } } internal static long BeginTimedOperation() { if (_verified) { ConfigEntry<bool> enabled = WorldEngineConfig.Enabled; if (enabled != null && enabled.Value) { return Stopwatch.GetTimestamp(); } } return 0L; } internal static void EndSave(long started) { Counter.RecordSaveDuration(started); } internal static void EndLoad(long started) { Counter.RecordLoadDuration(started); if (ZDOMan.instance != null) { Capture(ZDOMan.instance); } } internal static void Reset() { Counter.Reset(); _nextCaptureTimestamp = 0L; _verified = false; } } internal static class PayloadObservation { private static ConditionalWeakTable<ZNetStats, PayloadMeter> _meters = new ConditionalWeakTable<ZNetStats, PayloadMeter>(); internal static PayloadMeter Meter(ZNetStats socket) { return _meters.GetValue(socket, (ZNetStats _) => new PayloadMeter()); } internal static void Sent(ZNetStats socket, int bytes) { if (_meters.TryGetValue(socket, out var value)) { value.Sent(bytes); } } internal static void Received(ZNetStats socket, int bytes) { if (_meters.TryGetValue(socket, out var value)) { value.Received(bytes); } } internal static void Reset() { _meters = new ConditionalWeakTable<ZNetStats, PayloadMeter>(); } } [HarmonyPatch(typeof(ZNetStats), "IncSentBytes", new Type[] { typeof(int) })] internal static class SentPayloadObservationPatch { private static void Postfix(ZNetStats __instance, int __0) { PayloadObservation.Sent(__instance, __0); } } [HarmonyPatch(typeof(ZNetStats), "IncRecvBytes", new Type[] { typeof(int) })] internal static class ReceivedPayloadObservationPatch { private static void Postfix(ZNetStats __instance, int __0) { PayloadObservation.Received(__instance, __0); } } internal static class SaveSmoothingRuntime { private static readonly object Gate = new object(); private static readonly FieldInfo SaveThreadField = AccessTools.Field(typeof(ZNet), "m_saveThread"); private static readonly MethodInfo SaveWorldMethod = AccessTools.Method(typeof(ZNet), "SaveWorld", new Type[1] { typeof(bool) }, (Type[])null); private static bool _pending; private static bool _dispatching; private static float _requestedAt; private static float _eligibleAt; internal static bool BeforeSave(ZNet network, bool sync, Thread saveThread) { if (!(WorldEngineConfig.SmoothWorldSaves?.Value ?? true) || sync) { return true; } lock (Gate) { if (_dispatching) { return true; } float unscaledTime = Time.unscaledTime; bool flag = saveThread?.IsAlive ?? false; bool flag2 = Time.unscaledDeltaTime * 1000f > FrameBudget(); if (!flag && !flag2) { return true; } if (!_pending) { _requestedAt = unscaledTime; } _pending = true; _eligibleAt = Math.Max(_eligibleAt, unscaledTime + (flag ? 0.25f : 0.05f)); return false; } } internal static void Tick() { ConfigEntry<bool> enabled = WorldEngineConfig.Enabled; if (enabled == null || !enabled.Value) { return; } ConfigEntry<bool> smoothWorldSaves = WorldEngineConfig.SmoothWorldSaves; if (smoothWorldSaves != null && !smoothWorldSaves.Value) { return; } ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null || !instance.IsServer()) { return; } bool flag; lock (Gate) { if (!_pending || _dispatching) { return; } float unscaledTime = Time.unscaledTime; if (unscaledTime < _eligibleAt) { return; } if (SaveThreadField?.GetValue(instance) is Thread { IsAlive: not false }) { _eligibleAt = unscaledTime + 0.25f; return; } bool num = Time.unscaledDeltaTime * 1000f <= FrameBudget(); float num2 = Math.Max(0f, Math.Min(30f, WorldEngineConfig.MaximumSaveDeferralSeconds?.Value ?? 5f)); if (!num && unscaledTime - _requestedAt < num2) { _eligibleAt = unscaledTime + 0.05f; return; } _pending = false; _dispatching = true; flag = true; } if (!flag) { return; } try { if (SaveWorldMethod == null) { throw new MissingMethodException("ZNet.SaveWorld(bool)"); } SaveWorldMethod.Invoke(instance, new object[1] { false }); } finally { lock (Gate) { _dispatching = false; } } } internal static void Reset() { lock (Gate) { _pending = false; _dispatching = false; _requestedAt = 0f; _eligibleAt = 0f; } } private static float FrameBudget() { return Math.Max(8f, Math.Min(100f, WorldEngineConfig.SaveFrameBudgetMilliseconds?.Value ?? 24f)); } } [HarmonyPatch(typeof(ZNet), "SaveWorld", new Type[] { typeof(bool) })] internal static class SmoothWorldSavePatch { [HarmonyPrefix] private static bool Prefix(ZNet __instance, bool sync, Thread ___m_saveThread) { return SaveSmoothingRuntime.BeforeSave(__instance, sync, ___m_saveThread); } } internal sealed class TransportSample { internal double? Rtt; internal double? Sent; internal double? Received; internal double? PendingBytes; internal double? InFlightBytes; internal int? SendMessages; internal int? ReceiveMessages; internal int? OutOfOrder; internal bool? SendWindowPressure; internal string Kind = "unavailable"; internal string Error; } internal static class TransportSampler { private static readonly FieldInfo SteamConnection = AccessTools.Field(typeof(ZSteamSocket), "m_con"); private static readonly FieldInfo SteamSend = AccessTools.Field(typeof(ZSteamSocket), "m_sendQueue"); private static readonly FieldInfo SteamReceive = AccessTools.Field(typeof(ZSteamSocket), "m_pkgQueue"); private static readonly FieldInfo PartyPeer = AccessTools.Field(typeof(ZPlayFabSocket), "m_peer"); private static readonly FieldInfo PartyFlight = AccessTools.Field(typeof(ZPlayFabSocket), "m_inFlightQueue"); private static readonly FieldInfo PartySend = AccessTools.Field(typeof(ZPlayFabSocket), "m_sendQueue"); private static readonly FieldInfo PartyReceive = AccessTools.Field(typeof(ZPlayFabSocket), "m_recvQueue"); private static readonly FieldInfo PartyOrder = AccessTools.Field(typeof(ZPlayFabSocket), "m_outOfOrderQueue"); private static readonly FieldInfo LocalEndpoint = AccessTools.Field(typeof(PlayFabMultiplayerManager), "_localEndPointHandle"); private static readonly FieldInfo RemoteEndpoint = AccessTools.Field(typeof(PlayFabPlayer), "_endPointHandle"); private static readonly PARTY_ENDPOINT_STATISTIC[] Statistics = (PARTY_ENDPOINT_STATISTIC[])(object)new PARTY_ENDPOINT_STATISTIC[2] { (PARTY_ENDPOINT_STATISTIC)8, (PARTY_ENDPOINT_STATISTIC)1 }; internal static TransportSample Read(ISocket socket, double now) { //IL_005b: 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) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Invalid comparison between Unknown and I4 //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00be: 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_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Expected O, but got Unknown TransportSample transportSample = new TransportSample(); try { if (socket == null || !socket.IsConnected()) { return transportSample; } if (socket is ZSteamSocket) { transportSample.Kind = "Steam/native bytes"; transportSample.SendMessages = Count(SteamSend, socket); transportSample.ReceiveMessages = Count(SteamReceive, socket); HSteamNetConnection val = (HSteamNetConnection)SteamConnection.GetValue(socket); SteamNetConnectionRealTimeStatus_t val2 = default(SteamNetConnectionRealTimeStatus_t); SteamNetConnectionRealTimeLaneStatus_t val3 = default(SteamNetConnectionRealTimeLaneStatus_t); if ((int)SteamNetworkingSockets.GetConnectionRealTimeStatus(val, ref val2, 0, ref val3) == 1) { transportSample.Rtt = Nonnegative(val2.m_nPing); transportSample.Sent = Nonnegative(val2.m_flOutBytesPerSec); transportSample.Received = Nonnegative(val2.m_flInBytesPerSec); transportSample.PendingBytes = (double)val2.m_cbPendingReliable + (double)val2.m_cbPendingUnreliable; transportSample.InFlightBytes = val2.m_cbSentUnackedReliable; } } else if (socket is ZPlayFabSocket) { transportSample.Kind = "PlayFab/socket payload bytes"; transportSample.SendMessages = Count(PartySend, socket); transportSample.ReceiveMessages = Count(PartyReceive, socket); transportSample.OutOfOrder = Count(PartyOrder, socket); object? value = PartyFlight.GetValue(socket); InFlightQueue val4 = (InFlightQueue)((value is InFlightQueue) ? value : null); if (val4 != null) { transportSample.InFlightBytes = val4.Bytes; } (double?, double?) tuple = PayloadObservation.Meter((ZNetStats)socket).Sample(now); transportSample.Sent = tuple.Item1; transportSample.Received = tuple.Item2; PlayFabPlayer[] array = PartyPeer.GetValue(socket) as PlayFabPlayer[]; PlayFabMultiplayerManager val5 = PlayFabMultiplayerManager.Get(); PARTY_ENDPOINT_HANDLE val6 = (PARTY_ENDPOINT_HANDLE)(((Object)(object)val5 == (Object)null) ? null : /*isinst with value type is only supported in some contexts*/); PARTY_ENDPOINT_HANDLE val7 = (PARTY_ENDPOINT_HANDLE)((array != null && array.Length == 1) ? /*isinst with value type is only supported in some contexts*/: null); ulong[] array2 = default(ulong[]); if (val6 != null && val7 != null && SDK.PartyEndpointGetEndpointStatistics(val6, (PARTY_ENDPOINT_HANDLE[])(object)new PARTY_ENDPOINT_HANDLE[1] { val7 }, Statistics, ref array2) == 0 && array2 != null && array2.Length == 2) { transportSample.Rtt = ((array2[0] != 0) ? new double?(array2[0]) : ((double?)null)); transportSample.PendingBytes = array2[1]; } } else { transportSample.Kind = ((object)socket).GetType().Name + "/unsupported metrics"; } } catch (Exception ex) { transportSample.Error = ex.GetType().Name; } if (socket is ZSteamSocket || socket is ZPlayFabSocket) { transportSample.SendWindowPressure = SendWindowPressure.Estimate(socket is ZPlayFabSocket, transportSample.PendingBytes, transportSample.InFlightBytes, transportSample.SendMessages); } return transportSample; } private static double? Nonnegative(double value) { if (!(value >= 0.0) || double.IsNaN(value) || double.IsInfinity(value)) { return null; } return value; } private static int? Count(FieldInfo field, object instance) { if (!(field?.GetValue(instance) is ICollection collection)) { return null; } return collection.Count; } } } namespace RunicWorldEngine.Core { internal static class CapacityAudit { internal sealed class Site { internal string Type; internal string Method; internal string MemberType; internal string Member; internal bool Previous; internal bool Transport; internal int Baseline; internal int Token; internal int Rva; } internal static readonly HashSet<string> Fingerprints = new HashSet<string>(StringComparer.Ordinal) { "EC5CA7EC57BA5C5A2EFF1C41FA3C7F6B2D75A497FC990D58F8ADDC3CD54BC7E0", "459DD8DBAB089DF496991274244B62297AD68764D988D78475D8251A20343E63", "F54B5B813E98AD518E07CF56E69A4864C4515FC3184472D31A4FFC3036D3D2A3", "F66F7EDC4D1A499F505B65F7924BF175A5383F7EC6EEC4C11FD6869DDD900DCE", "490240F2759B3EDF43BE848F6ACBC4DB524913E72514C6051C434062DFC77434", "3AFFCFECC1E54E67D24BCA4783D924B027F8858F2CF9DAEC11EE49E3B2ACE6FE", "DD13270F59DB84CCCDBB943803EE216854704FDCED7612443D7CDB6222AF1117", "4C2CF929012527CCDCE74F530E008B34A250C8A4006A16C2EFD65AFA374A95A4", "C25809B87CB42B4553CF5EB3E6AB3FF058CD0F7575C22E83D30179A769A68DAE", "CD68B17D73F15C90C439F2E0A2622188140C0767BEAAEE4DB1AF6807898A674C" }; internal static Site[] Sites(bool dedicated) { return new Site[5] { new Site { Type = "ZNet", Method = "RPC_PeerInfo", MemberType = "ZNet", Member = "GetNrOfPlayers", Previous = true, Baseline = 10 }, new Site { Type = "ZSteamMatchmaking", Method = "RegisterServer", MemberType = (dedicated ? "Steamworks.SteamGameServer" : "Steamworks.SteamMatchmaking"), Member = (dedicated ? "SetMaxPlayerCount" : "CreateLobby"), Baseline = 10 }, new Site { Type = "ZPlayFabMatchmaking", Method = "SetPlatformMatchmakingData", MemberType = "Splatform.MultiplayerSessionData", Member = "m_maxPlayers", Baseline = 10 }, new Site { Type = "ZPlayFabMatchmaking", Method = "CreateLobby", MemberType = "PlayFab.MultiplayerModels.CreateLobbyRequest", Member = "MaxPlayers", Baseline = (dedicated ? 11 : 10), Transport = true }, new Site { Type = "ZPlayFabMatchmaking", Method = "CreateAndJoinNetwork", MemberType = "PlayFab.Party.PlayFabNetworkConfiguration", Member = "set_MaxPlayerCount", Baseline = (dedicated ? 11 : 10), Transport = true } }.Concat((!dedicated) ? ((IEnumerable<Site>)Array.Empty<Site>()) : ((IEnumerable<Site>)new Site[1] { new Site { Type = "SteamManager", Method = "Awake", MemberType = "Steamworks.SteamGameServer", Member = "SetMaxPlayerCount", Baseline = 64 } })).ToArray(); } internal static int Limit(int players, bool dedicated, bool transport) { if (players < 2 || players > 64) { throw new ArgumentOutOfRangeException("players"); } checked { return players + (unchecked(dedicated && transport) ? 1 : 0); } } internal static string Fingerprint(MethodDefinition method) { string s = string.Join("\n", ((IEnumerable<Instruction>)method.Body.Instructions).Select((Instruction i) => ((object)i).ToString())) + "\n" + string.Join("\n", ((IEnumerable<ExceptionHandler>)method.Body.ExceptionHandlers).Select(delegate(ExceptionHandler e) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) object[] obj = new object[7] { e.HandlerType, null, null, null, null, null, null }; Instruction tryStart = e.TryStart; obj[1] = ((tryStart != null) ? new int?(tryStart.Offset) : ((int?)null)); Instruction tryEnd = e.TryEnd; obj[2] = ((tryEnd != null) ? new int?(tryEnd.Offset) : ((int?)null)); Instruction handlerStart = e.HandlerStart; obj[3] = ((handlerStart != null) ? new int?(handlerStart.Offset) : ((int?)null)); Instruction handlerEnd = e.HandlerEnd; obj[4] = ((handlerEnd != null) ? new int?(handlerEnd.Offset) : ((int?)null)); Instruction filterStart = e.FilterStart; obj[5] = ((filterStart != null) ? new int?(filterStart.Offset) : ((int?)null)); TypeReference catchType = e.CatchType; obj[6] = ((catchType != null) ? ((MemberReference)catchType).FullName : null); return string.Format("{0}|{1}|{2}|{3}|{4}|{5}|{6}", obj); })); using SHA256 sHA = SHA256.Create(); return BitConverter.ToString(sHA.ComputeHash(Encoding.UTF8.GetBytes(s))).Replace("-", ""); } internal static Site[] Validate(AssemblyDefinition assembly, bool dedicated) { //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) Site[] array = Sites(dedicated); HashSet<Instruction> hashSet = new HashSet<Instruction>(); Site[] array2 = array; foreach (Site site in array2) { MethodDefinition val = ((IEnumerable<MethodDefinition>)((IEnumerable<TypeDefinition>)assembly.MainModule.Types).Single((TypeDefinition t) => ((MemberReference)t).FullName == site.Type).Methods).Single((MethodDefinition m) => ((MemberReference)m).Name == site.Method); if (!val.HasBody || !Fingerprints.Contains(Fingerprint(val))) { throw new InvalidOperationException("Unaudited player-cap method: " + site.Type + "." + site.Method); } Collection<Instruction> instructions = val.Body.Instructions; int num = 0; for (int num2 = 0; num2 < instructions.Count; num2++) { int num3 = num2 + ((!site.Previous) ? 1 : (-1)); if (!TryConstant(instructions[num2], out var value) || num3 < 0 || num3 >= instructions.Count) { continue; } object operand = instructions[num3].Operand; MemberReference val2 = (MemberReference)((operand is MemberReference) ? operand : null); if (val2 != null && !(val2.Name != site.Member) && !(((MemberReference)val2.DeclaringType).FullName != site.MemberType)) { if (value != site.Baseline) { throw new InvalidOperationException("Changed capacity literal in " + ((MemberReference)val).FullName); } num++; hashSet.Add(instructions[num2]); } } if (num != 1) { throw new InvalidOperationException("Expected exactly one cap site: " + ((MemberReference)val).FullName); } Site site2 = site; MetadataToken metadataToken = ((MemberReference)val).MetadataToken; site2.Token = ((MetadataToken)(ref metadataToken)).ToInt32(); site.Rva = val.RVA; } foreach (TypeDefinition item in AllTypes((IEnumerable<TypeDefinition>)assembly.MainModule.Types)) { foreach (MethodDefinition item2 in ((IEnumerable<MethodDefinition>)item.Methods).Where((MethodDefinition m) => m.HasBody)) { Collection<Instruction> instructions2 = item2.Body.Instructions; for (int num4 = 0; num4 < instructions2.Count; num4++) { if (TryConstant(instructions2[num4], out var value2) && !hashSet.Contains(instructions2[num4])) { MemberReference val3 = (MemberReference)((num4 + 1 < instructions2.Count) ? /*isinst with value type is only supported in some contexts*/: null); MemberReference val4 = (MemberReference)((num4 > 0) ? /*isinst with value type is only supported in some contexts*/: null); if ((!(((MemberReference)item).FullName == "ServerListEntryData") || !(((MemberReference)item2).Name == ".ctor") || !(((val3 != null) ? val3.Name : null) == "m_playerLimit")) && (!(((MemberReference)item).FullName == "ServerMatchmakingData") || !(((MemberReference)item2).Name == ".ctor") || !(((val3 != null) ? val3.Name : null) == "m_playerLimit") || value2 != 0) && (!(((MemberReference)item).FullName == "ZNet") || !(((MemberReference)item2).Name == "UpdateNetTime") || !(((val4 != null) ? val4.Name : null) == "GetNrOfPlayers") || value2 != 0) && (((val4 != null) ? val4.Name : null) == "GetNrOfPlayers" || (val3 != null && new string[7] { "SetMaxPlayerCount", "set_MaxPlayerCount", "MaxPlayers", "m_maxPlayers", "m_playerLimit", "CreateLobby", "SetLobbyMemberLimit" }.Contains(val3.Name)))) { throw new InvalidOperationException("Unaccounted literal limit: " + ((MemberReference)item2).FullName + " / " + (object)instructions2[num4]); } } } } } return array; } internal static bool IsDedicated(AssemblyDefinition assembly) { //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Invalid comparison between Unknown and I4 Collection<Instruction> instructions = ((IEnumerable<MethodDefinition>)((IEnumerable<TypeDefinition>)assembly.MainModule.Types).Single((TypeDefinition t) => ((MemberReference)t).Name == "ZNet").Methods).Single((MethodDefinition m) => ((MemberReference)m).Name == "IsDedicated").Body.Instructions; if (instructions.Count == 2) { OpCode opCode = instructions[1].OpCode; if ((int)((OpCode)(ref opCode)).Code == 41 && TryConstant(instructions[0], out var value) && (value == 0 || value == 1)) { return value == 1; } } throw new InvalidOperationException("Unknown dedicated-server build marker."); } internal static byte[] MethodCode(byte[] image, int rva) { if (image == null || image.Length < 64 || image[0] != 77 || image[1] != 90) { throw new InvalidOperationException("Invalid game PE image."); } int num = BitConverter.ToInt32(image, 60); if (BitConverter.ToInt32(image, num) != 17744) { throw new InvalidOperationException("Invalid PE signature."); } int num2 = BitConverter.ToUInt16(image, num + 6); int num3 = num + 24 + BitConverter.ToUInt16(image, num + 20); for (int i = 0; i < num2; i++) { int num4 = checked(num3 + i * 40); int num5 = BitConverter.ToInt32(image, num4 + 12); int num6 = BitConverter.ToInt32(image, num4 + 16); if (rva < num5 || (long)rva - (long)num5 >= num6) { continue; } int num7 = checked(BitConverter.ToInt32(image, num4 + 20) + rva - num5); int num8; int num9; if ((image[num7] & 3) == 2) { num8 = 1; num9 = image[num7] >> 2; } else { if ((image[num7] & 3) != 3) { throw new InvalidOperationException("Unknown method header."); } num8 = (BitConverter.ToUInt16(image, num7) >> 12) * 4; num9 = BitConverter.ToInt32(image, num7 + 4); } if (num8 < 1 || num9 < 0 || (long)num7 + (long)num8 + num9 > image.Length) { throw new InvalidOperationException("Truncated method body."); } byte[] array = new byte[num9]; Buffer.BlockCopy(image, num7 + num8, array, 0, num9); return array; } throw new InvalidOperationException("Method RVA outside game PE sections."); } internal static IEnumerable<TypeDefinition> AllTypes(IEnumerable<TypeDefinition> types) { foreach (TypeDefinition type in types) { yield return type; foreach (TypeDefinition item in AllTypes((IEnumerable<TypeDefinition>)type.NestedTypes)) { yield return item; } } } internal static bool TryConstant(Instruction instruction, out int value) { //IL_0004: 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) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Invalid comparison between Unknown and I4 //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Invalid comparison between Unknown and I4 //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Invalid comparison between Unknown and I4 //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Invalid comparison between Unknown and I4 //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Expected I4, but got Unknown value = 0; OpCode opCode = instruction.OpCode; if ((int)((OpCode)(ref opCode)).Code != 32) { opCode = instruction.OpCode; if ((int)((OpCode)(ref opCode)).Code != 31) { opCode = instruction.OpCode; if ((int)((OpCode)(ref opCode)).Code >= 22) { opCode = instruction.OpCode; if ((int)((OpCode)(ref opCode)).Code <= 30) { opCode = instruction.OpCode; value = ((OpCode)(ref opCode)).Code - 22; return true; } } return false; } } value = Convert.ToInt32(instruction.Operand); return true; } } internal static class CapacityRewrite { internal static List<CodeInstruction> Apply(IEnumerable<CodeInstruction> instructions, CapacityAudit.Site site, int players, bool dedicated) { List<CodeInstruction> list = instructions.ToList(); List<int> list2 = new List<int>(); for (int i = 0; i < list.Count; i++) { int num = i + ((!site.Previous) ? 1 : (-1)); if (CodeInstructionExtensions.LoadsConstant(list[i], (long)site.Baseline) && num >= 0 && num < list.Count && list[num].operand is MemberInfo memberInfo && memberInfo.Name == site.Member && memberInfo.DeclaringType.FullName == site.MemberType) { list2.Add(i); } } if (list2.Count != 1) { throw new InvalidOperationException("Capacity transpiler expected one replacement: " + site.Type + "." + site.Method); } int num2 = CapacityAudit.Limit(players, dedicated, site.Transport); list[list2[0]].opcode = OpCodes.Ldc_I4; list[list2[0]].operand = num2; return list; } } internal static class SendWindowPressure { internal static bool? Estimate(bool playFab, double? queuedBytes, double? inFlightBytes, int? appMessages) { if (appMessages > 0) { return true; } if (playFab) { if (!inFlightBytes.HasValue) { return null; } return inFlightBytes.Value * 0.25 >= 8192.0; } if (!queuedBytes.HasValue || !inFlightBytes.HasValue) { return null; } return queuedBytes.Value + inFlightBytes.Value >= 8192.0; } } internal sealed class ByteRate { private int _previous; private double _time; private bool _seeded; internal double? Sample(int value, double now) { uint num = (uint)(value - _previous); double num2 = now - _time; double? result = ((_seeded && num2 > 0.0 && num <= int.MaxValue) ? new double?((double)num / num2) : ((double?)null)); _seeded = true; _previous = value; _time = now; return result; } } internal sealed class WarningLatch { private bool _condition; private bool _active; private bool _seeded; private double _changedAt; private double _lastWarning = double.NegativeInfinity; internal int Observe(bool condition, double now, double hold, double cooldown) { if (!_seeded || condition != _condition) { _seeded = true; _condition = condition; _changedAt = now; } if (now - _changedAt < hold) { return 0; } if (condition && now - _lastWarning >= cooldown) { _active = true; _lastWarning = now; return 1; } if (!condition && _active) { _active = false; return -1; } return 0; } } internal sealed class PayloadMeter { private int _sent; private int _received; private readonly ByteRate _sentRate = new ByteRate(); private readonly ByteRate _receivedRate = new ByteRate(); internal void Sent(int bytes) { if (bytes > 0) { Interlocked.Add(ref _sent, bytes); } } internal void Received(int bytes) { if (bytes > 0) { Interlocked.Add(ref _received, bytes); } } internal (double? Sent, double? Received) Sample(double now) { return (Sent: _sentRate.Sample(Volatile.Read(in _sent), now), Received: _receivedRate.Sample(Volatile.Read(in _received), now)); } } internal sealed class TransferCounter<TKey> { private readonly int _maximum; private readonly Dictionary<TKey, double> _recent = new Dictionary<TKey, double>(); private readonly Queue<TKey> _order = new Queue<TKey>(); internal long Assigned; internal long Released; internal long Transferred; internal long RapidTransfers; internal int Tracked => _recent.Count; internal TransferCounter(int maximum) { _maximum = Math.Max(1, maximum); } internal void Record(TKey id, long before, long after, double now) { if (before == after) { return; } if (before == 0L) { Assigned++; return; } if (after == 0L) { Released++; return; } Transferred++; if (_recent.TryGetValue(id, out var value) && now - value <= 10.0) { RapidTransfers++; } if (!_recent.ContainsKey(id)) { if (_recent.Count >= _maximum) { _recent.Remove(_order.Dequeue()); } _order.Enqueue(id); } _recent[id] = now; } internal void ResetInterval() { Assigned = (Released = (Transferred = (RapidTransfers = 0L))); } internal void Clear() { ResetInterval(); _recent.Clear(); _order.Clear(); } } internal sealed class ObservatoryCounter { private readonly object _gate = new object(); private int _created; private int _destroyed; private long _sequence; private double _lastSaveMilliseconds; private double _lastLoadMilliseconds; private ZdoObservatorySnapshot _current = ZdoObservatorySnapshot.Empty; internal ZdoObservatorySnapshot Current { get { lock (_gate) { return _current; } } } internal void MarkCreated() { lock (_gate) { _created = SaturatingIncrement(_created); } } internal void MarkDestroyed() { lock (_gate) { _destroyed = SaturatingIncrement(_destroyed); } } internal void RecordSaveDuration(long startedTimestamp) { RecordDuration(startedTimestamp, save: true); } internal void RecordLoadDuration(long startedTimestamp) { RecordDuration(startedTimestamp, save: false); } internal ZdoObservatorySnapshot Capture(long unixMilliseconds, int totalObjects, int connectedPeers, int sentLastSecond, int receivedLastSecond) { lock (_gate) { _sequence = ((_sequence == long.MaxValue) ? long.MaxValue : (_sequence + 1)); _current = new ZdoObservatorySnapshot(_sequence, Math.Max(0L, unixMilliseconds), Math.Max(0, totalObjects), Math.Max(0, connectedPeers), _created, _destroyed, Math.Max(0, sentLastSecond), Math.Max(0, receivedLastSecond), _lastSaveMilliseconds, _lastLoadMilliseconds); _created = 0; _destroyed = 0; return _current; } } internal void Reset() { lock (_gate) { _created = 0; _destroyed = 0; _sequence = 0L; _lastSaveMilliseconds = 0.0; _lastLoadMilliseconds = 0.0; _current = ZdoObservatorySnapshot.Empty; } } private void RecordDuration(long startedTimestamp, bool save) { if (startedTimestamp <= 0) { return; } long num = Stopwatch.GetTimestamp() - startedTimestamp; if (num < 0) { return; } double num2 = (double)num * 1000.0 / (double)Stopwatch.Frequency; lock (_gate) { if (save) { _lastSaveMilliseconds = num2; } else { _lastLoadMilliseconds = num2; } } } private static int SaturatingIncrement(int value) { if (value != int.MaxValue) { return value + 1; } return value; } } } namespace RunicWorldEngine.Contracts { internal sealed class ZdoObservatorySnapshot { internal long Sequence { get; } internal long CapturedUnixMilliseconds { get; } internal int TotalObjects { get; } internal int ConnectedPeers { get; } internal int CreatedSincePreviousSample { get; } internal int DestroyedSincePreviousSample { get; } internal int SentLastSecond { get; } internal int ReceivedLastSecond { get; } internal double LastSaveMilliseconds { get; } internal double LastLoadMilliseconds { get; } internal static ZdoObservatorySnapshot Empty { get; } = new ZdoObservatorySnapshot(0L, 0L, 0, 0, 0, 0, 0, 0, 0.0, 0.0); internal ZdoObservatorySnapshot(long sequence, long capturedUnixMilliseconds, int totalObjects, int connectedPeers, int createdSincePreviousSample, int destroyedSincePreviousSample, int sentLastSecond, int receivedLastSecond, double lastSaveMilliseconds, double lastLoadMilliseconds) { Sequence = Math.Max(0L, sequence); CapturedUnixMilliseconds = Math.Max(0L, capturedUnixMilliseconds); TotalObjects = Math.Max(0, totalObjects); ConnectedPeers = Math.Max(0, connectedPeers); CreatedSincePreviousSample = Math.Max(0, createdSincePreviousSample); DestroyedSincePreviousSample = Math.Max(0, destroyedSincePreviousSample); SentLastSecond = Math.Max(0, sentLastSecond); ReceivedLastSecond = Math.Max(0, receivedLastSecond); LastSaveMilliseconds = Math.Max(0.0, lastSaveMilliseconds); LastLoadMilliseconds = Math.Max(0.0, lastLoadMilliseconds); } } }