protected override void ReadUndoData(List <Player.UndoPos> 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, Vec3U16[] marks, ref byte[] temp, DateTime start) { List <ChunkHeader> list = new List <ChunkHeader>(); int timeDelta = (int)DateTime.UtcNow.Subtract(Server.StartTime).TotalSeconds; Player.UndoPos Pos = default(Player.UndoPos); Vec3U16 min = marks[0], max = 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 || (p.level != null && !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); }