示例#1
0
        protected override void Save(UndoCache buffer, string path)
        {
            using (FileStream fs = File.Create(path)) {
                BinaryWriter  w          = new BinaryWriter(fs);
                long          entriesPos = 0;
                ChunkHeader   last       = default(ChunkHeader);
                UndoCacheNode node       = buffer.Head;

                while (node != null)
                {
                    List <UndoCacheItem> items = node.Items;
                    for (int i = 0; i < items.Count; i++)
                    {
                        UndoCacheItem uP       = items[i];
                        DateTime      time     = node.BaseTime.AddSeconds(uP.TimeDelta);
                        int           timeDiff = (int)(time - last.BaseTime).TotalSeconds;
                        if (last.LevelName != node.MapName || timeDiff > (65535 >> 2) || last.Entries == ushort.MaxValue)
                        {
                            WriteChunkEntries(w, last.Entries, entriesPos);
                            last = WriteEmptyChunk(w, node, time, ref entriesPos);
                        }

                        int flags = (uP.Flags & 0xC000) | timeDiff;
                        w.Write((ushort)flags); w.Write(uP.Index);
                        w.Write(uP.Type); w.Write(uP.NewType);
                        last.Entries++;
                    }
                    if (last.Entries > 0)
                    {
                        WriteChunkEntries(w, last.Entries, entriesPos);
                    }
                    node = node.Next;
                }
            }
        }
示例#2
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.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);
        }
示例#3
0
        public static UndoCacheNode Make(Level lvl, DateTime time)
        {
            UndoCacheNode node = new UndoCacheNode();

            node.MapName  = lvl.name;
            node.Width    = lvl.Width; node.Height = lvl.Height; node.Length = lvl.Length;
            node.BaseTime = time;
            return(node);
        }
示例#4
0
        static ChunkHeader WriteEmptyChunk(BinaryWriter w, UndoCacheNode node, DateTime time, ref long entriesPos)
        {
            ChunkHeader header = default(ChunkHeader);

            time = time.ToUniversalTime();
            byte[] mapBytes = Encoding.UTF8.GetBytes(node.MapName);
            w.Write((ushort)mapBytes.Length);
            w.Write(mapBytes); header.LevelName  = node.MapName;
            w.Write(time.Ticks); header.BaseTime = time;

            entriesPos = w.BaseStream.Position;
            w.Write((ushort)0);
            w.Write((ushort)node.Width); header.Width   = (ushort)node.Width;
            w.Write((ushort)node.Height); header.Height = (ushort)node.Height;
            w.Write((ushort)node.Length); header.Length = (ushort)node.Length;
            return(header);
        }
示例#5
0
        protected override void Save(List <Player.UndoPos> buffer, string path)
        {
            UndoCacheNode node           = new UndoCacheNode();
            string        lastLoggedName = "";

            using (FileStream fs = File.Create(path)) {
                BinaryWriter w          = new BinaryWriter(fs);
                long         entriesPos = 0;
                ChunkHeader  last       = default(ChunkHeader);

                foreach (Player.UndoPos uP in buffer)
                {
                    DateTime time     = Server.StartTime.AddSeconds(uP.timeDelta);
                    int      timeDiff = (int)(time - last.BaseTime).TotalSeconds;
                    if (last.LevelName != uP.mapName || timeDiff > (65535 >> 2) || last.Entries == ushort.MaxValue)
                    {
                        if (!LevelInfo.ExistsOffline(uP.mapName))
                        {
                            if (uP.mapName != lastLoggedName)
                            {
                                lastLoggedName = uP.mapName;
                                Server.s.Log("Missing map file \"" + lastLoggedName + "\", skipping undo entries");
                            }
                            continue;
                        }

                        Vec3U16 dims = IMapImporter.Formats[0].ReadDimensions(LevelInfo.LevelPath(uP.mapName));
                        node.Width = dims.X; node.Height = dims.Y; node.Length = dims.Z;
                        WriteChunkEntries(w, last.Entries, entriesPos);
                        node.MapName = uP.mapName;
                        last         = WriteEmptyChunk(w, node, time, ref entriesPos);
                    }

                    UndoCacheItem item  = UndoCacheItem.Make(node, 0, uP);
                    int           flags = (item.Flags & 0xC000) | timeDiff;
                    w.Write((ushort)flags); w.Write(item.Index);
                    w.Write(item.Type); w.Write(item.NewType);
                    last.Entries++;
                }
                if (last.Entries > 0)
                {
                    WriteChunkEntries(w, last.Entries, entriesPos);
                }
            }
        }
示例#6
0
        /// <summary> Removes all items from the cache and resets the state to default. </summary>
        public void Clear()
        {
            Count = 0;
            if (Tail == null)
            {
                return;
            }
            LastClear = DateTime.UtcNow;

            UndoCacheNode node = Tail;

            while (node != null)
            {
                node.Items = null;
                node       = node.Prev;
            }
            Tail = null; Head = null;
        }
示例#7
0
        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;
            }
        }
示例#8
0
        /// <summary> Appends an item to the cache. </summary>
        public void Add(Level lvl, Player.UndoPos item)
        {
            lock (AddLock) {
                DateTime time = Server.StartTime.AddTicks(item.timeDelta * TimeSpan.TicksPerSecond);
                if (Tail == null)
                {
                    Tail = UndoCacheNode.Make(lvl, time); Head = Tail;
                }

                if (lvl.name != Tail.MapName || lvl.Width != Tail.Width || lvl.Height != Tail.Height ||
                    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;
                }

                short timeDiff = (short)(time - Tail.BaseTime).TotalSeconds;
                Tail.Items.Add(UndoCacheItem.Make(Tail, timeDiff, ref item));
                Count++;
            }
        }
示例#9
0
 public static UndoCacheItem Make(UndoCacheNode node, short timeDelta, Player.UndoPos pos)
 {
     return(Make(node, timeDelta, ref pos));
 }