From 075e99f118dad702f40d737e1df0941108c68157 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Fri, 19 Aug 2016 23:55:26 +1000 Subject: [PATCH] [Major WIP] Rewrite UndoFile classes to be much more extensible. --- Player/Undo/UndoFile.cs | 33 +++---- Player/Undo/UndoFileBin.cs | 138 ++++++---------------------- Player/Undo/UndoFileCBin.cs | 177 +++++++++--------------------------- Player/Undo/UndoFileText.cs | 113 +++++------------------ 4 files changed, 112 insertions(+), 349 deletions(-) diff --git a/Player/Undo/UndoFile.cs b/Player/Undo/UndoFile.cs index f2ea3f2a7..27b079042 100644 --- a/Player/Undo/UndoFile.cs +++ b/Player/Undo/UndoFile.cs @@ -29,17 +29,18 @@ namespace MCGalaxy.Util { public static UndoFile BinFormat = new UndoFileBin(); public static UndoFile NewFormat = new UndoFileCBin(); + protected class UndoEntriesArgs { + public Player Player; + public byte[] Temp; + public bool Stop; + public DateTime StartRange; + } + protected abstract void SaveUndoData(List buffer, string path); protected abstract void SaveUndoData(UndoCache buffer, string path); - - protected abstract void ReadUndoData(List buffer, string path); - protected abstract bool UndoEntry(Player p, string path, Vec3S32[] marks, - ref byte[] temp, DateTime start); - - protected abstract bool HighlightEntry(Player p, string path, - ref byte[] temp, DateTime start); + protected abstract IEnumerable GetEntries(Stream s, UndoEntriesArgs args); protected abstract string Extension { get; } @@ -66,8 +67,8 @@ namespace MCGalaxy.Util { } using (IDisposable locker = cache.ClearLock.AccquireWriteLock()) { - lock (cache.AddLock) - cache.Clear(); + lock (cache.AddLock) + cache.Clear(); } } @@ -138,17 +139,17 @@ namespace MCGalaxy.Util { buffer.CheckIfSend(false); } } else { - bool diffBlock = Block.Convert(lvlTile) != Block.Convert(P.newtype); + bool diffBlock = Block.Convert(lvlTile) != Block.Convert(P.newtype); if (!diffBlock && lvlTile == Block.custom_block) - diffBlock = lvl.GetExtTile(P.x, P.y, P.z) != P.newExtType; + diffBlock = lvl.GetExtTile(P.x, P.y, P.z) != P.newExtType; - if (diffBlock) { + if (diffBlock) { buffer.Add(lvl.PosToInt(P.x, P.y, P.z), P.newtype, P.newExtType); buffer.CheckIfSend(false); } lvl.SetTile(P.x, P.y, P.z, P.newtype); if (P.newtype == Block.custom_block) - lvl.SetExtTile(P.x, P.y, P.z, P.newExtType); + lvl.SetExtTile(P.x, P.y, P.z, P.newExtType); } } } @@ -156,9 +157,9 @@ namespace MCGalaxy.Util { protected static void HighlightBlock(Player p, Level lvl, byte type, byte newType, ushort x, ushort y, ushort z) { byte block = (newType == Block.air - || Block.Convert(type) == Block.water || type == Block.waterstill - || Block.Convert(type) == Block.lava || type == Block.lavastill) - ? Block.red : Block.green; + || Block.Convert(type) == Block.water || type == Block.waterstill + || Block.Convert(type) == Block.lava || type == Block.lavastill) + ? Block.red : Block.green; p.SendBlockchange(x, y, z, block); } diff --git a/Player/Undo/UndoFileBin.cs b/Player/Undo/UndoFileBin.cs index 174ca65ed..672fa9a57 100644 --- a/Player/Undo/UndoFileBin.cs +++ b/Player/Undo/UndoFileBin.cs @@ -19,7 +19,6 @@ using System; using System.Collections.Generic; using System.IO; using System.Text; -using MCGalaxy.Drawing; namespace MCGalaxy.Util { @@ -36,123 +35,46 @@ namespace MCGalaxy.Util { throw new NotSupportedException("Non-optimised binary undo files have been deprecated"); } - protected override void ReadUndoData(List buffer, string path) { - Player.UndoPos Pos; - using (Stream fs = File.OpenRead(path)) - using (BinaryReader r = new BinaryReader(fs)) - { - int approxEntries = (int)(fs.Length / entrySize); - if (buffer.Capacity < approxEntries) - buffer.Capacity = approxEntries; - while (fs.Position < fs.Length) { - ChunkHeader chunk = ReadHeader(fs, r); - Pos.mapName = chunk.LevelName; - - for (int j = 0; j < chunk.Entries; j++ ) { - DateTime rawTime = chunk.BaseTime.AddSeconds(r.ReadUInt16()); - Pos.timeDelta = (int)rawTime.Subtract(Server.StartTime).TotalSeconds; - Pos.x = r.ReadUInt16(); Pos.y = r.ReadUInt16(); Pos.z = r.ReadUInt16(); - Pos.type = r.ReadByte(); Pos.extType = r.ReadByte(); - Pos.newtype = r.ReadByte(); Pos.newExtType = r.ReadByte(); - buffer.Add(Pos); - } - } - } - } - - protected override bool UndoEntry(Player p, string path, Vec3S32[] marks, - ref byte[] temp, DateTime start) { + protected override IEnumerable GetEntries(Stream s, UndoEntriesArgs args) { List list = new List(); - int timeDelta = (int)DateTime.UtcNow.Subtract(Server.StartTime).TotalSeconds; - Player.UndoPos Pos = default(Player.UndoPos); - Vec3U16 min = (Vec3U16)marks[0], max = (Vec3U16)marks[1]; - bool undoArea = min.X != ushort.MaxValue; + Player.UndoPos pos = default(Player.UndoPos); + bool super = args.Player == null || args.Player.ircNick != null; + DateTime start = args.StartRange; - using (Stream fs = File.OpenRead(path)) - using (BinaryReader r = new BinaryReader(fs)) - { - ReadHeaders(list, r); - for (int i = list.Count - 1; i >= 0; i--) { - ChunkHeader chunk = list[i]; - Level lvl; - if (!CheckChunk(chunk, start, p, out lvl)) return false; - if (lvl == null) continue; - bool super = p == null || p.ircNick != null; - if (!super && !p.level.name.CaselessEq(lvl.name)) continue; + ReadHeaders(list, s); + for (int i = list.Count - 1; i >= 0; i--) { + ChunkHeader chunk = list[i]; + // Can we safely discard the entire chunk? + bool inRange = chunk.BaseTime.AddTicks(65536 * TimeSpan.TicksPerSecond) >= start; + if (!inRange) { args.Stop = true; yield break; } + if (!super && !args.Player.level.name.CaselessEq(chunk.LevelName)) continue; + + s.Seek(chunk.DataPosition, SeekOrigin.Begin); + if (args.Temp == null) + args.Temp = new byte[ushort.MaxValue * entrySize]; + s.Read(args.Temp, 0, chunk.Entries * entrySize); + byte[] temp = args.Temp; + + 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 < start) { args.Stop = true; yield break; } - BufferedBlockSender buffer = new BufferedBlockSender(lvl); - if (!undoArea) { - min = new Vec3U16(0, 0, 0); - max = new Vec3U16((ushort)(lvl.Width - 1), (ushort)(lvl.Height - 1), (ushort)(lvl.Length - 1)); - } + pos.x = U16(temp, offset + 2); + pos.y = U16(temp, offset + 4); + pos.z = U16(temp, offset + 6); - Pos.mapName = chunk.LevelName; - fs.Seek(chunk.DataPosition, SeekOrigin.Begin); - if (temp == null) temp = new byte[ushort.MaxValue * entrySize]; - fs.Read(temp, 0, chunk.Entries * entrySize); - - 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 < start) { buffer.CheckIfSend(true); return false; } - Pos.x = U16(temp, offset + 2); Pos.y = U16(temp, offset + 4); Pos.z = U16(temp, offset + 6); - if (Pos.x < min.X || Pos.y < min.Y || Pos.z < min.Z || - Pos.x > max.X || Pos.y > max.Y || Pos.z > max.Z) continue; - - Pos.type = temp[offset + 8]; Pos.extType = temp[offset + 9]; - Pos.newtype = temp[offset + 10]; Pos.newExtType = temp[offset + 11]; - UndoBlock(p, lvl, Pos, timeDelta, buffer); - } - buffer.CheckIfSend(true); + pos.type = temp[offset + 8]; pos.extType = temp[offset + 9]; + pos.newtype = temp[offset + 10]; pos.newExtType = temp[offset + 11]; + yield return pos; } } - return true; - } - - protected override bool HighlightEntry(Player p, string path, - ref byte[] temp, DateTime start) { - List list = new List(); - - using (Stream fs = File.OpenRead(path)) - using (BinaryReader r = new BinaryReader(fs)) - { - ReadHeaders(list, r); - for (int i = list.Count - 1; i >= 0; i--) { - ChunkHeader chunk = list[i]; - Level lvl; - if (!CheckChunk(chunk, start, p, out lvl)) - return false; - if (lvl == null || lvl != p.level) continue; - - fs.Seek(chunk.DataPosition, SeekOrigin.Begin); - if (temp == null) temp = new byte[ushort.MaxValue * entrySize]; - fs.Read(temp, 0, chunk.Entries * entrySize); - - 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 < start) return false; - ushort x = U16(temp, offset + 2), y = U16(temp, offset + 4), z = U16(temp, offset + 6); - HighlightBlock(p, lvl, temp[offset + 8], temp[offset + 10], x, y, z); - } - } - } - return true; } static ushort U16(byte[] buffer, int offset) { return (ushort)(buffer[offset + 0] | buffer[offset + 1] << 8); } - static bool CheckChunk(ChunkHeader chunk, DateTime start, Player p, out Level lvl) { - DateTime time = chunk.BaseTime; - lvl = null; - if (time.AddTicks(65536 * TimeSpan.TicksPerSecond) < start) - return false; // we can safely discard the entire chunk - lvl = LevelInfo.FindExact(chunk.LevelName); - return true; - } - struct ChunkHeader { public string LevelName; public DateTime BaseTime; @@ -160,8 +82,8 @@ namespace MCGalaxy.Util { public long DataPosition; } - static void ReadHeaders(List list, BinaryReader r) { - Stream s = r.BaseStream; + static void ReadHeaders(List list, Stream s) { + BinaryReader r = new BinaryReader(s); long len = s.Length; while (s.Position < len) { ChunkHeader header = ReadHeader(s, r); diff --git a/Player/Undo/UndoFileCBin.cs b/Player/Undo/UndoFileCBin.cs index 79f22bb9b..11ef15b9f 100644 --- a/Player/Undo/UndoFileCBin.cs +++ b/Player/Undo/UndoFileCBin.cs @@ -19,7 +19,6 @@ using System; using System.Collections.Generic; using System.IO; using System.Text; -using MCGalaxy.Drawing; using MCGalaxy.Levels.IO; namespace MCGalaxy.Util { @@ -98,130 +97,47 @@ namespace MCGalaxy.Util { } } } - - protected override void ReadUndoData(List buffer, string path) { - Player.UndoPos Pos; - UndoCacheItem item = default(UndoCacheItem); - using (Stream fs = File.OpenRead(path)) - using (BinaryReader r = new BinaryReader(fs)) - { - int approxEntries = (int)(fs.Length / entrySize); - if (buffer.Capacity < approxEntries) - buffer.Capacity = approxEntries; - while (fs.Position < fs.Length) { - ChunkHeader chunk = ReadHeader(fs, r); - Pos.mapName = chunk.LevelName; - - for (int j = 0; j < chunk.Entries; j++ ) { - item.Flags = r.ReadUInt16(); - DateTime time = chunk.BaseTime.AddTicks((item.Flags & 0x3FFF) * TimeSpan.TicksPerSecond); - Pos.timeDelta = (int)time.Subtract(Server.StartTime).TotalSeconds; - int index = r.ReadInt32(); - Pos.x = (ushort)(index % chunk.Width); - Pos.y = (ushort)((index / chunk.Width) / chunk.Length); - Pos.z = (ushort)((index / chunk.Width) % chunk.Length); - - item.Type = r.ReadByte(); - item.NewType = r.ReadByte(); - item.GetBlock(out Pos.type, out Pos.extType); - item.GetNewBlock(out Pos.newtype, out Pos.newExtType); - buffer.Add(Pos); - } - } - } - } - - protected override bool UndoEntry(Player p, string path, Vec3S32[] marks, - ref byte[] temp, DateTime start) { - List list = new List(); - int timeDelta = (int)DateTime.UtcNow.Subtract(Server.StartTime).TotalSeconds; - Player.UndoPos Pos = default(Player.UndoPos); - Vec3U16 min = (Vec3U16)marks[0], max = (Vec3U16)marks[1]; - bool undoArea = min.X != ushort.MaxValue; - UndoCacheItem item = default(UndoCacheItem); - - using (Stream fs = File.OpenRead(path)) - using (BinaryReader r = new BinaryReader(fs)) - { - ReadHeaders(list, r); - for (int i = list.Count - 1; i >= 0; i--) { - ChunkHeader chunk = list[i]; - Level lvl; - if (!CheckChunk(chunk, start, p, out lvl)) return false; - if (lvl == null) continue; - bool super = p == null || p.ircNick != null; - if (!super && !p.level.name.CaselessEq(lvl.name)) continue; - - BufferedBlockSender buffer = new BufferedBlockSender(lvl); - if (!undoArea) { - min = new Vec3U16(0, 0, 0); - max = new Vec3U16((ushort)(lvl.Width - 1), (ushort)(lvl.Height - 1), (ushort)(lvl.Length - 1)); - } - - Pos.mapName = chunk.LevelName; - fs.Seek(chunk.DataPosition, SeekOrigin.Begin); - if (temp == null) temp = new byte[ushort.MaxValue * entrySize]; - fs.Read(temp, 0, chunk.Entries * entrySize); - - for (int j = chunk.Entries - 1; j >= 0; j-- ) { - int offset = j * entrySize; - item.Flags = U16(temp, offset + 0); - DateTime time = chunk.BaseTime.AddTicks((item.Flags & 0x3FFF) * TimeSpan.TicksPerSecond); - if (time < start) { buffer.CheckIfSend(true); return false; } - - int index = I32(temp, offset + 2); - Pos.x = (ushort)(index % chunk.Width); - Pos.y = (ushort)((index / chunk.Width) / chunk.Length); - Pos.z = (ushort)((index / chunk.Width) % chunk.Length); - if (Pos.x < min.X || Pos.y < min.Y || Pos.z < min.Z || - Pos.x > max.X || Pos.y > max.Y || Pos.z > max.Z) continue; - - item.Type = temp[offset + 6]; - item.NewType = temp[offset + 7]; - item.GetBlock(out Pos.type, out Pos.extType); - item.GetNewBlock(out Pos.newtype, out Pos.newExtType); - UndoBlock(p, lvl, Pos, timeDelta, buffer); - } - buffer.CheckIfSend(true); - } - } - return true; - } - protected override bool HighlightEntry(Player p, string path, - ref byte[] temp, DateTime start) { + protected override IEnumerable GetEntries(Stream s, UndoEntriesArgs args) { List list = new List(); - - using (Stream fs = File.OpenRead(path)) - using (BinaryReader r = new BinaryReader(fs)) - { - ReadHeaders(list, r); - for (int i = list.Count - 1; i >= 0; i--) { - ChunkHeader chunk = list[i]; - Level lvl; - if (!CheckChunk(chunk, start, p, out lvl)) - return false; - if (lvl == null || lvl != p.level) continue; + Player.UndoPos pos = default(Player.UndoPos); + UndoCacheItem item = default(UndoCacheItem); + bool super = args.Player == null || args.Player.ircNick != null; + DateTime start = args.StartRange; + + ReadHeaders(list, s); + for (int i = list.Count - 1; i >= 0; i--) { + ChunkHeader chunk = list[i]; + // Can we safely discard the entire chunk? + bool inRange = chunk.BaseTime.AddTicks((65536 >> 2) * TimeSpan.TicksPerSecond) >= start; + if (!inRange) { args.Stop = true; yield break; } + if (!super && !args.Player.level.name.CaselessEq(chunk.LevelName)) continue; + pos.mapName = chunk.LevelName; + + s.Seek(chunk.DataPosition, SeekOrigin.Begin); + if (args.Temp == null) + args.Temp = new byte[ushort.MaxValue * entrySize]; + s.Read(args.Temp, 0, chunk.Entries * entrySize); + byte[] temp = args.Temp; + + for (int j = chunk.Entries - 1; j >= 0; j-- ) { + int offset = j * entrySize; + item.Flags = U16(temp, offset + 0); + DateTime time = chunk.BaseTime.AddTicks((item.Flags & 0x3FFF) * TimeSpan.TicksPerSecond); + if (time < start) { args.Stop = true; yield break; } - fs.Seek(chunk.DataPosition, SeekOrigin.Begin); - if (temp == null) temp = new byte[ushort.MaxValue * entrySize]; - fs.Read(temp, 0, chunk.Entries * entrySize); + int index = I32(temp, offset + 2); + pos.x = (ushort)(index % chunk.Width); + pos.y = (ushort)((index / chunk.Width) / chunk.Length); + pos.z = (ushort)((index / chunk.Width) % chunk.Length); - for (int j = chunk.Entries - 1; j >= 0; j-- ) { - int offset = j * entrySize; - ushort flags = U16(temp, offset + 0); - DateTime time = chunk.BaseTime.AddTicks((flags & 0x3FFF) * TimeSpan.TicksPerSecond); - if (time < start) return false; - - int index = I32(temp, offset + 2); - ushort x = (ushort)(index % chunk.Width); - ushort y = (ushort)((index / chunk.Width) / chunk.Length); - ushort z = (ushort)((index / chunk.Width) % chunk.Length); - HighlightBlock(p, lvl, temp[offset + 6], temp[offset + 7], x, y, z); - } + item.Type = temp[offset + 6]; + item.NewType = temp[offset + 7]; + item.GetBlock(out pos.type, out pos.extType); + item.GetNewBlock(out pos.newtype, out pos.newExtType); + yield return pos; } } - return true; } static ushort U16(byte[] buffer, int offset) { @@ -229,30 +145,21 @@ namespace MCGalaxy.Util { } static int I32(byte[] buffer, int offset) { - return buffer[offset + 0] | buffer[offset + 1] << 8 | + return buffer[offset + 0] | buffer[offset + 1] << 8 | buffer[offset + 2] << 16 | buffer[offset + 3] << 24; } - static bool CheckChunk(ChunkHeader chunk, DateTime start, Player p, out Level lvl) { - DateTime time = chunk.BaseTime; - lvl = null; - if (time.AddTicks((65536 >> 2) * TimeSpan.TicksPerSecond) < start) - return false; // we can safely discard the entire chunk - lvl = LevelInfo.FindExact(chunk.LevelName); - return true; - } - struct ChunkHeader { public string LevelName; - public DateTime BaseTime; + public DateTime BaseTime; public ushort Entries; public ushort Width, Height, Length; public long DataPosition; } - static void ReadHeaders(List list, BinaryReader r) { - Stream s = r.BaseStream; - long len = s.Length; + static void ReadHeaders(List list, Stream s) { + BinaryReader r = new BinaryReader(s); + long len = s.Length; while (s.Position < len) { ChunkHeader header = ReadHeader(s, r); s.Seek(header.Entries * entrySize, SeekOrigin.Current); @@ -263,12 +170,12 @@ namespace MCGalaxy.Util { static ChunkHeader ReadHeader(Stream s, BinaryReader r) { ChunkHeader header = default(ChunkHeader); byte[] mapNameData = r.ReadBytes(r.ReadUInt16()); - header.LevelName = Encoding.UTF8.GetString(mapNameData); + header.LevelName = Encoding.UTF8.GetString(mapNameData); header.BaseTime = new DateTime(r.ReadInt64(), DateTimeKind.Utc); header.Entries = r.ReadUInt16(); header.Width = r.ReadUInt16(); - header.Height = r.ReadUInt16(); + header.Height = r.ReadUInt16(); header.Length = r.ReadUInt16(); header.DataPosition = s.Position; return header; diff --git a/Player/Undo/UndoFileText.cs b/Player/Undo/UndoFileText.cs index 690207b4e..d21c87402 100644 --- a/Player/Undo/UndoFileText.cs +++ b/Player/Undo/UndoFileText.cs @@ -19,7 +19,6 @@ using System; using System.Collections.Generic; using System.Globalization; using System.IO; -using MCGalaxy.Drawing; namespace MCGalaxy.Util { @@ -35,98 +34,32 @@ namespace MCGalaxy.Util { throw new NotSupportedException("Text undo files have been deprecated"); } - protected override void ReadUndoData(List buffer, string path) { - Player.UndoPos Pos; - Pos.extType = 0; Pos.newExtType = 0; - string[] lines = File.ReadAllText(path).Split(' '); - int approxEntries = (int)(lines.Length / 7); - if (buffer.Capacity < approxEntries) - buffer.Capacity = approxEntries; + protected override IEnumerable GetEntries(Stream s, UndoEntriesArgs args) { + Player.UndoPos pos = default(Player.UndoPos); + string[] lines = new StreamReader(s).ReadToEnd().Split(' '); + Player p = args.Player; + bool super = p == null || p.ircNick != null; + DateTime start = args.StartRange; - for (int i = 0; i < lines.Length; i += 7) { - if (lines[i].Length == 0) continue; - Pos.mapName = lines[i]; - Pos.x = ushort.Parse(lines[i + 1]); - Pos.y = ushort.Parse(lines[i + 2]); - Pos.z = ushort.Parse(lines[i + 3]); + // because we have space to end of each entry, need to subtract one otherwise we'll start at a "". + for (int i = (lines.Length - 1) / 7; i >= 0; i--) { + // line format: mapName x y z date oldblock newblock + string timeRaw = lines[(i * 7) - 3].Replace('&', ' '); + DateTime time = DateTime.Parse(timeRaw, CultureInfo.InvariantCulture); + if (time < start) { args.Stop = true; yield break; } - string time = lines[i + 4].Replace('&', ' '); - DateTime rawTime = DateTime.Parse(time, CultureInfo.InvariantCulture); - Pos.timeDelta = (int)rawTime.Subtract(Server.StartTimeLocal).TotalSeconds; - Pos.type = byte.Parse(lines[i + 5]); - Pos.newtype = byte.Parse(lines[i + 6]); - buffer.Add(Pos); + string map = lines[(i * 7) - 7]; + if (!super && !p.level.name.CaselessEq(map)) continue; + pos.mapName = map; + + pos.x = Convert.ToUInt16(lines[(i * 7) - 6]); + pos.y = Convert.ToUInt16(lines[(i * 7) - 5]); + pos.z = Convert.ToUInt16(lines[(i * 7) - 4]); + + pos.newtype = Convert.ToByte(lines[(i * 7) - 1]); + pos.type = Convert.ToByte(lines[(i * 7) - 2]); + yield return pos; } } - - protected override bool UndoEntry(Player p, string path, Vec3S32[] marks, - ref byte[] temp, DateTime start) { - Player.UndoPos Pos = default(Player.UndoPos); - int timeDelta = (int)DateTime.UtcNow.Subtract(Server.StartTime).TotalSeconds; - string[] lines = File.ReadAllText(path).Split(' '); - Vec3U16 min = (Vec3U16)marks[0], max = (Vec3U16)marks[1]; - bool undoArea = min.X != ushort.MaxValue; - BufferedBlockSender buffer = new BufferedBlockSender(); - string last = null; - - // because we have space to end of each entry, need to subtract one otherwise we'll start at a "". - 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], start)) return false; - Level lvl = LevelInfo.FindExact(lines[(i * 7) - 7]); - if (lvl == null || (p.level != null && !p.level.name.CaselessEq(lvl.name))) - continue; - if (!undoArea) { - min = new Vec3U16(0, 0, 0); - max = new Vec3U16((ushort)(lvl.Width - 1), (ushort)(lvl.Height - 1), (ushort)(lvl.Length - 1)); - } - if (last == null || last != lvl.name) { - buffer.CheckIfSend(true); - last = lvl.name; - } - buffer.level = lvl; - Pos.mapName = lvl.name; - - Pos.x = Convert.ToUInt16(lines[(i * 7) - 6]); - Pos.y = Convert.ToUInt16(lines[(i * 7) - 5]); - Pos.z = Convert.ToUInt16(lines[(i * 7) - 4]); - if (Pos.x < min.X || Pos.y < min.Y || Pos.z < min.Z || - Pos.x > max.X || Pos.y > max.Y || Pos.z > max.Z) continue; - - Pos.newtype = Convert.ToByte(lines[(i * 7) - 1]); - Pos.type = Convert.ToByte(lines[(i * 7) - 2]); - UndoBlock(p, lvl, Pos, timeDelta, buffer); - } catch { - } - } - buffer.CheckIfSend(true); - return true; - } - - protected override bool HighlightEntry(Player p, string path, ref byte[] temp, DateTime start) { - string[] lines = File.ReadAllText(path).Split(' '); - // because we have space to end of each entry, need to subtract one otherwise we'll start at a "". - 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], start)) return false; - Level lvl = LevelInfo.FindExact(lines[(i * 7) - 7]); - if (lvl == null || lvl != p.level) continue; - - ushort x = Convert.ToUInt16(lines[(i * 7) - 6]); - ushort y = Convert.ToUInt16(lines[(i * 7) - 5]); - ushort z = Convert.ToUInt16(lines[(i * 7) - 4]); - HighlightBlock(p, lvl, Convert.ToByte(lines[(i * 7) - 2]), Convert.ToByte(lines[(i * 7) - 1]), x, y, z); - } catch { } - } - return true; - } - - static bool InTime(string line, DateTime start) { - line = line.Replace('&', ' '); - DateTime time = DateTime.Parse(line, CultureInfo.InvariantCulture); - return time >= start; - } } }