using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Threading; using BepInEx; using BepInEx.Logging; using HarmonyLib; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("ScheduledMessages")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+ecf8632be9bd7c7009759f58bceb43c3d43c5ecd")] [assembly: AssemblyProduct("ScheduledMessages")] [assembly: AssemblyTitle("ScheduledMessages")] [assembly: AssemblyVersion("1.0.0.0")] namespace ScheduledMessages; public class ScheduledMessage { public int Hour; public int Minute; public string Time; public string Message; } public class ScheduledMessagesConfig { public int UtcOffset; public string WelcomeMessage; public int WelcomeDelay; public List ScheduledMessages = new List(); } [BepInPlugin("com.byawn.scheduledmessages", "ScheduledMessages", "1.5.0")] public class ScheduledMessagesPlugin : BaseUnityPlugin { public const string PluginGUID = "com.byawn.scheduledmessages"; public const string PluginName = "ScheduledMessages"; public const string PluginVersion = "1.5.0"; internal static ManualLogSource Log; private Harmony harmony; private ScheduledMessagesConfig config; private readonly HashSet sentThisMinute = new HashSet(); private int lastCheckedMinute = -1; private readonly HashSet knownPeers = new HashSet(); private string configPath; private FileSystemWatcher configWatcher; private DateTime lastConfigReload = DateTime.MinValue; private void Awake() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; harmony = new Harmony("com.byawn.scheduledmessages"); harmony.PatchAll(); configPath = Path.Combine(Paths.ConfigPath, "scheduledmessages.cfg"); LoadConfig(); StartConfigWatcher(); Log.LogInfo((object)"ScheduledMessages v1.5.0 loaded."); } private void LoadConfig() { if (!File.Exists(configPath)) { Log.LogError((object)("Config not found at " + configPath + ". No welcome or scheduled messages will be sent.")); return; } ScheduledMessagesConfig scheduledMessagesConfig = new ScheduledMessagesConfig(); string[] array = File.ReadAllLines(configPath); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (string.IsNullOrEmpty(text) || text.StartsWith("#")) { continue; } if (text.StartsWith("timezone=")) { int.TryParse(text.Substring("timezone=".Length).Trim(), out scheduledMessagesConfig.UtcOffset); continue; } if (text.StartsWith("welcome=")) { scheduledMessagesConfig.WelcomeMessage = text.Substring("welcome=".Length).Trim(); continue; } if (text.StartsWith("welcome-delay=")) { int.TryParse(text.Substring("welcome-delay=".Length).Trim(), out scheduledMessagesConfig.WelcomeDelay); continue; } int num = text.IndexOf(' '); if (num >= 0) { string text2 = text.Substring(0, num).Trim(); string text3 = text.Substring(num + 1).Trim(); if (TryParseTime(text2, out var hour, out var minute) && !string.IsNullOrEmpty(text3)) { scheduledMessagesConfig.ScheduledMessages.Add(new ScheduledMessage { Hour = hour, Minute = minute, Time = text2, Message = text3 }); } } } config = scheduledMessagesConfig; LogConfig(); } private void LogConfig() { Log.LogInfo((object)$"Config loaded: timezone={config.UtcOffset}"); Log.LogInfo((object)("Config loaded: welcome=" + config.WelcomeMessage)); Log.LogInfo((object)$"Config loaded: welcome-delay={config.WelcomeDelay}"); foreach (ScheduledMessage scheduledMessage in config.ScheduledMessages) { Log.LogInfo((object)("Config loaded: " + scheduledMessage.Time + " " + scheduledMessage.Message)); } } private void StartConfigWatcher() { configWatcher = new FileSystemWatcher(Paths.ConfigPath, "scheduledmessages.cfg"); configWatcher.NotifyFilter = NotifyFilters.LastWrite; configWatcher.Changed += OnConfigChanged; configWatcher.EnableRaisingEvents = true; } private void OnConfigChanged(object sender, FileSystemEventArgs e) { if (!((DateTime.Now - lastConfigReload).TotalSeconds < 1.0)) { lastConfigReload = DateTime.Now; Thread.Sleep(200); Log.LogInfo((object)"Config file changed, reloading..."); LoadConfig(); } } private void Update() { if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return; } if (!string.IsNullOrEmpty(config.WelcomeMessage)) { CheckForNewPeers(); } if (!config.ScheduledMessages.Any()) { return; } DateTime dateTime = DateTime.UtcNow.AddHours(config.UtcOffset); int num = dateTime.Hour * 60 + dateTime.Minute; if (num != lastCheckedMinute) { sentThisMinute.Clear(); lastCheckedMinute = num; } foreach (ScheduledMessage scheduledMessage in config.ScheduledMessages) { int num2 = scheduledMessage.Hour * 60 + scheduledMessage.Minute; string item = scheduledMessage.Time + "|" + scheduledMessage.Message; if (num == num2 && !sentThisMinute.Contains(item)) { Broadcast(scheduledMessage.Message); sentThisMinute.Add(item); } } } private void CheckForNewPeers() { if (string.IsNullOrEmpty(config.WelcomeMessage)) { return; } List peers = ZNet.instance.GetPeers(); foreach (ZNetPeer item in peers) { if (item.m_uid != 0L && !knownPeers.Contains(item.m_uid)) { knownPeers.Add(item.m_uid); Log.LogInfo((object)$"New peer connected: {item.m_playerName} ({item.m_uid}), sending welcome message in {config.WelcomeDelay} seconds."); ((MonoBehaviour)this).StartCoroutine(SendDelayedWelcome(item)); } } HashSet currentUids = new HashSet(peers.Select((ZNetPeer p) => p.m_uid)); knownPeers.RemoveWhere((long uid) => !currentUids.Contains(uid)); } private IEnumerator SendDelayedWelcome(ZNetPeer peer) { yield return (object)new WaitForSeconds((float)config.WelcomeDelay); if (peer == null) { Log.LogInfo((object)"[Welcome] no peer found to send welcome to."); yield break; } ShowMessage((MessageType)2, config.WelcomeMessage); Log.LogInfo((object)("[Welcome] Sent to " + peer.m_playerName + ": " + config.WelcomeMessage)); } private void Broadcast(string text) { if (!ZNet.instance.GetPeers().Any()) { Log.LogInfo((object)("[Scheduled] No peers connected, skipping: " + text)); return; } ShowMessage((MessageType)2, text); Log.LogInfo((object)("[Scheduled] " + text)); } private static void ShowMessage(MessageType type, string text) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected I4, but got Unknown if (!string.IsNullOrWhiteSpace(text) && ZRoutedRpc.instance != null) { ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "ShowMessage", new object[2] { (int)type, text }); } } private bool TryParseTime(string timeStr, out int hour, out int minute) { hour = 0; minute = 0; if (string.IsNullOrWhiteSpace(timeStr)) { return false; } string[] array = timeStr.Split(':'); if (array.Length != 2) { return false; } if (int.TryParse(array[0], out hour) && int.TryParse(array[1], out minute) && hour >= 0 && hour < 24 && minute >= 0) { return minute < 60; } return false; } private void OnDestroy() { configWatcher?.Dispose(); Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } }