using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Utils; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] [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 DagrAndNott { public enum DayPhase { Dawn, Day, Dusk, Night } [BepInPlugin("com.bigai.dagrnott_customdaycycle", "DagrNott_CustomDayCycle", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public class CustomDayCyclePlugin : BaseUnityPlugin { [HarmonyPatch(typeof(Game), "Start")] public static class Patch_Game_Start { [HarmonyPostfix] public static void Postfix() { RegisterRPCs(); } } [HarmonyPatch(typeof(Terminal), "TryRunCommand")] public static class Patch_Terminal_TryRunCommand { [HarmonyPrefix] public static bool Prefix(Terminal __instance, string text) { try { if (string.IsNullOrWhiteSpace(text)) { return true; } string text2 = text.Trim(); if (text2.StartsWith("dn ", StringComparison.OrdinalIgnoreCase) || text2.Equals("dn", StringComparison.OrdinalIgnoreCase) || text2.StartsWith("/dn ", StringComparison.OrdinalIgnoreCase) || text2.Equals("/dn", StringComparison.OrdinalIgnoreCase) || text2.StartsWith("dagrandnott ", StringComparison.OrdinalIgnoreCase) || text2.Equals("dagrandnott", StringComparison.OrdinalIgnoreCase) || text2.StartsWith("/dagrandnott ", StringComparison.OrdinalIgnoreCase) || text2.Equals("/dagrandnott", StringComparison.OrdinalIgnoreCase)) { SendAdminCommand(text2); return false; } } catch (Exception arg) { ManualLogSource log = Log; if (log != null) { log.LogError((object)$"[DagrAndNott] Error in TryRunCommand prefix: {arg}"); } } return true; } } [HarmonyPatch(typeof(EnvMan), "FixedUpdate")] public static class Patch_EnvMan_FixedUpdate { [HarmonyTranspiler] private static IEnumerable Transpiler(IEnumerable instructions) { MethodInfo getTimeSeconds = AccessTools.Method(typeof(ZNet), "GetTimeSeconds", (Type[])null, (Type[])null); MethodInfo getVisualTimeSeconds = AccessTools.Method(typeof(CustomDayCyclePlugin), "GetVisualTimeSeconds", (Type[])null, (Type[])null); bool replaced = false; foreach (CodeInstruction instruction in instructions) { if (!replaced && CodeInstructionExtensions.Calls(instruction, getTimeSeconds)) { instruction.opcode = OpCodes.Pop; instruction.operand = null; replaced = true; yield return instruction; yield return new CodeInstruction(OpCodes.Call, (object)getVisualTimeSeconds); } else { yield return instruction; } } if (!replaced) { Log.LogError((object)"[DagrAndNott] EnvMan.FixedUpdate did not contain ZNet.GetTimeSeconds; visual time patch was not applied."); } } } public const string PluginGUID = "com.bigai.dagrnott_customdaycycle"; public const string PluginName = "DagrNott_CustomDayCycle"; public const string PluginVersion = "1.0.0"; internal static ManualLogSource Log; private static ConfigEntry configDawnMultiplier; private static ConfigEntry configDayMultiplier; private static ConfigEntry configDuskMultiplier; private static ConfigEntry configNightMultiplier; private static ConfigEntry configLogPhaseTransitions; private static DayPhase? lastLoggedPhase = null; private readonly Harmony harmony = new Harmony("com.bigai.dagrnott_customdaycycle"); private static readonly FieldInfo FiAdminList = typeof(ZNet).GetField("m_adminList", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); public const string RpcCommand = "DagrAndNott_Cmd"; public const string RpcResponse = "DagrAndNott_Resp"; private static bool _rpcsRegistered; private void Awake() { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Expected O, but got Unknown //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Expected O, but got Unknown //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Expected O, but got Unknown //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Expected O, but got Unknown //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; configDawnMultiplier = ((BaseUnityPlugin)this).Config.Bind("DayCycle", "DawnMultiplier", 0.9f, new ConfigDescription("Visual time speed multiplier during Dawn.", (AcceptableValueBase)(object)new AcceptableValueRange(0.05f, 4f), new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true } })); configDayMultiplier = ((BaseUnityPlugin)this).Config.Bind("DayCycle", "DayMultiplier", 0.5f, new ConfigDescription("Visual time speed multiplier during Day.", (AcceptableValueBase)(object)new AcceptableValueRange(0.05f, 4f), new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true } })); configDuskMultiplier = ((BaseUnityPlugin)this).Config.Bind("DayCycle", "DuskMultiplier", 0.9f, new ConfigDescription("Visual time speed multiplier during Dusk.", (AcceptableValueBase)(object)new AcceptableValueRange(0.05f, 4f), new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true } })); configNightMultiplier = ((BaseUnityPlugin)this).Config.Bind("DayCycle", "NightMultiplier", 0.3f, new ConfigDescription("Visual time speed multiplier during Night.", (AcceptableValueBase)(object)new AcceptableValueRange(0.05f, 4f), new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true } })); configLogPhaseTransitions = ((BaseUnityPlugin)this).Config.Bind("Logging", "LogPhaseTransitions", true, "Log when day/night phase transitions occur to the server console."); ApplyPatch(harmony, typeof(Patch_Game_Start)); ApplyPatch(harmony, typeof(Patch_Terminal_TryRunCommand)); ApplyPatch(harmony, typeof(Patch_EnvMan_FixedUpdate)); Log.LogInfo((object)"[DagrNott_CustomDayCycle] Harmony patching complete."); GetEstimatedCycleLengths(out var dawnMins, out var dayMins, out var duskMins, out var nightMins, out var totalMins); Log.LogInfo((object)"DagrNott_CustomDayCycle v1.0.0 loaded successfully."); Log.LogInfo((object)$"Cycle Timing: Dawn={configDawnMultiplier.Value:F2}x (~{dawnMins:F1}m), Day={configDayMultiplier.Value:F2}x (~{dayMins:F1}m), Dusk={configDuskMultiplier.Value:F2}x (~{duskMins:F1}m), Night={configNightMultiplier.Value:F2}x (~{nightMins:F1}m) | Estimated Total: ~{totalMins:F1} mins"); Log.LogInfo((object)"[DagrAndNott] Jotunn synchronizes cycle settings; all clients require DagrAndNott. Network time and water simulation are unchanged."); } private static void ApplyPatch(Harmony harmony, Type patchType) { try { harmony.CreateClassProcessor(patchType).Patch(); Log.LogInfo((object)("[DagrNott_CustomDayCycle] Patched: " + patchType.Name)); } catch (Exception ex) { Log.LogError((object)("[DagrNott_CustomDayCycle] Failed to apply patch " + patchType.Name + ": " + ex.Message)); } } public static DayPhase GetDayPhase(float fraction, out float multiplier, out string phaseName) { if (fraction < 0.15f) { multiplier = configDawnMultiplier.Value; phaseName = "Dawn"; return DayPhase.Dawn; } if (fraction < 0.65f) { multiplier = configDayMultiplier.Value; phaseName = "Day"; return DayPhase.Day; } if (fraction < 0.8f) { multiplier = configDuskMultiplier.Value; phaseName = "Dusk"; return DayPhase.Dusk; } multiplier = configNightMultiplier.Value; phaseName = "Night"; return DayPhase.Night; } public static void GetEstimatedCycleLengths(out float dawnMins, out float dayMins, out float duskMins, out float nightMins, out float totalMins) { float num = Mathf.Max(0.001f, configDawnMultiplier.Value); float num2 = Mathf.Max(0.001f, configDayMultiplier.Value); float num3 = Mathf.Max(0.001f, configDuskMultiplier.Value); float num4 = Mathf.Max(0.001f, configNightMultiplier.Value); dawnMins = 4.5f / num; dayMins = 15f / num2; duskMins = 4.5f / num3; nightMins = 6f / num4; totalMins = dawnMins + dayMins + duskMins + nightMins; } public static bool IsAdmin(long senderId) { if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || !ZNet.instance.IsDedicated()) { return true; } if (senderId == 0L) { return true; } ZNetPeer peer = ZNet.instance.GetPeer(senderId); if (peer == null) { return false; } ISocket socket = peer.m_socket; string text = ((socket != null) ? socket.GetHostName() : null); if (string.IsNullOrEmpty(text)) { ZRpc rpc = peer.m_rpc; if (((rpc != null) ? rpc.GetSocket() : null) != null) { text = peer.m_rpc.GetSocket().GetHostName(); } } if (string.IsNullOrEmpty(text)) { return false; } try { object obj = ((FiAdminList != null) ? FiAdminList.GetValue(ZNet.instance) : Traverse.Create((object)ZNet.instance).Field("m_adminList").GetValue()); if (obj == null) { return false; } SyncedList val = (SyncedList)((obj is SyncedList) ? obj : null); ulong result; if (val != null) { if (val.Contains(text)) { return true; } if (ulong.TryParse(text, out result) && val.Contains("Steam_" + text)) { return true; } return false; } MethodInfo method = obj.GetType().GetMethod("Contains", new Type[1] { typeof(string) }); if (method != null) { if ((bool)(method.Invoke(obj, new object[1] { text }) ?? ((object)false))) { return true; } if (ulong.TryParse(text, out result) && (bool)(method.Invoke(obj, new object[1] { "Steam_" + text }) ?? ((object)false))) { return true; } } } catch (Exception ex) { ManualLogSource log = Log; if (log != null) { log.LogError((object)("[DagrAndNott] IsAdmin check error: " + ex.Message)); } } return false; } public static string BuildStatusMessage(EnvMan envMan) { double num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : 0.0); double num2 = (((Object)(object)envMan != (Object)null) ? ((double)envMan.m_dayLengthSec) : 1800.0); if (num2 <= 0.0) { num2 = 1800.0; } float num3 = (float)(num % num2 / num2); if (num3 < 0f) { num3 += 1f; } long num4 = (((Object)(object)envMan != (Object)null) ? envMan.GetDay(num) : ((long)(num / num2))); GetDayPhase(num3, out var multiplier, out var phaseName); GetEstimatedCycleLengths(out var dawnMins, out var dayMins, out var duskMins, out var nightMins, out var totalMins); float num5 = num3 * 100f; StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("[DagrAndNott Status]"); stringBuilder.AppendLine($"• Current Phase: {phaseName} ({multiplier:F2}x speed)"); stringBuilder.AppendLine($"• Day Progress: {num5:F1}% (Day {num4})"); stringBuilder.AppendLine($"• Estimated Cycle: {totalMins:F1} mins (Vanilla: 30.0 mins)"); stringBuilder.AppendLine("• Configured Multipliers:"); stringBuilder.AppendLine($" Dawn: {configDawnMultiplier.Value:F2}x (~{dawnMins:F1}m) | Day: {configDayMultiplier.Value:F2}x (~{dayMins:F1}m)"); stringBuilder.Append($" Dusk: {configDuskMultiplier.Value:F2}x (~{duskMins:F1}m) | Night: {configNightMultiplier.Value:F2}x (~{nightMins:F1}m)"); return stringBuilder.ToString(); } public static void RegisterRPCs() { if (!_rpcsRegistered && ZRoutedRpc.instance != null) { _rpcsRegistered = true; try { ZRoutedRpc.instance.Register("DagrAndNott_Cmd", (Action)RPC_AdminCommand); } catch (ArgumentException) { } try { ZRoutedRpc.instance.Register("DagrAndNott_Resp", (Action)RPC_AdminResponse); } catch (ArgumentException) { } ManualLogSource log = Log; if (log != null) { log.LogInfo((object)"[DagrAndNott] Network RPC handlers registered."); } } } private static void RPC_AdminCommand(long sender, string text) { if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return; } ZNetPeer peer = ZNet.instance.GetPeer(sender); string text2; if (peer == null) { text2 = sender.ToString(); } else { string playerName = peer.m_playerName; ISocket socket = peer.m_socket; text2 = playerName + " (" + (((socket != null) ? socket.GetHostName() : null) ?? sender.ToString()) + ")"; } string text3 = text2; if (!IsAdmin(sender)) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)("[DagrAndNott] Non-admin " + text3 + " tried to run: " + text)); } ZRoutedRpc.instance.InvokeRoutedRPC(sender, "DagrAndNott_Resp", new object[1] { "[DagrAndNott] Access denied: You are not listed in the server's adminlist.txt." }); return; } ManualLogSource log2 = Log; if (log2 != null) { log2.LogInfo((object)("[DagrAndNott] Executing command '" + text + "' for admin " + text3)); } string text4 = ExecuteCommand(text); ZRoutedRpc.instance.InvokeRoutedRPC(sender, "DagrAndNott_Resp", new object[1] { text4 }); } private static void RPC_AdminResponse(long sender, string response) { DisplayResponse(response); } public static void DisplayResponse(string response) { if (!string.IsNullOrEmpty(response)) { ManualLogSource log = Log; if (log != null) { log.LogInfo((object)("\n" + response)); } if ((Object)(object)Chat.instance != (Object)null) { ((Terminal)Chat.instance).AddString(response); } if ((Object)(object)Player.m_localPlayer != (Object)null) { ((Character)Player.m_localPlayer).Message((MessageType)1, "[DagrAndNott] Status output sent to chat & log.", 0, (Sprite)null); } else if ((Object)(object)MessageHud.instance != (Object)null) { MessageHud.instance.ShowMessage((MessageType)1, "[DagrAndNott] Status output sent to chat & log.", 0, (Sprite)null, false); } } } public static void SendAdminCommand(string text) { ManualLogSource log = Log; if (log != null) { log.LogInfo((object)("[DagrAndNott] Handling command: '" + text + "'")); } if (string.IsNullOrWhiteSpace(text)) { return; } if (!text.StartsWith("/", StringComparison.OrdinalIgnoreCase)) { text = "/" + text; } if ((Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer()) { DisplayResponse(ExecuteCommand(text)); } else if (ZRoutedRpc.instance != null) { ManualLogSource log2 = Log; if (log2 != null) { log2.LogInfo((object)("[DagrAndNott] Sending admin command to server: " + text)); } ZRoutedRpc.instance.InvokeRoutedRPC(0L, "DagrAndNott_Cmd", new object[1] { text }); } else { DisplayResponse(ExecuteCommand(text)); } } public static string ExecuteCommand(string text) { string text2 = text; if (text2.StartsWith("/dagrandnott", StringComparison.OrdinalIgnoreCase)) { text2 = text2.Substring(12).Trim(); } else if (text2.StartsWith("dagrandnott", StringComparison.OrdinalIgnoreCase)) { text2 = text2.Substring(11).Trim(); } else if (text2.StartsWith("/dn", StringComparison.OrdinalIgnoreCase)) { text2 = text2.Substring(3).Trim(); } else if (text2.StartsWith("dn", StringComparison.OrdinalIgnoreCase)) { text2 = text2.Substring(2).Trim(); } string[] array = text2.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (((array.Length != 0) ? array[0].ToLowerInvariant() : "status") == "status") { return BuildStatusMessage(EnvMan.instance); } return "[DagrAndNott Commands]\n• /dn or /dn status - Display current phase, day progress, and cycle configuration."; } public static double GetVisualTimeSeconds() { if ((Object)(object)ZNet.instance == (Object)null || (Object)(object)EnvMan.instance == (Object)null) { return 0.0; } double num = EnvMan.instance.m_dayLengthSec; if (num <= 0.0) { return ZNet.instance.GetTimeSeconds(); } double timeSeconds = ZNet.instance.GetTimeSeconds(); double num2 = num * 0.15 / (double)Mathf.Max(0.05f, configDawnMultiplier.Value); double num3 = num * 0.5 / (double)Mathf.Max(0.05f, configDayMultiplier.Value); double num4 = num * 0.15 / (double)Mathf.Max(0.05f, configDuskMultiplier.Value); double num5 = num * 0.2 / (double)Mathf.Max(0.05f, configNightMultiplier.Value); double num6 = num2 + num3 + num4 + num5; double num7 = timeSeconds % num6; long num8 = (long)Math.Floor(timeSeconds / num6); double num9 = ((num7 < num2) ? (num7 * (double)configDawnMultiplier.Value) : (((num7 -= num2) < num3) ? (num * 0.15 + num7 * (double)configDayMultiplier.Value) : ((!((num7 -= num3) < num4)) ? (num * 0.8 + (num7 - num4) * (double)configNightMultiplier.Value) : (num * 0.65 + num7 * (double)configDuskMultiplier.Value)))); return (double)num8 * num + num9; } } }