Use delegate instead of iterator for old undo files

This commit is contained in:
UnknownShadow200 2017-06-08 21:19:30 +10:00
parent 1c7e51ab67
commit 7470e95de4
6 changed files with 69 additions and 64 deletions

View File

@ -38,7 +38,7 @@ namespace MCGalaxy.Undo {
public static UndoFormat NewFormat = new UndoFormatCBin();
/// <summary> Enumerates through all the entries in the undo file. </summary>
public abstract IEnumerable<UndoFormatEntry> GetEntries(Stream s, UndoFormatArgs args);
public abstract void EnumerateEntries(Stream s, UndoFormatArgs args);
/// <summary> File extension of undo files in this format. </summary>
protected abstract string Ext { get; }
@ -113,15 +113,21 @@ namespace MCGalaxy.Undo {
public bool Stop;
/// <summary> First instance in time that undo data should be retrieved back to. </summary>
internal readonly DateTime Start;
internal readonly DateTime Start;
public UndoFormatArgs(string lvlName, DateTime start) {
LevelName = lvlName; Start = start;
/// <summary> Last instance in time that undo data should be retrieved up to. </summary>
internal readonly DateTime End;
/// <summary> Performs action on the given undo format entry. </summary>
public Action<UndoFormatEntry> Output;
public UndoFormatArgs(string lvlName, DateTime start, DateTime end,
Action<UndoFormatEntry> output) {
LevelName = lvlName; Start = start; End = end; Output = output;
}
}
public struct UndoFormatEntry {
public DateTime Time;
public ushort X, Y, Z;
public ExtBlock Block;
public ExtBlock NewBlock;

View File

@ -28,17 +28,17 @@ namespace MCGalaxy.Undo {
protected override string Ext { get { return ".unbin"; } }
const int entrySize = 12;
public override IEnumerable<UndoFormatEntry> GetEntries(Stream s, UndoFormatArgs args) {
public override void EnumerateEntries(Stream s, UndoFormatArgs args) {
List<ChunkHeader> list = new List<ChunkHeader>();
UndoFormatEntry pos;
DateTime start = args.Start;
DateTime time;
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; }
bool inRange = chunk.BaseTime.AddTicks(65536 * TimeSpan.TicksPerSecond) >= args.Start;
if (!inRange) { args.Stop = true; return; }
if (!args.LevelName.CaselessEq(chunk.LevelName)) continue;
s.Seek(chunk.DataPosition, SeekOrigin.Begin);
@ -49,8 +49,9 @@ namespace MCGalaxy.Undo {
for (int j = chunk.Entries - 1; j >= 0; j-- ) {
int offset = j * entrySize;
pos.Time = chunk.BaseTime.AddTicks(U16(temp, offset + 0) * TimeSpan.TicksPerSecond);
if (pos.Time < start) { args.Stop = true; yield break; }
time = chunk.BaseTime.AddTicks(U16(temp, offset + 0) * TimeSpan.TicksPerSecond);
if (time < args.Start) { args.Stop = true; return; }
if (time > args.End) continue;
pos.X = U16(temp, offset + 2);
pos.Y = U16(temp, offset + 4);
@ -60,11 +61,12 @@ namespace MCGalaxy.Undo {
pos.Block.ExtID = temp[offset + 9];
pos.NewBlock.BlockID = temp[offset + 10];
pos.NewBlock.ExtID = temp[offset + 11];
yield return pos;
args.Output(pos);
}
}
}
static ushort U16(byte[] buffer, int offset) {
return (ushort)(buffer[offset + 0] | buffer[offset + 1] << 8);
}

View File

@ -28,17 +28,17 @@ namespace MCGalaxy.Undo {
protected override string Ext { get { return ".uncbin"; } }
const int entrySize = 8;
public override IEnumerable<UndoFormatEntry> GetEntries(Stream s, UndoFormatArgs args) {
public override void EnumerateEntries(Stream s, UndoFormatArgs args) {
List<ChunkHeader> list = new List<ChunkHeader>();
UndoFormatEntry pos;
DateTime start = args.Start;
DateTime time;
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; }
bool inRange = chunk.BaseTime.AddTicks((65536 >> 2) * TimeSpan.TicksPerSecond) >= args.Start;
if (!inRange) { args.Stop = true; return; }
if (!args.LevelName.CaselessEq(chunk.LevelName)) continue;
s.Seek(chunk.DataPosition, SeekOrigin.Begin);
@ -55,8 +55,9 @@ namespace MCGalaxy.Undo {
// TODO: should this be instead:
// int delta = Flags & 0x3FFF;
// timeDeltaSeconds = delta >= 0x2000 ? (short)(delta - 16384) : (short)delta;
pos.Time = chunk.BaseTime.AddTicks((flags & 0x3FFF) * TimeSpan.TicksPerSecond);
if (pos.Time < start) { args.Stop = true; yield break; }
time = chunk.BaseTime.AddTicks((flags & 0x3FFF) * TimeSpan.TicksPerSecond);
if (time < args.Start) { args.Stop = true; return; }
if (time > args.End) continue;
int index = I32(temp, offset + 2);
pos.X = (ushort)(index % chunk.Width);
@ -65,11 +66,12 @@ namespace MCGalaxy.Undo {
pos.Block = ExtBlock.FromRaw(temp[offset + 6], (flags & (1 << 14)) != 0);
pos.NewBlock = ExtBlock.FromRaw(temp[offset + 7], (flags & (1 << 15)) != 0);
yield return pos;
args.Output(pos);
}
}
}
static ushort U16(byte[] buffer, int offset) {
return (ushort)(buffer[offset + 0] | buffer[offset + 1] << 8);
}

View File

@ -27,18 +27,19 @@ namespace MCGalaxy.Undo {
protected override string Ext { get { return ".undo"; } }
public override IEnumerable<UndoFormatEntry> GetEntries(Stream s, UndoFormatArgs args) {
public override void EnumerateEntries(Stream s, UndoFormatArgs args) {
UndoFormatEntry pos = default(UndoFormatEntry);
string[] lines = new StreamReader(s).ReadToEnd().SplitSpaces();
DateTime start = args.Start;
DateTime time;
// because we have space to end of each entry, need to subtract one otherwise we'll start at a "".
const int items = 7;
for (int i = (lines.Length - 1) / items; i > 0; i--) {
// line format: mapName x y z date oldblock newblock
string timeRaw = lines[(i * items) - 3].Replace('&', ' ');
pos.Time = DateTime.Parse(timeRaw, CultureInfo.InvariantCulture);
if (pos.Time < start) { args.Stop = true; yield break; }
time = DateTime.Parse(timeRaw, CultureInfo.InvariantCulture);
if (time < args.Start) { args.Stop = true; return; }
if (time > args.End) continue;
string map = lines[(i * items) - 7];
if (!args.LevelName.CaselessEq(map)) continue;
@ -49,7 +50,7 @@ namespace MCGalaxy.Undo {
pos.Block.BlockID = byte.Parse(lines[(i * items) - 2]);
pos.NewBlock.BlockID = byte.Parse(lines[(i * items) - 1]);
yield return pos;
args.Output(pos);
}
}
}

View File

@ -67,8 +67,8 @@ namespace MCGalaxy.Drawing.Ops {
}
}
UndoFormatArgs args = new UndoFormatArgs(Level.name, Start);
DoOldHighlight(args);
UndoFormatArgs args = new UndoFormatArgs(Level.name, Start, DateTime.MaxValue, OldHighlightBlock);
PerformOldHighlight(args);
}
Action<DrawOpBlock> output;
@ -80,8 +80,8 @@ namespace MCGalaxy.Drawing.Ops {
ExtBlock newBlock = ExtBlock.FromRaw(e.NewRaw, (e.Flags & BlockDBFlags.NewCustom) != 0);
ExtBlock highlight = (newBlock.BlockID == Block.air
|| Block.Convert(oldBlock.BlockID) == Block.water || oldBlock.BlockID == Block.waterstill
|| Block.Convert(oldBlock.BlockID) == Block.lava || oldBlock.BlockID == Block.lavastill)
|| Block.Convert(oldBlock.BlockID) == Block.water || oldBlock.BlockID == Block.waterstill
|| Block.Convert(oldBlock.BlockID) == Block.lava || oldBlock.BlockID == Block.lavastill)
? DeleteHighlight : PlaceHighlight;
int x = e.Index % dims.X;
@ -95,35 +95,32 @@ namespace MCGalaxy.Drawing.Ops {
}
void DoOldHighlight(UndoFormatArgs args) {
List<string> files = UndoFormat.GetUndoFiles(who.ToLower());
void PerformOldHighlight(UndoFormatArgs args) {
List<string> files = UndoFormat.GetUndoFiles(who.ToLower());
if (files.Count == 0) return;
found = true;
foreach (string file in files) {
using (Stream s = File.OpenRead(file)) {
DoOldHighlight(s, UndoFormat.GetFormat(file), args);
UndoFormat.GetFormat(file).EnumerateEntries(s, args);
if (args.Stop) break;
}
}
}
void DoOldHighlight(Stream s, UndoFormat format, UndoFormatArgs args) {
DrawOpBlock block;
void OldHighlightBlock(UndoFormatEntry P) {
ExtBlock old = P.Block, newBlock = P.NewBlock;
if (P.X < Min.X || P.Y < Min.Y || P.Z < Min.Z) return;
if (P.X > Max.X || P.Y > Max.Y || P.Z > Max.Z) return;
foreach (UndoFormatEntry P in format.GetEntries(s, args)) {
ExtBlock old = P.Block, newBlock = P.NewBlock;
if (P.X < Min.X || P.Y < Min.Y || P.Z < Min.Z) continue;
if (P.X > Max.X || P.Y > Max.Y || P.Z > Max.Z) continue;
block.Block = (newBlock.BlockID == Block.air
|| Block.Convert(old.BlockID) == Block.water || old.BlockID == Block.waterstill
|| Block.Convert(old.BlockID) == Block.lava || old.BlockID == Block.lavastill)
? DeleteHighlight : PlaceHighlight;
block.X = P.X; block.Y = P.Y; block.Z = P.Z;
output(block);
}
DrawOpBlock block;
block.Block = (newBlock.BlockID == Block.air
|| Block.Convert(old.BlockID) == Block.water || old.BlockID == Block.waterstill
|| Block.Convert(old.BlockID) == Block.lava || old.BlockID == Block.lavastill)
? DeleteHighlight : PlaceHighlight;
block.X = P.X; block.Y = P.Y; block.Z = P.Z;
output(block);
}
}
}

View File

@ -71,8 +71,8 @@ namespace MCGalaxy.Drawing.Ops {
}
}
UndoFormatArgs args = new UndoFormatArgs(Level.name, Start);
DoOldUndo(args);
UndoFormatArgs args = new UndoFormatArgs(Level.name, Start, End, OldUndoBlock);
PerformOldUndo(args);
}
Action<DrawOpBlock> output;
@ -93,34 +93,31 @@ namespace MCGalaxy.Drawing.Ops {
}
void DoOldUndo(UndoFormatArgs args) {
void PerformOldUndo(UndoFormatArgs args) {
List<string> files = UndoFormat.GetUndoFiles(who.ToLower());
if (files.Count == 0) return;
found = true;
foreach (string file in files) {
using (Stream s = File.OpenRead(file)) {
DoOldUndo(s, UndoFormat.GetFormat(file), args);
UndoFormat.GetFormat(file).EnumerateEntries(s, args);
if (args.Stop) break;
}
}
}
void DoOldUndo(Stream s, UndoFormat format, UndoFormatArgs args) {
DrawOpBlock block;
foreach (UndoFormatEntry P in format.GetEntries(s, args)) {
if (P.Time > End) continue;
if (P.X < Min.X || P.Y < Min.Y || P.Z < Min.Z) continue;
if (P.X > Max.X || P.Y > Max.Y || P.Z > Max.Z) continue;
void OldUndoBlock(UndoFormatEntry P) {
if (P.X < Min.X || P.Y < Min.Y || P.Z < Min.Z) return;
if (P.X > Max.X || P.Y > Max.Y || P.Z > Max.Z) return;
byte lvlBlock = Level.GetTile(P.X, P.Y, P.Z);
if (lvlBlock == P.NewBlock.BlockID || Block.Convert(lvlBlock) == Block.water
|| Block.Convert(lvlBlock) == Block.lava || lvlBlock == Block.grass) {
byte lvlBlock = Level.GetTile(P.X, P.Y, P.Z);
if (lvlBlock == P.NewBlock.BlockID || Block.Convert(lvlBlock) == Block.water
|| Block.Convert(lvlBlock) == Block.lava || lvlBlock == Block.grass) {
block.X = P.X; block.Y = P.Y; block.Z = P.Z;
block.Block = P.Block;
output(block);
}
DrawOpBlock block;
block.X = P.X; block.Y = P.Y; block.Z = P.Z;
block.Block = P.Block;
output(block);
}
}
}