Fix bugs in UndoFileBin, also add new 'ReadUndoData' method to allow for converting between the formats.

This commit is contained in:
UnknownShadow200 2016-01-03 23:34:13 +11:00
parent 3075dc9221
commit ee720499b4
4 changed files with 190 additions and 97 deletions

View File

@ -25,10 +25,13 @@ namespace MCGalaxy.Util {
public abstract class UndoFile {
protected const string undoDir = "extra/undo", prevUndoDir = "extra/undoPrevious";
public static UndoFile Instance = new UndoFileText();
public static UndoFile OldFormat = new UndoFileText();
public static UndoFile NewFormat = new UndoFileBin();
protected abstract void SaveUndoData(List<Player.UndoPos> buffer, string path);
protected abstract void ReadUndoData(List<Player.UndoPos> buffer, string path);
protected abstract bool UndoEntry(Player p, string path, long seconds);
protected abstract bool HighlightEntry(Player p, string path, long seconds);
@ -39,9 +42,7 @@ namespace MCGalaxy.Util {
if( p == null || p.UndoBuffer == null || p.UndoBuffer.Count < 1) return;
CreateDefaultDirectories();
DirectoryInfo di = new DirectoryInfo(undoDir);
if (di.GetDirectories("*").Length >= Server.totalUndo) {
if (Directory.GetDirectories(undoDir).Length >= Server.totalUndo) {
Directory.Delete(prevUndoDir, true);
Directory.Move(undoDir, prevUndoDir);
Directory.CreateDirectory(undoDir);
@ -51,11 +52,9 @@ namespace MCGalaxy.Util {
if (!Directory.Exists(playerDir))
Directory.CreateDirectory(playerDir);
di = new DirectoryInfo(playerDir);
string ext = Instance.Extension;
int numFiles = di.GetFiles("*" + ext).Length;
string path = Path.Combine(playerDir, numFiles + ext);
Instance.SaveUndoData(p.UndoBuffer, path);
int numFiles = Directory.GetFiles(playerDir).Length;
string path = Path.Combine(playerDir, numFiles + NewFormat.Extension);
NewFormat.SaveUndoData(p.UndoBuffer, path);
}
public static void UndoPlayer(Player p, string targetName, long seconds, ref bool FoundUser) {
@ -74,26 +73,70 @@ namespace MCGalaxy.Util {
string path = Path.Combine(dir, name);
if (!Directory.Exists(path))
return;
DirectoryInfo di = new DirectoryInfo(path);
string ext = Instance.Extension;
int numFiles = di.GetFiles("*" + ext).Length;
string[] files = Directory.GetFiles(path);
Array.Sort<string>(files, CompareFiles);
for (int i = files.Length - 1; i >= 0; i--) {
path = files[i];
string file = Path.GetFileName(path);
if (file.Length == 0 || file[0] < '0' || file[0] > '9')
continue;
UndoFile format = null;
if (path.EndsWith(OldFormat.Extension)) format = OldFormat;
if (path.EndsWith(NewFormat.Extension)) format = NewFormat;
if (format == null) continue;
for (int i = numFiles - 1; i >= 0; i--) {
string undoPath = Path.Combine(path, i + ext);
if (highlight) {
if (!Instance.HighlightEntry(p, undoPath, seconds)) break;
if (!format.HighlightEntry(p, path, seconds)) break;
} else {
if (!Instance.UndoEntry(p, undoPath, seconds)) break;
if (!format.UndoEntry(p, path, seconds)) break;
}
}
FoundUser = true;
}
static int CompareFiles(string a, string b) {
int aNumEnd = a.IndexOf('.'), bNumEnd = b.IndexOf('.');
if (aNumEnd < 0 || bNumEnd < 0) return a.CompareTo(b);
int aNum, bNum;
if (!int.TryParse(a.Substring(0, aNumEnd), out aNum) ||
!int.TryParse(b.Substring(0, bNumEnd), out bNum))
return a.CompareTo(b);
return aNum.CompareTo(bNum);
}
public static void CreateDefaultDirectories() {
if (!Directory.Exists(undoDir))
Directory.CreateDirectory(undoDir);
if (!Directory.Exists(prevUndoDir))
Directory.CreateDirectory(prevUndoDir);
}
public static void UpgradePlayerUndoFiles(string name) {
UpgradeFiles(undoDir, name);
UpgradeFiles(prevUndoDir, name);
}
static void UpgradeFiles(string dir, string name) {
string path = Path.Combine(dir, name);
if (!Directory.Exists(path))
return;
string[] files = Directory.GetFiles(path);
List<Player.UndoPos> buffer = new List<Player.UndoPos>();
for (int i = 0; i < files.Length; i++) {
path = files[i];
if (!path.EndsWith(OldFormat.Extension))
continue;
buffer.Clear();
OldFormat.ReadUndoData(buffer, path);
string newPath = Path.ChangeExtension(path, NewFormat.Extension);
NewFormat.SaveUndoData(buffer, newPath);
File.Delete(path);
}
}
}
}

View File

@ -53,7 +53,30 @@ namespace MCGalaxy.Util {
}
}
// TODO: untested
protected override void ReadUndoData(List<Player.UndoPos> buffer, string path) {
DateTime now = DateTime.Now;
Player.UndoPos Pos;
using (Stream fs = File.OpenRead(path))
using (BinaryReader r = new BinaryReader(fs))
{
int approxEntries = (int)(fs.Length / 12);
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++ ) {
Pos.timePlaced = chunk.BaseTime.AddSeconds(r.ReadUInt16());
Pos.x = r.ReadUInt16(); Pos.y = r.ReadUInt16(); Pos.z = r.ReadUInt16();
Pos.type = r.ReadByte(); r.ReadByte(); // block definitions placeholder
Pos.newtype = r.ReadByte(); r.ReadByte(); // block definitions placeholder
buffer.Add(Pos);
}
}
}
}
protected override bool UndoEntry(Player p, string path, long seconds) {
List<ChunkHeader> list = new List<ChunkHeader>();
DateTime now = DateTime.Now;
@ -70,10 +93,11 @@ namespace MCGalaxy.Util {
return false;
if (lvl == null || lvl != p.level) continue;
Pos.mapName = chunk.LevelName;
fs.Seek(chunk.DataPosition, SeekOrigin.Begin);
for (int j = 0; j < chunk.Entries; j++ ) {
DateTime time = chunk.BaseTime.AddSeconds(r.ReadUInt16());
if (time >= now) return false;
if (time.AddSeconds(seconds) < now) return false;
Pos.x = r.ReadUInt16(); Pos.y = r.ReadUInt16(); Pos.z = r.ReadUInt16();
Pos.type = lvl.GetTile(Pos.x, Pos.y, Pos.z);
@ -95,7 +119,6 @@ namespace MCGalaxy.Util {
return true;
}
// TODO: untested
protected override bool HighlightEntry(Player p, string path, long seconds) {
List<ChunkHeader> list = new List<ChunkHeader>();
DateTime now = DateTime.Now;
@ -110,10 +133,11 @@ namespace MCGalaxy.Util {
if (!CheckChunk(chunk, now, seconds, p, out lvl))
return false;
if (lvl == null || lvl != p.level) continue;
fs.Seek(chunk.DataPosition, SeekOrigin.Begin);
for (int j = 0; j < chunk.Entries; j++ ) {
DateTime time = chunk.BaseTime.AddSeconds(r.ReadUInt16());
if (time >= now) return false;
if (time.AddSeconds(seconds) < now) return false;
ushort x = r.ReadUInt16(), y = r.ReadUInt16(), z = r.ReadUInt16();
byte lvlTile = lvl.GetTile(x, y, z);
@ -135,7 +159,7 @@ namespace MCGalaxy.Util {
static bool CheckChunk(ChunkHeader chunk, DateTime now, long seconds, Player p, out Level lvl) {
DateTime time = chunk.BaseTime;
lvl = null;
if (time.AddSeconds(65536).AddSeconds(seconds) >= now)
if (time.AddSeconds(65536).AddSeconds(seconds) < now)
return false; // we can safely discard the entire chunk
lvl = Level.FindExact(chunk.LevelName);
@ -153,6 +177,13 @@ namespace MCGalaxy.Util {
Stream s = r.BaseStream;
long len = s.Length;
while (s.Position < len) {
ChunkHeader header = ReadHeader(s, r);
s.Seek(header.Entries * 12, SeekOrigin.Current);
list.Add(header);
}
}
static ChunkHeader ReadHeader(Stream s, BinaryReader r) {
ChunkHeader header = default(ChunkHeader);
byte[] mapNameData = r.ReadBytes(r.ReadUInt16());
header.LevelName = Encoding.UTF8.GetString(mapNameData);
@ -160,9 +191,7 @@ namespace MCGalaxy.Util {
header.BaseTime = new DateTime(r.ReadInt64(), DateTimeKind.Local);
header.Entries = r.ReadUInt16();
header.DataPosition = s.Position;
s.Seek(header.Entries * 12, SeekOrigin.Current);
list.Add(header);
}
return header;
}
static void WriteChunkEntries(BinaryWriter w, ushort entries, long entriesPos) {

View File

@ -38,6 +38,27 @@ namespace MCGalaxy.Util {
}
}
protected override void ReadUndoData(List<Player.UndoPos> buffer, string path) {
Player.UndoPos Pos;
string[] lines = File.ReadAllText(path).Split(' ');
int approxEntries = (int)(lines.Length / 7);
if (buffer.Capacity < approxEntries)
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]);
Pos.timePlaced = DateTime.Parse(lines[i + 4], CultureInfo.InvariantCulture);
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, long seconds) {
Player.UndoPos Pos;
string[] lines = File.ReadAllText(path).Split(' ');