diff --git a/Commands/Moderation/CmdHighlight.cs b/Commands/Moderation/CmdHighlight.cs
index 3f572604d..ae0ad06bb 100644
--- a/Commands/Moderation/CmdHighlight.cs
+++ b/Commands/Moderation/CmdHighlight.cs
@@ -56,7 +56,8 @@ namespace MCGalaxy.Commands {
PerformHighlight(p, seconds, who.UndoBuffer);
}
- UndoFile.HighlightPlayer(p, name.ToLower(), seconds, ref FoundUser);
+ DateTime start = DateTime.UtcNow.AddTicks(-seconds * TimeSpan.TicksPerSecond);
+ UndoFile.HighlightPlayer(p, name.ToLower(), start, ref FoundUser);
if (FoundUser) {
Player.SendMessage(p, "Now highlighting &b" + seconds + " %Sseconds for " + Server.FindColor(name) + name);
Player.SendMessage(p, "&cUse /reload to un-highlight");
diff --git a/Commands/building/CmdUndo.cs b/Commands/building/CmdUndo.cs
index da5d01cb6..5b55d6184 100644
--- a/Commands/building/CmdUndo.cs
+++ b/Commands/building/CmdUndo.cs
@@ -94,7 +94,7 @@ namespace MCGalaxy.Commands
}
UndoOnlineDrawOp op = new UndoOnlineDrawOp();
- op.seconds = seconds;
+ op.Start = DateTime.UtcNow.AddTicks(-seconds * TimeSpan.TicksPerSecond);
op.who = who;
op.Perform(null, p, null, null);
@@ -114,7 +114,7 @@ namespace MCGalaxy.Commands
}
UndoOfflineDrawOp op = new UndoOfflineDrawOp();
- op.seconds = seconds;
+ op.Start = DateTime.UtcNow.AddTicks(-seconds * TimeSpan.TicksPerSecond);
op.whoName = whoName;
op.Perform(null, p, null, null);
diff --git a/Drawing/DrawOps/DrawOp.cs b/Drawing/DrawOps/DrawOp.cs
index c1981da33..98ff42bc2 100644
--- a/Drawing/DrawOps/DrawOp.cs
+++ b/Drawing/DrawOps/DrawOp.cs
@@ -160,20 +160,18 @@ namespace MCGalaxy.Drawing.Ops {
UndoDrawOpEntry entry = new UndoDrawOpEntry();
entry.DrawOpName = op.Name;
entry.LevelName = p.level.name;
- entry.SetStart(p);
- DateTime start = DateTime.UtcNow;
+ entry.Start = DateTime.UtcNow;
bool needReveal = op.DetermineDrawOpMethod(p.level, affected);
op.Perform(marks, p, p.level, brush);
- entry.SetEnd(p);
+ entry.End = DateTime.UtcNow;
- if (start > p.UndoBuffer.LastClear) {
+ if (entry.Start > p.UndoBuffer.LastClear) {
UndoDrawOpEntry[] items = p.UndoDrawOps.Items;
if (items.Length == 20)
p.UndoDrawOps.Remove(items[0]);
} else { // UndoBuffer has been cleared during the draw op.
- entry.StartNode = p.UndoBuffer.Head;
- entry.StartIndex = 0;
+ entry.Start = p.UndoBuffer.LastClear;
p.RemoveInvalidUndos();
}
p.UndoDrawOps.Add(entry);
diff --git a/Drawing/DrawOps/UndoDrawOp.cs b/Drawing/DrawOps/UndoDrawOp.cs
index 126c00067..6d63da806 100644
--- a/Drawing/DrawOps/UndoDrawOp.cs
+++ b/Drawing/DrawOps/UndoDrawOp.cs
@@ -26,7 +26,12 @@ namespace MCGalaxy.Drawing.Ops {
public override string Name { get { return "UndoOnline"; } }
- internal long seconds;
+ /// Point in time that the /undo should go backwards up to.
+ public DateTime Start = DateTime.MinValue;
+
+ /// Point in time that the /undo should start updating blocks.
+ public DateTime End = DateTime.MaxValue;
+
internal Player who;
internal Level saveLevel = null;
@@ -35,7 +40,7 @@ namespace MCGalaxy.Drawing.Ops {
public override void Perform(Vector3U16[] marks, Player p, Level lvl, Brush brush) {
PerformUndo(p, ref saveLevel);
bool foundUser = false;
- UndoFile.UndoPlayer(p, who.name.ToLower(), seconds, ref foundUser);
+ UndoFile.UndoPlayer(p, who.name.ToLower(), Start, ref foundUser);
}
void PerformUndo(Player p, ref Level saveLvl) {
@@ -54,8 +59,9 @@ namespace MCGalaxy.Drawing.Ops {
UndoCacheItem item = items[i];
ushort x, y, z;
node.Unpack(item.Index, out x, out y, out z);
- DateTime time = node.BaseTime.AddTicks((item.TimeDelta + seconds) * TimeSpan.TicksPerSecond);
- if (time < DateTime.UtcNow) { buffer.CheckIfSend(true); return; }
+ DateTime time = node.BaseTime.AddTicks(item.TimeDelta * TimeSpan.TicksPerSecond);
+ if (time > End) continue;
+ if (time < Start) { buffer.CheckIfSend(true); return; }
byte b = lvl.GetTile(x, y, z);
byte newTile = 0, newExtTile = 0;
@@ -91,14 +97,16 @@ namespace MCGalaxy.Drawing.Ops {
public override string Name { get { return "UndoOffline"; } }
- internal long seconds;
+ /// Point in time that the /undo should go backwards up to.
+ public DateTime Start = DateTime.MinValue;
+
internal string whoName;
internal bool foundUser = false;
public override int GetBlocksAffected(Level lvl, Vector3U16[] marks) { return 0; }
public override void Perform(Vector3U16[] marks, Player p, Level lvl, Brush brush) {
- UndoFile.UndoPlayer(p, whoName.ToLower(), seconds, ref foundUser);
+ UndoFile.UndoPlayer(p, whoName.ToLower(), Start, ref foundUser);
}
}
diff --git a/MCGalaxy_.csproj b/MCGalaxy_.csproj
index 6056a955c..80ea4f160 100644
--- a/MCGalaxy_.csproj
+++ b/MCGalaxy_.csproj
@@ -480,7 +480,6 @@
-
diff --git a/Player/Player.cs b/Player/Player.cs
index b9ed6ec7a..51a114e71 100644
--- a/Player/Player.cs
+++ b/Player/Player.cs
@@ -951,7 +951,7 @@ Next: continue;
internal void RemoveInvalidUndos() {
UndoDrawOpEntry[] items = UndoDrawOps.Items;
for (int i = 0; i < items.Length; i++) {
- if (!items[i].IsValid(this))
+ if (items[i].End < UndoBuffer.LastClear)
UndoDrawOps.Remove(items[i]);
}
}
diff --git a/Player/Undo/UndoCache.cs b/Player/Undo/UndoCache.cs
index dff418c04..6488aadde 100644
--- a/Player/Undo/UndoCache.cs
+++ b/Player/Undo/UndoCache.cs
@@ -19,7 +19,6 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
-using System.Threading;
namespace MCGalaxy.Util {
@@ -101,7 +100,7 @@ namespace MCGalaxy.Util {
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct UndoCacheItem {
public int Index;
- public byte Type, NewType;
+ public byte Type, NewType;
public ushort Flags; // upper 2 bits for 'ext' or 'physics' type, lower 14 bits for time delta.
public short TimeDelta {
@@ -141,7 +140,7 @@ namespace MCGalaxy.Util {
item.Flags |= (ushort)(1 << 14);
} else {
item.Type = pos.type;
- }
+ }
if (pos.newtype == Block.custom_block) {
item.NewType = pos.newExtType;
item.Flags |= (ushort)(1 << 15);
@@ -151,4 +150,10 @@ namespace MCGalaxy.Util {
return item;
}
}
+
+ public sealed class UndoDrawOpEntry {
+ public string DrawOpName;
+ public string LevelName;
+ public DateTime Start, End;
+ }
}
diff --git a/Player/Undo/UndoDrawOpEntry.cs b/Player/Undo/UndoDrawOpEntry.cs
deleted file mode 100644
index de0082c3f..000000000
--- a/Player/Undo/UndoDrawOpEntry.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- Copyright 2015 MCGalaxy
-
- Dual-licensed under the Educational Community License, Version 2.0 and
- the GNU General Public License, Version 3 (the "Licenses"); you may
- not use this file except in compliance with the Licenses. You may
- obtain a copy of the Licenses at
-
- http://www.opensource.org/licenses/ecl2.php
- http://www.gnu.org/licenses/gpl-3.0.html
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the Licenses are distributed on an "AS IS"
- BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- or implied. See the Licenses for the specific language governing
- permissions and limitations under the Licenses.
- */
-using System;
-
-namespace MCGalaxy.Util {
-
- public class UndoDrawOpEntry {
-
- public string DrawOpName;
- public string LevelName;
- public UndoCacheNode StartNode;
- public int StartIndex;
- public UndoCacheNode EndNode;
- public int EndIndex;
-
- public void SetStart(Player p) {
- StartNode = p.UndoBuffer.Tail;
- if (StartNode != null)
- StartIndex = StartNode.Items.Count;
- }
-
- public void SetEnd(Player p) {
- EndNode = p.UndoBuffer.Tail;
- if (EndNode != null)
- EndIndex = EndNode.Items.Count;
- }
-
- public bool IsValid(Player p) {
- UndoCache buffer = p.UndoBuffer;
- if (p.UndoBuffer.Tail == null) return false;
-
- UndoCacheNode node = p.UndoBuffer.Tail;
- while ((node = node.Prev) != null) {
- if (node == EndNode) return true;
- }
- return false;
- }
- }
-}
diff --git a/Player/Undo/UndoFile.cs b/Player/Undo/UndoFile.cs
index d926dfc7f..40792ffeb 100644
--- a/Player/Undo/UndoFile.cs
+++ b/Player/Undo/UndoFile.cs
@@ -34,9 +34,9 @@ namespace MCGalaxy.Util {
protected abstract void ReadUndoData(List buffer, string path);
- protected abstract bool UndoEntry(Player p, string path, ref byte[] temp, long seconds);
+ protected abstract bool UndoEntry(Player p, string path, ref byte[] temp, DateTime start);
- protected abstract bool HighlightEntry(Player p, string path, ref byte[] temp, long seconds);
+ protected abstract bool HighlightEntry(Player p, string path, ref byte[] temp, DateTime start);
protected abstract string Extension { get; }
@@ -59,17 +59,17 @@ namespace MCGalaxy.Util {
NewFormat.SaveUndoData(p.UndoBuffer, path);
}
- public static void UndoPlayer(Player p, string targetName, long seconds, ref bool FoundUser) {
- FilterEntries(p, undoDir, targetName, seconds, false, ref FoundUser);
- FilterEntries(p, prevUndoDir, targetName, seconds, false, ref FoundUser);
+ public static void UndoPlayer(Player p, string targetName, DateTime start, ref bool FoundUser) {
+ FilterEntries(p, undoDir, targetName, start, false, ref FoundUser);
+ FilterEntries(p, prevUndoDir, targetName, start, false, ref FoundUser);
}
- public static void HighlightPlayer(Player p, string targetName, long seconds, ref bool FoundUser) {
- FilterEntries(p, undoDir, targetName, seconds, true, ref FoundUser);
- FilterEntries(p, prevUndoDir, targetName, seconds, true, ref FoundUser);
+ public static void HighlightPlayer(Player p, string targetName, DateTime start, ref bool FoundUser) {
+ FilterEntries(p, undoDir, targetName, start, true, ref FoundUser);
+ FilterEntries(p, prevUndoDir, targetName, start, true, ref FoundUser);
}
- static void FilterEntries(Player p, string dir, string name, long seconds, bool highlight, ref bool FoundUser) {
+ static void FilterEntries(Player p, string dir, string name, DateTime start, bool highlight, ref bool FoundUser) {
string path = Path.Combine(dir, name);
if (!Directory.Exists(path))
return;
@@ -89,9 +89,9 @@ namespace MCGalaxy.Util {
if (format == null) continue;
if (highlight) {
- if (!format.HighlightEntry(p, path, ref temp, seconds)) break;
+ if (!format.HighlightEntry(p, path, ref temp, start)) break;
} else {
- if (!format.UndoEntry(p, path, ref temp, seconds)) break;
+ if (!format.UndoEntry(p, path, ref temp, start)) break;
}
}
FoundUser = true;
diff --git a/Player/Undo/UndoFileBin.cs b/Player/Undo/UndoFileBin.cs
index e4e836f94..904f50a86 100644
--- a/Player/Undo/UndoFileBin.cs
+++ b/Player/Undo/UndoFileBin.cs
@@ -116,13 +116,11 @@ namespace MCGalaxy.Util {
}
}
- protected override bool UndoEntry(Player p, string path, ref byte[] temp, long seconds) {
+ protected override bool UndoEntry(Player p, string path, ref byte[] temp, DateTime start) {
List list = new List();
- DateTime now = DateTime.UtcNow;
int timeDelta = (int)DateTime.UtcNow.Subtract(Server.StartTime).TotalSeconds;
Player.UndoPos Pos;
bool isPlayer = p != null && p.group.Permission < LevelPermission.Nobody;
- seconds *= TimeSpan.TicksPerSecond;
using (Stream fs = File.OpenRead(path))
using (BinaryReader r = new BinaryReader(fs))
@@ -131,7 +129,7 @@ namespace MCGalaxy.Util {
for (int i = list.Count - 1; i >= 0; i--) {
ChunkHeader chunk = list[i];
Level lvl;
- if (!CheckChunk(chunk, now, seconds, p, out lvl))
+ if (!CheckChunk(chunk, start, p, out lvl))
return false;
if (lvl == null || (isPlayer && lvl != p.level)) continue;
BufferedBlockSender buffer = new BufferedBlockSender(lvl);
@@ -144,7 +142,7 @@ namespace MCGalaxy.Util {
for (int j = chunk.Entries - 1; j >= 0; j-- ) {
int offset = j * entrySize;
DateTime time = chunk.BaseTime.AddTicks(U16(temp, offset + 0) * TimeSpan.TicksPerSecond);
- if (time.AddTicks(seconds) < now) { buffer.CheckIfSend(true); return false; }
+ if (time < start) { buffer.CheckIfSend(true); return false; }
Pos.x = U16(temp, offset + 2); Pos.y = U16(temp, offset + 4); Pos.z = U16(temp, offset + 6);
Pos.type = lvl.GetTile(Pos.x, Pos.y, Pos.z);
@@ -169,10 +167,8 @@ namespace MCGalaxy.Util {
return true;
}
- protected override bool HighlightEntry(Player p, string path, ref byte[] temp, long seconds) {
+ protected override bool HighlightEntry(Player p, string path, ref byte[] temp, DateTime start) {
List list = new List();
- DateTime now = DateTime.UtcNow;
- seconds *= TimeSpan.TicksPerSecond;
using (Stream fs = File.OpenRead(path))
using (BinaryReader r = new BinaryReader(fs))
@@ -181,7 +177,7 @@ namespace MCGalaxy.Util {
for (int i = list.Count - 1; i >= 0; i--) {
ChunkHeader chunk = list[i];
Level lvl;
- if (!CheckChunk(chunk, now, seconds, p, out lvl))
+ if (!CheckChunk(chunk, start, p, out lvl))
return false;
if (lvl == null || lvl != p.level) continue;
@@ -192,7 +188,7 @@ namespace MCGalaxy.Util {
for (int j = chunk.Entries - 1; j >= 0; j-- ) {
int offset = j * entrySize;
DateTime time = chunk.BaseTime.AddTicks(U16(temp, offset + 0) * TimeSpan.TicksPerSecond);
- if (time.AddTicks(seconds) < now) return false;
+ if (time < start) return false;
ushort x = U16(temp, offset + 2), y = U16(temp, offset + 4), z = U16(temp, offset + 6);
byte lvlTile = lvl.GetTile(x, y, z);
@@ -215,12 +211,11 @@ namespace MCGalaxy.Util {
return (ushort)(buffer[offset + 0] | buffer[offset + 1] << 8);
}
- static bool CheckChunk(ChunkHeader chunk, DateTime now, long ticks, Player p, out Level lvl) {
+ static bool CheckChunk(ChunkHeader chunk, DateTime start, Player p, out Level lvl) {
DateTime time = chunk.BaseTime;
lvl = null;
- if (time.AddTicks(65536 * TimeSpan.TicksPerSecond + ticks) < now)
- return false; // we can safely discard the entire chunk
-
+ if (time.AddTicks(65536 * TimeSpan.TicksPerSecond) < start)
+ return false; // we can safely discard the entire chunk
lvl = LevelInfo.FindExact(chunk.LevelName);
return true;
}
diff --git a/Player/Undo/UndoFileText.cs b/Player/Undo/UndoFileText.cs
index a96d2245f..5c3a8d48f 100644
--- a/Player/Undo/UndoFileText.cs
+++ b/Player/Undo/UndoFileText.cs
@@ -67,7 +67,7 @@ namespace MCGalaxy.Util {
}
}
- protected override bool UndoEntry(Player p, string path, ref byte[] temp, long seconds) {
+ protected override bool UndoEntry(Player p, string path, ref byte[] temp, DateTime start) {
Player.UndoPos Pos;
int timeDelta = (int)DateTime.UtcNow.Subtract(Server.StartTime).TotalSeconds;
Pos.extType = 0; Pos.newExtType = 0;
@@ -77,7 +77,7 @@ namespace MCGalaxy.Util {
for (int i = (lines.Length - 1) / 7; i >= 0; i--) {
try {
// line format: mapName x y z date oldblock newblock
- if (!InTime(lines[(i * 7) - 3], seconds)) return false;
+ if (!InTime(lines[(i * 7) - 3], start)) return false;
Level lvl = LevelInfo.FindExact(lines[(i * 7) - 7]);
if (lvl == null) continue;
@@ -102,7 +102,7 @@ namespace MCGalaxy.Util {
return true;
}
- protected override bool HighlightEntry(Player p, string path, ref byte[] temp, long seconds) {
+ protected override bool HighlightEntry(Player p, string path, ref byte[] temp, DateTime start) {
Player.UndoPos Pos;
Pos.extType = 0; Pos.newExtType = 0;
string[] lines = File.ReadAllText(path).Split(' ');
@@ -110,7 +110,7 @@ namespace MCGalaxy.Util {
for (int i = (lines.Length - 1) / 7; i >= 0; i--) {
try {
// line format: mapName x y z date oldblock newblock
- if (!InTime(lines[(i * 7) - 3], seconds)) return false;
+ if (!InTime(lines[(i * 7) - 3], start)) return false;
Level foundLevel = LevelInfo.FindExact(lines[(i * 7) - 7]);
if (foundLevel == null || foundLevel != p.level) continue;
@@ -133,11 +133,10 @@ namespace MCGalaxy.Util {
return true;
}
- static bool InTime(string line, long seconds) {
+ static bool InTime(string line, DateTime start) {
line = line.Replace('&', ' ');
- DateTime time = DateTime.Parse(line, CultureInfo.InvariantCulture)
- .AddSeconds(seconds);
- return time >= DateTime.Now;
+ DateTime time = DateTime.Parse(line, CultureInfo.InvariantCulture);
+ return time >= start;
}
}
}