mirror of
https://github.com/ClassiCube/MCGalaxy.git
synced 2025-09-23 04:32:50 -04:00
Use delegate instead of iterator for old undo files
This commit is contained in:
parent
1c7e51ab67
commit
7470e95de4
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user