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 Sono v1.0.0
Sono.dll
Decompiled 3 days agousing System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("0.0.0.0")] namespace Sono; internal sealed class ServerRules { internal bool Enabled; internal bool NightRequired; internal bool DelayEnabled; internal double DelaySeconds; internal bool BedPlayersOnly; internal bool PermissionAllowed; internal double AfkMinutes; internal bool CapSpeed; internal double MaxSpeed; internal bool TimedEffects; internal static ServerRules Defaults() { ServerRules serverRules = new ServerRules(); serverRules.Enabled = true; serverRules.NightRequired = true; serverRules.DelayEnabled = false; serverRules.DelaySeconds = 10.0; serverRules.BedPlayersOnly = true; serverRules.PermissionAllowed = true; serverRules.AfkMinutes = 1.0; serverRules.CapSpeed = true; serverRules.MaxSpeed = 60.0; serverRules.TimedEffects = true; return serverRules; } internal string Serialize() { string[] value = new string[11] { "1", B(Enabled), B(NightRequired), B(DelayEnabled), D(DelaySeconds), B(BedPlayersOnly), B(PermissionAllowed), D(AfkMinutes), B(CapSpeed), D(MaxSpeed), B(TimedEffects) }; return string.Join("|", value); } internal static bool TryDeserialize(string payload, out ServerRules rules) { rules = null; if (string.IsNullOrEmpty(payload)) { return false; } string[] array = payload.Split('|'); if (array.Length != 11 || array[0] != "1") { return false; } if (!bool.TryParse(array[1], out var result) || !bool.TryParse(array[2], out var result2) || !bool.TryParse(array[3], out var result3) || !TryDouble(array[4], out var value) || !bool.TryParse(array[5], out var result4) || !bool.TryParse(array[6], out var result5) || !TryDouble(array[7], out var value2) || !bool.TryParse(array[8], out var result6) || !TryDouble(array[9], out var value3) || !bool.TryParse(array[10], out var result7)) { return false; } rules = new ServerRules { Enabled = result, NightRequired = result2, DelayEnabled = result3, DelaySeconds = Math.Max(0.0, Math.Min(120.0, value)), BedPlayersOnly = result4, PermissionAllowed = result5, AfkMinutes = Math.Max(0.0, Math.Min(60.0, value2)), CapSpeed = result6, MaxSpeed = Math.Max(1.0, Math.Min(240.0, value3)), TimedEffects = result7 }; return true; } internal static string B(bool value) { if (!value) { return "false"; } return "true"; } internal static string D(double value) { return value.ToString("R", CultureInfo.InvariantCulture); } internal static bool TryDouble(string text, out double value) { return double.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out value); } } internal struct SleeperState { internal long Owner; internal bool InBed; internal string Name; internal bool IgnoresSleep; internal SleeperState(long owner, bool inBed, string name, bool ignoresSleep) { Owner = owner; InBed = inBed; Name = name; IgnoresSleep = ignoresSleep; } } internal static class SleepCore { internal const double VanillaSleepDelay = 10.0; internal const int MaxSubsteps = 240; internal static bool EveryoneReady(IList<SleeperState> players, bool permissionAllowed, IDictionary<long, bool> permits, List<long> blockers, List<string> sleepers) { blockers.Clear(); sleepers.Clear(); for (int i = 0; i < players.Count; i++) { SleeperState sleeperState = players[i]; bool value; if (sleeperState.InBed) { sleepers.Add(sleeperState.Name); } else if (!sleeperState.IgnoresSleep && (!permissionAllowed || !permits.TryGetValue(sleeperState.Owner, out value) || !value)) { blockers.Add(sleeperState.Owner); } } if (sleepers.Count > 0) { return blockers.Count == 0; } return false; } internal static double CountdownStartValue(double now, ServerRules rules) { double num = (rules.DelayEnabled ? rules.DelaySeconds : 0.0); return now - (10.0 - num); } internal static bool IsAfk(double now, double lastActivity, double afkMinutes) { if (afkMinutes > 0.0) { return now - lastActivity >= afkMinutes * 60.0; } return false; } internal static double CappedSkipSpeed(double vanillaSpeed, ServerRules rules) { if (!rules.Enabled || !rules.CapSpeed) { return vanillaSpeed; } return Math.Max(1.0, Math.Min(vanillaSpeed, rules.MaxSpeed)); } internal static float EffectMultiplier(ServerRules rules, bool skipActive, double skipSpeed, double skipEnd, double now) { if (!rules.Enabled || !rules.TimedEffects || !skipActive || now >= skipEnd) { return 1f; } double val = (rules.CapSpeed ? rules.MaxSpeed : skipSpeed); return (float)(1.0 + Math.Max(0.0, Math.Min(skipSpeed, val))); } internal static void RunSubsteps(float dt, float multiplier, Action<float> step) { float num = dt * multiplier; int num2 = Math.Min(240, Math.Max(1, (int)Math.Ceiling(multiplier))); float obj = num / (float)num2; for (int i = 0; i < num2; i++) { step(obj); } } } internal sealed class SleepGate { private bool _wasEligible; internal void Reset() { _wasEligible = false; } internal int Step(bool eligible) { int result = 0; if (eligible && !_wasEligible) { result = 1; } else if (!eligible && _wasEligible) { result = -1; } _wasEligible = eligible; return result; } } internal sealed class PermissionState { internal bool Manual; private double _lastActivity; private bool _sent; private bool _sentValue; internal PermissionState(double now) { _lastActivity = now; } internal void Activity(double now) { _lastActivity = now; } internal void Forget() { _sent = false; } internal bool Effective(ServerRules rules, double now) { if (rules.Enabled && rules.PermissionAllowed) { if (!Manual) { return SleepCore.IsAfk(now, _lastActivity, rules.AfkMinutes); } return true; } return false; } internal bool NeedsSend(ServerRules rules, double now, out bool value) { value = Effective(rules, now); if (_sent && value == _sentValue) { return false; } _sent = true; _sentValue = value; return true; } } [BepInPlugin("razaotium.sono", "Sono", "1.0.0")] public sealed class SonoPlugin : BaseUnityPlugin { [HarmonyPatch(typeof(Game), "UpdateSleeping")] private static class UpdateSleepingPatch { [HarmonyPriority(800)] private static bool Prefix(Game __instance) { ServerRules rules = Rules; if (!rules.Enabled || SleepingField == null || LastSleepTimeField == null) { return true; } if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || (Object)(object)EnvMan.instance == (Object)null) { return false; } double timeSeconds = ZNet.instance.GetTimeSeconds(); if ((bool)SleepingField.GetValue(__instance)) { if (EnvMan.instance.IsTimeSkipping() || CinematicsManager.IsPlaying()) { return false; } LastSleepTimeField.SetValue(__instance, timeSeconds); SleepingField.SetValue(__instance, false); ZRoutedRpc.instance.InvokeRoutedRPC(0L, "SleepStop", new object[0]); return false; } if (EnvMan.instance.IsTimeSkipping()) { return false; } string text = WhyNotSleeping(rules); bool flag = text.Length == 0; if (text != _lastReason) { if (text.Length > 0 && SleeperNames.Count > 0) { Log.LogInfo((object)("Not sleeping yet: " + text + ".")); } _lastReason = ((SleeperNames.Count > 0) ? text : ""); } int num = Gate.Step(flag); if (num > 0) { LastSleepTimeField.SetValue(__instance, SleepCore.CountdownStartValue(timeSeconds, rules)); Log.LogInfo((object)("Everyone is ready: " + SleeperNames.Count + "/" + Players.Count + " in bed.")); } else if (num < 0) { Log.LogInfo((object)"Sleep cancelled: conditions no longer met."); } if (!flag) { return false; } if (timeSeconds - (double)LastSleepTimeField.GetValue(__instance) < 10.0) { return false; } EnvMan.instance.SkipToMorning(); SleepingField.SetValue(__instance, true); ZRoutedRpc.instance.InvokeRoutedRPC(0L, "SleepStart", new object[0]); return false; } } [HarmonyPatch(typeof(Game), "SleepStart")] private static class SleepStartPatch { [HarmonyPriority(800)] private static bool Prefix() { Gate.Reset(); ServerRules rules = Rules; if (!rules.Enabled || !rules.BedPlayersOnly) { return true; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null && ((Character)localPlayer).InBed()) { localPlayer.SetSleeping(true); } return false; } } [HarmonyPatch(typeof(Game), "SleepStop")] private static class SleepStopPatch { [HarmonyPriority(800)] private static void Prefix() { _skipActive = false; } } [HarmonyPatch(typeof(EnvMan), "SkipToMorning")] private static class SkipToMorningPatch { private static void Postfix(EnvMan __instance) { if (!(TimeSkipSpeedField == null) && !(SkipToTimeField == null)) { double num = (double)TimeSkipSpeedField.GetValue(__instance); double num2 = SleepCore.CappedSkipSpeed(num, Rules); if (num2 != num) { TimeSkipSpeedField.SetValue(__instance, num2); } Log.LogInfo((object)("Skipping to morning at " + num2.ToString("0.##") + "x.")); _skipActive = true; _skipSpeed = num2; _skipEnd = (double)SkipToTimeField.GetValue(__instance); BroadcastSkipState(0L); } } } [HarmonyPatch(typeof(SEMan), "Update")] private static class StatusEffectTimePatch { private static bool _inSubstep; private static bool Prefix(SEMan __instance, ZDO zdo, float dt) { if (_inSubstep) { return true; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || !object.ReferenceEquals(__instance, ((Character)localPlayer).GetSEMan()) || (Object)(object)ZNet.instance == (Object)null) { return true; } float num = SleepCore.EffectMultiplier(Rules, _skipActive, _skipSpeed, _skipEnd, ZNet.instance.GetTimeSeconds()); if (num <= 1f) { return true; } _inSubstep = true; try { SleepCore.RunSubsteps(dt, num, delegate(float step) { __instance.Update(zdo, step); }); } finally { _inSubstep = false; } return false; } } public const string PluginGuid = "razaotium.sono"; public const string PluginName = "Sono"; public const string PluginVersion = "1.0.0"; private const string PermitRpc = "Sono_SetPermit"; private const string RulesRequestRpc = "Sono_RequestRules"; private const string RulesSyncRpc = "Sono_SyncRules"; private const string SkipStateRpc = "Sono_SkipState"; private const float RulesRequestInterval = 3f; private static readonly Dictionary<long, bool> PermittedByPeer = new Dictionary<long, bool>(); private static readonly List<SleeperState> Players = new List<SleeperState>(); private static readonly List<long> Blockers = new List<long>(); private static readonly List<string> SleeperNames = new List<string>(); private static readonly SleepGate Gate = new SleepGate(); private static readonly int GhostIgnoreSleepHash = "DEV_GhostIgnoreSleep".GetHashCode(); private static string _lastReason = ""; private static readonly FieldInfo LastSleepTimeField = AccessTools.Field(typeof(Game), "m_lastSleepTime"); private static readonly FieldInfo SleepingField = AccessTools.Field(typeof(Game), "m_sleeping"); private static readonly FieldInfo TimeSkipSpeedField = AccessTools.Field(typeof(EnvMan), "m_timeSkipSpeed"); private static readonly FieldInfo SkipToTimeField = AccessTools.Field(typeof(EnvMan), "m_skipToTime"); private static readonly MethodInfo GetServerPeerIdMethod = AccessTools.Method(typeof(ZRoutedRpc), "GetServerPeerID", (Type[])null, (Type[])null); internal static ManualLogSource Log; internal static ConfigEntry<bool> ModEnabled; internal static ConfigEntry<bool> RequireNight; internal static ConfigEntry<bool> UseSleepDelay; internal static ConfigEntry<double> SleepDelaySeconds; internal static ConfigEntry<bool> OnlyBedPlayersSleep; internal static ConfigEntry<bool> AllowPermission; internal static ConfigEntry<double> AfkMinutes; internal static ConfigEntry<KeyCode> ToggleKey; internal static ConfigEntry<bool> CapSkipSpeed; internal static ConfigEntry<double> MaximumSkipSpeed; internal static ConfigEntry<bool> AccelerateStatusEffects; private static readonly ServerRules DefaultRules = ServerRules.Defaults(); private static ServerRules _rules = ServerRules.Defaults(); private static bool _receivedServerRules; private static bool _skipActive; private static double _skipSpeed = 1.0; private static double _skipEnd; private Harmony _harmony; private float _nextRulesRequest; private ZRoutedRpc _registeredRpc; private FileSystemWatcher _configWatcher; private volatile bool _configReloadRequested; private PermissionState _permission; private Vector3 _lastMousePosition; private static ServerRules Rules { get { if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { return _rules; } if (!_receivedServerRules) { return DefaultRules; } return _rules; } } private void Awake() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; BindConfiguration(); ReadRulesFromConfiguration(); SubscribeToRuleChanges(); StartConfigWatcher(); _permission = new PermissionState(Time.unscaledTime); _harmony = new Harmony("razaotium.sono"); _harmony.PatchAll(typeof(SonoPlugin).Assembly); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Sono 1.0.0 loaded; waiting for the server rules."); } private void BindConfiguration() { //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Expected O, but got Unknown //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Expected O, but got Unknown ModEnabled = BindServer("1 - General", "Enabled", value: true, "Turns every Sono change on or off. False restores vanilla sleep. Editing the server CFG while it runs applies to everyone immediately."); RequireNight = BindServer("2 - Starting Sleep", "RequireNight", value: true, "Only allows sleep after nightfall, when the evening music starts. Vanilla also allows the afternoon."); UseSleepDelay = BindServer("2 - Starting Sleep", "UseSleepDelay", value: false, "Waits SleepDelaySeconds before skipping to morning. Off by default: like vanilla, the night skips as soon as everyone is ready."); SleepDelaySeconds = ((BaseUnityPlugin)this).Config.Bind<double>("2 - Starting Sleep", "SleepDelaySeconds", 10.0, new ConfigDescription("Seconds between the conditions being met and the skip to morning. Vanilla has no such wait: sleep starts almost as soon as everyone lies down. 0 matches vanilla. [SERVER RULE]", (AcceptableValueBase)(object)new AcceptableValueRange<double>(0.0, 120.0), new object[0])); OnlyBedPlayersSleep = BindServer("3 - Experience", "OnlyPlayersInBedSleep", value: true, "Only players in bed get the sleep screen, text, dream and Rested bonus. False uses vanilla SleepStart for everyone."); AllowPermission = BindServer("4 - Permission", "AllowPermission", value: true, "Like vanilla, the night only skips when every player is in bed, but a player can press the key to let the others sleep without them. False requires everyone in bed, exactly like vanilla."); AfkMinutes = ((BaseUnityPlugin)this).Config.Bind<double>("4 - Permission", "AfkMinutes", 1.0, new ConfigDescription("A player with no mouse or keyboard input for this many minutes counts as letting the others sleep, until they move again. 0 turns it off. [SERVER RULE]", (AcceptableValueBase)(object)new AcceptableValueRange<double>(0.0, 60.0), new object[0])); ToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("4 - Permission", "TogglePermissionKey", (KeyCode)288, "Local client setting, not enforced by the server. Toggles whether the others may sleep without you."); CapSkipSpeed = BindServer("5 - Time", "CapSkipSpeed", value: true, "Caps the skip-to-morning speed at MaximumSkipSpeed. Vanilla skips the rest of the night in 12 real seconds at a constant speed and stops at dawn."); MaximumSkipSpeed = ((BaseUnityPlugin)this).Config.Bind<double>("5 - Time", "MaximumSkipSpeed", 60.0, new ConfigDescription("Maximum world seconds per real second when CapSkipSpeed=true. Night is 30% of the day, so from nightfall vanilla skips at about 45x with a 30-minute day; only a lower cap makes the skip longer. [SERVER RULE]", (AcceptableValueBase)(object)new AcceptableValueRange<double>(1.0, 240.0), new object[0])); AccelerateStatusEffects = BindServer("6 - Consequences", "AccelerateStatusEffects", value: true, "Every player's buffs, debuffs and their ticks run down with the skipped night, asleep or awake. Rested is granted on waking, so it is unaffected. Food is not touched."); } private ConfigEntry<bool> BindServer(string section, string key, bool value, string description) { return ((BaseUnityPlugin)this).Config.Bind<bool>(section, key, value, description + " [SERVER RULE]"); } private void SubscribeToRuleChanges() { ((BaseUnityPlugin)this).Config.SettingChanged += OnServerRuleChanged; ((BaseUnityPlugin)this).Config.ConfigReloaded += OnServerConfigReloaded; } private void StartConfigWatcher() { string configFilePath = ((BaseUnityPlugin)this).Config.ConfigFilePath; string directoryName = Path.GetDirectoryName(configFilePath); string fileName = Path.GetFileName(configFilePath); if (!string.IsNullOrEmpty(directoryName) && !string.IsNullOrEmpty(fileName)) { _configWatcher = new FileSystemWatcher(directoryName, fileName); _configWatcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite; _configWatcher.Changed += OnConfigFileChanged; _configWatcher.Created += OnConfigFileChanged; _configWatcher.Renamed += OnConfigFileRenamed; _configWatcher.EnableRaisingEvents = true; } } private void OnConfigFileChanged(object sender, FileSystemEventArgs args) { _configReloadRequested = true; } private void OnConfigFileRenamed(object sender, RenamedEventArgs args) { _configReloadRequested = true; } private void OnServerRuleChanged(object sender, SettingChangedEventArgs args) { ApplyAndBroadcastServerRules(); } private void OnServerConfigReloaded(object sender, EventArgs args) { ApplyAndBroadcastServerRules(); } private static void ApplyAndBroadcastServerRules() { if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer()) { ReadRulesFromConfiguration(); BroadcastRules(); } } private static void ReadRulesFromConfiguration() { ServerRules serverRules = new ServerRules(); serverRules.Enabled = ModEnabled.Value; serverRules.NightRequired = RequireNight.Value; serverRules.DelayEnabled = UseSleepDelay.Value; serverRules.DelaySeconds = SleepDelaySeconds.Value; serverRules.BedPlayersOnly = OnlyBedPlayersSleep.Value; serverRules.PermissionAllowed = AllowPermission.Value; serverRules.AfkMinutes = AfkMinutes.Value; serverRules.CapSpeed = CapSkipSpeed.Value; serverRules.MaxSpeed = MaximumSkipSpeed.Value; serverRules.TimedEffects = AccelerateStatusEffects.Value; _rules = serverRules; _receivedServerRules = true; } private void OnDestroy() { if (_configWatcher != null) { _configWatcher.EnableRaisingEvents = false; _configWatcher.Dispose(); _configWatcher = null; } if (_harmony != null) { _harmony.UnpatchSelf(); } } private void Update() { //IL_009c: Unknown result type (might be due to invalid IL or missing references) RegisterRpcIfNeeded(); if (_configReloadRequested) { _configReloadRequested = false; if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { try { ((BaseUnityPlugin)this).Config.Reload(); Log.LogInfo((object)"CFG reloaded live; rules sent to clients."); } catch (Exception ex) { Log.LogWarning((object)("Failed to reload CFG live: " + ex.Message)); } } } UpdateServerSkipState(); RequestRulesWhenConnected(); if (!((Object)(object)Player.m_localPlayer == (Object)null)) { TrackActivity(); ServerRules rules = Rules; if (ToggleKey != null && Input.GetKeyDown(ToggleKey.Value)) { TogglePermission(rules); } SyncPermission(rules); } } private void TrackActivity() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_000f: 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_0042: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) Vector3 mousePosition = Input.mousePosition; if (!Input.anyKey && !(mousePosition != _lastMousePosition)) { Vector2 mouseScrollDelta = Input.mouseScrollDelta; if (!(((Vector2)(ref mouseScrollDelta)).sqrMagnitude > 0f)) { goto IL_0040; } } _permission.Activity(Time.unscaledTime); goto IL_0040; IL_0040: _lastMousePosition = mousePosition; } private void TogglePermission(ServerRules rules) { //IL_007f: Unknown result type (might be due to invalid IL or missing references) if (!rules.Enabled || !rules.PermissionAllowed) { ((Character)Player.m_localPlayer).Message((MessageType)2, "The server requires everyone in bed; there is nothing to toggle.", 0, (Sprite)null, false); return; } _permission.Manual = !_permission.Manual; string text = (_permission.Manual ? "the others MAY sleep without you" : "the others must WAIT for you"); ((Character)Player.m_localPlayer).Message((MessageType)2, string.Concat("Sleep: ", text, ". Press ", ToggleKey.Value, " to change."), 0, (Sprite)null, false); } private void SyncPermission(ServerRules rules) { if (ZRoutedRpc.instance != null && !((Object)(object)ZNet.instance == (Object)null) && (ZNet.instance.IsServer() || _receivedServerRules) && _permission.NeedsSend(rules, Time.unscaledTime, out var value)) { if (ZNet.instance.IsServer()) { SetPermitted(ZNet.GetUID(), value); return; } ZRoutedRpc.instance.InvokeRoutedRPC(0L, "Sono_SetPermit", new object[1] { value }); } } private void RegisterRpcIfNeeded() { ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null && !object.ReferenceEquals(instance, _registeredRpc)) { instance.Register<bool>("Sono_SetPermit", (Action<long, bool>)RpcSetPermit); instance.Register("Sono_RequestRules", (Action<long>)RpcRequestRules); instance.Register<string>("Sono_SyncRules", (Action<long, string>)RpcReceiveRules); instance.Register<string>("Sono_SkipState", (Action<long, string>)RpcReceiveSkipState); _registeredRpc = instance; _skipActive = false; _permission.Forget(); PermittedByPeer.Clear(); if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { ReadRulesFromConfiguration(); BroadcastRules(); } else { _receivedServerRules = false; _nextRulesRequest = 0f; } } } private void RequestRulesWhenConnected() { if (!_receivedServerRules && ZRoutedRpc.instance != null && !((Object)(object)ZNet.instance == (Object)null) && !ZNet.instance.IsServer()) { ZNetPeer serverPeer = ZNet.instance.GetServerPeer(); if (serverPeer != null && serverPeer.IsReady() && !(Time.unscaledTime < _nextRulesRequest)) { _nextRulesRequest = Time.unscaledTime + 3f; ZRoutedRpc.instance.InvokeRoutedRPC(0L, "Sono_RequestRules", new object[0]); } } } private static void UpdateServerSkipState() { if (_skipActive && !((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer() && (!((Object)(object)EnvMan.instance != (Object)null) || !EnvMan.instance.IsTimeSkipping())) { _skipActive = false; BroadcastSkipState(0L); } } private static void RpcSetPermit(long sender, bool permit) { if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer()) { SetPermitted(sender, permit); } } private static void SetPermitted(long peerId, bool permit) { PermittedByPeer[peerId] = permit; Log.LogInfo((object)("Sleep permission from " + peerId + ": " + (permit ? "may sleep without them" : "wait for them"))); } private static void RpcRequestRules(long sender) { if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer() && ZRoutedRpc.instance != null) { ZRoutedRpc.instance.InvokeRoutedRPC(sender, "Sono_SyncRules", new object[1] { _rules.Serialize() }); if (_skipActive) { BroadcastSkipState(sender); } } } private static void BroadcastSkipState(long target) { if (ZRoutedRpc.instance != null && !((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer()) { string text = (_skipActive ? "1" : "0") + "|" + ServerRules.D(_skipSpeed) + "|" + ServerRules.D(_skipEnd); ZRoutedRpc.instance.InvokeRoutedRPC(target, "Sono_SkipState", new object[1] { text }); } } private static bool IsFromServer(long sender) { long serverPeerId = GetServerPeerId(); if (serverPeerId != 0) { return sender == serverPeerId; } return true; } private static void RpcReceiveSkipState(long sender, string payload) { if (!((Object)(object)ZNet.instance == (Object)null) && !ZNet.instance.IsServer() && IsFromServer(sender)) { string[] array = (payload ?? "").Split('|'); if (array.Length != 3 || !ServerRules.TryDouble(array[1], out var value) || !ServerRules.TryDouble(array[2], out var value2)) { Log.LogWarning((object)"Invalid time-skip packet; ignored."); return; } _skipActive = array[0] == "1"; _skipSpeed = Math.Max(1.0, Math.Min(240.0, value)); _skipEnd = value2; } } private static void BroadcastRules() { if (ZRoutedRpc.instance != null && !((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer()) { ZRoutedRpc.instance.InvokeRoutedRPC(0L, "Sono_SyncRules", new object[1] { _rules.Serialize() }); } } private static void RpcReceiveRules(long sender, string payload) { if ((Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer()) { return; } if (!IsFromServer(sender)) { Log.LogWarning((object)"Rules packet ignored: sender is not the server."); return; } if (!ServerRules.TryDeserialize(payload, out var rules)) { Log.LogWarning((object)"Invalid rules packet from the server; keeping the previous rules."); return; } bool flag = _receivedServerRules && _rules.Enabled != rules.Enabled; _rules = rules; _receivedServerRules = true; if (flag && (Object)(object)Player.m_localPlayer != (Object)null) { ((Character)Player.m_localPlayer).Message((MessageType)2, "Sono " + (rules.Enabled ? "ENABLED" : "DISABLED") + " for the whole server.", 0, (Sprite)null, false); } Log.LogInfo((object)"Sono rules received from the server."); } private static long GetServerPeerId() { if (ZRoutedRpc.instance == null || GetServerPeerIdMethod == null) { return 0L; } return (long)GetServerPeerIdMethod.Invoke(ZRoutedRpc.instance, null); } private static string WhyNotSleeping(ServerRules rules) { Players.Clear(); List<ZDO> allCharacterZDOS = ZNet.instance.GetAllCharacterZDOS(); for (int i = 0; i < allCharacterZDOS.Count; i++) { ZDO val = allCharacterZDOS[i]; Players.Add(new SleeperState(val.GetOwner(), val.GetBool(ZDOVars.s_inBed, false), val.GetString(ZDOVars.s_playerName, "?"), val.GetBool(GhostIgnoreSleepHash, false))); } bool flag = SleepCore.EveryoneReady(Players, rules.PermissionAllowed, PermittedByPeer, Blockers, SleeperNames); bool num; if (!rules.NightRequired) { if (EnvMan.IsAfternoon()) { goto IL_00b7; } num = !EnvMan.IsNight(); } else { num = !EnvMan.IsNight(); } if (num) { return "not night yet"; } goto IL_00b7; IL_00b7: if (!flag) { if (SleeperNames.Count != 0) { return Blockers.Count + " player(s) awake without permission"; } return "nobody in bed"; } return ""; } }