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.1.0
RunicWorldEngine.dll
Decompiled 27 minutes agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Threading; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using RunicWorldEngine.Contracts; using RunicWorldEngine.Core; using RunicWorldEngine.Integration; 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.1.0.0")] [assembly: AssemblyInformationalVersion("1.1.0")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyVersion("1.1.0.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 RunicWorldEngine { internal static class WorldEngineConfig { 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_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Expected O, but got Unknown //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Expected O, but got Unknown Enabled = config.Bind<bool>("General", "Enabled", true, "Enable bounded world-state observation and optional save smoothing. When false, no Harmony patches or runtime state are created. This never enables deletion or network sync rescheduling."); LogPeriodicSummary = config.Bind<bool>("Diagnostics", "LogPeriodicSummary", false, "Write rate-limited aggregate ZDO counts and traffic to the BepInEx log."); SummaryIntervalSeconds = config.Bind<float>("Diagnostics", "SummaryIntervalSeconds", 30f, new ConfigDescription("Seconds between optional aggregate summaries.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 600f), Array.Empty<object>())); SmoothWorldSaves = config.Bind<bool>("Save Smoothing", "Enabled", true, "Coalesce overlapping asynchronous world saves and defer the main-thread PrepareSave capture until a stable frame. Synchronous shutdown saves are never deferred."); SaveFrameBudgetMilliseconds = config.Bind<float>("Save Smoothing", "FrameBudgetMilliseconds", 24f, new ConfigDescription("Prefer to start asynchronous PrepareSave only when the previous unscaled frame was at or below this duration.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(8f, 100f), Array.Empty<object>())); MaximumSaveDeferralSeconds = config.Bind<float>("Save Smoothing", "MaximumDeferralSeconds", 5f, new ConfigDescription("Maximum time an asynchronous save may wait for a stable frame. The save then starts even if frames remain busy.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 30f), Array.Empty<object>())); } } [BepInPlugin("chazman.RunicWorldEngine", "Runic World Engine", "1.1.0")] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "chazman.RunicWorldEngine"; public const string Name = "Runic World Engine"; public const string Version = "1.1.0"; 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); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Runic World Engine v1.1.0 ready: bounded aggregate ZDO observability. 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(); ConfigEntry<bool> enabled = WorldEngineConfig.Enabled; if (enabled == null || !enabled.Value) { return; } ConfigEntry<bool> logPeriodicSummary = WorldEngineConfig.LogPeriodicSummary; if (logPeriodicSummary != null && logPeriodicSummary.Value) { float unscaledTime = Time.unscaledTime; if (!(unscaledTime < _nextSummaryAt)) { _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.")); } } } private void OnDestroy() { Shutdown(); } private void Shutdown() { try { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } catch { } _harmony = null; ObservatoryRuntime.Reset(); SaveSmoothingRuntime.Reset(); } } } namespace RunicWorldEngine.Integration { [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), "SaveAsync", new Type[] { typeof(BinaryWriter) })] internal static class ZdoSaveTimingPatch { 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), "Load", new Type[] { typeof(BinaryReader), typeof(int) })] internal static class ZdoLoadTimingPatch { 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 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 0.221.12 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 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); } } } namespace RunicWorldEngine.Core { 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); } } }