diff --git a/MCGalaxy/Database/BlockDB/BlockDB.cs b/MCGalaxy/Database/BlockDB/BlockDB.cs
index 02d715a08..0e3c5e48e 100644
--- a/MCGalaxy/Database/BlockDB/BlockDB.cs
+++ b/MCGalaxy/Database/BlockDB/BlockDB.cs
@@ -65,12 +65,12 @@ namespace MCGalaxy.DB {
public void WriteEntries() {
if (Cache.Head == null) return;
- ValidateBackingFile();
+ BlockDBFile format = ValidateBackingFile();
using (Stream s = OpenWrite()) {
// This truncates the lower 4 bits off - so e.g. if a power off occurred
// and 21 bytes were in the file, this sets the position to byte 16
s.Position = s.Length & ~0x0F;
- BlockDBFile.WriteEntries(s, Cache);
+ format.WriteEntries(s, Cache);
Cache.Clear();
}
}
@@ -93,11 +93,11 @@ namespace MCGalaxy.DB {
Vec3U16 dims;
using (Stream s = OpenRead()) {
- BlockDBFile.ReadHeader(s, out dims);
+ BlockDBFile format = BlockDBFile.ReadHeader(s, out dims);
if (x >= dims.X || y >= dims.Y || z >= dims.Z) return;
int index = (y * dims.Z + z) * dims.X + x;
- BlockDBFile.FindChangesAt(s, index, output);
+ format.FindChangesAt(s, index, output);
}
FindInMemoryAt(x, y, z, output);
}
@@ -131,8 +131,8 @@ namespace MCGalaxy.DB {
if (!File.Exists(FilePath)) return false;
using (Stream s = OpenRead()) {
- BlockDBFile.ReadHeader(s, out dims);
- return BlockDBFile.FindChangesBy(s, ids, startDelta, endDelta, output);
+ BlockDBFile format = BlockDBFile.ReadHeader(s, out dims);
+ return format.FindChangesBy(s, ids, startDelta, endDelta, output);
}
}
@@ -175,9 +175,10 @@ namespace MCGalaxy.DB {
/// Checks if the backing file exists on disc, and if not, creates it.
/// Also recreates the backing file if dimensions on disc are less than those in memory.
- void ValidateBackingFile() {
+ BlockDBFile ValidateBackingFile() {
Vec3U16 fileDims;
+ BlockDBFile format = BlockDBFile.V1;
if (!File.Exists(FilePath)) {
using (Stream s = OpenWrite()) {
fileDims = Dims;
@@ -185,12 +186,13 @@ namespace MCGalaxy.DB {
}
} else {
using (Stream s = OpenRead()) {
- BlockDBFile.ReadHeader(s, out fileDims);
+ format = BlockDBFile.ReadHeader(s, out fileDims);
}
if (fileDims.X < Dims.X || fileDims.Y < Dims.Y || fileDims.Z < Dims.Z) {
BlockDBFile.ResizeBackingFile(this);
}
}
+ return format;
}
diff --git a/MCGalaxy/Database/BlockDB/BlockDBFile.V1.cs b/MCGalaxy/Database/BlockDB/BlockDBFile.V1.cs
new file mode 100644
index 000000000..875b5188e
--- /dev/null
+++ b/MCGalaxy/Database/BlockDB/BlockDBFile.V1.cs
@@ -0,0 +1,158 @@
+/*
+ Copyright 2015 MCGalaxy
+
+ Dual-licensed under the Educational Community License, Version 2.0 and
+ the GNU General Public License, Version 3 (the "Licenses"); you may
+ not use this file except in compliance with the Licenses. You may
+ obtain a copy of the Licenses at
+
+ http://www.opensource.org/licenses/ecl2.php
+ http://www.gnu.org/licenses/gpl-3.0.html
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the Licenses are distributed on an "AS IS"
+ BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ or implied. See the Licenses for the specific language governing
+ permissions and limitations under the Licenses.
+ */
+using System;
+using System.IO;
+using MCGalaxy.Util;
+using MCGalaxy.Maths;
+
+namespace MCGalaxy.DB {
+
+ public unsafe sealed class BlockDBFile_V1 : BlockDBFile {
+
+ public override void WriteEntries(Stream s, FastList entries) {
+ byte[] bulk = new byte[BulkEntries * EntrySize];
+ WriteEntries(s, bulk, entries.Items, entries.Count);
+ }
+
+ public override void WriteEntries(Stream s, BlockDBCache cache) {
+ byte[] bulk = new byte[BulkEntries * EntrySize];
+ BlockDBCacheNode node = cache.Tail;
+
+ while (node != null) {
+ WriteEntries(s, bulk, node);
+ lock (cache.Locker)
+ node = node.Next;
+ }
+ }
+
+ static void WriteEntries(Stream s, byte[] bulk, BlockDBEntry[] entries, int count) {
+ for (int i = 0; i < count; i += BulkEntries) {
+ int bulkCount = Math.Min(BulkEntries, count - i);
+ for (int j = 0; j < bulkCount; j++) {
+ WriteEntry(entries[i + j], bulk, j * EntrySize);
+ }
+ s.Write(bulk, 0, bulkCount * EntrySize);
+ }
+ }
+
+ static void WriteEntries(Stream s, byte[] bulk, BlockDBCacheNode node) {
+ int count = node.Count;
+ for (int i = 0; i < count; i += BulkEntries) {
+ int bulkCount = Math.Min(BulkEntries, count - i);
+ for (int j = 0; j < bulkCount; j++) {
+ BlockDBEntry entry = node.Unpack(node.Entries[i + j]);
+ WriteEntry(entry, bulk, j * EntrySize);
+ }
+ s.Write(bulk, 0, bulkCount * EntrySize);
+ }
+ }
+
+ // Inlined WriteI32/WriteU16 for better performance
+ static void WriteEntry(BlockDBEntry entry, byte[] bulk, int index) {
+ bulk[index + 0 ] = (byte)(entry.PlayerID);
+ bulk[index + 1 ] = (byte)(entry.PlayerID >> 8);
+ bulk[index + 2 ] = (byte)(entry.PlayerID >> 16);
+ bulk[index + 3 ] = (byte)(entry.PlayerID >> 24);
+
+ bulk[index + 4 ] = (byte)(entry.TimeDelta);
+ bulk[index + 5 ] = (byte)(entry.TimeDelta >> 8);
+ bulk[index + 6 ] = (byte)(entry.TimeDelta >> 16);
+ bulk[index + 7 ] = (byte)(entry.TimeDelta >> 24);
+
+ bulk[index + 8 ] = (byte)(entry.Index);
+ bulk[index + 9 ] = (byte)(entry.Index >> 8);
+ bulk[index + 10] = (byte)(entry.Index >> 16);
+ bulk[index + 11] = (byte)(entry.Index >> 24);
+
+ bulk[index + 12] = entry.OldRaw;
+ bulk[index + 13] = entry.NewRaw;
+ bulk[index + 14] = (byte)(entry.Flags);
+ bulk[index + 15] = (byte)(entry.Flags >> 8);
+ }
+
+
+ public override void FindChangesAt(Stream s, int index, Action output) {
+ byte[] bulk = new byte[BulkEntries * EntrySize];
+ fixed (byte* ptr = bulk) {
+ int dbEntries = (int)(s.Length / EntrySize) - HeaderEntries;
+ while (dbEntries > 0) {
+ int count = Math.Min(dbEntries, BulkEntries);
+ ReadFully(s, bulk, count * EntrySize);
+ BlockDBEntry* entryPtr = (BlockDBEntry*)ptr;
+
+ for (int i = 0; i < count; i++) {
+ if (entryPtr->Index == index) {
+ output(*entryPtr);
+ }
+ entryPtr++;
+ }
+ dbEntries -= count;
+ }
+ }
+ }
+
+ public override bool FindChangesBy(Stream s, int[] ids, int start, int end, Action output) {
+ byte[] bulk = new byte[BulkEntries * EntrySize];
+ fixed (byte* ptr = bulk) {
+ int dbEntries = (int)(s.Length / EntrySize) - HeaderEntries;
+
+ while (dbEntries > 0) {
+ int count = Math.Min(dbEntries, BulkEntries);
+ // find the correct position for the start of this bulk read
+ s.Position = (dbEntries - count + HeaderEntries) * (long)EntrySize;
+
+ ReadFully(s, bulk, count * EntrySize);
+ BlockDBEntry* entryPtr = (BlockDBEntry*)ptr;
+ entryPtr += (count - 1);
+
+ for (int i = count - 1; i >= 0; i--) {
+ if (entryPtr->TimeDelta < start) return true;
+
+ if (entryPtr->TimeDelta <= end) {
+ for (int j = 0; j < ids.Length; j++) {
+ if (entryPtr->PlayerID != ids[j]) continue;
+ output(*entryPtr); break;
+ }
+ }
+ entryPtr--;
+ }
+ dbEntries -= count;
+ }
+ }
+ return false;
+ }
+
+ static ushort ReadU16(byte[] array, int offset) {
+ return (ushort)(array[offset] | array[offset + 1] << 8);
+ }
+
+ static void WriteU16(ushort value, byte[] array, int index) {
+ array[index++] = (byte)(value);
+ array[index++] = (byte)(value >> 8);
+ }
+
+ static void ReadFully(Stream stream, byte[] dst, int count) {
+ int total = 0;
+ do {
+ int read = stream.Read(dst, total, count - total);
+ if (read == 0) throw new EndOfStreamException();
+ total += read;
+ } while (total < count);
+ }
+ }
+}
\ No newline at end of file
diff --git a/MCGalaxy/Database/BlockDB/BlockDBFile.cs b/MCGalaxy/Database/BlockDB/BlockDBFile.cs
index c7b0fd48b..fcdfec414 100644
--- a/MCGalaxy/Database/BlockDB/BlockDBFile.cs
+++ b/MCGalaxy/Database/BlockDB/BlockDBFile.cs
@@ -22,13 +22,15 @@ using MCGalaxy.Maths;
namespace MCGalaxy.DB {
- public unsafe static class BlockDBFile {
+ public unsafe abstract class BlockDBFile {
public const byte Version = 1;
public const int EntrySize = 16;
public const int HeaderEntries = 1;
public const int BulkEntries = 256;
+ public static BlockDBFile V1 = new BlockDBFile_V1();
+
public static string FilePath(string map) { return "blockdb/" + map + ".cbdb"; }
public static string DumpPath(string map) { return "blockdb/" + map + ".dump"; }
public static string TempPath(string map) { return "blockdb/" + map + ".temp"; }
@@ -43,7 +45,7 @@ namespace MCGalaxy.DB {
s.Write(header, 0, EntrySize);
}
- public static void ReadHeader(Stream s, out Vec3U16 dims) {
+ public static BlockDBFile ReadHeader(Stream s, out Vec3U16 dims) {
dims = default(Vec3U16);
byte[] header = new byte[EntrySize * HeaderEntries];
ReadFully(s, header, header.Length);
@@ -57,125 +59,20 @@ namespace MCGalaxy.DB {
dims.X = ReadU16(header, 10);
dims.Y = ReadU16(header, 12);
dims.Z = ReadU16(header, 14);
+ return V1;
}
- public static void WriteEntries(Stream s, FastList entries) {
- byte[] bulk = new byte[BulkEntries * EntrySize];
- WriteEntries(s, bulk, entries.Items, entries.Count);
- }
+ public abstract void WriteEntries(Stream s, FastList entries);
- public static void WriteEntries(Stream s, BlockDBCache cache) {
- byte[] bulk = new byte[BulkEntries * EntrySize];
- BlockDBCacheNode node = cache.Tail;
-
- while (node != null) {
- WriteEntries(s, bulk, node);
- lock (cache.Locker)
- node = node.Next;
- }
- }
-
- static void WriteEntries(Stream s, byte[] bulk, BlockDBEntry[] entries, int count) {
- for (int i = 0; i < count; i += BulkEntries) {
- int bulkCount = Math.Min(BulkEntries, count - i);
- for (int j = 0; j < bulkCount; j++) {
- WriteEntry(entries[i + j], bulk, j * EntrySize);
- }
- s.Write(bulk, 0, bulkCount * EntrySize);
- }
- }
-
- static void WriteEntries(Stream s, byte[] bulk, BlockDBCacheNode node) {
- int count = node.Count;
- for (int i = 0; i < count; i += BulkEntries) {
- int bulkCount = Math.Min(BulkEntries, count - i);
- for (int j = 0; j < bulkCount; j++) {
- BlockDBEntry entry = node.Unpack(node.Entries[i + j]);
- WriteEntry(entry, bulk, j * EntrySize);
- }
- s.Write(bulk, 0, bulkCount * EntrySize);
- }
- }
-
- // Inlined WriteI32/WriteU16 for better performance
- static void WriteEntry(BlockDBEntry entry, byte[] bulk, int index) {
- bulk[index + 0 ] = (byte)(entry.PlayerID);
- bulk[index + 1 ] = (byte)(entry.PlayerID >> 8);
- bulk[index + 2 ] = (byte)(entry.PlayerID >> 16);
- bulk[index + 3 ] = (byte)(entry.PlayerID >> 24);
-
- bulk[index + 4 ] = (byte)(entry.TimeDelta);
- bulk[index + 5 ] = (byte)(entry.TimeDelta >> 8);
- bulk[index + 6 ] = (byte)(entry.TimeDelta >> 16);
- bulk[index + 7 ] = (byte)(entry.TimeDelta >> 24);
-
- bulk[index + 8 ] = (byte)(entry.Index);
- bulk[index + 9 ] = (byte)(entry.Index >> 8);
- bulk[index + 10] = (byte)(entry.Index >> 16);
- bulk[index + 11] = (byte)(entry.Index >> 24);
-
- bulk[index + 12] = entry.OldRaw;
- bulk[index + 13] = entry.NewRaw;
- bulk[index + 14] = (byte)(entry.Flags);
- bulk[index + 15] = (byte)(entry.Flags >> 8);
- }
-
+ public abstract void WriteEntries(Stream s, BlockDBCache cache);
/// Iterates from the very oldest to newest entry in the BlockDB.
- public static void FindChangesAt(Stream s, int index, Action output) {
- byte[] bulk = new byte[BulkEntries * EntrySize];
- fixed (byte* ptr = bulk) {
- int dbEntries = (int)(s.Length / EntrySize) - HeaderEntries;
- while (dbEntries > 0) {
- int count = Math.Min(dbEntries, BulkEntries);
- ReadFully(s, bulk, count * EntrySize);
- BlockDBEntry* entryPtr = (BlockDBEntry*)ptr;
-
- for (int i = 0; i < count; i++) {
- if (entryPtr->Index == index) {
- output(*entryPtr);
- }
- entryPtr++;
- }
- dbEntries -= count;
- }
- }
- }
+ public abstract void FindChangesAt(Stream s, int index, Action output);
/// Iterates from the very newest to oldest entry in the BlockDB.
/// whether an entry before start time was reached.
- public static bool FindChangesBy(Stream s, int[] ids, int start, int end,
- Action output) {
- byte[] bulk = new byte[BulkEntries * EntrySize];
- fixed (byte* ptr = bulk) {
- int dbEntries = (int)(s.Length / EntrySize) - HeaderEntries;
-
- while (dbEntries > 0) {
- int count = Math.Min(dbEntries, BulkEntries);
- // find the correct position for the start of this bulk read
- s.Position = (dbEntries - count + HeaderEntries) * (long)EntrySize;
-
- ReadFully(s, bulk, count * EntrySize);
- BlockDBEntry* entryPtr = (BlockDBEntry*)ptr;
- entryPtr += (count - 1);
-
- for (int i = count - 1; i >= 0; i--) {
- if (entryPtr->TimeDelta < start) return true;
-
- if (entryPtr->TimeDelta <= end) {
- for (int j = 0; j < ids.Length; j++) {
- if (entryPtr->PlayerID != ids[j]) continue;
- output(*entryPtr); break;
- }
- }
- entryPtr--;
- }
- dbEntries -= count;
- }
- }
- return false;
- }
+ public abstract bool FindChangesBy(Stream s, int[] ids, int start, int end, Action output);
/// Deletes the backing file on disc if it exists.
diff --git a/MCGalaxy/Database/BlockDB/BlockDBTableDumper.cs b/MCGalaxy/Database/BlockDB/BlockDBTableDumper.cs
index 75dd09e2e..dd02caa5a 100644
--- a/MCGalaxy/Database/BlockDB/BlockDBTableDumper.cs
+++ b/MCGalaxy/Database/BlockDB/BlockDBTableDumper.cs
@@ -93,7 +93,7 @@ namespace MCGalaxy.DB {
if (buffer.Count == 0) return;
if (!force && buffer.Count < 4096) return;
- BlockDBFile.WriteEntries(stream, buffer);
+ BlockDBFile.V1.WriteEntries(stream, buffer);
buffer.Count = 0;
}
diff --git a/MCGalaxy/MCGalaxy_.csproj b/MCGalaxy/MCGalaxy_.csproj
index 71d9f28b7..f3e6d7028 100644
--- a/MCGalaxy/MCGalaxy_.csproj
+++ b/MCGalaxy/MCGalaxy_.csproj
@@ -407,6 +407,7 @@
+