static void UndoBlock(UndoFormatArgs args, Level lvl, UndoFormatEntry P) { byte lvlBlock = lvl.GetTile(P.X, P.Y, P.Z); if (lvlBlock == P.NewBlock || Block.Convert(lvlBlock) == Block.water || Block.Convert(lvlBlock) == Block.lava || lvlBlock == Block.grass) { if (args.Player != null) { DrawOpBlock block; block.X = P.X; block.Y = P.Y; block.Z = P.Z; block.Block = P.Block; block.ExtBlock = P.ExtBlock; args.Output(block); } else { Player.GlobalBlockchange(lvl, P.X, P.Y, P.Z, P.Block, P.ExtBlock); // TODO: rewrite this :/ lvl.SetTile(P.X, P.Y, P.Z, P.Block); if (P.Block != Block.custom_block) { return; } lvl.SetExtTile(P.X, P.Y, P.Z, P.ExtBlock); } } }
public static void DoUndoArea(Stream s, Vec3S32 min, Vec3S32 max, UndoFormat format, UndoFormatArgs args) { Level lvl = args.Player == null ? null : args.Player.level; string lastMap = null; foreach (UndoFormatEntry P in format.GetEntries(s, args)) { if (P.LevelName != lastMap) { lvl = LevelInfo.FindExact(P.LevelName); } if (lvl == null || P.Time > args.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; } UndoBlock(args, lvl, P); } }
public override void EnumerateEntries(Stream s, UndoFormatArgs args) { List <ChunkHeader> list = new List <ChunkHeader>(); UndoFormatEntry pos; 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) >= args.Start; if (!inRange) { args.Finished = true; return; } if (!args.Map.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; ushort flags = U16(temp, offset + 0); // upper 2 bits for 'ext' or 'physics' type, lower 14 bits for time delta. // TODO: should this be instead: // int delta = Flags & 0x3FFF; // timeDeltaSeconds = delta >= 0x2000 ? (short)(delta - 16384) : (short)delta; time = chunk.BaseTime.AddTicks((flags & 0x3FFF) * TimeSpan.TicksPerSecond); if (time < args.Start) { args.Finished = true; return; } if (time > args.End) { continue; } 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); pos.Block = Block.FromRaw(temp[offset + 6], (flags & (1 << 14)) != 0); pos.NewBlock = Block.FromRaw(temp[offset + 7], (flags & (1 << 15)) != 0); args.Output(pos); } } }
protected override IEnumerable <UndoFormatEntry> GetEntries(Stream s, UndoFormatArgs args) { List <ChunkHeader> list = new List <ChunkHeader>(); UndoFormatEntry pos; UndoCacheItem item = default(UndoCacheItem); bool super = Player.IsSuper(args.Player); DateTime start = args.Start; 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.LevelName = 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); pos.Time = chunk.BaseTime.AddTicks((item.Flags & 0x3FFF) * TimeSpan.TicksPerSecond); if (pos.Time < start) { args.Stop = true; yield break; } 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); item.Type = temp[offset + 6]; item.NewType = temp[offset + 7]; item.GetBlock(out pos.Block, out pos.ExtBlock); item.GetNewBlock(out pos.NewBlock, out pos.NewExtBlock); yield return(pos); } } }
public override void EnumerateEntries(Stream s, UndoFormatArgs args) { List <ChunkHeader> list = new List <ChunkHeader>(); UndoFormatEntry pos; 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) >= args.Start; if (!inRange) { args.Stop = true; return; } if (!args.LevelName.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; 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); pos.Z = U16(temp, offset + 6); pos.Block.BlockID = temp[offset + 8]; pos.Block.ExtID = temp[offset + 9]; pos.NewBlock.BlockID = temp[offset + 10]; pos.NewBlock.ExtID = temp[offset + 11]; args.Output(pos); } } }
protected override IEnumerable <UndoFormatEntry> GetEntries(Stream s, UndoFormatArgs args) { List <ChunkHeader> list = new List <ChunkHeader>(); UndoFormatEntry pos; bool super = Player.IsSuper(args.Player); DateTime start = args.Start; 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; } pos.LevelName = 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; pos.Time = chunk.BaseTime.AddTicks(U16(temp, offset + 0) * TimeSpan.TicksPerSecond); if (pos.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); pos.Block = temp[offset + 8]; pos.ExtBlock = temp[offset + 9]; pos.NewBlock = temp[offset + 10]; pos.NewExtBlock = temp[offset + 11]; yield return(pos); } } }
public static void DoRedo(Stream s, UndoFormat format, UndoFormatArgs args) { DrawOpBlock block; foreach (UndoFormatEntry P in format.GetEntries(s, args)) { if (P.Time > args.End) { continue; } block.X = P.X; block.Y = P.Y; block.Z = P.Z; block.Block = P.Block; block.ExtBlock = P.ExtBlock; args.Output(block); } }
public static void DoHighlight(Stream s, UndoFormat format, UndoFormatArgs args) { BufferedBlockSender buffer = new BufferedBlockSender(args.Player); Level lvl = args.Player.level; foreach (UndoFormatEntry P in format.GetEntries(s, args)) { byte block = P.Block, newBlock = P.NewBlock; byte highlight = (newBlock == Block.air || Block.Convert(block) == Block.water || block == Block.waterstill || Block.Convert(block) == Block.lava || block == Block.lavastill) ? Block.red : Block.green; buffer.Add(lvl.PosToInt(P.X, P.Y, P.Z), highlight, 0); } buffer.Send(true); }
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>(); UndoFormatArgs args = new UndoFormatArgs(null, DateTime.MinValue, DateTime.MaxValue, null); for (int i = 0; i < files.Length; i++) { path = files[i]; if (!path.EndsWith(BinFormat.Ext) && !path.EndsWith(TxtFormat.Ext)) { continue; } IEnumerable <UndoFormatEntry> data = null; Player.UndoPos pos; using (FileStream s = File.OpenRead(path)) { data = path.EndsWith(BinFormat.Ext) ? BinFormat.GetEntries(s, args) : TxtFormat.GetEntries(s, args); foreach (UndoFormatEntry P in data) { pos.x = P.X; pos.y = P.Y; pos.z = P.Z; pos.type = P.Block; pos.extType = P.ExtBlock; pos.newtype = P.NewBlock; pos.newExtType = P.NewExtBlock; pos.timeDelta = (int)P.Time.Subtract(Server.StartTimeLocal).TotalSeconds; pos.mapName = P.LevelName; buffer.Add(pos); } buffer.Reverse(); string newPath = Path.ChangeExtension(path, NewFormat.Ext); NewFormat.Save(buffer, newPath); } File.Delete(path); } }
public static void DoUndo(Stream s, UndoFormat format, UndoFormatArgs args) { Level lvl = args.Player == null ? null : args.Player.level; string lastMap = null; foreach (UndoFormatEntry P in format.GetEntries(s, args)) { if (P.LevelName != lastMap) { lvl = LevelInfo.FindExact(P.LevelName); } if (lvl == null || P.Time > args.End) { continue; } UndoBlock(args, lvl, P); } }
protected override IEnumerable <UndoFormatEntry> GetEntries(Stream s, UndoFormatArgs args) { UndoCacheNode node = cache.Tail; if (node == null) { yield break; } UndoFormatEntry pos; bool super = Player.IsSuper(args.Player); DateTime start = args.Start; while (node != null) { Level lvl = LevelInfo.FindExact(node.MapName); if (!super && !args.Player.level.name.CaselessEq(node.MapName)) { node = node.Prev; continue; } List <UndoCacheItem> items = node.Items; pos.LevelName = node.MapName; for (int i = items.Count - 1; i >= 0; i--) { UndoCacheItem item = items[i]; DateTime time = node.BaseTime.AddTicks(item.TimeDelta * TimeSpan.TicksPerSecond); if (time < start) { args.Stop = true; yield break; } pos.Time = time; node.Unpack(item.Index, out pos.X, out pos.Y, out pos.Z); item.GetBlock(out pos.Block, out pos.ExtBlock); item.GetNewBlock(out pos.NewBlock, out pos.NewExtBlock); yield return(pos); } node = node.Prev; } }
public static void DoUndo(string target, ref bool found, UndoFormatArgs args) { List <string> files = GetUndoFiles(target); if (files.Count == 0) { return; } found = true; foreach (string file in files) { using (Stream s = File.OpenRead(file)) { DoUndo(s, GetFormat(file), args); if (args.Stop) { break; } } } }
public override void EnumerateEntries(Stream s, UndoFormatArgs args) { UndoFormatEntry pos = default(UndoFormatEntry); string[] lines = new StreamReader(s).ReadToEnd().SplitSpaces(); 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('&', ' '); 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; } pos.X = ushort.Parse(lines[(i * items) - 6]); pos.Y = ushort.Parse(lines[(i * items) - 5]); pos.Z = ushort.Parse(lines[(i * items) - 4]); pos.Block.BlockID = byte.Parse(lines[(i * items) - 2]); pos.NewBlock.BlockID = byte.Parse(lines[(i * items) - 1]); args.Output(pos); } }
protected override IEnumerable <UndoFormatEntry> GetEntries(Stream s, UndoFormatArgs args) { UndoFormatEntry pos; pos.NewExtBlock = 0; pos.ExtBlock = 0; string[] lines = new StreamReader(s).ReadToEnd().Split(' '); Player p = args.Player; bool super = p == null || p.ircNick != null; DateTime start = args.Start; // 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; } string map = lines[(i * items) - 7]; if (!super && !p.level.name.CaselessEq(map)) { continue; } pos.LevelName = map; pos.X = ushort.Parse(lines[(i * items) - 6]); pos.Y = ushort.Parse(lines[(i * items) - 5]); pos.Z = ushort.Parse(lines[(i * items) - 4]); pos.Block = byte.Parse(lines[(i * items) - 2]); pos.NewBlock = byte.Parse(lines[(i * items) - 1]); yield return(pos); } }
/// <summary> Enumerates through all the entries in the undo file. </summary> public abstract void EnumerateEntries(Stream s, UndoFormatArgs args);
protected abstract IEnumerable <UndoFormatEntry> GetEntries(Stream s, UndoFormatArgs args);