diff --git a/CHANGELOG.md b/CHANGELOG.md
index 522803c3..1a58f138 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -41,6 +41,8 @@ This is the rolling changelog for TShock for Terraria. Use past tense when addin
* Changed SendTileRect handling from a denylist to an allowlist with stricter checks. This prevents essentially all exploits involving this packet. Most notably this stops people from placing arbitrary tiles with arbitrary framing values, which are the root of most exploits. (@punchready)
* Removed the config options `TileRectangleSizeThreshold` and `KickOnTileRectangleSizeThresholdBroken` because they are made obsolete by the new system, which will only allow valid rectangle sizes (at a maximum of only 4 by 4 tiles in 1.4.3.6). (@punchready)
* Bumped Newtonsoft Json to 13.0.1. (@dependabot)
+* Added a second `Utils.TryParseTime` method for parsing large, positive time spans. (@punchready)
+* Fixed `/tempgroup` breaking on durations greater than roughly 24 days. (@punchready)
## TShock 4.5.17
* Fixed duplicate characters (twins) after repeatedly logging in as the same character due to connection not being immediately closed during `NetHooks_NameCollision`. (@gohjoseph)
diff --git a/TShockAPI/Commands.cs b/TShockAPI/Commands.cs
index af5b06e4..170de6c0 100644
--- a/TShockAPI/Commands.cs
+++ b/TShockAPI/Commands.cs
@@ -1511,7 +1511,7 @@ namespace TShockAPI
}
}
- if (TShock.Utils.TryParseTime(duration, out int seconds))
+ if (TShock.Utils.TryParseTime(duration, out ulong seconds))
{
expiration = DateTime.UtcNow.AddSeconds(seconds);
}
@@ -1879,7 +1879,7 @@ namespace TShockAPI
if (args.Parameters.Count > 2)
{
- int time;
+ ulong time;
if (!TShock.Utils.TryParseTime(args.Parameters[2], out time))
{
args.Player.SendErrorMessage("Invalid time string! Proper format: _d_h_m_s, with at least one time specifier.");
@@ -1887,7 +1887,7 @@ namespace TShockAPI
return;
}
- ply[0].tempGroupTimer = new System.Timers.Timer(time * 1000);
+ ply[0].tempGroupTimer = new System.Timers.Timer(time * 1000d);
ply[0].tempGroupTimer.Elapsed += ply[0].TempGroupTimerElapsed;
ply[0].tempGroupTimer.Start();
}
diff --git a/TShockAPI/Utils.cs b/TShockAPI/Utils.cs
index cb38a5ea..bcc34ab2 100644
--- a/TShockAPI/Utils.cs
+++ b/TShockAPI/Utils.cs
@@ -574,7 +574,7 @@ namespace TShockAPI
var sb = new StringBuilder(3);
for (int i = 0; i < str.Length; i++)
{
- if (Char.IsDigit(str[i]) || (str[i] == '-' || str[i] == '+' || str[i] == ' '))
+ if (char.IsDigit(str[i]) || str[i] == '-' || str[i] == '+' || str[i] == ' ')
sb.Append(str[i]);
else
{
@@ -607,6 +607,82 @@ namespace TShockAPI
return true;
}
+ ///
+ /// Attempts to parse a string as a positive timespan (_d_m_h_s).
+ ///
+ /// The time string.
+ /// The seconds.
+ /// Whether the string was parsed successfully.
+ public bool TryParseTime(string str, out ulong seconds)
+ {
+ seconds = 0;
+
+ if (string.IsNullOrWhiteSpace(str))
+ {
+ return false;
+ }
+
+ var sb = new StringBuilder(3);
+ for (int i = 0; i < str.Length; i++)
+ {
+ if (char.IsDigit(str[i]) || str[i] == '-' || str[i] == '+' || str[i] == ' ')
+ sb.Append(str[i]);
+ else
+ {
+ int num;
+ if (!int.TryParse(sb.ToString().Trim(' '), out num))
+ return false;
+
+ sb.Clear();
+
+ if (num == 0)
+ {
+ continue;
+ }
+
+ int numSeconds;
+ switch (str[i])
+ {
+ case 's':
+ numSeconds = num;
+ break;
+ case 'm':
+ numSeconds = num * 60;
+ break;
+ case 'h':
+ numSeconds = num * 60 * 60;
+ break;
+ case 'd':
+ numSeconds = num * 60 * 60 * 24;
+ break;
+ default:
+ return false;
+ }
+
+ if (numSeconds > 0)
+ {
+ if (ulong.MaxValue - seconds < (uint)numSeconds)
+ {
+ return false;
+ }
+
+ seconds += (uint)numSeconds;
+ }
+ else if (seconds >= (uint)Math.Abs(numSeconds))
+ {
+ seconds -= (uint)Math.Abs(numSeconds);
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+ if (sb.Length != 0)
+ return false;
+ return true;
+ }
+
///
/// Searches for a projectile by identity and owner
///