Make the cleaning command "/sp cleardb" work through the console.
To automate the plugin with each wipe
Suggestion to improve
using System; using System.IO; using System.Collections.Generic; using Oxide.Core; using Oxide.Core.Plugins; using Oxide.Game.Rust.Cui; using UnityEngine; #region patches /* * 2.3.3 : Added Clans under same checks as Friends * : Added CanLootHackCrate * : Fix for timer */ #endregion namespace Oxide.Plugins { [Info("Start Protection", "Krungh Crow", "2.3.3")] [Description("Protects new players when they first connect after a server wipe")] public class StartProtection : RustPlugin { [PluginReference] Plugin Friends, ImageLibrary,Clans, Duelist, EventManager, NoEscape; class StoredData { public Dictionary<ulong, ProtectionInfo> Players = new Dictionary<ulong, ProtectionInfo>(); public StoredData() { } } class StoredPlayersData { public HashSet Players = new HashSet(); public StoredPlayersData() { } } class ProtectionInfo { public ulong UserId; public int TimeLeft; public bool Multiple; public int InitTimestamp; public ProtectionInfo() { } } Timer ProtectionTimer; StoredData storedData; StoredPlayersData storedPlayersData; static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); static readonly double MaxUnixSeconds = (DateTime.MaxValue - UnixEpoch).TotalSeconds; string nofight_png; bool subscribed = false; #region Config private bool Changed = false; private bool bProtectionEnabled; private bool bSleeperProtection; private bool bHelicopterProtection; private bool bCanPickupWeapons; private string UIIcon; private bool canLootHeli; private bool canLootDrop; private bool canLootHackCrate; private bool canLootFriends; private bool canLootFriendDeployables; private bool showUIIcon; private bool bUseRaidZones; private string UIIconAnchorMin; private string UIIconAnchorMax; private int UISecondsWarningBeforeEnd; private int UIIconFontSize; private string UILayer; private int iTime; private int iTimeAssign; private int iPunishment; private int iInactiveDays; private int iUpdateTimerInterval; private void LoadVariables() { canLootHeli = Convert.ToBoolean(GetConfig("Settings","canLootHeli", false)); canLootDrop = Convert.ToBoolean(GetConfig("Settings", "canLootDrop", false)); canLootHackCrate = Convert.ToBoolean(GetConfig("Settings", "canLootHackCrate", false)); canLootFriends = Convert.ToBoolean(GetConfig("Settings","canLootFriends", false)); canLootFriendDeployables = Convert.ToBoolean(GetConfig("Settings","canLootFriendDeployables", true)); bProtectionEnabled = Convert.ToBoolean(GetConfig("Settings","bProtectionEnabled", true)); bSleeperProtection = Convert.ToBoolean(GetConfig("Settings","bSleeperProtection", true)); bHelicopterProtection = Convert.ToBoolean(GetConfig("Settings","bHelicopterProtection", false)); bCanPickupWeapons = Convert.ToBoolean(GetConfig("Settings", "bCanPickupWeapons", false)); iUpdateTimerInterval = Convert.ToInt32(GetConfig("Settings","iUpdateTimerInterval", 60)); bUseRaidZones = Convert.ToBoolean(GetConfig("Settings", "bUseRaidZones", false)); iTime = Convert.ToInt32(GetConfig("Settings", "iTime", 1800)); iTimeAssign = Convert.ToInt32(GetConfig("Settings","iTimeAssign", 1800)); iPunishment = Convert.ToInt32(GetConfig("Settings","iPunishment", 600)); iInactiveDays = Convert.ToInt32(GetConfig("Settings", "iInactiveDays", 1)); UIIcon = Convert.ToString(GetConfig("Settings", "UIIcon", "https://i.imgur.com/hom6JrH.png")); showUIIcon = Convert.ToBoolean(GetConfig("Settings", "showUIIcon", true)); UIIconAnchorMin = Convert.ToString(GetConfig("Settings", "UIIconAnchorMin", "0.245 0.025")); UIIconAnchorMax = Convert.ToString(GetConfig("Settings", "UIIconAnchorMax", "0.290 0.095")); UIIconFontSize = Convert.ToInt32(GetConfig("Settings", "UIIconFontSize", 16)); UILayer = Convert.ToString(GetConfig("Settings", "UILayer", "Hud")); UISecondsWarningBeforeEnd = Convert.ToInt32(GetConfig("Settings", "UISecondsWarningBeforeEnd", 10)); if (Changed) { SaveConfig(); Changed = false; } } private object GetConfig(string menu, string datavalue, object defaultValue) { var data = Config[menu] as Dictionary<string, object>; if (data == null) { data = new Dictionary<string, object>(); Config[menu] = data; Changed = true; } object value; if (!data.TryGetValue(datavalue, out value)) { value = defaultValue; data[datavalue] = value; Changed = true; } return value; } void SaveData() { Interface.Oxide.DataFileSystem.WriteObject(this.Title, storedData); Interface.Oxide.DataFileSystem.WriteObject(this.Title+"Players", storedPlayersData); } #endregion #region Commands [ConsoleCommand("sp.assign")] void cmdAssignProtection(ConsoleSystem.Arg arg) { var player = arg?.Connection?.player ?? null; if ((player != null && arg.Connection?.authLevel < 2) || arg.Args == null || arg?.Args?.Length <= 0) return; ulong userid; if (!ulong.TryParse(arg.Args[0], out userid)) return; BasePlayer target = BasePlayer.FindByID(userid); if (target == null) return; bool inRaid = (bool)(NoEscape?.Call("IsRaidBlocked", target) ?? "false"); if (inRaid) { SendReply(target, "Protection cannot be assigned in raidblock!"); return; } if (storedPlayersData.Players.Contains(userid)) storedPlayersData.Players.Remove(userid); if (storedData.Players.ContainsKey(userid)) storedData.Players.Remove(userid); Log("assign {userid}","assign"); OnPlayerFirstInit(userid,iTimeAssign); ProtectionInfo p = null; if (storedData.Players.TryGetValue(userid, out p)) { int minutes = Convert.ToInt32(TimeSpan.FromSeconds(p.TimeLeft).TotalMinutes); if (showUIIcon) SPUiUser(BasePlayer.Find(userid.ToString()),minutes.ToString()); } } [ConsoleCommand("sp.cleardb")] void cmdClearDB(ConsoleSystem.Arg arg) { if (arg.Connection?.authLevel < 2) { SendReply(arg, "You don't have permission to use this command"); return; } storedData.Players.Clear(); storedPlayersData.Players.Clear(); SendReply(arg, "Start Protection database has been cleared"); SaveData(); } [ConsoleCommand("sp.end")] void cmdEndProtection(ConsoleSystem.Arg arg) { var player = arg?.Connection?.player ?? null; if ((player != null && arg.Connection?.authLevel < 2) || arg.Args == null || arg?.Args?.Length <= 0) return; ulong userid; if (!ulong.TryParse(arg.Args[0], out userid)) { SendReply(arg, "no player defined"); return; } ProtectionInfo p = null; if (storedData.Players.TryGetValue(userid, out p)) { BasePlayer pl = BasePlayer.FindByID(userid); if (pl != null) { Log("Start protection disabled by admin for " + " [" + userid.ToString() + "]", "assign"); EndProtection(pl); } else SendReply(arg, "no player found"); } else SendReply(arg, "player has no SP"); } Dictionary<string, string> logging = new Dictionary<string, string>(); void Log(string text, string filename = "stat") { if (!logging.ContainsKey(filename)) logging.Add(filename, $"[{DateTime.Now}]" + text + "\r\n"); else logging[filename] += text + "\r\n"; } [ChatCommand("sp")] private void SPCommand(BasePlayer player, string command, string[] args) { if (bProtectionEnabled == false && player.net.connection.authLevel <2) { PrintToChatEx(player, GetMessage("tDisabled", player.UserIDString)); return; } if (args.Length == 0 || args.Length > 2) { PrintToChatEx(player, "USAGE: /sp "); if (player.net.connection.authLevel >= 2) { PrintToChatEx(player, "<color=yellow>ADMIN: /sp "); } } else if (args[0] == "me") { if (player.net.connection.authLevel >= 2) { if (storedPlayersData.Players.Contains(player.userID)) { storedPlayersData.Players.Remove(player.userID); } OnPlayerFirstInit(player.userID); ProtectionInfo p = null; if (storedData.Players.TryGetValue(player.userID, out p)) { int minutes = Convert.ToInt32(TimeSpan.FromSeconds(p.TimeLeft).TotalMinutes); Log("Start protection enabled for " + player.displayName + " [" + player.userID.ToString() + "] - Duration: " + minutes + " minutes."); string parsed_config = GetMessage("tFirstSpawn", player.UserIDString); parsed_config = parsed_config.Replace("{minutes_left}", minutes.ToString()); PrintToChatEx(player, parsed_config); if (showUIIcon) SPUiUser(BasePlayer.Find(player.userID.ToString()),minutes.ToString()); } else { Log($"Failed for {player.userID}..."); } } else { PrintToChatEx(player, GetMessage("tNoAuthLevel", player.UserIDString)); } } else if (args[0] == "cleardb") { if (player.net.connection.authLevel >= 2) { storedData.Players.Clear(); storedPlayersData.Players.Clear(); PrintToChatEx(player, GetMessage("tDBCleared", player.UserIDString)); SaveData(); } else { PrintToChatEx(player, GetMessage("tNoAuthLevel", player.UserIDString)); } } else if (args[0] == "togglesleep") { if (player.net.connection.authLevel >= 2) { if (bSleeperProtection == true) { PrintToChatEx(player, "Sleep Protection: <color=red>disabled."); Log("Start Protection sleeper protection has been disabled by " + player.displayName + " (type /sp togglesleep to enable)."); Config["bSleeperProtection"] = false; SaveConfig(); } else { PrintToChatEx(player, "Sleep Protection: <color=green>enabled."); Log("Start Protection sleeper protection has been enabled by " + player.displayName + " (type /sp togglesleep to disabled)."); Config["bSleeperProtection"] = true; SaveConfig(); } } else { PrintToChatEx(player, GetMessage("tNoAuthLevel", player.UserIDString)); } } else if (args[0] == "toggle") { if (player.net.connection.authLevel >= 2) { if (bProtectionEnabled == true) { if (ProtectionTimer != null) { ProtectionTimer.Destroy(); } PrintToChatEx(player, GetMessage("tDisabled", player.UserIDString)); Puts("Start Protection has been disabled by " + player.displayName + " (type /sp toggle to enable)."); Config["bProtectionEnabled"] = false; SaveConfig(); } else { ProtectionTimer = timer.Repeat(iUpdateTimerInterval, 0, () => UpdateProtectedList(true)); PrintToChatEx(player, GetMessage("tEnabled", player.UserIDString)); int minutes = Convert.ToInt32(TimeSpan.FromSeconds(iTime).TotalMinutes); Puts("Start Protection has been enabled by " + player.displayName + " [Minutes: " + minutes.ToString() + "] (type /sp toggle to disable)."); Config["bProtectionEnabled"] = true; SaveConfig(); } } else { PrintToChatEx(player, GetMessage("tNoAuthLevel", player.UserIDString)); } } else if (args[0] == "end") { ProtectionInfo p = null; if (storedData.Players.TryGetValue(player.userID, out p)) { Log("Start protection disabled by user " + player.displayName + " [" + player.userID.ToString() + "]"); EndProtection(player); } else { PrintToChatEx(player, GetMessage("tNoProtection", player.UserIDString)); } } else if (args[0] == "time") { ProtectionInfo p = null; if (storedData.Players.TryGetValue(player.userID, out p)) { string minutes = Convert.ToInt32(TimeSpan.FromSeconds(p.TimeLeft).TotalMinutes).ToString(); string parsed_config = GetMessage("tSpawn", player.UserIDString); parsed_config = parsed_config.Replace("{minutes_left}", minutes.ToString()); PrintToChatEx(player, parsed_config); } else { PrintToChatEx(player, GetMessage("tNoProtection", player.UserIDString)); } } } #endregion #region Oxide Hooks void OnEnterZone(string zoneid, BasePlayer player) { if (!storedData.Players.ContainsKey(player.userID)) return; bool inRaid = (bool)(NoEscape?.Call("IsRaidBlocked", player) ?? "false"); if (inRaid) EndProtection(player, true); } void OnExitZone(string zone, BasePlayer player) { if (!storedData.Players.ContainsKey(player.userID)) return; if (endingProtectionRaid.Contains(player.userID)) endingProtectionRaid.Remove(player.userID); } protected override void LoadDefaultConfig() { Puts("No configuration file found, generating..."); LoadVariables(); } void StartSubscribe(bool subscribe) { subscribed = subscribe; if (subscribe) { ProtectionTimer = timer.Repeat(iUpdateTimerInterval, 0, () => UpdateProtectedList(true)); if (bUseRaidZones) { Subscribe(nameof(OnEnterZone)); Subscribe(nameof(OnExitZone)); } //Subscribe(nameof(OnEntityTakeDamage)); Subscribe(nameof(OnItemPickup)); Subscribe(nameof(OnLootEntity)); Subscribe(nameof(OnPlayerSleepEnded)); Subscribe(nameof(OnPlayerDisconnected)); } else { if (ProtectionTimer != null) ProtectionTimer.Destroy(); Unsubscribe(nameof(OnEnterZone)); Unsubscribe(nameof(OnExitZone)); //Unsubscribe(nameof(OnEntityTakeDamage)); Unsubscribe(nameof(OnItemPickup)); Unsubscribe(nameof(OnLootEntity)); Unsubscribe(nameof(OnPlayerSleepEnded)); Unsubscribe(nameof(OnPlayerDisconnected)); } } private void OnServerInitialized() { ImageLibrary?.CallHook("AddImage", UIIcon, "noak47", iconID); if (bProtectionEnabled == true) { RemoveOldUsers(); if (HasProtectedPlayer()) { StartSubscribe(true); } string minutes = Convert.ToInt32(TimeSpan.FromSeconds(iTime).TotalMinutes).ToString(); Puts("Start Protection has been enabled [Minutes: " + minutes + "] (type /sp toggle to disable)."); foreach (BasePlayer player in BasePlayer.activePlayerList) { if (storedData.Players.ContainsKey(player.userID)) { DestroyUi(player); } } } else { Puts("Start Protection is not enabled (type /sp toggle to enable)."); } LoadImage(); } ulong iconID = 0U; private void LoadImage() { if (!(bool)(ImageLibrary?.CallHook("IsReady") ?? false) || !(bool)(ImageLibrary?.CallHook("HasImage", "noak47", iconID) ?? false)) { PrintWarning("Waiting for ImageLibrary to finish image processing!"); timer.In(10, LoadImage); return; } nofight_png = (string)(ImageLibrary?.CallHook("GetImage", "noak47", iconID) ?? ""); foreach (BasePlayer player in BasePlayer.activePlayerList) { if (!permission.UserExists(player.userID.ToString()) || !storedPlayersData.Players.Contains(player.userID)) { OnPlayerFirstInit(player.userID); if (showUIIcon) SPUiUser(player); } } } private void Init() { storedData = Interface.Oxide.DataFileSystem.ReadObject(this.Title); storedPlayersData = Interface.Oxide.DataFileSystem.ReadObject(this.Title+"Players"); LoadVariables(); StartSubscribe(false); } void Unload() { Puts("Saving protection database..."); if (ProtectionTimer != null) { ProtectionTimer.Destroy(); } foreach (BasePlayer player in BasePlayer.activePlayerList) { if (storedData.Players.ContainsKey(player.userID)) { DestroyUi(player); } } SaveLogs(); SaveData(); } void SaveLogs() { foreach (var x in logging) { if (x.Value != "") { LogToFile(x.Key, x.Value, this); } } logging.Clear(); } void OnServerSave() { SaveLogs(); SaveData(); } void OnServerShutdown() => SaveData(); void OnPlayerFirstInit(ulong steamid, int timeleft = -1) { if (!subscribed) StartSubscribe(true); ProtectionInfo p = null; if (storedData.Players.TryGetValue(steamid, out p)) { if (p.Multiple == false && p.TimeLeft == iTime) { Log("Removing " + steamid + " from protection list, cleaning up..."); storedData.Players.Remove(steamid); OnPlayerFirstInit(steamid,timeleft); } } else { var info = new ProtectionInfo(); if (timeleft == -1) timeleft = iTime; info.TimeLeft = timeleft; info.Multiple = false; info.InitTimestamp = UnixTimeStampUTC();// Timestamp info.UserId = steamid; storedData.Players.Add(steamid, info); } } void OnPlayerDisconnected(BasePlayer player) { if (subscribed && storedData.Players.ContainsKey(player.userID)) { if (!HasProtectedPlayer(player)) { StartSubscribe(false); } } } private void OnNewSave() { storedData.Players.Clear(); storedPlayersData.Players.Clear(); SaveData(); PrintWarning("Wipe detected, cleared data"); } void OnPlayerConnected(BasePlayer player) { if (!storedPlayersData.Players.Contains(player.userID)) { OnPlayerFirstInit(player.userID); } } private void OnPlayerSleepEnded(BasePlayer player) { if (!(bool)(Interface.Oxide.CallHook("CanShowUI", player) ?? true)) { timer.In(3,()=> { OnPlayerSleepEnded(player); }); return; } ProtectionInfo p = null; if (storedData.Players.TryGetValue(player.userID, out p)) { int minutes = 0; if (!p.Multiple) { minutes = Convert.ToInt32(TimeSpan.FromSeconds(p.TimeLeft).TotalMinutes); Log("Start protection enabled for " + player.displayName + " [" + player.userID.ToString() + "] - Duration: " + minutes + " minutes."); string parsed_config = GetMessage("tFirstSpawn", player.UserIDString); parsed_config = parsed_config.Replace("{minutes_left}", minutes.ToString()); SPUi(player, parsed_config); p.Multiple = true; } else { minutes = Convert.ToInt32(TimeSpan.FromSeconds(p.TimeLeft).TotalMinutes); string parsed_config = GetMessage("tSpawn", player.UserIDString); parsed_config = parsed_config.Replace("{minutes_left}", minutes.ToString()); PrintToChatEx(player, parsed_config); } if (showUIIcon) SPUiUser(player,minutes.ToString()); } } private HitInfo OnEntityTakeDamage(BaseCombatEntity entity, HitInfo hitInfo) { if (bProtectionEnabled == true) { if (entity is BasePlayer) { var player = entity as BasePlayer; if (player.userID<76560000000000000L || player is NPCPlayer) return null; ProtectionInfo p = null; ProtectionInfo z = null; if (hitInfo.Initiator is BasePlayer) { var attacker = hitInfo.Initiator as BasePlayer; if (attacker.userID<76560000000000000L || attacker is NPCPlayer) return null; if (storedData.Players.TryGetValue(player.userID, out p)) { if (storedData.Players.TryGetValue(attacker.userID, out z)) { if (attacker.userID == player.userID) { return null; } else { PunishPlayer(attacker); Log("Punishing " + attacker.displayName.ToString() + " for attempting to pvp."); } } if (attacker.userID != player.userID) { if (player.IsSleeping()) { //TODO possibly bug if (bSleeperProtection == false) { storedData.Players.Remove(player.userID); storedPlayersData.Players.Add(player.userID); Log("Removed " + player.displayName.ToString() + " (Sleeping) from the Start Protection list."); return null; } } } PrintToChatEx(attacker, GetMessage("tAttackAttempt", attacker.UserIDString)); hitInfo.damageTypes.ScaleAll(0f); return hitInfo; } else { if (storedData.Players.TryGetValue(attacker.userID, out p)) { PunishPlayer(attacker); Log("Punishing " + attacker.displayName.ToString() + " for attempting to pvp."); hitInfo.damageTypes.ScaleAll(0f); return hitInfo; } } } else if (hitInfo.Initiator is BaseHelicopter) { if (bHelicopterProtection == true) { if (player == null) { return null; } if (storedData.Players.TryGetValue(player.userID, out z)) { hitInfo.damageTypes.ScaleAll(0f); return hitInfo; } } } } else if(entity is BuildingBlock || entity is Door || (entity.PrefabName?.Contains("building") ?? false) || (entity.PrefabName?.Contains("deployable") ?? false)) { if (hitInfo.Initiator is BasePlayer && entity.OwnerID!=0 && entity.OwnerID!=(hitInfo.Initiator as BasePlayer).userID) { ProtectionInfo p = null; var attacker = hitInfo.Initiator as BasePlayer; if ((entity as BaseEntity).OwnerID!=attacker.userID) { if (storedData.Players.TryGetValue(attacker.userID, out p)) { PunishPlayer(attacker); Log("Punishing " + attacker.displayName.ToString() + " for attempting to blow."); hitInfo.damageTypes.ScaleAll(0f); return hitInfo; } } } } else if(entity is LootableCorpse && (entity as LootableCorpse).playerSteamID > 76560000000000000L) { if (hitInfo.Initiator is BasePlayer) { ProtectionInfo p = null; var attacker = hitInfo.Initiator as BasePlayer; if ((entity as LootableCorpse).playerSteamID!=attacker.userID) { if (storedData.Players.TryGetValue(attacker.userID, out p)) { PunishPlayer(attacker); Log("Punishing " + attacker.displayName.ToString() + " for attempting to corpse."); hitInfo.damageTypes.ScaleAll(0f); return hitInfo; } } } } } return null; } object OnItemPickup(Item item, BasePlayer player) { if (bProtectionEnabled == true && !bCanPickupWeapons) { ProtectionInfo p = null; var hasProtection = storedData.Players.TryGetValue(player.userID, out p); if (!hasProtection) return null; if (item.info.category == ItemCategory.Weapon) { string minutes = Convert.ToInt32(TimeSpan.FromSeconds(p.TimeLeft).TotalMinutes).ToString(); string parsed_config = GetMessage("cantDo", player.UserIDString); parsed_config = parsed_config.Replace("{minutes_left}", minutes.ToString()); SPUi(player,parsed_config); return false; } } return null; } void OnLootEntity(BasePlayer player, BaseEntity entity) { if (bProtectionEnabled == true) { ProtectionInfo p = null; var hasProtection = storedData.Players.TryGetValue(player.userID, out p); if (!hasProtection) return; var corpse = entity as LootableCorpse; var sleeper = entity as BasePlayer; string minutes = Convert.ToInt32(TimeSpan.FromSeconds(p.TimeLeft).TotalMinutes).ToString(); string parsed_config = GetMessage("cantDo", player.UserIDString); parsed_config = parsed_config.Replace("{minutes_left}", minutes.ToString()); //can loot corpses own and bots if (corpse != null && corpse.playerSteamID!=player.userID && corpse.playerSteamID> 76560000000000000L) { SPUi(player,parsed_config); timer.Once(0.01f, player.EndLooting); } //can loot friend sleeper else if (sleeper != null && canLootFriends && (!(bool) (Friends?.CallHook("AreFriends", sleeper.userID,player.userID) ?? false) || !(bool)(Clans?.CallHook("IsClanMember", entity.OwnerID, player.userID) ?? false)) ) { SPUi(player,parsed_config); timer.Once(0.01f, player.EndLooting); } //can loot self or bot dropped rust_backpack else if (entity.PrefabName.Contains("item_drop")) { if ((entity as DroppedItemContainer).playerSteamID == 0) { SPUi(player,parsed_config); timer.Once(0.01f, player.EndLooting); } else if ((entity as DroppedItemContainer).playerSteamID!=player.userID && (entity as DroppedItemContainer).playerSteamID> 76560000000000000L && !(canLootFriends && ((bool) (Friends?.CallHook("AreFriends", entity.OwnerID,player.userID) ?? false)) || (bool)(Clans?.CallHook("IsClanMember", entity.OwnerID, player.userID) ?? false))) { SPUi(player,parsed_config); timer.Once(0.01f, player.EndLooting); } } //no loot heli or supply else if (!canLootHeli && entity.PrefabName.Contains("heli_crate")) { SPUi(player,parsed_config); timer.Once(0.01f, player.EndLooting); } else if (!canLootDrop && entity.PrefabName.Contains("supply_drop")) { SPUi(player,parsed_config); timer.Once(0.01f, player.EndLooting); } //no loot hackablecrate//hackablecrate else if (!canLootHackCrate && entity.PrefabName.Contains("hackablecrate")) { SPUi(player, parsed_config); timer.Once(0.01f, player.EndLooting); } //can loot friends deployables or own else if (entity.PrefabName.Contains("deployable") && entity.OwnerID!=0 && entity.OwnerID!=player.userID) { if (!(canLootFriendDeployables && ((bool) (Friends?.CallHook("AreFriends", entity.OwnerID,player.userID) ?? false) || (bool) (Clans?.CallHook("IsClanMember", entity.OwnerID, player.userID) ?? false)))) { SPUi(player,parsed_config); timer.Once(0.01f, player.EndLooting); } } } } #endregion #region UI void DestroyUi(BasePlayer player) { CuiHelper.DestroyUi(player, "SPUiUser"); } private void SPUiUser(BasePlayer player, string inputText = "") { DestroyUi(player); if (inputText=="") { ProtectionInfo p = null; if (storedData.Players.TryGetValue(player.userID, out p)) { inputText = Convert.ToInt32(TimeSpan.FromSeconds(p.TimeLeft).TotalMinutes).ToString(); } } var elements = new CuiElementContainer(); var panel = elements.Add(new CuiPanel() { Image = { Color = "0.75 0.75 0.75 0.0" }, RectTransform = { AnchorMin = UIIconAnchorMin, AnchorMax = UIIconAnchorMax } }, "Hud", "SPUiUser"); elements.Add(new CuiElement() { Parent = "SPUiUser", Components = { new CuiRawImageComponent {Png = nofight_png, Sprite = "assets/content/textures/generic/fulltransparent.tga" }, new CuiRectTransformComponent {AnchorMin = "0 0", AnchorMax = "1 1" } } }); elements.Add(new CuiLabel() { Text = { Text = String.Format(GetMessage("UIText",player.UserIDString),inputText), FontSize = UIIconFontSize, Color = "1 1 1 1", Align = TextAnchor.MiddleCenter }, RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1" } }, "SPUiUser"); elements.Add(new CuiButton { Button = { Command = "spinfo.show", Color = "0.8 0.8 0.8 0" }, RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1" }, Text = { Text = "", FontSize = 22, Align = TextAnchor.MiddleCenter } }, "SPUiUser"); // Create the UI elements CuiHelper.AddUi(player, elements); } private void SPUi(BasePlayer player, string inputText) { CuiHelper.DestroyUi(player,"SPUi"); var elements = new CuiElementContainer() { { new CuiPanel { Image = { Color = "0.1 0.1 0.1 0.5" }, RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1" }, CursorEnabled = true }, new CuiElement().Parent = "Overlay", "SPUi" } }; elements.Add(new CuiElement { Parent = "SPUi", Components = { new CuiTextComponent { Color = "1 1 1 1.0", Text = inputText, FontSize = 30, Align = TextAnchor.MiddleCenter}, new CuiOutlineComponent { Distance = "1 1", Color = "0.0 0.0 0.0 1.0" }, new CuiRectTransformComponent { AnchorMin = "0 0", AnchorMax = "1 1" } } }); elements.Add(new CuiButton { Button = { Close = "SPUi", Color = "0.8 0.8 0.8 0" }, RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1" }, Text = { Text = "", FontSize = 22, Align = TextAnchor.MiddleCenter } }, "SPUi"); CuiHelper.AddUi(player, elements); timer.Once(7f, () => { CuiHelper.DestroyUi(player,"SPUi"); }); } #endregion #region API private object HasProtection(BasePlayer player) { ProtectionInfo p = null; return storedData.Players.TryGetValue(player.userID, out p); } object CanDuel(BasePlayer player) { return HasProtection(player); } object CanEventJoin(BasePlayer player) { ProtectionInfo p = null; if (storedData.Players.TryGetValue(player.userID, out p)) return "You cannot enter with start protection"; return null; } #endregion #region Helpers private void PrintToChatEx(BasePlayer player, string result, string tcolour = "orange") { PrintToChat(player, "<color=\"" + tcolour + "\">[" + GetMessage("title", player.UserIDString) + "] " + result); } HashSet endingProtection = new HashSet(); HashSet endingProtectionRaid = new HashSet(); void RunEndingEffect(BasePlayer player) { if (player != null) { if (!(endingProtection.Contains(player.userID) || endingProtectionRaid.Contains(player.userID))) return; Effect.server.Run("assets/prefabs/locks/keypad/effects/lock.code.shock.prefab", player.transform.position, new Vector3()); } } void EndProtection(BasePlayer player, bool fromRaid = false) { if (endingProtection.Contains(player.userID) || endingProtectionRaid.Contains(player.userID)) return; if (fromRaid) endingProtectionRaid.Add(player.userID); else endingProtection.Add(player.userID); int maxWait = fromRaid ? UISecondsWarningBeforeEnd * 2 : UISecondsWarningBeforeEnd; SPUi(player, fromRaid ? String.Format(GetMessage("EndWarningRaid", player.UserIDString), maxWait) : String.Format(GetMessage("EndWarning", player.UserIDString), maxWait)); for (int i = 1; i < maxWait; i++) { timer.In(i * 1, () => { RunEndingEffect(player); }); } ulong ID = player.userID; timer.In(maxWait, () => { if (!(endingProtection.Contains(player.userID) || endingProtectionRaid.Contains(player.userID))) return; endingProtection.Remove(player.userID); endingProtectionRaid.Remove(player.userID); if (player != null) { Effect.server.Run("assets/prefabs/locks/keypad/effects/lock.code.shock.prefab", player.transform.position, new Vector3()); Effect.server.Run("assets/prefabs/instruments/guitar/effects/guitarpluck.prefab", player.transform.position, new Vector3()); /*if (fromRaid) { bool inRaid = (bool)(NoEscape?.Call("CanRaidCommand", player, "tp") ?? "false"); if (!inRaid) return; }*/ PrintToChatEx(player, GetMessage("tProtectionEnded", player.UserIDString)); //SPUi(player, GetMessage("tProtectionEnded", player.UserIDString)); DestroyUi(player); } storedData.Players.Remove(ID); storedPlayersData.Players.Add(ID); if (subscribed && !HasProtectedPlayer()) { StartSubscribe(false); } }); } private void UpdateProtectedListEx(BasePlayer player,bool init=false) { if (player != null) { ProtectionInfo p = null; if (storedData.Players.TryGetValue(player.userID, out p)) { if (p.TimeLeft >= 1 && p.TimeLeft <= iTime) { p.TimeLeft = p.TimeLeft - iUpdateTimerInterval; if (init) { int minutes = Convert.ToInt32(TimeSpan.FromSeconds(p.TimeLeft).TotalMinutes); if (showUIIcon) SPUiUser(player,minutes.ToString()); } } else { EndProtection(player); } } } } private void UpdateProtectedList(bool init = false) { foreach (BasePlayer player in BasePlayer.activePlayerList) { UpdateProtectedListEx(player, init); } } bool HasProtectedPlayer(BasePlayer exclude = null) { foreach (BasePlayer player in BasePlayer.activePlayerList) { if (exclude!=null && player.userID == exclude.userID) continue; if (storedData.Players.ContainsKey(player.userID)) { return true; } } return false; } public Int32 UnixTimeStampUTC() { Int32 unixTimeStamp; DateTime currentTime = DateTime.Now; DateTime zuluTime = currentTime.ToUniversalTime(); DateTime unixEpoch = new DateTime(1970, 1, 1); unixTimeStamp = (Int32)(zuluTime.Subtract(unixEpoch)).TotalSeconds; return unixTimeStamp; } public static DateTime UnixTimeStampToDateTime(double unixTimeStamp) { return unixTimeStamp > MaxUnixSeconds ? UnixEpoch.AddMilliseconds(unixTimeStamp) : UnixEpoch.AddSeconds(unixTimeStamp); } private void RemoveOldUsers() { int removed = 0; new List(storedData.Players.Keys).ForEach(u => { ulong steamid = u; ProtectionInfo item = null; if (storedData.Players.TryGetValue(steamid, out item)) { if (item.InitTimestamp == 0) { storedData.Players.Remove(steamid); storedPlayersData.Players.Add(steamid); removed++; } else { DateTime compareDate = UnixTimeStampToDateTime(item.InitTimestamp); var days = (DateTime.Now - compareDate).Days; if (days >= iInactiveDays) { storedData.Players.Remove(steamid); storedPlayersData.Players.Add(steamid); removed++; } } } }); if (removed >= 1) { Puts("Removing " + removed.ToString() + " old entries from the protection list."); } else { Puts("Entry list up to date."); } } private void PunishPlayer(BasePlayer player, int new_time = -1, bool message = true) { ProtectionInfo p = null; if (storedData.Players.TryGetValue(player.userID, out p)) { int punish = 0; if (new_time != -1) { punish = new_time; } else { punish = iPunishment; } p.TimeLeft = Math.Max(p.TimeLeft - punish,0); if (message) { int minutes = Convert.ToInt32(TimeSpan.FromSeconds(p.TimeLeft).TotalMinutes); string punishment = Convert.ToInt32(TimeSpan.FromSeconds(punish).TotalMinutes).ToString(); string parsed_config = GetMessage("tPunishment", player.UserIDString); parsed_config = parsed_config.Replace("{minutes_revoked}", punishment.ToString()); parsed_config = parsed_config.Replace("{minutes_left}", minutes.ToString()); //PrintToChatEx(player, parsed_config); SPUi(player,parsed_config); if (showUIIcon) { if (minutes > 0) SPUiUser(player, minutes.ToString()); else DestroyUi(player); } } if (p.TimeLeft <= 0) { UpdateProtectedListEx(player); } } } #endregion #region Localization protected override void LoadDefaultMessages() { lang.RegisterMessages(new Dictionary<string, string> { {"title", "StartProtection"}, {"tPunishment", "<color=red>You have been punished for attempting to PVP with Start Protection Enabled!\n{minutes_revoked} minutes revoked.\nYou now have <color=#FF3300>{minutes_left} minutes left before your Start Protection is disabled."}, {"tFirstSpawn", "Start protection enabled for {minutes_left} minutes, during this time you will not be able to pvp on any level.\nYou can check how much time you have left - /sp time\nTo turn protection off - /sp end" }, {"tSpawn", "You have {minutes_left} minutes left before your Start Protection is disabled."}, {"cantDo", "You have PVP Protection and can't loot/pickup that.\n{minutes_left} minutes left before your Start Protection is disabled.\nTo turn protection off - /sp end"}, {"tProtectionEnded", "Start protection <color=#FF3300>disabled, you are now on your own."}, {"tNoProtection", "Start protection status is currently <color=#FF3300>disabled."}, {"tAttackAttempt","The player you are trying to attack has Start Protection enabled and <color=#FF3300>cannot be damaged."}, {"tDisabled", "Start Protection is currently <color=#FF3300>disabled server-wide."}, {"tEnabled", "Start Protection has been <color=#66FF66>enabled, new players will now be protected upon spawning."}, {"tNoAuthLevel", "You <color=#FF3300>do not have access to this command."}, {"tDBCleared", "You have <color=#FF3300>cleared the Start Protection database."}, {"UIText", "NO PVP\n{0} min."}, {"EndWarning", "<color=red>Warning! Your protection will end in {0} seconds."}, {"EndWarningRaid", "<color=red>Warning! Leave RaidBlock or your protection will end in {0} seconds."}, }, this); lang.RegisterMessages(new Dictionary<string, string> { {"title", "Защита"}, {"tPunishment", "<color=red>Вы наказаны за пвп с включенной защитой!\n{minutes_revoked} минут отнято от защиты.\nОсталось {minutes_left} минут до конца защиты.\nВыключить свою защиту - /sp end"}, {"tFirstSpawn", "Защита от пвп включена на {minutes_left} минут, в это время нельзя пвп.\n\nСколько времени осталось, наберите - /sp time\n\nВыключить свою защиту - /sp end" }, {"tSpawn", "Осталось {minutes_left} минут до конца защиты."}, {"cantDo", "Ты находишься под защитой от пвп и не можешь открыть/взять это.\nОсталось {minutes_left} минут до конца защиты.\nВыключить свою защиту - /sp end "}, {"tProtectionEnded", "Защита выключена."}, {"tNoProtection", "Защита на данный момент <color=#FF3300>выключена"}, {"tAttackAttempt","Игрок находится под защитой, его <color=#FF3300>нельзя убить"}, {"tDisabled", "Защита <color=#FF3300>выключена для сервера."}, {"tEnabled", "Защита <color=#66FF66>включена, новые игроки будут защищены."}, {"tNoAuthLevel", "Нет доступа к этой команде"}, {"tDBCleared", "База защиты очищена"}, {"UIText", "NO PVP\n{0} мин."}, {"EndWarning", "<color=red>Внимание! Твоя защита закончится через {0} секунд."}, {"EndWarningRaid", "<color=red>Внимание! Покинь зону рейда или твоя защита закончится через {0} секунд."}, }, this,"ru"); } string GetMessage(string key, string steamId = null) => lang.GetMessage(key, this, steamId); #endregion } }