Decompiled source of DagrNott CustomDayCycle v1.0.0

BepInEx\plugins\DagrNott_CustomDayCycle\DagrNott_CustomDayCycle.dll

Decompiled 10 hours ago
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<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> 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<float> configDawnMultiplier;

		private static ConfigEntry<float> configDayMultiplier;

		private static ConfigEntry<float> configDuskMultiplier;

		private static ConfigEntry<float> configNightMultiplier;

		private static ConfigEntry<bool> 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<float>("DayCycle", "DawnMultiplier", 0.9f, new ConfigDescription("Visual time speed multiplier during Dawn.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 4f), new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			configDayMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("DayCycle", "DayMultiplier", 0.5f, new ConfigDescription("Visual time speed multiplier during Day.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 4f), new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			configDuskMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("DayCycle", "DuskMultiplier", 0.9f, new ConfigDescription("Visual time speed multiplier during Dusk.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 4f), new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			configNightMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("DayCycle", "NightMultiplier", 0.3f, new ConfigDescription("Visual time speed multiplier during Night.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 4f), new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			configLogPhaseTransitions = ((BaseUnityPlugin)this).Config.Bind<bool>("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("<color=#E0B084><b>[DagrAndNott Status]</b></color>");
			stringBuilder.AppendLine($"• <b>Current Phase:</b> <color=#98E274>{phaseName}</color> ({multiplier:F2}x speed)");
			stringBuilder.AppendLine($"• <b>Day Progress:</b> {num5:F1}% (Day {num4})");
			stringBuilder.AppendLine($"• <b>Estimated Cycle:</b> {totalMins:F1} mins (Vanilla: 30.0 mins)");
			stringBuilder.AppendLine("• <b>Configured Multipliers:</b>");
			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<string>("DagrAndNott_Cmd", (Action<long, string>)RPC_AdminCommand);
				}
				catch (ArgumentException)
				{
				}
				try
				{
					ZRoutedRpc.instance.Register<string>("DagrAndNott_Resp", (Action<long, string>)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] { "<color=#FF4444>[DagrAndNott] Access denied: You are not listed in the server's adminlist.txt.</color>" });
				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, "<color=#E0B084>[DagrAndNott]</color> Status output sent to chat & log.", 0, (Sprite)null);
				}
				else if ((Object)(object)MessageHud.instance != (Object)null)
				{
					MessageHud.instance.ShowMessage((MessageType)1, "<color=#E0B084>[DagrAndNott]</color> 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 "<color=#E0B084><b>[DagrAndNott Commands]</b></color>\n• <b>/dn</b> or <b>/dn status</b> - 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;
		}
	}
}