Пример #1
0
        /// <summary>
        ///     Saves all history entries in the Entries list to file.
        /// </summary>
        public void SaveEntries()
        {
            if (FileCompressed()) // -- Need to make sure the file is decompressed just as a sanity check before editing any data.
                GZip.DecompressFile(_baseName + ".hch");

            var indexTableSize = (_thisMap.CWMap.SizeX*_thisMap.CWMap.SizeY*_thisMap.CWMap.SizeZ)*4;

            using (var fs = new FileStream(_baseName + ".hch", FileMode.Open)) {
                lock (_eLock) {
                    foreach (var h in Entries) {
                        var temp = new byte[4];
                        var index = (h.Y*_thisMap.CWMap.SizeZ + h.Z)*_thisMap.CWMap.SizeX + h.X;

                        fs.Seek(index*4, SeekOrigin.Begin);
                        fs.Read(temp, 0, 4);

                        var entryIndex = BitConverter.ToInt32(temp, 0);

                        if (entryIndex == 0) {
                            // -- There are no entries for this block yet.
                            fs.Seek(0, SeekOrigin.End); // -- Seek to the end of the file.
                            var endLocation = ((int) fs.Position - indexTableSize); // -- Store the index for this entry

                            fs.WriteByte(1); // -- There is now 1 entry
                            fs.Write(h.ToByteArray(), 0, 10); // -- And this is the data.

                            fs.Seek(index*4, SeekOrigin.Begin); // -- Seek back to the Int for this block.
                            fs.Write(BitConverter.GetBytes(endLocation), 0, 4);
                            // -- Write in the location for that block's entries.
                            continue; // -- Move on to the next HistoryEntry.
                        }

                        // -- There is already one or more entries for this block.
                        fs.Seek(indexTableSize + entryIndex, SeekOrigin.Begin);
                        // -- Seek to the position for this block
                        var numEntries = fs.ReadByte(); // -- And get the number of entries.

                        // -- Before adding anything, we'll check to see if this user already has an entry.
                        var tempArray = new HistoryEntry[numEntries];
                        var shift = false;

                        for (var i = 0; i < numEntries; i++) // -- Modify the timestamp and block if so..
                        {
                            // -- Load the entries for checking.
                            var thisEntry = new byte[10];

                            fs.Read(thisEntry, 0, 10);
                            tempArray[i] = HistoryEntry.FromByteArray(thisEntry, h.X, h.Y, h.Z);

                            if (tempArray[i].Player == h.Player) {
                                // -- If there is a player, update the new block, and the change time.
                                tempArray[i].Timestamp = h.Timestamp;
                                tempArray[i].NewBlock = h.NewBlock;
                                shift = true; // -- This entry now needs to be shifted.
                            }

                        }

                        if (shift) {
                            tempArray = tempArray.OrderBy(o => o.Timestamp).ToArray();
                            // -- If there was an entry, order the array...
                            fs.Seek((indexTableSize + entryIndex) + 1, SeekOrigin.Begin);
                            // -- Seek to the beginning of the entries..

                            foreach (var z in tempArray) // -- Write the newly ordered entries
                                fs.Write(z.ToByteArray(), 0, 10);

                            continue; // -- Move to the next iteration.
                        }

                        // -- If the user did not have any previous entries...
                        // -- Now We'll handle the easy case first, if we've already reached the maximum.

                        if (numEntries == ServerCore.MaxHistoryEntries) {
                            tempArray[0] = h; // -- Overwrite the old entry with the newest one.
                            tempArray = tempArray.OrderBy(o => o.Timestamp).ToArray();
                            // -- Order the array by timestamp, so that our new entry is at the end.

                            fs.Seek((indexTableSize + entryIndex) + 1, SeekOrigin.Begin);
                            // -- Seek to the beginning of the entries..

                            foreach (var z in tempArray) // -- Write the newly ordered entries
                                fs.Write(z.ToByteArray(), 0, 10);

                            continue; // -- Move on to the next iteration.
                        }

                        // -- And finally, the condition that causes fragmentation :( Actually creating an entry.

                        fs.Seek(0, SeekOrigin.End);
                        var endPosition = ((int) fs.Position - indexTableSize);
                        fs.WriteByte((byte) (numEntries + 1));

                        foreach (var z in tempArray)
                            fs.Write(z.ToByteArray(), 0, 10);

                        fs.Write(h.ToByteArray(), 0, 10);

                        fs.Seek(index*4, SeekOrigin.Begin); // -- Seek back to the Int for this block.
                        fs.Write(BitConverter.GetBytes(endPosition), 0, 4);
                        // -- Write in the location for that block's entries.

                        _fragmented = true;
                        // -- Annnd that's all folks!
                    }
                    Entries.Clear();
                }
            }
        }