From 7bb22c4c69260ca8c336e013589a75a8bf50cb7d Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Mon, 29 Aug 2016 17:44:00 +1000 Subject: [PATCH] Support timespans in /undo and /highlight. --- Commands/Information/CmdAbout.cs | 2 +- Commands/Moderation/CmdHighlight.cs | 41 ++++++++++--------- Commands/Moderation/CmdTempBan.cs | 2 +- Commands/Moderation/CmdTempRank.cs | 2 +- Commands/Moderation/CmdUndoArea.cs | 19 ++++----- Commands/building/CmdUndo.cs | 63 ++++++++++++++++------------- Commands/other/CmdHackRank.cs | 10 ++--- Drawing/Brushes/SimpleBrushes.cs | 2 - Drawing/DrawOps/UndoDrawOp.cs | 12 +++--- Player/Player.Fields.cs | 2 +- util/TimeUtils.cs | 2 +- 11 files changed, 82 insertions(+), 75 deletions(-) diff --git a/Commands/Information/CmdAbout.cs b/Commands/Information/CmdAbout.cs index 3d2a0a51a..8779b7c72 100644 --- a/Commands/Information/CmdAbout.cs +++ b/Commands/Information/CmdAbout.cs @@ -84,7 +84,7 @@ namespace MCGalaxy.Commands { static void Output(Player p, string user, byte block, bool deleted, TimeSpan delta) { string bName = Block.Name(block); - Player.Message(p, "{0} ago {1} {2}", + Player.Message(p, "{0} ago {1} {2}", delta.Shorten(true, false), PlayerInfo.GetColoredName(p, user), deleted ? "&4deleted%S (using " + bName + ")" : "&3placed%S " + bName); } diff --git a/Commands/Moderation/CmdHighlight.cs b/Commands/Moderation/CmdHighlight.cs index bf0c45a29..44d092f57 100644 --- a/Commands/Moderation/CmdHighlight.cs +++ b/Commands/Moderation/CmdHighlight.cs @@ -32,26 +32,22 @@ namespace MCGalaxy.Commands { public CmdHighlight() { } public override void Use(Player p, string message) { - long seconds; + TimeSpan delta; bool found = false; if (Player.IsSuper(p)) { MessageInGameOnly(p); return; } if (message == "") message = p.name + " 1800"; string[] args = message.Split(' '); - string name = args[0]; if (args.Length >= 2) { - if (!long.TryParse(args[1], out seconds)) { - Player.Message(p, "Invalid seconds."); return; - } - } else if (long.TryParse(args[0], out seconds)) { + if (!args[1].TryParseShort(p, 's', "highlight the past", out delta)) return; + } else if (ParseTimespan(args[0], out delta)) { args[0] = p.name; } else { - seconds = 30 * 60; + delta = TimeSpan.FromMinutes(30); } - if (seconds <= 0) seconds = 30 * 60; - DateTime start = DateTime.UtcNow.AddTicks(-seconds * TimeSpan.TicksPerSecond); - - Player who = PlayerInfo.Find(name); + + DateTime start = DateTime.UtcNow.Subtract(delta); + Player who = PlayerInfo.Find(args[0]); bool done = false; if (who != null) { found = true; @@ -60,17 +56,25 @@ namespace MCGalaxy.Commands { done = HighlightBlocks(p, start, cache); } } - if (!done) UndoFormat.DoHighlight(p, name.ToLower(), start, ref found); + if (!done) UndoFormat.DoHighlight(p, args[0].ToLower(), start, ref found); if (found) { - Player.Message(p, "Now highlighting &b{0} %Sseconds for {1}", - seconds, PlayerInfo.GetColoredName(p, name)); + Player.Message(p, "Now highlighting past &b{0} %Sfor {1}", + delta.Shorten(), PlayerInfo.GetColoredName(p, args[0])); Player.Message(p, "&cUse /reload to un-highlight"); } else { Player.Message(p, "Could not find player specified."); } } + static bool ParseTimespan(string input, out TimeSpan delta) { + delta = TimeSpan.Zero; + try { delta = input.ParseShort('s'); return true; + } catch (ArgumentException) { return false; + } catch (FormatException) { return false; + } + } + static bool HighlightBlocks(Player p, DateTime start, UndoCache cache) { UndoFormatArgs args = new UndoFormatArgs(p, start); UndoFormat format = new UndoFormatOnline(cache); @@ -79,10 +83,11 @@ namespace MCGalaxy.Commands { } public override void Help(Player p) { - Player.Message(p, "%T/highlight [player] [seconds]"); - Player.Message(p, "%HHighlights blocks modified by [player] in the last [seconds]"); - Player.Message(p, "%HIf no [seconds] is given, highlights for last 30 minutes"); - Player.Message(p, "&c/highlight cannot be disabled, you must use /reload to un-highlight"); + Player.Message(p, "%T/highlight [player] "); + Player.Message(p, "%HHighlights blocks modified by [player] in the past "); + Player.Message(p, "%H e.g. to highlight for 90 minutes, would be %S1h30m"); + Player.Message(p, "%HIf is not given, highlights for last 30 minutes"); + Player.Message(p, "&c/highlight cannot be disabled, use /reload to un-highlight"); } } } diff --git a/Commands/Moderation/CmdTempBan.cs b/Commands/Moderation/CmdTempBan.cs index 0ccff3e4f..a155dd331 100644 --- a/Commands/Moderation/CmdTempBan.cs +++ b/Commands/Moderation/CmdTempBan.cs @@ -70,7 +70,7 @@ namespace MCGalaxy.Commands.Moderation { public override void Help(Player p) { Player.Message(p, "%T/tempban [name] [timespan] "); Player.Message(p, "%HBans [name] for [timespan]. Max is 1 day, default is 1 hour."); - Player.Message(p, "%H e.g. to tempban for 90 minutes, [timespan] would be 1h30m"); + Player.Message(p, "%H e.g. to tempban for 90 minutes, [timespan] would be %S1h30m"); Player.Message(p, "%HTemp bans will reset on server restart"); Player.Message(p, "%HFor , @number can be used as a shortcut for that rule."); } diff --git a/Commands/Moderation/CmdTempRank.cs b/Commands/Moderation/CmdTempRank.cs index f4de2e49e..7acf8fa7d 100644 --- a/Commands/Moderation/CmdTempRank.cs +++ b/Commands/Moderation/CmdTempRank.cs @@ -159,7 +159,7 @@ namespace MCGalaxy.Commands.Moderation { public override void Help(Player p) { Player.Message(p, "%T/temprank [player] [rank] [timespan]"); Player.Message(p, "%HSets a temporary rank for the specified player."); - Player.Message(p, "%H e.g. to temprank for 90 minutes, [timespan] would be 1h30m"); + Player.Message(p, "%H e.g. to temprank for 90 minutes, [timespan] would be %S1h30m"); Player.Message(p, "%T/temprank [player] info"); Player.Message(p, "%HLists information about the temp rank for the given player."); Player.Message(p, "%T/temprank delete %H- Removes player's temp rank."); diff --git a/Commands/Moderation/CmdUndoArea.cs b/Commands/Moderation/CmdUndoArea.cs index ba9d43578..8376ed0e8 100644 --- a/Commands/Moderation/CmdUndoArea.cs +++ b/Commands/Moderation/CmdUndoArea.cs @@ -35,7 +35,8 @@ namespace MCGalaxy.Commands { string[] parts = message.Split(' '); args.message = parts[0]; - args.seconds = CmdUndo.GetSeconds(p, null, parts.Length > 1 ? parts[1] : "30"); + args.delta = CmdUndo.GetDelta(p, null, parts.Length > 1 ? parts[1] : "30"); + if (args.delta == TimeSpan.MinValue) return; Player.Message(p, "Place two blocks to determine the edges."); p.MakeSelection(2, args, DoUndo); @@ -56,13 +57,13 @@ namespace MCGalaxy.Commands { } UndoOnlineDrawOp op = new UndoOnlineDrawOp(); - op.Start = DateTime.UtcNow.AddTicks(-args.seconds * TimeSpan.TicksPerSecond); + op.Start = DateTime.UtcNow.Subtract(args.delta); op.who = who; DrawOp.DoDrawOp(op, null, p, marks); Player.SendChatFrom(who, who.ColoredName + - "%S's actions for the past &b" + args.seconds + " seconds were undone.", false); - Server.s.Log(who.name + "'s actions for the past " + args.seconds + " seconds were undone."); + "%S's actions for the past &b" + args.delta.Shorten() + " %Swere undone.", false); + Server.s.Log(who.name + "'s actions for the past " + args.delta.Shorten() + " were undone."); } void UndoOfflinePlayer(Player p, string whoName, UndoArgs args, Vec3S32[] marks) { @@ -72,21 +73,21 @@ namespace MCGalaxy.Commands { } UndoOfflineDrawOp op = new UndoOfflineDrawOp(); - op.Start = DateTime.UtcNow.AddTicks(-args.seconds * TimeSpan.TicksPerSecond); + op.Start = DateTime.UtcNow.Subtract(args.delta); op.whoName = whoName; DrawOp.DoDrawOp(op, null, p, marks); if (op.found) { - Chat.MessageAll("{0}{1}%S's actions for the past &b{2} %Sseconds were undone.", - group.color, whoName, args.seconds); - Server.s.Log(whoName + "'s actions for the past " + args.seconds + " seconds were undone."); + Chat.MessageAll("{0}{1}%S's actions for the past &b{2} %Swere undone.", + group.color, whoName, args.delta.Shorten()); + Server.s.Log(whoName + "'s actions for the past " + args.delta.Shorten() + " were undone."); p.level.Save(true); } else { Player.Message(p, "Could not find player specified."); } } - struct UndoArgs { public string message; public long seconds; } + struct UndoArgs { public string message; public TimeSpan delta; } public override void Help(Player p) { Player.Message(p, "%T/undoarea [player] [seconds]"); diff --git a/Commands/building/CmdUndo.cs b/Commands/building/CmdUndo.cs index b06863dc6..ae2ad1ae1 100644 --- a/Commands/building/CmdUndo.cs +++ b/Commands/building/CmdUndo.cs @@ -48,7 +48,8 @@ namespace MCGalaxy.Commands.Building { string[] parts = message.Split(' '); bool undoPhysics = parts[0].CaselessEq("physics"); Player who = undoPhysics ? null : PlayerInfo.Find(parts[0]); - long seconds = GetSeconds(p, who, parts.Length > 1 ? parts[1] : "30"); + TimeSpan delta = GetDelta(p, who, parts.Length > 1 ? parts[1] : "30"); + if (delta == TimeSpan.MinValue) return; if (parts.Length > 1 && parts[1].CaselessEq("update")) { UndoFormat.UpgradePlayerUndoFiles(parts[0]); @@ -57,29 +58,33 @@ namespace MCGalaxy.Commands.Building { } if (who != null) - UndoOnlinePlayer(p, seconds, who); + UndoOnlinePlayer(p, delta, who); else if (undoPhysics) - UndoLevelPhysics(p, seconds); + UndoLevelPhysics(p, delta); else - UndoOfflinePlayer(p, seconds, parts[0]); + UndoOfflinePlayer(p, delta, parts[0]); } const int undoMax = -1; // allows everything to be undone. - internal static long GetSeconds(Player p, Player who, string param) { - long secs; + internal static TimeSpan GetDelta(Player p, Player who, string param) { + TimeSpan delta; + bool canAll = p == null || p == who || p.group.maxUndo == undoMax; + if (param.CaselessEq("all")) { - secs = (p == null || p.group.maxUndo == undoMax || p == who) ? int.MaxValue : p.group.maxUndo; - } else if (!long.TryParse(param, out secs)) { - Player.Message(p, "Invalid seconds, using 30 seconds."); - return 30; + return TimeSpan.FromSeconds(canAll ? int.MaxValue : p.group.maxUndo); + } else if (!param.TryParseShort(p, 's', "undo the past", out delta)) { + Player.Message(p, "Undoing for 30 seconds."); + return TimeSpan.MinValue; } - if (secs == 0) secs = 5400; - if (p != null && p != who && p.group.maxUndo != undoMax && secs > p.group.maxUndo) { - Player.Message(p, p.group.name + "s may only undo up to " + p.group.maxUndo + " seconds."); - return p.group.maxUndo; + if (delta.TotalSeconds == 0) + delta = TimeSpan.FromMinutes(90); + if (!canAll && delta.TotalSeconds > p.group.maxUndo) { + Player.Message(p, "{0}%Ss may only undo up to {1} seconds.", + p.group.ColoredName, p.group.maxUndo); + return TimeSpan.FromSeconds(p.group.maxUndo); } - return secs; + return delta; } void UndoSelf(Player p) { @@ -108,36 +113,36 @@ namespace MCGalaxy.Commands.Building { Player.Message(p, "Try using %T/undo %Sinstead."); } - void UndoOnlinePlayer(Player p, long seconds, Player who) { + void UndoOnlinePlayer(Player p, TimeSpan delta, Player who) { if (p != null && p != who && !CheckUndoPerms(p, who.group)) return; UndoOnlineDrawOp op; if (p == who) op = new UndoSelfDrawOp(); else op = new UndoOnlineDrawOp(); - op.Start = DateTime.UtcNow.AddTicks(-seconds * TimeSpan.TicksPerSecond); + op.Start = DateTime.UtcNow.Subtract(delta); op.who = who; DrawOp.DoDrawOp(op, null, p, new Vec3S32[] { Vec3U16.MaxVal, Vec3U16.MaxVal } ); if (p == who) { - Player.Message(p, "Undid your actions for the past &b" + seconds + " %Sseconds."); + Player.Message(p, "Undid your actions for the past &b" + delta.Shorten() + "%S."); } else { - Player.SendChatFrom(who, who.ColoredName + "%S's actions for the past &b" + seconds + " seconds were undone.", false); + Player.SendChatFrom(who, who.ColoredName + "%S's actions for the past &b" + delta.Shorten() + " %Swere undone.", false); } - Server.s.Log(who.name + "'s actions for the past " + seconds + " seconds were undone."); + Server.s.Log(who.name + "'s actions for the past " + delta.Shorten() + " were undone."); } - void UndoOfflinePlayer(Player p, long seconds, string whoName) { + void UndoOfflinePlayer(Player p, TimeSpan delta, string whoName) { if (p != null && !CheckUndoPerms(p, Group.findPlayerGroup(whoName))) return; UndoOfflineDrawOp op = new UndoOfflineDrawOp(); - op.Start = DateTime.UtcNow.AddTicks(-seconds * TimeSpan.TicksPerSecond); + op.Start = DateTime.UtcNow.Subtract(delta); op.whoName = whoName; DrawOp.DoDrawOp(op, null, p, new Vec3S32[] { Vec3U16.MaxVal, Vec3U16.MaxVal } ); if (op.found) { - Chat.MessageAll("{0}%S's actions for the past &b{1} %Sseconds were undone.", - PlayerInfo.GetColoredName(p, whoName), seconds); - Server.s.Log(whoName + "'s actions for the past " + seconds + " seconds were undone."); + Chat.MessageAll("{0}%S's actions for the past &b{1} %S were undone.", + PlayerInfo.GetColoredName(p, whoName), delta.Shorten()); + Server.s.Log(whoName + "'s actions for the past " + delta.Shorten() + " were undone."); if (p != null) p.level.Save(true); } else { Player.Message(p, "Could not find player specified."); @@ -150,18 +155,18 @@ namespace MCGalaxy.Commands.Building { return true; } - void UndoLevelPhysics(Player p, long seconds) { + void UndoLevelPhysics(Player p, TimeSpan delta) { if (!CheckExtraPerm(p, 2)) { MessageNeedExtra(p, "undo physics.", 2); return; } if (p != null && !p.group.CanExecute("physics")) { Player.Message(p, "You can only undo physics if you can use /physics."); return; } CmdPhysics.SetPhysics(p.level, 0); UndoPhysicsDrawOp op = new UndoPhysicsDrawOp(); - op.seconds = seconds; + op.Start = DateTime.UtcNow.Subtract(delta); DrawOp.DoDrawOp(op, null, p, new Vec3S32[] { Vec3U16.MaxVal, Vec3U16.MaxVal } ); - Chat.MessageAll("Physics were undone &b{0} %Sseconds", seconds); - Server.s.Log( "Physics were undone &b" + seconds + " %Sseconds"); + Chat.MessageAll("Physics were undone &b{0}", delta.Shorten()); + Server.s.Log("Physics were undone &b" + delta.Shorten()); p.level.Save(true); } diff --git a/Commands/other/CmdHackRank.cs b/Commands/other/CmdHackRank.cs index de7b708b8..431f24f91 100644 --- a/Commands/other/CmdHackRank.cs +++ b/Commands/other/CmdHackRank.cs @@ -37,12 +37,10 @@ namespace MCGalaxy.Commands { if (p.hackrank) { Player.Message(p, Colors.red + "You have already hacked a rank!"); return; } - Group grp = Group.Find(message); - if (grp != null) { - DoFakeRank(p, grp); - } else { - Player.Message(p, "Invalid Rank!"); - } + + Group grp = Group.FindMatches(p, message); + if (grp == null) return; + DoFakeRank(p, grp); } void DoFakeRank(Player p, Group newRank) { diff --git a/Drawing/Brushes/SimpleBrushes.cs b/Drawing/Brushes/SimpleBrushes.cs index bdd329ed8..d6365bc0b 100644 --- a/Drawing/Brushes/SimpleBrushes.cs +++ b/Drawing/Brushes/SimpleBrushes.cs @@ -33,8 +33,6 @@ namespace MCGalaxy.Drawing.Brushes { public override byte NextBlock(DrawOp op) { return block; } public override byte NextExtBlock(DrawOp op) { return extBlock; } - - // TODO: OVerride validate } public sealed class StripedBrush : Brush { diff --git a/Drawing/DrawOps/UndoDrawOp.cs b/Drawing/DrawOps/UndoDrawOp.cs index bb3d4ab94..c14d9d8f5 100644 --- a/Drawing/DrawOps/UndoDrawOp.cs +++ b/Drawing/DrawOps/UndoDrawOp.cs @@ -94,7 +94,7 @@ namespace MCGalaxy.Drawing.Ops { public override string Name { get { return "UndoPhysics"; } } public override bool AffectedByTransform { get { return false; } } - internal long seconds; + internal DateTime Start; public override long BlocksAffected(Level lvl, Vec3S32[] marks) { return -1; } @@ -103,30 +103,30 @@ namespace MCGalaxy.Drawing.Ops { int count = lvl.currentUndo; for (int i = count; i >= 0; i--) { try { - if (!CheckBlockPhysics(p, lvl, seconds, i)) break; + if (!CheckBlockPhysics(p, lvl, i)) break; } catch { } } } else { int count = lvl.currentUndo; for (int i = count; i >= 0; i--) { try { - if (!CheckBlockPhysics(p, lvl, seconds, i)) break; + if (!CheckBlockPhysics(p, lvl, i)) break; } catch { } } for (int i = lvl.UndoBuffer.Count - 1; i > count; i--) { try { - if (!CheckBlockPhysics(p, lvl, seconds, i)) break; + if (!CheckBlockPhysics(p, lvl, i)) break; } catch { } } } yield break; } - bool CheckBlockPhysics(Player p, Level lvl, long seconds, int i) { + bool CheckBlockPhysics(Player p, Level lvl, int i) { Level.UndoPos undo = lvl.UndoBuffer[i]; byte b = lvl.GetTile(undo.index); DateTime time = Server.StartTime.AddTicks((undo.flags >> 2) * TimeSpan.TicksPerSecond); - if (time.AddTicks(seconds * TimeSpan.TicksPerSecond) < DateTime.UtcNow) return false; + if (time < Start) return false; byte newType = (undo.flags & 2) != 0 ? Block.custom_block : undo.newRawType; if (b == newType || Block.Convert(b) == Block.water || Block.Convert(b) == Block.lava) { diff --git a/Player/Player.Fields.cs b/Player/Player.Fields.cs index 18bce4878..6bd367f76 100644 --- a/Player/Player.Fields.cs +++ b/Player/Player.Fields.cs @@ -84,7 +84,7 @@ namespace MCGalaxy { DateTime startTime; public TimeSpan time { get { return DateTime.UtcNow - startTime; } - set { startTime = DateTime.UtcNow.Add(-value); } + set { startTime = DateTime.UtcNow.Subtract(value); } } public string name; diff --git a/util/TimeUtils.cs b/util/TimeUtils.cs index f9fe4e08d..26aedb554 100644 --- a/util/TimeUtils.cs +++ b/util/TimeUtils.cs @@ -29,7 +29,7 @@ namespace MCGalaxy { Add(ref time, value.Days, 'd', spaces); Add(ref time, value.Hours, 'h', spaces); Add(ref time, value.Minutes, 'm', spaces); - if (seconds && value.Days < 1) + if (value.TotalMinutes <= 1 || (seconds && value.Days < 1)) Add(ref time, value.Seconds, 's', spaces); if (time == "") time = seconds ? "0s" : "0m";