diff --git a/AriasServerUtils/ASUModSystem.cs b/AriasServerUtils/ASUModSystem.cs index b7bc9a2..ad0a547 100644 --- a/AriasServerUtils/ASUModSystem.cs +++ b/AriasServerUtils/ASUModSystem.cs @@ -8,6 +8,7 @@ using Vintagestory.API.Common.Entities; using Vintagestory.API.Config; using Vintagestory.API.MathTools; using Vintagestory.API.Server; +using Vintagestory.API.Util; using Vintagestory.GameContent; namespace AriasServerUtils @@ -72,6 +73,7 @@ namespace AriasServerUtils api.Event.ServerRunPhase(EnumServerRunPhase.GameReady, OnGameReady); api.Event.ServerRunPhase(EnumServerRunPhase.Shutdown, OnShutdown); api.Event.Timer(OnCheckModDirty, 20); + api.Event.Timer(OnCheckPlayerCooldowns, 1); api.Event.PlayerDeath += OnPlayerDeath; api.Event.PlayerJoin += OnPlayerJoin; api.Event.PlayerDisconnect += OnPlayerDC; @@ -163,6 +165,27 @@ namespace AriasServerUtils api.ChatCommands.Create("rtp").RequiresPlayer().RequiresPrivilege(Privilege.chat).WithDescription("Seeks a position possibly thousands of blocks away to teleport to.").HandleWith(Events.HandleRTP); } + private void OnCheckPlayerCooldowns() + { + foreach (var cdEntry in ServerUtilities.mPlayerData) + { + List toRemove = new(); + foreach (var cd in cdEntry.Value.ActiveCooldowns) + { + if (cd.Value < TimeUtil.GetUnixEpochTimestamp()) + { + toRemove.Add(cd.Key); + } + } + + foreach (var item in toRemove) + { + cdEntry.Value.ActiveCooldowns.Remove(item); + } + + if (toRemove.Count > 0) MarkDirty(); + } + } public static void NewBackCacheForPlayer(IServerPlayer player) { @@ -290,7 +313,10 @@ namespace AriasServerUtils config = API.LoadModConfig(GetConfigurationFile("global", ModConfigType.Global)); if (config == null) config = new ASUModConfig(); - // -> Step 2. Load Mod Warps <- + // Step 2. Check if there are new or missing cooldowns + config.SanityCheckCooldowns(); + + // -> Step 3. Load Mod Warps <- serverWarps = API.LoadModConfig(GetConfigurationFile("warps", ModConfigType.Global)); if (serverWarps == null) serverWarps = new Warps(); } diff --git a/AriasServerUtils/EventHandler.cs b/AriasServerUtils/EventHandler.cs index 8ef9e33..5529cf4 100644 --- a/AriasServerUtils/EventHandler.cs +++ b/AriasServerUtils/EventHandler.cs @@ -6,6 +6,7 @@ using Vintagestory.API.Common; using Vintagestory.API.Config; using Vintagestory.API.MathTools; using Vintagestory.API.Server; +using Vintagestory.API.Util; namespace AriasServerUtils { @@ -18,6 +19,12 @@ namespace AriasServerUtils internal static TextCommandResult HandleBack(TextCommandCallingArgs args) { + PlayerStorage ps = ServerUtilities.GetPlayerData(args.Caller.Player as IServerPlayer); + if (ps.ActiveCooldowns.ContainsKey(CooldownType.Back)) + { + return TextCommandResult.Success(Lang.Get($"{ServerUtilities.MOD_ID}:cmd-cooldown", "/back", TimeUtil.EncodeTimeNotation(ps.ActiveCooldowns.Get(CooldownType.Back) - TimeUtil.GetUnixEpochTimestamp()))); + } + PlayerPosition pos = ServerUtilities.backCaches.ReadAndPopNewestPosition(args.Caller.Player.PlayerName); if (pos == null) { @@ -27,6 +34,9 @@ namespace AriasServerUtils { // Go back to old position pos.Merge(args.Caller.Player.Entity); + ps.ActiveCooldowns.Add(CooldownType.Back, TimeUtil.DecodeTimeNotation(ServerUtilities.config.Cooldowns.Get(CooldownType.Back)) + TimeUtil.GetUnixEpochTimestamp()); + ServerUtilities.MarkDirty(); + return TextCommandResult.Success(Lang.Get($"{ServerUtilities.MOD_ID}:back")); } @@ -44,8 +54,19 @@ namespace AriasServerUtils { if (args.Caller.Player is IServerPlayer isp) { + + PlayerStorage ps = ServerUtilities.GetPlayerData(isp); + if (ps.ActiveCooldowns.ContainsKey(CooldownType.RTP)) + { + return TextCommandResult.Success(Lang.Get($"{ServerUtilities.MOD_ID}:cmd-cooldown", "/rtp", TimeUtil.EncodeTimeNotation(ps.ActiveCooldowns.Get(CooldownType.RTP) - TimeUtil.GetUnixEpochTimestamp()))); + } + + ServerUtilities.SendMessageTo(isp, Lang.Get($"{ServerUtilities.MOD_ID}:rtp-search")); + ps.ActiveCooldowns.Add(CooldownType.RTP, TimeUtil.DecodeTimeNotation(ServerUtilities.config.Cooldowns.Get(CooldownType.RTP)) + TimeUtil.GetUnixEpochTimestamp()); + ServerUtilities.MarkDirty(); + PlayerPosition pPos = RTPFactory.GetRandomPosition(isp); if (pPos == null) { @@ -103,6 +124,12 @@ namespace AriasServerUtils if (args.Caller.Player is IServerPlayer isp) { PlayerStorage data = ServerUtilities.GetPlayerData(isp); + if (data.ActiveCooldowns.ContainsKey(CooldownType.Home)) + { + return TextCommandResult.Success(Lang.Get($"{ServerUtilities.MOD_ID}:cmd-cooldown", "/home", TimeUtil.EncodeTimeNotation(data.ActiveCooldowns.Get(CooldownType.Home) - TimeUtil.GetUnixEpochTimestamp()))); + } + + if (data.Homes.ContainsKey(homeName)) { ServerUtilities.NewBackCacheForPlayer(isp); @@ -114,6 +141,11 @@ namespace AriasServerUtils { ServerUtilities.SendMessageTo(isp, Lang.Get($"{ServerUtilities.MOD_ID}:home-no")); } + + + + data.ActiveCooldowns.Add(CooldownType.Home, TimeUtil.DecodeTimeNotation(ServerUtilities.config.Cooldowns.Get(CooldownType.Home)) + TimeUtil.GetUnixEpochTimestamp()); + ServerUtilities.MarkDirty(); } return TextCommandResult.Success(); @@ -219,10 +251,23 @@ namespace AriasServerUtils { if (args.Caller.Player is IServerPlayer isp) { + + PlayerStorage data = ServerUtilities.GetPlayerData(isp); + if (data.ActiveCooldowns.ContainsKey(CooldownType.Spawn)) + { + return TextCommandResult.Success(Lang.Get($"{ServerUtilities.MOD_ID}:cmd-cooldown", "/spawn", TimeUtil.EncodeTimeNotation(data.ActiveCooldowns.Get(CooldownType.Spawn) - TimeUtil.GetUnixEpochTimestamp()))); + } + ServerUtilities.SendMessageTo(isp, Lang.Get($"{ServerUtilities.MOD_ID}:tp-spawn")); ServerUtilities.NewBackCacheForPlayer(isp); ServerUtilities.config.Spawn.Merge(args.Caller.Player.Entity); + + + + + data.ActiveCooldowns.Add(CooldownType.Spawn, TimeUtil.DecodeTimeNotation(ServerUtilities.config.Cooldowns.Get(CooldownType.Spawn)) + TimeUtil.GetUnixEpochTimestamp()); + ServerUtilities.MarkDirty(); } } @@ -294,12 +339,26 @@ namespace AriasServerUtils if (args.Caller.Player is IServerPlayer isp) { + PlayerStorage data = ServerUtilities.GetPlayerData(isp); + if (data.ActiveCooldowns.ContainsKey(CooldownType.Warp)) + { + return TextCommandResult.Success(Lang.Get($"{ServerUtilities.MOD_ID}:cmd-cooldown", "/warp", TimeUtil.EncodeTimeNotation(data.ActiveCooldowns.Get(CooldownType.Warp) - TimeUtil.GetUnixEpochTimestamp()))); + } + + if (ServerUtilities.serverWarps.warps.ContainsKey(name)) { ServerUtilities.NewBackCacheForPlayer(isp); ServerUtilities.serverWarps.warps[name].Location.Merge(isp.Entity); ServerUtilities.SendMessageTo(isp, Lang.Get($"{ServerUtilities.MOD_ID}:warp-set", name)); + + + + + + data.ActiveCooldowns.Add(CooldownType.Warp, TimeUtil.DecodeTimeNotation(ServerUtilities.config.Cooldowns.Get(CooldownType.Warp)) + TimeUtil.GetUnixEpochTimestamp()); + ServerUtilities.MarkDirty(); } else { diff --git a/AriasServerUtils/Globals.cs b/AriasServerUtils/Globals.cs index 98f125c..37be46e 100644 --- a/AriasServerUtils/Globals.cs +++ b/AriasServerUtils/Globals.cs @@ -19,11 +19,53 @@ namespace AriasServerUtils public int MaxBackCache { get; set; } = 10; public int PlayerSleepingPercentage { get; set; } = 50; public int MaxRTPBlockDistance { get; set; } = 5000; + public Dictionary Cooldowns { get; set; } = new Dictionary + { + { CooldownType.Home, "5s" }, + { CooldownType.Warp, "10s" }, + { CooldownType.Spawn, "5s" }, + { CooldownType.RTP, "30s" }, + { CooldownType.Back, "5s" } + }; + + public Dictionary GetDefaultCooldowns() + { + return new Dictionary{ + + { CooldownType.Home, "5s" }, + { CooldownType.Warp, "10s" }, + { CooldownType.Spawn, "5s" }, + { CooldownType.RTP, "30s" }, + { CooldownType.Back, "5s" } + }; + } + + public void SanityCheckCooldowns() + { + foreach (var cd in GetDefaultCooldowns()) + { + if (!Cooldowns.ContainsKey(cd.Key)) + { + Cooldowns.Add(cd.Key, cd.Value); + ServerUtilities.MarkDirty(); + } + } + } public PlayerPosition Spawn { get; set; } } + [Serializable] + public enum CooldownType + { + Home, // Default: 5s + Warp, // Default 10s + Spawn, // Default 5s + RTP, // Default 30s + Back // Default 5s + } + [Serializable] public class Warp { diff --git a/AriasServerUtils/PlayerData.cs b/AriasServerUtils/PlayerData.cs index c31560d..baec1b3 100644 --- a/AriasServerUtils/PlayerData.cs +++ b/AriasServerUtils/PlayerData.cs @@ -78,6 +78,7 @@ namespace AriasServerUtils public class PlayerStorage { public Dictionary Homes = new Dictionary(); + public Dictionary ActiveCooldowns = new(); } /// diff --git a/AriasServerUtils/RTPFactory.cs b/AriasServerUtils/RTPFactory.cs index 1390eda..ddc1c35 100644 --- a/AriasServerUtils/RTPFactory.cs +++ b/AriasServerUtils/RTPFactory.cs @@ -8,6 +8,7 @@ using Vintagestory.API.MathTools; using Vintagestory.API.Server; using Vintagestory.GameContent; +namespace AriasServerUtils; public class RTPFactory { /// diff --git a/AriasServerUtils/TimeUtil.cs b/AriasServerUtils/TimeUtil.cs new file mode 100644 index 0000000..aca557e --- /dev/null +++ b/AriasServerUtils/TimeUtil.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.Linq; + + +namespace AriasServerUtils +{ + public static class TimeUtil + { + private static readonly Dictionary TimeUnits = new() + { + { 's', 1 }, // seconds + { 'm', 60 }, // minutes + { 'h', 3600 }, // hours + { 'd', 86400 }, // days + { 'w', 604800 }, // weeks + { 'M', 2592000 }, // months (approx. 30 days) + { 'y', 31536000 } // years (365 days) + }; + + public static long DecodeTimeNotation(string input) + { + if (string.IsNullOrWhiteSpace(input)) return 0; + + long totalSeconds = 0; + int number = 0; + + foreach (char c in input) + { + if (char.IsDigit(c)) + { + number = number * 10 + (c - '0'); + } + else if (TimeUnits.TryGetValue(c, out int unitSeconds)) + { + totalSeconds += number * unitSeconds; + number = 0; + } + else + { + throw new FormatException($"Invalid time unit: {c}"); + } + } + + return totalSeconds; + } + + public static string EncodeTimeNotation(long seconds) + { + if (seconds <= 0) return "0s"; + + var result = new List(); + + foreach (var (unit, unitSeconds) in TimeUnits.OrderByDescending(u => u.Value)) + { + long value = seconds / unitSeconds; + if (value > 0) + { + result.Add($"{value}{unit}"); + seconds %= unitSeconds; + } + } + + return string.Join("", result); + } + + public static long GetUnixEpochTimestamp() + { + return DateTimeOffset.UtcNow.ToUnixTimeSeconds(); + } + } +} diff --git a/AriasServerUtils/modinfo.json b/AriasServerUtils/modinfo.json index e73b8ac..ac727a0 100644 --- a/AriasServerUtils/modinfo.json +++ b/AriasServerUtils/modinfo.json @@ -3,8 +3,8 @@ "modid": "ariasserverutils", "name": "Aria's Server Utilities", "authors": ["zontreck"], - "description": "A collection of server utilities\n\nBuild Date: 03-06-2025 @ 5:19 PM MST", - "version": "1.0.4-dev.8", + "description": "A collection of server utilities\n\nBuild Date: 03-06-2025 @ 6:16 PM MST", + "version": "1.0.4-dev.10", "dependencies": { "game": "" }