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 Bedtime v1.1.0
plugins/Bedtime.dll
Decompiled 5 days agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("Bedtime")] [assembly: AssemblyProduct("Bedtime")] [assembly: AssemblyFileVersion("1.1.0.0")] [assembly: AssemblyCopyright("Copyright (c) 2026 AugusDogus")] [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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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 Bedtime { internal sealed class BedAnnouncements { private string? _lastMessage; public string? Update(int inBed, IReadOnlyCollection<string> awakePlayers, bool showAwakePlayers = true, bool repeat = false) { int num = inBed + awakePlayers.Count; if (num <= 1 || inBed == 0) { Clear(); return null; } if (awakePlayers.Count == 0) { return ChangedMessage("Everyone went to sleep. Sweet dreams!", repeat); } StringBuilder stringBuilder = new StringBuilder(); if (showAwakePlayers) { stringBuilder.Append('\n', awakePlayers.Count + 1); } stringBuilder.Append($"{inBed} of {num} players asleep"); if (showAwakePlayers) { List<string> list = new List<string>(awakePlayers.Count); foreach (string awakePlayer in awakePlayers) { list.Add(DisplayName(awakePlayer)); } list.Sort(StringComparer.Ordinal); stringBuilder.Append("\nNot Sleeping:"); foreach (string item in list) { stringBuilder.Append("\n• ").Append(item); } } return ChangedMessage(stringBuilder.ToString(), repeat); } private string? ChangedMessage(string message, bool repeat) { if (!repeat && message == _lastMessage) { return null; } _lastMessage = message; return message; } private static string DisplayName(string name) { StringBuilder stringBuilder = new StringBuilder(name.Length); foreach (char c in name) { StringBuilder stringBuilder2 = stringBuilder; stringBuilder2.Append(c switch { '<' => '‹', '>' => '›', '$' => '$', '\\' => '\', _ => (!char.IsControl(c) && !char.IsWhiteSpace(c)) ? c : ' ', }); } string text = stringBuilder.ToString().Trim(); if (text.Length != 0) { return text; } return "Unknown player"; } public void Clear() { _lastMessage = null; } } internal static class ChatCommand { private static readonly int SayHash = StringExtensionMethods.GetStableHashCode("Say"); private static readonly int ChatHash = StringExtensionMethods.GetStableHashCode("ChatMessage"); public static bool IsReplay(ZPackage packet, long peerId) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) int pos = packet.GetPos(); try { packet.ReadLong(); if (packet.ReadLong() != peerId) { return false; } packet.ReadLong(); ZDOID val = packet.ReadZDOID(); int num = packet.ReadInt(); bool num2 = num == SayHash && !((ZDOID)(ref val)).IsNone() && ((ZDOID)(ref val)).UserID == peerId; bool flag = num == ChatHash && ((ZDOID)(ref val)).IsNone(); if (!num2 && !flag) { return false; } ZPackage val2 = packet.ReadPackage(); if (flag) { val2.ReadVector3(); } int num3 = val2.ReadInt(); if (num3 < 0 || num3 > 2) { return false; } new UserInfo().Deserialize(ref val2); return ReplayRequest.Matches(val2.ReadString()); } catch (IOException) { return false; } catch (ArgumentException) { return false; } finally { packet.SetPos(pos); } } } [BepInPlugin("augusdogus.mods.Bedtime", "Bedtime", "1.1.0")] public sealed class Plugin : BaseUnityPlugin { [HarmonyPatch(typeof(Game), "UpdateSleeping")] private static class SleepUpdatePatch { [HarmonyPrefix] private static void Prefix(bool ___m_sleeping) { _instance?.AnnounceBeds(___m_sleeping); } } [HarmonyPatch(typeof(ZRoutedRpc), "RPC_RoutedRPC")] private static class ChatCommandPatch { [HarmonyPrefix] private static bool Prefix(ZRpc rpc, ZPackage pkg) { Plugin instance = _instance; ZNet instance2 = ZNet.instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance2 == (Object)null || !instance2.IsServer() || !instance2.IsDedicated()) { return true; } foreach (ZNetPeer peer in instance2.GetPeers()) { if (peer.m_rpc == rpc && peer.IsReady()) { if (!ChatCommand.IsReplay(pkg, peer.m_uid)) { return true; } if (instance._replayRequest.TryAccept(Time.realtimeSinceStartupAsDouble)) { instance._replayPending = true; } return false; } } return true; } } public const string PluginId = "augusdogus.mods.Bedtime"; public const string PluginVersion = "1.1.0"; private readonly BedAnnouncements _announcements = new BedAnnouncements(); private readonly Harmony _harmony = new Harmony("augusdogus.mods.Bedtime"); private readonly ReplayRequest _replayRequest = new ReplayRequest(); private bool _replayPending; private bool _showAwakePlayers = true; private static Plugin? _instance; private void Awake() { _instance = this; try { _showAwakePlayers = ((BaseUnityPlugin)this).Config.Bind<bool>("Announcements", "ShowAwakePlayers", true, "Show the Not Sleeping list below the bed count. Disable for count-only announcements. Restart the server after changing this setting.").Value; _harmony.PatchAll(typeof(SleepUpdatePatch)); _harmony.PatchAll(typeof(ChatCommandPatch)); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Bedtime loaded. Bed announcements run on dedicated servers; vanilla sleep rules are unchanged."); } catch (Exception error) { DisableAnnouncements(error); } } private void OnDestroy() { _instance = null; _harmony.UnpatchSelf(); } private void AnnounceBeds(bool sleeping) { try { bool replayPending = _replayPending; _replayPending = false; ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null || !instance.IsServer() || !instance.IsDedicated() || sleeping) { _announcements.Clear(); return; } ZRoutedRpc instance2 = ZRoutedRpc.instance; if (instance2 == null) { return; } List<ZDO> allCharacterZDOS = instance.GetAllCharacterZDOS(); int num = 0; List<string> list = new List<string>(); foreach (ZDO item in allCharacterZDOS) { if (item.GetBool(ZDOVars.s_inBed, false)) { num++; } else { list.Add(item.GetString(ZDOVars.s_playerName, "Unknown player")); } } string text = _announcements.Update(num, list, _showAwakePlayers, replayPending); if (text != null) { instance2.InvokeRoutedRPC(0L, "ShowMessage", new object[2] { 1, text }); } } catch (Exception error) { DisableAnnouncements(error); } } private void DisableAnnouncements(Exception error) { _instance = null; ((BaseUnityPlugin)this).Logger.LogError((object)("Bedtime could not initialize or announce bed states and has stopped announcements. " + $"Vanilla sleeping and world data are unchanged. Check mod/game compatibility and restart the server. {error}")); } } internal sealed class ReplayRequest { private double _nextAllowedAt; public static bool Matches(string text) { string text2 = text.Trim(); if (text2.Length < 3) { return false; } string text3 = text2; foreach (char c in text3) { if ((c != 'Z' && c != 'z') || 1 == 0) { return false; } } return true; } public bool TryAccept(double now) { if (now < _nextAllowedAt) { return false; } _nextAllowedAt = now + 5.0; return true; } } }