mirror of
https://github.com/ClassiCube/MCGalaxy.git
synced 2025-09-22 12:05:51 -04:00
[Major WIP] Rewrite UndoFile classes to be much more extensible.
This commit is contained in:
parent
6b7b3cd191
commit
075e99f118
@ -29,17 +29,18 @@ namespace MCGalaxy.Util {
|
|||||||
public static UndoFile BinFormat = new UndoFileBin();
|
public static UndoFile BinFormat = new UndoFileBin();
|
||||||
public static UndoFile NewFormat = new UndoFileCBin();
|
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<Player.UndoPos> buffer, string path);
|
protected abstract void SaveUndoData(List<Player.UndoPos> buffer, string path);
|
||||||
|
|
||||||
protected abstract void SaveUndoData(UndoCache buffer, string path);
|
protected abstract void SaveUndoData(UndoCache buffer, string path);
|
||||||
|
|
||||||
protected abstract void ReadUndoData(List<Player.UndoPos> buffer, string path);
|
protected abstract IEnumerable<Player.UndoPos> GetEntries(Stream s, UndoEntriesArgs args);
|
||||||
|
|
||||||
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 string Extension { get; }
|
protected abstract string Extension { get; }
|
||||||
|
|
||||||
|
@ -19,7 +19,6 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using MCGalaxy.Drawing;
|
|
||||||
|
|
||||||
namespace MCGalaxy.Util {
|
namespace MCGalaxy.Util {
|
||||||
|
|
||||||
@ -36,123 +35,46 @@ namespace MCGalaxy.Util {
|
|||||||
throw new NotSupportedException("Non-optimised binary undo files have been deprecated");
|
throw new NotSupportedException("Non-optimised binary undo files have been deprecated");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void ReadUndoData(List<Player.UndoPos> buffer, string path) {
|
protected override IEnumerable<Player.UndoPos> GetEntries(Stream s, UndoEntriesArgs args) {
|
||||||
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) {
|
|
||||||
List<ChunkHeader> list = new List<ChunkHeader>();
|
List<ChunkHeader> list = new List<ChunkHeader>();
|
||||||
int timeDelta = (int)DateTime.UtcNow.Subtract(Server.StartTime).TotalSeconds;
|
Player.UndoPos pos = default(Player.UndoPos);
|
||||||
Player.UndoPos Pos = default(Player.UndoPos);
|
bool super = args.Player == null || args.Player.ircNick != null;
|
||||||
Vec3U16 min = (Vec3U16)marks[0], max = (Vec3U16)marks[1];
|
DateTime start = args.StartRange;
|
||||||
bool undoArea = min.X != ushort.MaxValue;
|
|
||||||
|
|
||||||
using (Stream fs = File.OpenRead(path))
|
ReadHeaders(list, s);
|
||||||
using (BinaryReader r = new BinaryReader(fs))
|
|
||||||
{
|
|
||||||
ReadHeaders(list, r);
|
|
||||||
for (int i = list.Count - 1; i >= 0; i--) {
|
for (int i = list.Count - 1; i >= 0; i--) {
|
||||||
ChunkHeader chunk = list[i];
|
ChunkHeader chunk = list[i];
|
||||||
Level lvl;
|
// Can we safely discard the entire chunk?
|
||||||
if (!CheckChunk(chunk, start, p, out lvl)) return false;
|
bool inRange = chunk.BaseTime.AddTicks(65536 * TimeSpan.TicksPerSecond) >= start;
|
||||||
if (lvl == null) continue;
|
if (!inRange) { args.Stop = true; yield break; }
|
||||||
bool super = p == null || p.ircNick != null;
|
if (!super && !args.Player.level.name.CaselessEq(chunk.LevelName)) continue;
|
||||||
if (!super && !p.level.name.CaselessEq(lvl.name)) continue;
|
|
||||||
|
|
||||||
BufferedBlockSender buffer = new BufferedBlockSender(lvl);
|
s.Seek(chunk.DataPosition, SeekOrigin.Begin);
|
||||||
if (!undoArea) {
|
if (args.Temp == null)
|
||||||
min = new Vec3U16(0, 0, 0);
|
args.Temp = new byte[ushort.MaxValue * entrySize];
|
||||||
max = new Vec3U16((ushort)(lvl.Width - 1), (ushort)(lvl.Height - 1), (ushort)(lvl.Length - 1));
|
s.Read(args.Temp, 0, chunk.Entries * entrySize);
|
||||||
}
|
byte[] temp = args.Temp;
|
||||||
|
|
||||||
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-- ) {
|
for (int j = chunk.Entries - 1; j >= 0; j-- ) {
|
||||||
int offset = j * entrySize;
|
int offset = j * entrySize;
|
||||||
DateTime time = chunk.BaseTime.AddTicks(U16(temp, offset + 0) * TimeSpan.TicksPerSecond);
|
DateTime time = chunk.BaseTime.AddTicks(U16(temp, offset + 0) * TimeSpan.TicksPerSecond);
|
||||||
if (time < start) { buffer.CheckIfSend(true); return false; }
|
if (time < start) { args.Stop = true; yield break; }
|
||||||
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.x = U16(temp, offset + 2);
|
||||||
Pos.newtype = temp[offset + 10]; Pos.newExtType = temp[offset + 11];
|
pos.y = U16(temp, offset + 4);
|
||||||
UndoBlock(p, lvl, Pos, timeDelta, buffer);
|
pos.z = U16(temp, offset + 6);
|
||||||
}
|
|
||||||
buffer.CheckIfSend(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool HighlightEntry(Player p, string path,
|
pos.type = temp[offset + 8]; pos.extType = temp[offset + 9];
|
||||||
ref byte[] temp, DateTime start) {
|
pos.newtype = temp[offset + 10]; pos.newExtType = temp[offset + 11];
|
||||||
List<ChunkHeader> list = new List<ChunkHeader>();
|
yield return pos;
|
||||||
|
|
||||||
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) {
|
static ushort U16(byte[] buffer, int offset) {
|
||||||
return (ushort)(buffer[offset + 0] | buffer[offset + 1] << 8);
|
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 {
|
struct ChunkHeader {
|
||||||
public string LevelName;
|
public string LevelName;
|
||||||
public DateTime BaseTime;
|
public DateTime BaseTime;
|
||||||
@ -160,8 +82,8 @@ namespace MCGalaxy.Util {
|
|||||||
public long DataPosition;
|
public long DataPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ReadHeaders(List<ChunkHeader> list, BinaryReader r) {
|
static void ReadHeaders(List<ChunkHeader> list, Stream s) {
|
||||||
Stream s = r.BaseStream;
|
BinaryReader r = new BinaryReader(s);
|
||||||
long len = s.Length;
|
long len = s.Length;
|
||||||
while (s.Position < len) {
|
while (s.Position < len) {
|
||||||
ChunkHeader header = ReadHeader(s, r);
|
ChunkHeader header = ReadHeader(s, r);
|
||||||
|
@ -19,7 +19,6 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using MCGalaxy.Drawing;
|
|
||||||
using MCGalaxy.Levels.IO;
|
using MCGalaxy.Levels.IO;
|
||||||
|
|
||||||
namespace MCGalaxy.Util {
|
namespace MCGalaxy.Util {
|
||||||
@ -99,129 +98,46 @@ namespace MCGalaxy.Util {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void ReadUndoData(List<Player.UndoPos> buffer, string path) {
|
protected override IEnumerable<Player.UndoPos> GetEntries(Stream s, UndoEntriesArgs args) {
|
||||||
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<ChunkHeader> list = new List<ChunkHeader>();
|
List<ChunkHeader> list = new List<ChunkHeader>();
|
||||||
int timeDelta = (int)DateTime.UtcNow.Subtract(Server.StartTime).TotalSeconds;
|
Player.UndoPos pos = default(Player.UndoPos);
|
||||||
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);
|
UndoCacheItem item = default(UndoCacheItem);
|
||||||
|
bool super = args.Player == null || args.Player.ircNick != null;
|
||||||
|
DateTime start = args.StartRange;
|
||||||
|
|
||||||
using (Stream fs = File.OpenRead(path))
|
ReadHeaders(list, s);
|
||||||
using (BinaryReader r = new BinaryReader(fs))
|
|
||||||
{
|
|
||||||
ReadHeaders(list, r);
|
|
||||||
for (int i = list.Count - 1; i >= 0; i--) {
|
for (int i = list.Count - 1; i >= 0; i--) {
|
||||||
ChunkHeader chunk = list[i];
|
ChunkHeader chunk = list[i];
|
||||||
Level lvl;
|
// Can we safely discard the entire chunk?
|
||||||
if (!CheckChunk(chunk, start, p, out lvl)) return false;
|
bool inRange = chunk.BaseTime.AddTicks((65536 >> 2) * TimeSpan.TicksPerSecond) >= start;
|
||||||
if (lvl == null) continue;
|
if (!inRange) { args.Stop = true; yield break; }
|
||||||
bool super = p == null || p.ircNick != null;
|
if (!super && !args.Player.level.name.CaselessEq(chunk.LevelName)) continue;
|
||||||
if (!super && !p.level.name.CaselessEq(lvl.name)) continue;
|
pos.mapName = chunk.LevelName;
|
||||||
|
|
||||||
BufferedBlockSender buffer = new BufferedBlockSender(lvl);
|
s.Seek(chunk.DataPosition, SeekOrigin.Begin);
|
||||||
if (!undoArea) {
|
if (args.Temp == null)
|
||||||
min = new Vec3U16(0, 0, 0);
|
args.Temp = new byte[ushort.MaxValue * entrySize];
|
||||||
max = new Vec3U16((ushort)(lvl.Width - 1), (ushort)(lvl.Height - 1), (ushort)(lvl.Length - 1));
|
s.Read(args.Temp, 0, chunk.Entries * entrySize);
|
||||||
}
|
byte[] temp = args.Temp;
|
||||||
|
|
||||||
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-- ) {
|
for (int j = chunk.Entries - 1; j >= 0; j-- ) {
|
||||||
int offset = j * entrySize;
|
int offset = j * entrySize;
|
||||||
item.Flags = U16(temp, offset + 0);
|
item.Flags = U16(temp, offset + 0);
|
||||||
DateTime time = chunk.BaseTime.AddTicks((item.Flags & 0x3FFF) * TimeSpan.TicksPerSecond);
|
DateTime time = chunk.BaseTime.AddTicks((item.Flags & 0x3FFF) * TimeSpan.TicksPerSecond);
|
||||||
if (time < start) { buffer.CheckIfSend(true); return false; }
|
if (time < start) { args.Stop = true; yield break; }
|
||||||
|
|
||||||
int index = I32(temp, offset + 2);
|
int index = I32(temp, offset + 2);
|
||||||
Pos.x = (ushort)(index % chunk.Width);
|
pos.x = (ushort)(index % chunk.Width);
|
||||||
Pos.y = (ushort)((index / chunk.Width) / chunk.Length);
|
pos.y = (ushort)((index / chunk.Width) / chunk.Length);
|
||||||
Pos.z = (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.Type = temp[offset + 6];
|
||||||
item.NewType = temp[offset + 7];
|
item.NewType = temp[offset + 7];
|
||||||
item.GetBlock(out Pos.type, out Pos.extType);
|
item.GetBlock(out pos.type, out pos.extType);
|
||||||
item.GetNewBlock(out Pos.newtype, out Pos.newExtType);
|
item.GetNewBlock(out pos.newtype, out pos.newExtType);
|
||||||
UndoBlock(p, lvl, Pos, timeDelta, buffer);
|
yield return pos;
|
||||||
}
|
|
||||||
buffer.CheckIfSend(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool HighlightEntry(Player p, string path,
|
|
||||||
ref byte[] temp, DateTime start) {
|
|
||||||
List<ChunkHeader> list = new List<ChunkHeader>();
|
|
||||||
|
|
||||||
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;
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ushort U16(byte[] buffer, int offset) {
|
static ushort U16(byte[] buffer, int offset) {
|
||||||
@ -233,15 +149,6 @@ namespace MCGalaxy.Util {
|
|||||||
buffer[offset + 2] << 16 | buffer[offset + 3] << 24;
|
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 {
|
struct ChunkHeader {
|
||||||
public string LevelName;
|
public string LevelName;
|
||||||
public DateTime BaseTime;
|
public DateTime BaseTime;
|
||||||
@ -250,8 +157,8 @@ namespace MCGalaxy.Util {
|
|||||||
public long DataPosition;
|
public long DataPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ReadHeaders(List<ChunkHeader> list, BinaryReader r) {
|
static void ReadHeaders(List<ChunkHeader> list, Stream s) {
|
||||||
Stream s = r.BaseStream;
|
BinaryReader r = new BinaryReader(s);
|
||||||
long len = s.Length;
|
long len = s.Length;
|
||||||
while (s.Position < len) {
|
while (s.Position < len) {
|
||||||
ChunkHeader header = ReadHeader(s, r);
|
ChunkHeader header = ReadHeader(s, r);
|
||||||
|
@ -19,7 +19,6 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using MCGalaxy.Drawing;
|
|
||||||
|
|
||||||
namespace MCGalaxy.Util {
|
namespace MCGalaxy.Util {
|
||||||
|
|
||||||
@ -35,98 +34,32 @@ namespace MCGalaxy.Util {
|
|||||||
throw new NotSupportedException("Text undo files have been deprecated");
|
throw new NotSupportedException("Text undo files have been deprecated");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void ReadUndoData(List<Player.UndoPos> buffer, string path) {
|
protected override IEnumerable<Player.UndoPos> GetEntries(Stream s, UndoEntriesArgs args) {
|
||||||
Player.UndoPos Pos;
|
Player.UndoPos pos = default(Player.UndoPos);
|
||||||
Pos.extType = 0; Pos.newExtType = 0;
|
string[] lines = new StreamReader(s).ReadToEnd().Split(' ');
|
||||||
string[] lines = File.ReadAllText(path).Split(' ');
|
Player p = args.Player;
|
||||||
int approxEntries = (int)(lines.Length / 7);
|
bool super = p == null || p.ircNick != null;
|
||||||
if (buffer.Capacity < approxEntries)
|
DateTime start = args.StartRange;
|
||||||
buffer.Capacity = approxEntries;
|
|
||||||
|
|
||||||
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]);
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 "".
|
// 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--) {
|
for (int i = (lines.Length - 1) / 7; i >= 0; i--) {
|
||||||
try {
|
|
||||||
// line format: mapName x y z date oldblock newblock
|
// line format: mapName x y z date oldblock newblock
|
||||||
if (!InTime(lines[(i * 7) - 3], start)) return false;
|
string timeRaw = lines[(i * 7) - 3].Replace('&', ' ');
|
||||||
Level lvl = LevelInfo.FindExact(lines[(i * 7) - 7]);
|
DateTime time = DateTime.Parse(timeRaw, CultureInfo.InvariantCulture);
|
||||||
if (lvl == null || (p.level != null && !p.level.name.CaselessEq(lvl.name)))
|
if (time < start) { args.Stop = true; yield break; }
|
||||||
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]);
|
string map = lines[(i * 7) - 7];
|
||||||
Pos.y = Convert.ToUInt16(lines[(i * 7) - 5]);
|
if (!super && !p.level.name.CaselessEq(map)) continue;
|
||||||
Pos.z = Convert.ToUInt16(lines[(i * 7) - 4]);
|
pos.mapName = map;
|
||||||
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.x = Convert.ToUInt16(lines[(i * 7) - 6]);
|
||||||
Pos.type = Convert.ToByte(lines[(i * 7) - 2]);
|
pos.y = Convert.ToUInt16(lines[(i * 7) - 5]);
|
||||||
UndoBlock(p, lvl, Pos, timeDelta, buffer);
|
pos.z = Convert.ToUInt16(lines[(i * 7) - 4]);
|
||||||
} catch {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buffer.CheckIfSend(true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool HighlightEntry(Player p, string path, ref byte[] temp, DateTime start) {
|
pos.newtype = Convert.ToByte(lines[(i * 7) - 1]);
|
||||||
string[] lines = File.ReadAllText(path).Split(' ');
|
pos.type = Convert.ToByte(lines[(i * 7) - 2]);
|
||||||
// because we have space to end of each entry, need to subtract one otherwise we'll start at a "".
|
yield return pos;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user