DB: Now the new BlockDB format works. Still quite a bit to do though.

This commit is contained in:
UnknownShadow200 2016-11-07 19:24:00 +11:00
parent 8485e00d91
commit e878d4699b
13 changed files with 134 additions and 72 deletions

View File

@ -18,6 +18,7 @@
using System;
using System.Collections.Generic;
using System.Data;
using MCGalaxy.DB;
using MCGalaxy.SQL;
using MCGalaxy.Util;
@ -46,14 +47,16 @@ namespace MCGalaxy.Commands {
byte id = b;
if (b == Block.custom_block)
id = p.level.GetExtTile(x, y, z);
Dictionary<int, string> names = new Dictionary<int, string>();
string blockName = p.level.BlockName(b, id);
Player.Message(p, "Block ({0}, {1}, {2}): &f{3} = {4}%S.", x, y, z, id, blockName);
bool foundAny = false;
ListFromDatabase(p, ref foundAny, x, y, z);
// TODO: List from BlockDB file
ListInMemory(p, ref foundAny, x, y, z);
ListFromDatabase(p, ref foundAny, names, x, y, z);
p.level.BlockDB.FindChangesAt(x, y, z,
entry => OutputEntry(p, ref foundAny, names, entry));
ListInMemory(p, ref foundAny, names, x, y, z);
if (!foundAny) Player.Message(p, "No block change records found for this block.");
OutputMessageBlock(p, b, id, x, y, z);
@ -63,7 +66,8 @@ namespace MCGalaxy.Commands {
GC.WaitForPendingFinalizers();
}
static void ListFromDatabase(Player p, ref bool foundAny, ushort x, ushort y, ushort z) {
static void ListFromDatabase(Player p, ref bool foundAny, Dictionary<int, string> names,
ushort x, ushort y, ushort z) {
DataTable Blocks = Database.Backend.GetRows("Block" + p.level.name, "*",
"WHERE X=@0 AND Y=@1 AND Z=@2", x, y, z);
DateTime now = DateTime.Now;
@ -71,13 +75,13 @@ namespace MCGalaxy.Commands {
for (int i = 0; i < Blocks.Rows.Count; i++) {
foundAny = true;
DataRow row = Blocks.Rows[i];
string user = row["Username"].ToString().Trim();
string name = row["Username"].ToString().Trim();
DateTime time = DateTime.Parse(row["TimePerformed"].ToString());
byte block = byte.Parse(row["Type"].ToString());
byte flags = ParseFlags(row["Deleted"].ToString());
bool deleted = (flags & 1) != 0, isExt = (flags & 2) != 0;
Output(p, user, block, isExt, deleted, now - time);
Output(p, name, block, isExt, deleted, now - time);
}
Blocks.Dispose();
}
@ -89,22 +93,29 @@ namespace MCGalaxy.Commands {
return byte.Parse(value);
}
static void ListInMemory(Player p, ref bool foundAny, ushort x, ushort y, ushort z) {
static void OutputEntry(Player p, ref bool foundAny, Dictionary<int, string> names, BlockDBEntry entry) {
DateTime now = DateTime.UtcNow;
string name = null;
if (!names.TryGetValue(entry.PlayerID, out name)) {
name = NameConverter.FindName(entry.PlayerID);
names[entry.PlayerID] = name;
}
foundAny = true;
DateTime time = BlockDB.Epoch.AddSeconds(entry.TimeDelta);
bool deleted = entry.NewRaw == 0;
bool extBlock = (entry.Flags & 0x8000) != 0;
Output(p, name, entry.NewRaw, extBlock, deleted, now - time);
}
static void ListInMemory(Player p, ref bool foundAny, Dictionary<int, string> names,
ushort x, ushort y, ushort z) {
int index = p.level.PosToInt(x, y, z);
DateTime now = DateTime.Now;
FastList<BlockDBEntry> entries = p.level.blockCache;
for (int i = 0; i < entries.Count; i++) {
if (entries.Items[i].Index != index) continue;
foundAny = true;
BlockDBEntry entry = entries.Items[i];
string user = entry.name.Trim();
DateTime time = BlockDB.Epoch.AddSeconds(entry.TimeDelta);
bool deleted = entry.NewRaw != 0;
bool extBlock = (entry.Flags & 0x8000) != 0;
Output(p, user, entry.NewRaw, extBlock, deleted, now - time);
if (entries.Items[i].Index != index) continue;
OutputEntry(p, ref foundAny, names, entries.Items[i]);
}
}

View File

@ -16,6 +16,7 @@
permissions and limitations under the Licenses.
*/
using System.IO;
namespace MCGalaxy.Commands {
public sealed class CmdHide : Command {
public override string name { get { return "hide"; } }

View File

@ -19,7 +19,7 @@ using System;
using System.IO;
using System.Threading;
namespace MCGalaxy {
namespace MCGalaxy.DB {
public unsafe partial class BlockDB {
@ -33,13 +33,12 @@ namespace MCGalaxy {
public string MapName;
/// <summary> The path of this BlockDB's backing file on disc. </summary>
public string FilePath { get { return "blockdefs/" + MapName + ".cbdb"; } }
public string FilePath { get { return "blockdb/" + MapName + ".cbdb"; } }
/// <summary> Base point in time that all time deltas are offset from.</summary>
public static DateTime Epoch = new DateTime(2000, 1, 1, 1, 1, 1, DateTimeKind.Utc);
readonly ReaderWriterLockSlim locker;
bool resizeRequired;
public BlockDB(Level lvl) {
MapName = lvl.name;
Width = lvl.Width; Height = lvl.Height; Length = lvl.Length;
@ -50,19 +49,18 @@ namespace MCGalaxy {
/// Also recreates the backing file if dimensions on disc are less than those in memory. </summary>
void ValidateBackingFile() {
Vec3U16 dims;
using (IDisposable writeLock = locker.AccquireWriteLock()) {
if (!File.Exists(FilePath)) {
using (Stream s = File.OpenWrite(FilePath)) {
dims = new Vec3U16(Width, Height, Length);
WriteHeader(s, dims);
}
} else {
using (Stream s = File.OpenRead(FilePath)) {
ReadHeader(s, out dims);
}
if (dims.X < Width || dims.Y < Height || dims.Z < Length) {
ResizeBackingFile();
}
if (!File.Exists(FilePath)) {
using (Stream s = File.OpenWrite(FilePath)) {
dims = new Vec3U16(Width, Height, Length);
WriteHeader(s, dims);
}
} else {
using (Stream s = File.OpenRead(FilePath)) {
ReadHeader(s, out dims);
}
if (dims.X < Width || dims.Y < Height || dims.Z < Length) {
ResizeBackingFile();
}
}
}
@ -74,13 +72,13 @@ namespace MCGalaxy {
static void WriteHeader(Stream s, Vec3U16 dims) {
byte[] header = new byte[entrySize];
byte[] header = new byte[entrySize * 4];
NetUtils.WriteAscii("CBDB_MCG", header, 0);
WriteU16(version, header, 8);
WriteU16(dims.X, header, 10);
WriteU16(dims.Y, header, 12);
WriteU16(dims.Z, header, 14);
s.Write(header, 0, header.Length);
s.Write(header, 0, entrySize);
}
static void ReadHeader(Stream s, out Vec3U16 dims) {

View File

@ -20,7 +20,7 @@ using System.IO;
using System.Runtime.InteropServices;
using MCGalaxy.Util;
namespace MCGalaxy {
namespace MCGalaxy.DB {
public unsafe partial class BlockDB {

View File

@ -0,0 +1,55 @@
/*
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.Collections.Generic;
using System.Data;
using MCGalaxy.SQL;
namespace MCGalaxy.DB {
/// <summary> Converts names to integer ids and back </summary>
public static class NameConverter {
public static string FindName(int id) {
List<string> invalid = Server.invalidIds.All();
if (id > int.MaxValue - invalid.Count)
return invalid[int.MaxValue - id];
using (DataTable ids = Database.Backend.GetRows("Players", "Name", "WHERE ID=@0", id)) {
if (ids.Rows.Count == 0) return null;
return ids.Rows[0]["Name"].ToString();
}
}
public static List<int> FindIds(string name) {
List<string> invalid = Server.invalidIds.All();
List<int> ids = new List<int>();
int index = invalid.IndexOf(name.ToLower());
if (index >= 0) ids.Add(int.MaxValue - index);
using (DataTable names = Database.Backend.GetRows("Players", "ID", "WHERE Name=@0", name)) {
foreach (DataRow row in names.Rows) {
string raw = row["ID"].ToString();
ids.Add(PlayerData.ParseInt(raw));
}
}
return ids;
}
}
}

View File

@ -18,6 +18,7 @@
using System;
using System.Collections.Generic;
using MCGalaxy.Blocks.Physics;
using MCGalaxy.DB;
using MCGalaxy.Games;
using MCGalaxy.SQL;
@ -428,14 +429,22 @@ namespace MCGalaxy {
}
public void AddToBlockDB(Player p, int index, byte block, byte extBlock, bool delete) {
if (!UseBlockDB) return;
BlockPos bP = default(BlockPos);
bP.name = p.name;
bP.index = index;
if (!UseBlockDB) return;
BlockDBEntry entry;
entry.PlayerID = p.UserID;
entry.TimeDelta = (int)DateTime.UtcNow.Subtract(BlockDB.Epoch).TotalSeconds;
entry.Index = index;
bP.SetData(block, extBlock, delete);
entry.OldRaw = Block.Invalid; // TODO: need to fill out old block properly
entry.NewRaw = delete ? Block.air : block;
entry.Flags = 0x1;
if (block == Block.custom_block) {
entry.Flags |= 0x8000;
entry.NewRaw = extBlock;
}
lock (blockCacheLock)
blockCache.Add(bP);
blockCache.Add(entry);
}
public void UpdateBlock(Player p, ushort x, ushort y, ushort z,

View File

@ -20,6 +20,7 @@ using System.Collections.Generic;
using System.Threading;
using MCGalaxy.Blocks;
using MCGalaxy.Blocks.Physics;
using MCGalaxy.DB;
using MCGalaxy.Config;
using MCGalaxy.Games;
using MCGalaxy.Util;

View File

@ -20,6 +20,7 @@ using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using MCGalaxy.Blocks;
using MCGalaxy.DB;
using MCGalaxy.Games;
using MCGalaxy.Generator;
using MCGalaxy.Levels.IO;
@ -476,25 +477,6 @@ namespace MCGalaxy {
return onLevel;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct BlockPos {
public string name;
public int flags, index; // bit 0 = is deleted, bit 1 = is ext, rest bits = time delta
public byte rawBlock;
public void SetData(byte block, byte extBlock, bool delete) {
TimeSpan delta = DateTime.UtcNow.Subtract(Server.StartTime);
flags = (int)delta.TotalSeconds << 2;
flags |= (byte)(delete ? 1 : 0);
if (block == Block.custom_block) {
rawBlock = extBlock; flags |= 2;
} else {
rawBlock = block;
}
}
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct UndoPos {
public int flags, index; // bit 0 = is old ext, bit 1 = is new ext, rest bits = time delta

View File

@ -407,8 +407,9 @@
<Compile Include="CorePlugin\CorePlugin.cs" />
<Compile Include="CorePlugin\ConnectHandler.cs" />
<Compile Include="Database\Backends\SQLite.cs" />
<Compile Include="Database\BlockDB.cs" />
<Compile Include="Database\BlockDB.Utils.cs" />
<Compile Include="Database\BlockDB\BlockDB.cs" />
<Compile Include="Database\BlockDB\BlockDB.Utils.cs" />
<Compile Include="Database\BlockDB\NameConverter.cs" />
<Compile Include="Database\ColumnDesc.cs" />
<Compile Include="Database\IDatabaseBackend.cs" />
<Compile Include="Database\Backends\MySQL.cs" />
@ -713,6 +714,7 @@
<Folder Include="Commands\World" />
<Folder Include="Commands\other" />
<Folder Include="Database\Backends" />
<Folder Include="Database\BlockDB" />
<Folder Include="Drawing\DrawOps" />
<Folder Include="Drawing\Brushes" />
<Folder Include="Drawing\Image" />

View File

@ -53,14 +53,13 @@ namespace MCGalaxy {
/// <summary> Adds or replaces the given name,
/// returning the index of the item within the list. </summary>
public int AddOrReplace(string p) {
public void AddOrReplace(string p) {
p = p.ToLower();
lock (locker) {
int idx = players.IndexOf(p);
if (idx >= 0) return idx;
if (idx >= 0) return;
players.Add(p);
return players.Count - 1;
}
}

View File

@ -18,6 +18,7 @@ using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using MCGalaxy.DB;
using MCGalaxy.Games;
using MCGalaxy.SQL;
using MCGalaxy.Undo;

View File

@ -19,7 +19,7 @@ using System;
using System.Data;
using MCGalaxy.SQL;
namespace MCGalaxy {
namespace MCGalaxy {
public class PlayerData {
public string Name, Color, Title, TitleColor, TotalTime, IP;
public DateTime FirstLogin, LastLogin;
@ -46,13 +46,14 @@ namespace MCGalaxy {
"totalDeaths, Money, totalBlocks, totalKicked, TimeSpent",
p.name, p.ip, now, now, 1, "", 0, 0, 0, 0, p.time.ToDBTime());
using (DataTable ids = Database.Backend.GetRows("Players",
"ID", "WHERE Name = @0", p.name)) {
using (DataTable ids = Database.Backend.GetRows("Players",
"ID", "WHERE Name = @0", p.name)) {
if (ids.Rows.Count > 0) {
string id = ids.Rows[0]["ID"].ToString();
p.UserID = PlayerData.ParseInt(id);
} else {
int index = Server.invalidIds.AddOrReplace(p.name);
Server.invalidIds.AddOrReplace(p.name);
int index = Server.invalidIds.All().IndexOf(p.name.ToLower());
p.UserID = int.MaxValue - index;
}
}
@ -126,7 +127,7 @@ namespace MCGalaxy {
// Try parse color name, then color code
string parsed = Colors.Parse(col);
if (parsed != "") return parsed;
if (parsed != "") return parsed;
return Colors.Name(col) == "" ? "" : col;
}

View File

@ -50,6 +50,8 @@ namespace MCGalaxy {
};
void InitDatabase() {
if (!Directory.Exists("blockdb")) Directory.CreateDirectory("blockdb");
try {
Database.Backend.CreateDatabase();
} catch (Exception e) {