using System; using System.Linq; using System.Collections.Generic; using Newtonsoft.Json; #region Changelogs and ToDo /********************************************************************** * * 1.0.0 : - Initial release * 1.0.1 : - Coding Optimisations * - Added messaging on refunding items * 1.0.2 : - More Optimisations added/changed * 1.0.3 : - Fixed switched counts * - Added Prefix and Chaticon to cfg * 1.0.4 : - Possible Nre Fix * - Added correct ResourceId * 1.0.5 : - Excempt of renaming softcore respawn bags * 1.0.6 : - Added permission NOCD_Perm * **********************************************************************/ #endregion namespace Oxide.Plugins { [Info("Better Beds", "Krungh Crow", "1.0.7", ResourceId = 531)] [Description("Edit various settings on sleepingbags and beds")] class BetterBeds : RustPlugin { #region Variables const string RestrictDef_Perm = "betterbeds.restrictdefault"; const string RestrictVip_Perm = "betterbeds.restrictvip"; const string RenameBlock_Perm = "betterbeds.renameblock"; const string Chat_Perm = "betterbeds.chat"; const string Admin_Perm = "betterbeds.admin"; const string NOCD_Perm = "betterbeds.nocd"; const string DenyPickup_Perm = "betterbeds.denypickup"; ulong chaticon = 0; string prefix; bool Debug = false; Dictionary BagIDs = new Dictionary(); Dictionary BedIDs = new Dictionary(); private int BagCount(BasePlayer player) => BagIDs.Where(x => x.Value == player.userID).Count(); private int BedCount(BasePlayer player) => BedIDs.Where(x => x.Value == player.userID).Count(); #endregion #region Configuration void Init() { if (!LoadConfigVariables()) { Puts("Config file issue detected. Please delete file, or check syntax and fix."); return; } permission.RegisterPermission(Admin_Perm, this); permission.RegisterPermission(NOCD_Perm, this); permission.RegisterPermission(Chat_Perm, this); permission.RegisterPermission(RestrictDef_Perm, this); permission.RegisterPermission(RestrictVip_Perm, this); permission.RegisterPermission(RenameBlock_Perm, this); permission.RegisterPermission(DenyPickup_Perm, this); Debug = configData.PlugCFG.Debug; prefix = configData.PlugCFG.Prefix; chaticon = configData.PlugCFG.Chaticon; if (Debug) Puts($"[Debug] trigger for Debug is true"); } private ConfigData configData; class ConfigData { [JsonProperty(PropertyName = "Settings Plugin")] public SettingsPlugin PlugCFG = new SettingsPlugin(); [JsonProperty(PropertyName = "Settings Global")] public SettingsGlobal Global = new SettingsGlobal(); [JsonProperty(PropertyName = "Settings Bags")] public SettingsBags SpawnBags = new SettingsBags(); [JsonProperty(PropertyName = "Settings Beds")] public SettingsBeds SpawnBeds = new SettingsBeds(); } class SettingsPlugin { [JsonProperty(PropertyName = "Debug")] public bool Debug = false; [JsonProperty(PropertyName = "Chat Steam64ID")] public ulong Chaticon = 0; [JsonProperty(PropertyName = "Chat Prefix")] public string Prefix = "[Better Beds] "; } class SettingsGlobal { [JsonProperty(PropertyName = "Bag cooldown")] public float BagCooldown = 30f; [JsonProperty(PropertyName = "Bed cooldown")] public float BedCooldown = 20f; [JsonProperty(PropertyName = "Only 1x rename per placement")] public bool OneRename = false; [JsonProperty(PropertyName = "NO bed/sleepingbag cooldown")] public bool NoBedCooldown = false; } class SettingsBags { [JsonProperty(PropertyName = "Refund Sleepingbags")] public bool RefundBags = true; [JsonProperty(PropertyName = "Max placements Default")] public int LimitBagsAmountDef = 5; [JsonProperty(PropertyName = "Max placements Vip")] public int LimitBagsAmountVip = 10; } class SettingsBeds { [JsonProperty(PropertyName = "Refund Beds")] public bool RefundBeds = true; [JsonProperty(PropertyName = "Max placements Default")] public int LimitBedsAmountDef = 1; [JsonProperty(PropertyName = "Max placements Vip")] public int LimitBedsAmountVip = 3; } private bool LoadConfigVariables() { try { configData = Config.ReadObject(); } catch { return false; } SaveConf(); return true; } protected override void LoadDefaultConfig() { Puts("Fresh install detected Creating a new config file."); configData = new ConfigData(); SaveConf(); } void SaveConf() => Config.WriteObject(configData, true); #endregion #region LanguageAPI protected override void LoadDefaultMessages() { lang.RegisterMessages(new Dictionary { ["InvalidInput"] = "Please enter a valid command!", ["BagText"] = "Welcome to our server", ["Version"] = "Version : V", ["LimitBags"] = "You have been limited to {0} sleepingbag(s)", ["LimitBeds"] = "You have been limited to {0} bed(s)", ["MaxLimitDefault"] = "You allready placed the limit of {0} for a player", ["MaxLimitVip"] = "You allready placed the limit of {0} for Vips", ["LimitHeader"] = "Your Restrictions and Placements :", ["Info"] = "\nAvailable Commands\n/bag info : Shows info on version/author and commands", ["InfoMyLimit"] = "\n/bag mylimit : Lists your restriction heights and placements", ["InventoryFull"] = "You had no inventory space no item refunded ! ", ["InventoryNotFull"] = "Your item has been refunded ! ", ["NoPermission"] = "You do not have permission to use that command!", ["RenameBlock"] = "Renaming is blocked on this server", ["RenameBlock2nd"] = "Max 1 rename allowed on this server ", ["BagsUsed"] = "You placed {0}", ["BagsLeft"] = "You have {0} placement(s) left", }, this); } #endregion #region Commands [ChatCommand("Bag")] private void cmdBags(BasePlayer player, string command, string[] args) { if (!permission.UserHasPermission(player.UserIDString, Chat_Perm)) { Player.Message(player, prefix + string.Format(msg("NoPermission", player.UserIDString)), chaticon); if (Debug) Puts($"[Debug] {player} had no permission for using Commands"); return; } if (args.Length == 0) { Player.Message(player, prefix + string.Format(msg("InvalidInput", player.UserIDString)), chaticon); } else { if (args[0].ToLower() == "info") { Player.Message(player, prefix + string.Format(msg("Version", player.UserIDString)) + this.Version.ToString() + " By : " + this.Author.ToString() + msg("Info") + msg("InfoMyLimit") , chaticon); return; } if (args[0].ToLower() == "mylimit") { if (permission.UserHasPermission(player.UserIDString, Chat_Perm)) { int LimitAmountBag = 0; int LimitAmountBed = 0; if (permission.UserHasPermission(player.UserIDString, RestrictVip_Perm)) { LimitAmountBag = configData.SpawnBags.LimitBagsAmountVip; LimitAmountBed = configData.SpawnBeds.LimitBedsAmountVip; } else if (permission.UserHasPermission(player.UserIDString, RestrictDef_Perm)) { LimitAmountBag = configData.SpawnBags.LimitBagsAmountDef; LimitAmountBed = configData.SpawnBeds.LimitBedsAmountDef; } Player.Message(player, prefix + "" + string.Format(msg("LimitHeader", player.UserIDString)) + "\n" + string.Format(msg("LimitBags", player.UserIDString), LimitAmountBag.ToString()) + " " + string.Format(msg("BagsUsed", player.UserIDString), BagCount(player).ToString() + "\n" + string.Format(msg("LimitBeds", player.UserIDString), LimitAmountBed.ToString()) + " " + string.Format(msg("BagsUsed", player.UserIDString), BedCount(player).ToString() + "\n" , chaticon))); return; } else { Player.Message(player, prefix + string.Format(msg("NoPermission", player.UserIDString)), chaticon); } } else { Player.Message(player, prefix + string.Format(msg("InvalidInput", player.UserIDString)), chaticon); } } } #endregion #region Hooks void OnServerInitialized() { foreach (var bag in BaseNetworkable.serverEntities.OfType()) { if (BedIDs.ContainsKey(bag.net.ID.Value) || BagIDs.ContainsKey(bag.net.ID.Value)) return; if (bag.ShortPrefabName.Contains("bed")) BedIDs.Add(bag.net.ID.Value, bag.OwnerID); else BagIDs.Add(bag.net.ID.Value, bag.OwnerID); } } void OnEntityKill(SleepingBag bag) { if (bag.ShortPrefabName.Contains("bed")) { if (BedIDs.ContainsKey(bag.net.ID.Value)) BedIDs.Remove(bag.net.ID.Value); } else if (BagIDs.ContainsKey(bag.net.ID.Value)) BagIDs.Remove(bag.net.ID.Value); } private object CanRenameBed(BasePlayer player, SleepingBag bag) { if (bag == null || bag.OwnerID == 0 || player == null) return true; //// ulong can't ever be null. Did you mean 0? if (permission.UserHasPermission(player.UserIDString, Admin_Perm)) return null; if (bag.niceName != (lang.GetMessage("BagText", this)) && configData.Global.OneRename) { Player.Message(player, prefix + string.Format(msg("RenameBlock2nd", player.UserIDString)), chaticon); if (Debug) Puts($"[Debug] {player} attempted to rename a bag/bed but it is allready renamed once"); return true; } if (bag.OwnerID != player.userID || permission.UserHasPermission(player.UserIDString, RenameBlock_Perm)) ////Comparing ownerID.ToString and userIDString...No need for 2X string cast...They're both ulong. { Player.Message(player, prefix + string.Format(msg("RenameBlock", player.UserIDString)), chaticon); if (Debug) Puts($"[Debug] {player} attempted to rename a bag/bed but had no permission"); return true; } return null; } private void OnEntitySpawned(SleepingBag bag) { if (bag.ShortPrefabName.Contains("bed")) //// added condtiion here, so beds are one list, and bags are another. { if (!BedIDs.ContainsKey(bag.net.ID.Value)) BedIDs.Add(bag.net.ID.Value, bag.OwnerID); } else { if (!BagIDs.ContainsKey(bag.net.ID.Value)) BagIDs.Add(bag.net.ID.Value, bag.OwnerID); } if (bag.ShortPrefabName.Contains("sleepingbag") || bag.ShortPrefabName.Contains("beachtowel")) { if (Debug) Puts($"[Debug] A player placed a sleepingbag or beachtowel (pre count check)"); BasePlayer player = BasePlayer.FindByID(bag.OwnerID); if (player == null) return; if (player.IsSleeping() == true || player.IsConnected == false) return; if (Debug) Puts($"[Debug] sleep and offline check"); bool limited = true; if (permission.UserHasPermission(player.UserIDString, Admin_Perm) == true) { limited = false; if (Debug) Puts($"[Debug] bypass was triggered for sleepingbags and beachtowels"); } if (limited) { int limit = configData.SpawnBags.LimitBagsAmountDef; int count = new int(); count = BagCount(player); if (permission.UserHasPermission(player.UserIDString, RestrictVip_Perm) == true) { limit = configData.SpawnBags.LimitBagsAmountVip; } else if (permission.UserHasPermission(player.UserIDString, RestrictDef_Perm) == true) { limit = configData.SpawnBags.LimitBagsAmountDef; } if (Debug) Puts($"[Debug] bag count {count}"); if (count - limit > 1) PrintWarning($"Player {player.displayName} has too many Bags ! Denying placement"); if (count > limit) NextTick(() => { RefundBag(bag, player); return; }); else Player.Message(player, prefix + string.Format(msg("BagsLeft", player.UserIDString), (limit - count)), chaticon); } } if (bag.ShortPrefabName.Contains("bed")) { if (Debug) Puts($"[Debug] A player placed a bed (pre count check)"); BasePlayer player = BasePlayer.FindByID(bag.OwnerID); if (player == null) return; if (player.IsSleeping() == true || player.IsConnected == false) return; if (Debug) Puts($"[Debug] sleep and offline check"); bool limited = true; if (permission.UserHasPermission(player.UserIDString, Admin_Perm) == true) { limited = false; if (Debug) Puts($"[Debug] Bypass was triggered for beds"); } if (limited) { int limit = configData.SpawnBags.LimitBagsAmountDef; int count = new int(); count = BedCount(player); if (permission.UserHasPermission(player.UserIDString, RestrictVip_Perm) == true) { limit = configData.SpawnBeds.LimitBedsAmountVip; } else if (permission.UserHasPermission(player.UserIDString, RestrictDef_Perm) == true) { limit = configData.SpawnBeds.LimitBedsAmountDef; } if (Debug) Puts($"bag count {count}"); if (count - limit > 1) PrintWarning($"Player {player.displayName} has too many Beds ! denying placement"); if (count > limit) NextTick(() => { RefundBed(bag, player); return; }); else Player.Message(player, prefix + string.Format(msg("BagsLeft", player.UserIDString), (limit - count)), chaticon); } } if (bag.niceName == "Unnamed Bag") { bag.niceName = lang.GetMessage("BagText", this); } return; } private object CanPickupEntity(BasePlayer player, BaseEntity entity) { if (entity.ShortPrefabName.Contains("sleepingbag") || entity.ShortPrefabName.Contains("bed") || entity.ShortPrefabName.Contains("beachtowel")) { if (permission.UserHasPermission(player.UserIDString, Admin_Perm)) return true; if (permission.UserHasPermission(player.UserIDString, DenyPickup_Perm) ) { Player.Message(player, prefix + string.Format(msg("pickup is disabled", player.UserIDString)), chaticon); if (Debug) Puts($"[Debug] {player} attempted to pickup a bag/bed but this is disabled"); return false; } return true; } return null; } private void OnPlayerDeath(BasePlayer player, HitInfo info) { if (!player) return; if (player.IsSleeping() == true || player.IsConnected == false) return; BagCooldownSet(player); } #endregion #region Methods private void BagCooldownSet(BasePlayer player) { if (!player) return; if (player.IsSleeping() == true || player.IsConnected == false) return; SleepingBag[] bags = SleepingBag.FindForPlayer(player.userID, true); foreach (SleepingBag bag in bags) if (!configData.Global.NoBedCooldown) { if (bag.ShortPrefabName.Contains("bed")) { bag.secondsBetweenReuses = configData.Global.BedCooldown; } else if (bag.ShortPrefabName.Contains("beachtowel")) { bag.secondsBetweenReuses = configData.Global.BedCooldown; } else { bag.secondsBetweenReuses = configData.Global.BagCooldown; } if (Debug) Puts($"[Debug] Counted and checked a total of {bags.Count()} Bagspawnpoints for [{player.displayName}]"); } else if (configData.Global.NoBedCooldown || permission.UserHasPermission(player.UserIDString, Admin_Perm) || permission.UserHasPermission(player.UserIDString, NOCD_Perm)) { bag.secondsBetweenReuses = 0; } } void RefundBag(BaseEntity entity, BasePlayer player) { if (Debug) Puts($"[Debug] cancelling a sleepingbag placement"); if (permission.UserHasPermission(player.UserIDString, RestrictVip_Perm) == true) { Player.Message(player, prefix + string.Format(msg("MaxLimitVip", player.UserIDString), configData.SpawnBags.LimitBagsAmountVip), chaticon); } else if (permission.UserHasPermission(player.UserIDString, RestrictDef_Perm) == true) { Player.Message(player, prefix + string.Format(msg("MaxLimitDefault", player.UserIDString), configData.SpawnBags.LimitBagsAmountDef), chaticon); } entity.KillMessage(); if (configData.SpawnBags.RefundBags) { Int32 number = -1754948969; if (entity.ShortPrefabName.Contains("beachtowel")) number = -8312704; var itemtogive = ItemManager.CreateByItemID(number, 1); if (!player.inventory.GiveItem(itemtogive)) { if (Debug) Puts($"[Debug] Bag refund canceled no room in inventory"); Player.Message(player, prefix + string.Format(msg("InventoryFull", player.UserIDString)), chaticon); itemtogive.Remove(0f); //// Destroy item if give isn't possible ItemManager.DoRemoves(); //// } else { if (Debug) Puts($"[Debug] Bag refunded"); Player.Message(player, prefix + string.Format(msg("InventoryNotFull", player.UserIDString)), chaticon); } if (Debug) Puts($"[Debug] Bag refund = true"); } } void RefundBed(BaseEntity entity, BasePlayer player) { if (Debug) Puts($"[Debug] cancelling a bed placement"); if (permission.UserHasPermission(player.UserIDString, RestrictVip_Perm) == true) { Player.Message(player, prefix + string.Format(msg("MaxLimitVip", player.UserIDString), configData.SpawnBeds.LimitBedsAmountVip), chaticon); } else if (permission.UserHasPermission(player.UserIDString, RestrictDef_Perm) == true) { Player.Message(player, prefix + string.Format(msg("MaxLimitDefault", player.UserIDString), configData.SpawnBeds.LimitBedsAmountDef), chaticon); } entity.KillMessage(); if (configData.SpawnBeds.RefundBeds) { var itemtogive = ItemManager.CreateByItemID(-1273339005, 1);//bed if (!player.inventory.GiveItem(itemtogive)) { if (Debug) Puts($"[Debug] Bed refund canceled no room in inventory"); Player.Message(player, prefix + string.Format(msg("InventoryFull", player.UserIDString)), chaticon); itemtogive.Remove(0f); //// Destroy item if give isn't possible ItemManager.DoRemoves(); //// } else { if (Debug) Puts($"[Debug] Bed refunded"); Player.Message(player, prefix + string.Format(msg("InventoryNotFull", player.UserIDString)), chaticon); } if (Debug) Puts($"[Debug] Bed refund = true"); } } #endregion #region Message helper private string msg(string key, string id = null) => lang.GetMessage(key, this, id); #endregion } }