using System; using System.Collections.Generic; using Newtonsoft.Json; using Oxide.Core; using UnityEngine; namespace Oxide.Plugins; [Info("Sleeper Guard", "Michael Keulemans", "1.0.0")] [Description("Protects a sleeping player from all damage for a set number of minutes after they log off.")] public class SleeperGuard : RustPlugin { private ConfigData _config; private Dictionary _asleep; private readonly Dictionary _warned = new Dictionary(); private class ConfigData { [JsonProperty("Minutes of protection")] public float Minutes = 30f; [JsonProperty("Message to the attacker")] public string Message = "That sleeper is protected for another {minutes} minutes."; } protected override void LoadDefaultConfig() => _config = new ConfigData(); protected override void LoadConfig() { base.LoadConfig(); try { _config = Config.ReadObject() ?? new ConfigData(); } catch (Exception ex) { Debug.LogException(ex); _config = new ConfigData(); } } protected override void SaveConfig() => Config.WriteObject(_config, true); private void Init() { try { _asleep = Interface.Oxide.DataFileSystem.ReadObject>(Name) ?? new Dictionary(); } catch (Exception ex) { Debug.LogException(ex); _asleep = new Dictionary(); Save(); } } private void OnServerInitialized() { var kept = new Dictionary(); var changed = false; foreach (var sleeper in BasePlayer.sleepingPlayerList) { var id = (ulong)sleeper.userID; if (!id.IsSteamId()) continue; DateTime since; if (_asleep.TryGetValue(id, out since)) kept[id] = since; else { kept[id] = DateTime.UtcNow; changed = true; } } if (kept.Count != _asleep.Count) changed = true; _asleep = kept; if (changed) Save(); } private void OnPlayerDisconnected(BasePlayer player, string reason) { var id = (ulong)player.userID; _asleep[id] = DateTime.UtcNow; _warned.Remove(id); Save(); } private void OnPlayerSleepEnded(BasePlayer player) => Forget(player); private void OnPlayerDeath(BasePlayer player, HitInfo info) => Forget(player); private object OnEntityTakeDamage(BasePlayer player, HitInfo info) { if (!player.IsSleeping()) return null; DateTime since; if (!_asleep.TryGetValue((ulong)player.userID, out since)) return null; var left = _config.Minutes - (float)(DateTime.UtcNow - since).TotalMinutes; if (left <= 0f) return null; Warn(player, info.InitiatorPlayer, left); return true; } private void Warn(BasePlayer sleeper, BasePlayer attacker, float left) { if (attacker == null || attacker == sleeper || attacker.IsNpc) return; var id = (ulong)attacker.userID; float last; if (_warned.TryGetValue(id, out last) && Time.realtimeSinceStartup - last < 10f) return; _warned[id] = Time.realtimeSinceStartup; PrintToChat(attacker, _config.Message.Replace("{minutes}", Mathf.CeilToInt(left).ToString())); } private void Forget(BasePlayer player) { if (_asleep.Remove((ulong)player.userID)) Save(); } private void Save() => Interface.Oxide.DataFileSystem.WriteObject(Name, _asleep); }