mirror of
https://github.com/ClassiCube/MCGalaxy.git
synced 2025-09-22 03:55:18 -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 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(UndoCache buffer, string path);
|
||||
|
||||
protected abstract void ReadUndoData(List<Player.UndoPos> 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<Player.UndoPos> 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);
|
||||
}
|
||||
|
||||
|
@ -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<Player.UndoPos> 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<Player.UndoPos> GetEntries(Stream s, UndoEntriesArgs args) {
|
||||
List<ChunkHeader> list = new List<ChunkHeader>();
|
||||
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<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;
|
||||
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<ChunkHeader> list, BinaryReader r) {
|
||||
Stream s = r.BaseStream;
|
||||
static void ReadHeaders(List<ChunkHeader> list, Stream s) {
|
||||
BinaryReader r = new BinaryReader(s);
|
||||
long len = s.Length;
|
||||
while (s.Position < len) {
|
||||
ChunkHeader header = ReadHeader(s, r);
|
||||
|
@ -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<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, Vec3S32[] 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 = (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<Player.UndoPos> GetEntries(Stream s, UndoEntriesArgs args) {
|
||||
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;
|
||||
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<ChunkHeader> list, BinaryReader r) {
|
||||
Stream s = r.BaseStream;
|
||||
long len = s.Length;
|
||||
static void ReadHeaders(List<ChunkHeader> 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;
|
||||
|
@ -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<Player.UndoPos> 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<Player.UndoPos> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user