diff --git a/Commands/Moderation/CmdHighlight.cs b/Commands/Moderation/CmdHighlight.cs index 83aff18f7..b1a326959 100644 --- a/Commands/Moderation/CmdHighlight.cs +++ b/Commands/Moderation/CmdHighlight.cs @@ -77,12 +77,14 @@ namespace MCGalaxy.Commands { for (int i = items.Count - 1; i >= 0; i--) { UndoCacheItem item = items[i]; ushort x, y, z; - node.Unpack(item.Index, out x, out y, out z); + node.Unpack(item.Index, out x, out y, out z); DateTime time = node.BaseTime.AddSeconds(item.TimeDelta + seconds); if (time < DateTime.UtcNow) return; byte b = lvl.GetTile(x, y, z); - if (b == item.NewType || Block.Convert(b) == Block.water || Block.Convert(b) == Block.lava) { + byte newTile = 0, newExtTile = 0; + item.GetNewExtBlock(out newTile, out newExtTile); + if (b == newTile || Block.Convert(b) == Block.water || Block.Convert(b) == Block.lava) { if (b == Block.air || Block.Convert(b) == Block.water || Block.Convert(b) == Block.lava) p.SendBlockchange(x, y, z, Block.red); else diff --git a/Commands/building/CmdRedo.cs b/Commands/building/CmdRedo.cs index 72d46bd14..fed70566b 100644 --- a/Commands/building/CmdRedo.cs +++ b/Commands/building/CmdRedo.cs @@ -49,13 +49,12 @@ namespace MCGalaxy.Commands { for (int i = items.Count - 1; i >= 0; i--) { UndoCacheItem item = items[i]; ushort x, y, z; - node.Unpack(item.Index, out x, out y, out z); + node.Unpack(item.Index, out x, out y, out z); + byte tile, extTile; + item.GetExtBlock(out tile, out extTile); - byte type = lvl.GetTile(x, y, z), extType = 0; - if (type == Block.custom_block) - extType = lvl.GetExtTile(x, y, z); - if (lvl.DoBlockchange(p, x, y, z, item.Type, item.ExtType)) { - buffer.Add(lvl.PosToInt(x, y, z), item.Type, item.ExtType); + if (lvl.DoBlockchange(p, x, y, z, tile, extTile)) { + buffer.Add(lvl.PosToInt(x, y, z), tile, extTile); buffer.CheckIfSend(false); } } diff --git a/Commands/building/CmdUndo.cs b/Commands/building/CmdUndo.cs index 2b7648d11..8950fd359 100644 --- a/Commands/building/CmdUndo.cs +++ b/Commands/building/CmdUndo.cs @@ -177,16 +177,21 @@ namespace MCGalaxy.Commands if (time < DateTime.UtcNow) { buffer.CheckIfSend(true); return; } byte b = lvl.GetTile(x, y, z); - if (b == item.NewType || Block.Convert(b) == Block.water || Block.Convert(b) == Block.lava) { + byte newTile = 0, newExtTile = 0; + item.GetNewExtBlock(out newTile, out newExtTile); + if (b == newTile || Block.Convert(b) == Block.water || Block.Convert(b) == Block.lava) { Player.UndoPos uP = default(Player.UndoPos); - uP.newtype = item.Type; uP.newExtType = item.ExtType; byte extType = 0; - if (b == Block.custom_block) extType = lvl.GetExtTile(x, y, z); - if (lvl.DoBlockchange(p, x, y, z, item.Type, item.ExtType)) { - buffer.Add(lvl.PosToInt(x, y, z), item.Type, item.ExtType); + if (b == Block.custom_block) extType = lvl.GetExtTile(x, y, z); + byte tile = 0, extTile = 0; + item.GetExtBlock(out tile, out extTile); + + if (lvl.DoBlockchange(p, x, y, z, tile, extTile)) { + buffer.Add(lvl.PosToInt(x, y, z), tile, extTile); buffer.CheckIfSend(false); } + uP.newtype = tile; uP.newExtType = extTile; uP.type = b; uP.extType = extType; uP.x = x; uP.y = y; uP.z = z; uP.mapName = node.MapName; diff --git a/Player/Undo/UndoCache.cs b/Player/Undo/UndoCache.cs index 55da35c66..d7a8cafd3 100644 --- a/Player/Undo/UndoCache.cs +++ b/Player/Undo/UndoCache.cs @@ -34,6 +34,8 @@ namespace MCGalaxy.Util { /// Total number of items in the cache. public volatile int Count; + public const int TimeDeltaMax = (1 << 13) - 1; + /// Appends an item to the cache. public void Add(Level lvl, Player.UndoPos item) { DateTime time = Server.StartTime.AddTicks(item.timeDelta * TimeSpan.TicksPerSecond); @@ -43,7 +45,7 @@ namespace MCGalaxy.Util { } if (lvl.name != Tail.MapName || lvl.Width != Tail.Width || lvl.Height != Tail.Height || - lvl.Length != Tail.Length || Math.Abs((time - Tail.BaseTime).TotalSeconds) > 32767) { + lvl.Length != Tail.Length || Math.Abs((time - Tail.BaseTime).TotalSeconds) > TimeDeltaMax) { UndoCacheNode node = UndoCacheNode.Make(lvl, time); Tail.Next = node; node.Prev = Tail; Tail = node; @@ -95,16 +97,53 @@ namespace MCGalaxy.Util { [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct UndoCacheItem { public int Index; - public byte Type, ExtType; - public byte NewType, NewExtType; - public short TimeDelta; + public byte Type, NewType; + public ushort Flags; // upper 2 bits for 'ext' or 'physics' type, lower 14 bits for time delta. + + public short TimeDelta { + get { + int delta = Flags & 0x3FFF; + return delta >= 0x2000 ? (short)(delta - 16384) : (short)delta; + } + } + + public void GetExtBlock(out byte type, out byte extType) { + if ((Flags & (1 << 14)) != 0) { + type = Block.custom_block; + extType = Type; + } else { + type = Type; + extType = 0; + } + } + + public void GetNewExtBlock(out byte type, out byte extType) { + if ((Flags & (1 << 15)) != 0) { + type = Block.custom_block; + extType = NewType; + } else { + type = NewType; + extType = 0; + } + } public static UndoCacheItem Make(UndoCacheNode node, short timeDelta, ref Player.UndoPos pos) { UndoCacheItem item = default(UndoCacheItem); item.Index = pos.x + node.Width * (pos.z + node.Length * pos.y); - item.Type = pos.type; item.ExtType = pos.extType; - item.NewType = pos.newtype; item.NewExtType = pos.newExtType; - item.TimeDelta = timeDelta; + item.Flags = (ushort)(timeDelta & 0x3FFF); + + if (pos.type == Block.custom_block) { + item.Type = pos.extType; + item.Flags |= (ushort)(1 << 14); + } else { + item.Type = pos.type; + } + if (pos.newtype == Block.custom_block) { + item.NewType = pos.newExtType; + item.Flags |= (ushort)(1 << 15); + } else { + item.NewType = pos.newtype; + } return item; } } diff --git a/Player/Undo/UndoFileBin.cs b/Player/Undo/UndoFileBin.cs index afead556a..f5146c706 100644 --- a/Player/Undo/UndoFileBin.cs +++ b/Player/Undo/UndoFileBin.cs @@ -70,13 +70,18 @@ namespace MCGalaxy.Util { WriteChunkEntries(w, last.Entries, entriesPos); last = WriteEmptyChunk(w, node.MapName, time, ref entriesPos); } + ushort x, y, z; node.Unpack(uP.Index, out x, out y, out z); + byte tile = 0, extTile = 0; + uP.GetExtBlock(out tile, out extTile); + byte newTile = 0, newExtTile = 0; + uP.GetNewExtBlock(out newTile, out newExtTile); w.Write((ushort)timeDiff); w.Write(x); w.Write(y); w.Write(z); - w.Write(uP.Type); w.Write(uP.ExtType); - w.Write(uP.NewType); w.Write(uP.NewExtType); + w.Write(tile); w.Write(extTile); + w.Write(newTile); w.Write(newExtTile); last.Entries++; } if (last.Entries > 0) @@ -152,7 +157,7 @@ namespace MCGalaxy.Util { Pos.newtype = oldType; Pos.newExtType = oldExtType; Pos.extType = newExtType; Pos.timeDelta = timeDelta; if (lvl.DoBlockchange(p, Pos.x, Pos.y, Pos.z, Pos.newtype, Pos.newExtType)) { - buffer.Add(lvl.PosToInt(Pos.x, Pos.y, Pos.z), Pos.newtype, Pos.newExtType); + buffer.Add(lvl.PosToInt(Pos.x, Pos.y, Pos.z), Pos.newtype, Pos.newExtType); buffer.CheckIfSend(false); } if (p != null) p.RedoBuffer.Add(lvl, Pos);