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 TimeControl v1.0.0
plugins/TimeControl.dll
Decompiled a day agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("TimeControl")] [assembly: AssemblyDescription("Adjusts the Valheim day/night cycle length via a multiplier, with server-authoritative sync and an exact mod-version gate.")] [assembly: AssemblyProduct("TimeControl")] [assembly: AssemblyCompany("drummercraig")] [assembly: ComVisible(false)] [assembly: AssemblyFileVersion("1.0.0")] [assembly: AssemblyVersion("1.0.0.0")] namespace TimeControl; [BepInPlugin("drummercraig.time_control", "TimeControl", "1.0.0")] public class TimeControlPlugin : BaseUnityPlugin { public const string PluginGuid = "drummercraig.time_control"; public const string PluginName = "TimeControl"; public const string PluginVersion = "1.0.0"; private void Awake() { TimeControlConfig.Log = ((BaseUnityPlugin)this).Logger; TimeControlConfig.Bind(((BaseUnityPlugin)this).Config); Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), (string)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)(string.Format("[TimeControl] v{0} loaded. DayLengthMultiplier={1:0.###} ", "1.0.0", TimeControlConfig.DayLengthMultiplier.Value) + "(local config; server value takes over when connected to a server).")); } } public static class TimeControlConfig { public static ManualLogSource Log; public static ConfigEntry<float> DayLengthMultiplier; public const float MinMultiplier = 0.1f; public const float MaxMultiplier = 100f; public static float ServerMultiplier = -1f; public static float EffectiveMultiplier => Mathf.Clamp((ServerMultiplier >= 0f) ? ServerMultiplier : DayLengthMultiplier.Value, 0.1f, 100f); public static void Bind(ConfigFile config) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown DayLengthMultiplier = config.Bind<float>("General", "DayLengthMultiplier", 4f, new ConfigDescription("Multiplier applied to the in-game day/night cycle length. 1.0 = vanilla (a full day is ~30 real minutes). 2.0 = days take twice as long; 4.0 = ~2 real hours per full day. Day and night both scale together (their ratio is fixed by Valheim and is preserved). When you join a server running TimeControl, the server's value is used instead of this one for that session, so everyone shares the same clock. Range: " + 0.1f + " to " + 100f + ".", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 100f), Array.Empty<object>())); DayLengthMultiplier.SettingChanged += delegate { DayLength.ApplyEffectiveMultiplier(); }; } } public static class DayLength { [HarmonyPatch(typeof(EnvMan), "Awake")] private static class EnvManAwakePatch { private static void Postfix() { ApplyEffectiveMultiplier(); } } private static long _vanillaBaseSec = -1L; public static bool HasBase => _vanillaBaseSec > 0; public static long VanillaBaseSec => _vanillaBaseSec; public static void ApplyEffectiveMultiplier() { EnvMan instance = EnvMan.instance; if ((Object)(object)instance == (Object)null) { return; } if (_vanillaBaseSec < 0) { _vanillaBaseSec = instance.m_dayLengthSec; } float effectiveMultiplier = TimeControlConfig.EffectiveMultiplier; long num = (long)((float)_vanillaBaseSec * effectiveMultiplier); if (num < 1) { num = 1L; } if (instance.m_dayLengthSec != num) { instance.m_dayLengthSec = num; ManualLogSource log = TimeControlConfig.Log; if (log != null) { log.LogInfo((object)($"[TimeControl] Day length set to {num}s " + $"(vanilla base {_vanillaBaseSec}s x {effectiveMultiplier:0.###}).")); } } } } public static class NetworkSync { [HarmonyPatch(typeof(ZNet), "OnNewConnection")] private static class OnNewConnectionPatch { private static void Postfix(ZNetPeer peer, ZNet __instance) { if (__instance.IsServer()) { peer.m_rpc.Register<string>("TimeControl_Version", (Action<ZRpc, string>)OnServerReceiveClientVersion); peer.m_rpc.Invoke("TimeControl_Version", new object[1] { "1.0.0" }); } else { _serverSentVersion = false; peer.m_rpc.Register<string>("TimeControl_Version", (Action<ZRpc, string>)OnClientReceiveServerVersion); peer.m_rpc.Register<float>("TimeControl_DayLength", (Action<ZRpc, float>)OnClientReceiveDayLength); peer.m_rpc.Invoke("TimeControl_Version", new object[1] { "1.0.0" }); } } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] private static class RpcPeerInfoPatch { private static bool Prefix(ZRpc rpc, ZNet __instance) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Invalid comparison between Unknown and I4 if (__instance.IsServer()) { if (!_validatedPeers.Contains(rpc)) { ManualLogSource log = TimeControlConfig.Log; if (log != null) { log.LogWarning((object)"[TimeControl] Disconnecting client without a matching TimeControl version."); } rpc.Invoke("Error", new object[1] { 3 }); return false; } SendDayLengthToPeer(rpc); return true; } if (!_serverSentVersion) { ManualLogSource log2 = TimeControlConfig.Log; if (log2 != null) { log2.LogWarning((object)"[TimeControl] Server is not running TimeControl. Disconnecting (incompatible version)."); } if ((int)ZNet.GetConnectionStatus() != 3) { SetClientConnectionError((ConnectionStatus)3); } if ((Object)(object)Game.instance != (Object)null) { Game.instance.Logout(true, true); } return false; } return true; } private static void SendDayLengthToPeer(ZRpc rpc) { try { rpc.Invoke("TimeControl_DayLength", new object[1] { TimeControlConfig.EffectiveMultiplier }); } catch (Exception ex) { ManualLogSource log = TimeControlConfig.Log; if (log != null) { log.LogWarning((object)("[TimeControl] Failed to push day length: " + ex.Message)); } } } } private const string RpcVersion = "TimeControl_Version"; private const string RpcDayLength = "TimeControl_DayLength"; private static readonly HashSet<ZRpc> _validatedPeers = new HashSet<ZRpc>(); private static bool _serverSentVersion; private static void OnServerReceiveClientVersion(ZRpc rpc, string clientVersion) { if (string.Equals(clientVersion, "1.0.0", StringComparison.Ordinal)) { _validatedPeers.Add(rpc); ManualLogSource log = TimeControlConfig.Log; if (log != null) { log.LogInfo((object)("[TimeControl] Client presented matching version " + clientVersion + ".")); } } else { ManualLogSource log2 = TimeControlConfig.Log; if (log2 != null) { log2.LogWarning((object)("[TimeControl] Client version '" + clientVersion + "' != server '1.0.0'. Will be disconnected at peer-info handshake.")); } } } private static void OnClientReceiveServerVersion(ZRpc rpc, string serverVersion) { _serverSentVersion = true; if (!string.Equals(serverVersion, "1.0.0", StringComparison.Ordinal)) { ManualLogSource log = TimeControlConfig.Log; if (log != null) { log.LogWarning((object)("[TimeControl] Server version '" + serverVersion + "' != client '1.0.0'. Disconnecting (incompatible version).")); } } else { ManualLogSource log2 = TimeControlConfig.Log; if (log2 != null) { log2.LogInfo((object)("[TimeControl] Server version " + serverVersion + " matches.")); } } } private static void OnClientReceiveDayLength(ZRpc rpc, float serverMultiplier) { TimeControlConfig.ServerMultiplier = serverMultiplier; ManualLogSource log = TimeControlConfig.Log; if (log != null) { log.LogInfo((object)$"[TimeControl] Adopting server day-length multiplier {serverMultiplier:0.###} for this session."); } DayLength.ApplyEffectiveMultiplier(); } private static void SetClientConnectionError(ConnectionStatus status) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) AccessTools.Field(typeof(ZNet), "m_connectionStatus")?.SetValue(null, status); } }