mirror of
https://github.com/ClassiCube/MCGalaxy.git
synced 2025-09-24 05:03:34 -04:00
Make BlockDBFile extensible
This commit is contained in:
parent
1ebdbd6e1f
commit
fb4b0ab88e
@ -65,12 +65,12 @@ namespace MCGalaxy.DB {
|
|||||||
public void WriteEntries() {
|
public void WriteEntries() {
|
||||||
if (Cache.Head == null) return;
|
if (Cache.Head == null) return;
|
||||||
|
|
||||||
ValidateBackingFile();
|
BlockDBFile format = ValidateBackingFile();
|
||||||
using (Stream s = OpenWrite()) {
|
using (Stream s = OpenWrite()) {
|
||||||
// This truncates the lower 4 bits off - so e.g. if a power off occurred
|
// 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
|
// and 21 bytes were in the file, this sets the position to byte 16
|
||||||
s.Position = s.Length & ~0x0F;
|
s.Position = s.Length & ~0x0F;
|
||||||
BlockDBFile.WriteEntries(s, Cache);
|
format.WriteEntries(s, Cache);
|
||||||
Cache.Clear();
|
Cache.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -93,11 +93,11 @@ namespace MCGalaxy.DB {
|
|||||||
Vec3U16 dims;
|
Vec3U16 dims;
|
||||||
|
|
||||||
using (Stream s = OpenRead()) {
|
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;
|
if (x >= dims.X || y >= dims.Y || z >= dims.Z) return;
|
||||||
|
|
||||||
int index = (y * dims.Z + z) * dims.X + x;
|
int index = (y * dims.Z + z) * dims.X + x;
|
||||||
BlockDBFile.FindChangesAt(s, index, output);
|
format.FindChangesAt(s, index, output);
|
||||||
}
|
}
|
||||||
FindInMemoryAt(x, y, z, output);
|
FindInMemoryAt(x, y, z, output);
|
||||||
}
|
}
|
||||||
@ -131,8 +131,8 @@ namespace MCGalaxy.DB {
|
|||||||
|
|
||||||
if (!File.Exists(FilePath)) return false;
|
if (!File.Exists(FilePath)) return false;
|
||||||
using (Stream s = OpenRead()) {
|
using (Stream s = OpenRead()) {
|
||||||
BlockDBFile.ReadHeader(s, out dims);
|
BlockDBFile format = BlockDBFile.ReadHeader(s, out dims);
|
||||||
return BlockDBFile.FindChangesBy(s, ids, startDelta, endDelta, output);
|
return format.FindChangesBy(s, ids, startDelta, endDelta, output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,9 +175,10 @@ namespace MCGalaxy.DB {
|
|||||||
|
|
||||||
/// <summary> Checks if the backing file exists on disc, and if not, creates it.
|
/// <summary> 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. </summary>
|
/// Also recreates the backing file if dimensions on disc are less than those in memory. </summary>
|
||||||
void ValidateBackingFile() {
|
BlockDBFile ValidateBackingFile() {
|
||||||
Vec3U16 fileDims;
|
Vec3U16 fileDims;
|
||||||
|
|
||||||
|
BlockDBFile format = BlockDBFile.V1;
|
||||||
if (!File.Exists(FilePath)) {
|
if (!File.Exists(FilePath)) {
|
||||||
using (Stream s = OpenWrite()) {
|
using (Stream s = OpenWrite()) {
|
||||||
fileDims = Dims;
|
fileDims = Dims;
|
||||||
@ -185,12 +186,13 @@ namespace MCGalaxy.DB {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
using (Stream s = OpenRead()) {
|
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) {
|
if (fileDims.X < Dims.X || fileDims.Y < Dims.Y || fileDims.Z < Dims.Z) {
|
||||||
BlockDBFile.ResizeBackingFile(this);
|
BlockDBFile.ResizeBackingFile(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return format;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
158
MCGalaxy/Database/BlockDB/BlockDBFile.V1.cs
Normal file
158
MCGalaxy/Database/BlockDB/BlockDBFile.V1.cs
Normal file
@ -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<BlockDBEntry> 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<BlockDBEntry> 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<BlockDBEntry> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -22,13 +22,15 @@ using MCGalaxy.Maths;
|
|||||||
|
|
||||||
namespace MCGalaxy.DB {
|
namespace MCGalaxy.DB {
|
||||||
|
|
||||||
public unsafe static class BlockDBFile {
|
public unsafe abstract class BlockDBFile {
|
||||||
|
|
||||||
public const byte Version = 1;
|
public const byte Version = 1;
|
||||||
public const int EntrySize = 16;
|
public const int EntrySize = 16;
|
||||||
public const int HeaderEntries = 1;
|
public const int HeaderEntries = 1;
|
||||||
public const int BulkEntries = 256;
|
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 FilePath(string map) { return "blockdb/" + map + ".cbdb"; }
|
||||||
public static string DumpPath(string map) { return "blockdb/" + map + ".dump"; }
|
public static string DumpPath(string map) { return "blockdb/" + map + ".dump"; }
|
||||||
public static string TempPath(string map) { return "blockdb/" + map + ".temp"; }
|
public static string TempPath(string map) { return "blockdb/" + map + ".temp"; }
|
||||||
@ -43,7 +45,7 @@ namespace MCGalaxy.DB {
|
|||||||
s.Write(header, 0, EntrySize);
|
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);
|
dims = default(Vec3U16);
|
||||||
byte[] header = new byte[EntrySize * HeaderEntries];
|
byte[] header = new byte[EntrySize * HeaderEntries];
|
||||||
ReadFully(s, header, header.Length);
|
ReadFully(s, header, header.Length);
|
||||||
@ -57,125 +59,20 @@ namespace MCGalaxy.DB {
|
|||||||
dims.X = ReadU16(header, 10);
|
dims.X = ReadU16(header, 10);
|
||||||
dims.Y = ReadU16(header, 12);
|
dims.Y = ReadU16(header, 12);
|
||||||
dims.Z = ReadU16(header, 14);
|
dims.Z = ReadU16(header, 14);
|
||||||
|
return V1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void WriteEntries(Stream s, FastList<BlockDBEntry> entries) {
|
public abstract void WriteEntries(Stream s, FastList<BlockDBEntry> entries);
|
||||||
byte[] bulk = new byte[BulkEntries * EntrySize];
|
|
||||||
WriteEntries(s, bulk, entries.Items, entries.Count);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
/// <summary> Iterates from the very oldest to newest entry in the BlockDB. </summary>
|
/// <summary> Iterates from the very oldest to newest entry in the BlockDB. </summary>
|
||||||
public static void FindChangesAt(Stream s, int index, Action<BlockDBEntry> output) {
|
public abstract void FindChangesAt(Stream s, int index, Action<BlockDBEntry> 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary> Iterates from the very newest to oldest entry in the BlockDB. </summary>
|
/// <summary> Iterates from the very newest to oldest entry in the BlockDB. </summary>
|
||||||
/// <returns> whether an entry before start time was reached. </returns>
|
/// <returns> whether an entry before start time was reached. </returns>
|
||||||
public static bool FindChangesBy(Stream s, int[] ids, int start, int end,
|
public abstract bool FindChangesBy(Stream s, int[] ids, int start, int end, Action<BlockDBEntry> output);
|
||||||
Action<BlockDBEntry> 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary> Deletes the backing file on disc if it exists. </summary>
|
/// <summary> Deletes the backing file on disc if it exists. </summary>
|
||||||
|
@ -93,7 +93,7 @@ namespace MCGalaxy.DB {
|
|||||||
if (buffer.Count == 0) return;
|
if (buffer.Count == 0) return;
|
||||||
if (!force && buffer.Count < 4096) return;
|
if (!force && buffer.Count < 4096) return;
|
||||||
|
|
||||||
BlockDBFile.WriteEntries(stream, buffer);
|
BlockDBFile.V1.WriteEntries(stream, buffer);
|
||||||
buffer.Count = 0;
|
buffer.Count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,6 +407,7 @@
|
|||||||
<Compile Include="Database\BlockDB\BlockDBFile.cs" />
|
<Compile Include="Database\BlockDB\BlockDBFile.cs" />
|
||||||
<Compile Include="Database\BlockDB\BlockDBEntry.cs" />
|
<Compile Include="Database\BlockDB\BlockDBEntry.cs" />
|
||||||
<Compile Include="Database\BlockDB\BlockDBChange.cs" />
|
<Compile Include="Database\BlockDB\BlockDBChange.cs" />
|
||||||
|
<Compile Include="Database\BlockDB\BlockDBFile.V1.cs" />
|
||||||
<Compile Include="Database\BlockDB\DBUpgrader.cs" />
|
<Compile Include="Database\BlockDB\DBUpgrader.cs" />
|
||||||
<Compile Include="Database\BlockDB\BlockDBTableDumper.cs" />
|
<Compile Include="Database\BlockDB\BlockDBTableDumper.cs" />
|
||||||
<Compile Include="Database\BlockDB\NameConverter.cs" />
|
<Compile Include="Database\BlockDB\NameConverter.cs" />
|
||||||
|
Loading…
x
Reference in New Issue
Block a user