예제 #1
0
        protected override void SaveUndoData(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.Tail;

                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.Prev;
                }
            }
        }
예제 #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
        protected override void SaveUndoData(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;
                        }

                        ushort width, height, length;
                        LvlFile.LoadDimensions(LevelInfo.LevelPath(uP.mapName), out width, out height, out length);
                        node.Width = width; node.Height = height; node.Length = length;
                        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);
                }
            }
        }
예제 #4
0
        /// <summary> Appends an item to the cache. </summary>
        public void Add(Level lvl, Player.UndoPos item)
        {
            DateTime time = Server.StartTime.AddTicks(item.timeDelta * TimeSpan.TicksPerSecond);

            if (Head == null)
            {
                Head = UndoCacheNode.Make(lvl, time);
                Tail = Head;
            }

            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++;
        }
예제 #5
0
        protected override void ReadUndoData(List <Player.UndoPos> buffer, string path)
        {
            Player.UndoPos Pos;
            UndoCacheItem  item = default(UndoCacheItem);

            using (Stream fs = File.OpenRead(path))
                using (BinaryReader r = new BinaryReader(fs))
                {
                    int approxEntries = (int)(fs.Length / entrySize);
                    if (buffer.Capacity < approxEntries)
                    {
                        buffer.Capacity = approxEntries;
                    }
                    while (fs.Position < fs.Length)
                    {
                        ChunkHeader chunk = ReadHeader(fs, r);
                        Pos.mapName = chunk.LevelName;

                        for (int j = 0; j < chunk.Entries; j++)
                        {
                            item.Flags = r.ReadUInt16();
                            DateTime time = chunk.BaseTime.AddTicks((item.Flags & 0x3FFF) * TimeSpan.TicksPerSecond);
                            Pos.timeDelta = (int)time.Subtract(Server.StartTime).TotalSeconds;
                            int index = r.ReadInt32();
                            Pos.x = (ushort)(index % chunk.Width);
                            Pos.y = (ushort)((index / chunk.Width) / chunk.Length);
                            Pos.z = (ushort)((index / chunk.Width) % chunk.Length);

                            item.Type    = r.ReadByte();
                            item.NewType = r.ReadByte();
                            item.GetBlock(out Pos.type, out Pos.extType);
                            item.GetNewBlock(out Pos.newtype, out Pos.newExtType);
                            buffer.Add(Pos);
                        }
                    }
                }
        }
예제 #6
0
        protected override bool UndoEntry(Player p, string path, Vec3U16[] marks,
                                          ref byte[] temp, DateTime start)
        {
            List <ChunkHeader> list = new List <ChunkHeader>();
            int timeDelta           = (int)DateTime.UtcNow.Subtract(Server.StartTime).TotalSeconds;

            Player.UndoPos Pos = default(Player.UndoPos);
            Vec3U16        min = marks[0], max = marks[1];
            bool           undoArea = min.X != ushort.MaxValue;
            UndoCacheItem  item     = default(UndoCacheItem);

            using (Stream fs = File.OpenRead(path))
                using (BinaryReader r = new BinaryReader(fs))
                {
                    ReadHeaders(list, r);
                    for (int i = list.Count - 1; i >= 0; i--)
                    {
                        ChunkHeader chunk = list[i];
                        Level       lvl;
                        if (!CheckChunk(chunk, start, p, out lvl))
                        {
                            return(false);
                        }
                        if (lvl == null || (p.level != null && !p.level.name.CaselessEq(lvl.name)))
                        {
                            continue;
                        }
                        BufferedBlockSender buffer = new BufferedBlockSender(lvl);
                        if (!undoArea)
                        {
                            min = new Vec3U16(0, 0, 0);
                            max = new Vec3U16((ushort)(lvl.Width - 1), (ushort)(lvl.Height - 1), (ushort)(lvl.Length - 1));
                        }

                        Pos.mapName = chunk.LevelName;
                        fs.Seek(chunk.DataPosition, SeekOrigin.Begin);
                        if (temp == null)
                        {
                            temp = new byte[ushort.MaxValue * entrySize];
                        }
                        fs.Read(temp, 0, chunk.Entries * entrySize);

                        for (int j = chunk.Entries - 1; j >= 0; j--)
                        {
                            int offset = j * entrySize;
                            item.Flags = U16(temp, offset + 0);
                            DateTime time = chunk.BaseTime.AddTicks((item.Flags & 0x3FFF) * TimeSpan.TicksPerSecond);
                            if (time < start)
                            {
                                buffer.CheckIfSend(true); return(false);
                            }

                            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);
                            if (Pos.x < min.X || Pos.y < min.Y || Pos.z < min.Z ||
                                Pos.x > max.X || Pos.y > max.Y || Pos.z > max.Z)
                            {
                                continue;
                            }

                            item.Type    = temp[offset + 6];
                            item.NewType = temp[offset + 7];
                            item.GetBlock(out Pos.type, out Pos.extType);
                            item.GetNewBlock(out Pos.newtype, out Pos.newExtType);
                            UndoBlock(p, lvl, Pos, timeDelta, buffer);
                        }
                        buffer.CheckIfSend(true);
                    }
                }
            return(true);
        }