Update /undo and /highlight code to work between a given start and end time.

This commit is contained in:
UnknownShadow200 2016-03-23 17:17:27 +11:00
parent 5c31e47667
commit 764bc394be
11 changed files with 58 additions and 107 deletions

View File

@ -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");

View File

@ -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);

View File

@ -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);

View File

@ -26,7 +26,12 @@ namespace MCGalaxy.Drawing.Ops {
public override string Name { get { return "UndoOnline"; } }
internal long seconds;
/// <summary> Point in time that the /undo should go backwards up to. </summary>
public DateTime Start = DateTime.MinValue;
/// <summary> Point in time that the /undo should start updating blocks. </summary>
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;
/// <summary> Point in time that the /undo should go backwards up to. </summary>
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);
}
}

View File

@ -480,7 +480,6 @@
<Compile Include="Player\Player.Handlers.cs" />
<Compile Include="Player\PlayerInfo.cs" />
<Compile Include="Player\Undo\UndoCache.cs" />
<Compile Include="Player\Undo\UndoDrawOpEntry.cs" />
<Compile Include="Player\Waypoint.cs" />
<Compile Include="Player\Player.Timers.cs" />
<Compile Include="Player\Undo\UndoFile.cs" />

View File

@ -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]);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}
}

View File

@ -34,9 +34,9 @@ namespace MCGalaxy.Util {
protected abstract void ReadUndoData(List<Player.UndoPos> 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;

View File

@ -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<ChunkHeader> list = new List<ChunkHeader>();
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<ChunkHeader> list = new List<ChunkHeader>();
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;
}

View File

@ -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;
}
}
}