diff --git a/MCGalaxy/Commands/Information/CmdAbout.cs b/MCGalaxy/Commands/Information/CmdAbout.cs index c8e88eca0..522d5548d 100644 --- a/MCGalaxy/Commands/Information/CmdAbout.cs +++ b/MCGalaxy/Commands/Information/CmdAbout.cs @@ -86,8 +86,8 @@ namespace MCGalaxy.Commands { byte flags = ParseFlags(row["Deleted"].ToString()); if ((flags & 1) == 0) { // block was placed - entry.NewRaw = byte.Parse(row["Type"].ToString()); - entry.Flags |= (flags & 2) != 0 ? BlockDBFlags.NewCustom : BlockDBFlags.None; + entry.NewRaw = byte.Parse(row["Type"].ToString()); + entry.Flags |= (flags & 2) != 0 ? BlockDBFlags.NewCustom : BlockDBFlags.None; } BlockDBChange.Output(p, name, entry); } @@ -114,8 +114,9 @@ namespace MCGalaxy.Commands { static void ListInMemory(Player p, ref bool foundAny, Dictionary names, ushort x, ushort y, ushort z) { - int index = p.level.PosToInt(x, y, z); - FastList entries = p.level.blockCache; + BlockDB blockDB = p.level.BlockDB; + int index = x + blockDB.Dims.X * (z + blockDB.Dims.Z * y); + FastList entries = blockDB.Cache; for (int i = 0; i < entries.Count; i++) { if (entries.Items[i].Index != index) continue; diff --git a/MCGalaxy/Database/BlockDB/BlockDB.cs b/MCGalaxy/Database/BlockDB/BlockDB.cs index c7fa65312..c9f4f01fc 100644 --- a/MCGalaxy/Database/BlockDB/BlockDB.cs +++ b/MCGalaxy/Database/BlockDB/BlockDB.cs @@ -24,7 +24,9 @@ namespace MCGalaxy.DB { public unsafe sealed class BlockDB { - public ushort Width, Height, Length; + /// Dimensions used to pack coordinates into an index. + /// May be different from actual level's dimensions, such as when the level has been resized. + public Vec3U16 Dims; /// The map/level name associated with this BlockDB. public string MapName; @@ -38,25 +40,69 @@ namespace MCGalaxy.DB { /// The path of this BlockDB's temp backing file on disc for resizing. public string TempPath { get { return "blockdb/" + MapName + ".temp"; } } + /// Used to synchronise adding to Cache by multiple threads. + internal readonly object CacheLock = new object(); + + /// In-memory list of recent BlockDB changes. + public FastList Cache = new FastList(); + + /// Whether changes are actually added to the BlockDB. + public bool Used; + readonly ReaderWriterLockSlim locker; public BlockDB(Level lvl) { MapName = lvl.name; - Width = lvl.Width; Height = lvl.Height; Length = lvl.Length; + ReadDimensions(); locker = new ReaderWriterLockSlim(); + + if (Dims.X < lvl.Width) Dims.X = lvl.Width; + if (Dims.Y < lvl.Height) Dims.Y = lvl.Height; + if (Dims.Z < lvl.Length) Dims.Z = lvl.Length; + } + + void ReadDimensions() { + if (!File.Exists(FilePath)) return; + using (Stream s = File.OpenRead(FilePath)) + BlockDBFile.ReadHeader(s, out Dims); } - public void AppendEntries(ref FastList entries, object lockObj) { + + public void Add(Player p, ushort x, ushort y, ushort z, ushort flags, + byte oldBlock, byte oldExt, byte block, byte ext) { + if (!Used) return; + BlockDBEntry entry; + entry.PlayerID = p.UserID; + entry.TimeDelta = (int)DateTime.UtcNow.Subtract(BlockDB.Epoch).TotalSeconds; + entry.Index = x + Dims.X * (z + Dims.Z * y); + + entry.OldRaw = oldBlock; entry.NewRaw = block; + entry.Flags = flags; + + if (block == Block.custom_block) { + entry.Flags |= BlockDBFlags.NewCustom; + entry.NewRaw = ext; + } + if (oldBlock == Block.custom_block) { + entry.Flags |= BlockDBFlags.OldCustom; + entry.OldRaw = oldExt; + } + + lock (CacheLock) + Cache.Add(entry); + } + + public void WriteEntries() { using (IDisposable writeLock = locker.AccquireWriteLock()) { - if (entries.Count == 0) return; + if (Cache.Count == 0) return; ValidateBackingFile(); using (Stream s = File.OpenWrite(FilePath)) { s.Position = s.Length; - BlockDBFile.WriteEntries(s, entries); + BlockDBFile.WriteEntries(s, Cache); - lock (lockObj) - entries = new FastList(); + lock (CacheLock) + Cache = new FastList(); } } } @@ -77,7 +123,7 @@ namespace MCGalaxy.DB { } } } - + /// Finds all block changes by the given player. public void FindChangesBy(int id, Action output, out Vec3U16 dims) { dims = default(Vec3U16); @@ -115,18 +161,18 @@ 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() { - Vec3U16 dims; + Vec3U16 fileDims; if (!File.Exists(FilePath)) { using (Stream s = File.OpenWrite(FilePath)) { - dims = new Vec3U16(Width, Height, Length); - BlockDBFile.WriteHeader(s, dims); + fileDims = Dims; + BlockDBFile.WriteHeader(s, fileDims); } } else { using (Stream s = File.OpenRead(FilePath)) { - BlockDBFile.ReadHeader(s, out dims); + BlockDBFile.ReadHeader(s, out fileDims); } - if (dims.X < Width || dims.Y < Height || dims.Z < Length) { + if (fileDims.X < Dims.X || fileDims.Y < Dims.Y || fileDims.Z < Dims.Z) { BlockDBFile.ResizeBackingFile(this); } } diff --git a/MCGalaxy/Database/BlockDB/BlockDBFile.cs b/MCGalaxy/Database/BlockDB/BlockDBFile.cs index 3a2f9be56..2e2433bf0 100644 --- a/MCGalaxy/Database/BlockDB/BlockDBFile.cs +++ b/MCGalaxy/Database/BlockDB/BlockDBFile.cs @@ -142,8 +142,8 @@ namespace MCGalaxy.DB { using (Stream src = File.OpenRead(db.FilePath), dst = File.Create(db.TempPath)) { Vec3U16 dims; ReadHeader(src, out dims); - WriteHeader(dst, new Vec3U16(db.Width, db.Height, db.Length)); - int width = db.Width, length = db.Length; + WriteHeader(dst, db.Dims); + int width = db.Dims.X, length = db.Dims.Z; byte[] bulk = new byte[bulkEntries * entrySize]; fixed (byte* ptr = bulk) { diff --git a/MCGalaxy/Drawing/DrawOps/DrawOp.Performer.cs b/MCGalaxy/Drawing/DrawOps/DrawOp.Performer.cs index a57ad9d1b..e7c9ac684 100644 --- a/MCGalaxy/Drawing/DrawOps/DrawOp.Performer.cs +++ b/MCGalaxy/Drawing/DrawOps/DrawOp.Performer.cs @@ -175,9 +175,10 @@ namespace MCGalaxy.Drawing.Ops { lvl.blockqueue.Clear(); } else { if (!lvl.DoBlockchange(p, b.X, b.Y, b.Z, b.Block, b.ExtBlock, true)) return; - + + lvl.BlockDB.Add(p, b.X, b.Y, b.Z, op.Flags, + old, oldExt, b.Block, b.ExtBlock); int index = lvl.PosToInt(b.X, b.Y, b.Z); - lvl.AddToBlockDB(p, index, old, oldExt, b.Block, b.ExtBlock, op.Flags); BlockQueue.Addblock(p, index, b.Block, b.ExtBlock); } op.TotalModified++; diff --git a/MCGalaxy/Levels/Level.Blocks.cs b/MCGalaxy/Levels/Level.Blocks.cs index ce64856b0..cf7929cde 100644 --- a/MCGalaxy/Levels/Level.Blocks.cs +++ b/MCGalaxy/Levels/Level.Blocks.cs @@ -146,7 +146,8 @@ namespace MCGalaxy { SetExtTileNoCheck(x, y, z, ext); if (p == null) return; - AddToBlockDB(p, index, oldBlock, oldExtBlock, block, ext, flags); + BlockDB.Add(p, x, y, z, flags, + oldBlock, oldExtBlock, block, ext); Player.UndoPos Pos; Pos.x = x; Pos.y = y; Pos.z = z; Pos.mapName = this.name; @@ -429,40 +430,17 @@ namespace MCGalaxy { return x >= 0 && y >= 0 && z >= 0 && x < Width && y < Height && z < Length; } - public void AddToBlockDB(Player p, int index, byte oldBlock, byte oldExt, - byte block, byte ext, ushort flags) { - if (!UseBlockDB) return; - BlockDBEntry entry; - entry.PlayerID = p.UserID; - entry.TimeDelta = (int)DateTime.UtcNow.Subtract(BlockDB.Epoch).TotalSeconds; - entry.Index = index; // TODO: WRONG WRONG WRONG, use blockdb file's dimensions - - entry.OldRaw = oldBlock; entry.NewRaw = block; - entry.Flags = flags; - - if (block == Block.custom_block) { - entry.Flags |= BlockDBFlags.NewCustom; - entry.NewRaw = ext; - } - if (oldBlock == Block.custom_block) { - entry.Flags |= BlockDBFlags.OldCustom; - entry.OldRaw = oldExt; - } - - lock (blockCacheLock) - blockCache.Add(entry); - } - public void UpdateBlock(Player p, ushort x, ushort y, ushort z, byte block, byte extBlock, ushort flags) { byte old = GetTile(x, y, z), oldExt = 0; if (old == Block.custom_block) oldExt = GetExtTile(x, y, z); bool drawn = (flags & BlockDBFlags.ManualPlace) != 0; - if (!DoBlockchange(p, x, y, z, block, extBlock, drawn)) return; - int index = PosToInt(x, y, z); - AddToBlockDB(p, index, old, oldExt, block, extBlock, flags); + if (!DoBlockchange(p, x, y, z, block, extBlock, drawn)) return; + BlockDB.Add(p, x, y, z, flags, + old, oldExt, block, extBlock); + int index = PosToInt(x, y, z); if (bufferblocks) BlockQueue.Addblock(p, index, block, extBlock); else diff --git a/MCGalaxy/Levels/Level.Fields.cs b/MCGalaxy/Levels/Level.Fields.cs index 656b0f367..42385029f 100644 --- a/MCGalaxy/Levels/Level.Fields.cs +++ b/MCGalaxy/Levels/Level.Fields.cs @@ -87,8 +87,7 @@ namespace MCGalaxy { public List UndoBuffer = new List(); public List ZoneList; public bool backedup; - internal readonly object blockCacheLock = new object(); - public FastList blockCache = new FastList(); + [ConfigBool("UseBlockDB", "Other", null, true)] public bool UseBlockDB = true; public BlockDB BlockDB; diff --git a/MCGalaxy/Levels/Level.cs b/MCGalaxy/Levels/Level.cs index a2056e1d7..69818e2da 100644 --- a/MCGalaxy/Levels/Level.cs +++ b/MCGalaxy/Levels/Level.cs @@ -108,7 +108,7 @@ namespace MCGalaxy { ListCheck.Clear(); listCheckExists.Clear(); ListUpdate.Clear(); listUpdateExists.Clear(); UndoBuffer.Clear(); - blockCache.Clear(); + BlockDB.Cache.Clear(); ZoneList.Clear(); lock (queueLock) @@ -374,6 +374,7 @@ namespace MCGalaxy { } catch (Exception e) { Server.ErrorLog(e); } + level.BlockDB.Used = level.UseBlockDB; BlockDefinition[] defs = BlockDefinition.Load(false, level); for (int i = 0; i < defs.Length; i++) { diff --git a/MCGalaxy/Levels/LevelDB.cs b/MCGalaxy/Levels/LevelDB.cs index deb92abd5..a209caabc 100644 --- a/MCGalaxy/Levels/LevelDB.cs +++ b/MCGalaxy/Levels/LevelDB.cs @@ -25,10 +25,10 @@ namespace MCGalaxy { public static class LevelDB { public unsafe static void SaveBlockDB(Level lvl) { - if (lvl.blockCache.Count == 0) return; - if (!lvl.UseBlockDB) { lvl.blockCache.Clear(); return; } + if (lvl.BlockDB.Cache.Count == 0) return; + if (!lvl.UseBlockDB) { lvl.BlockDB.Cache.Clear(); return; } - lvl.BlockDB.AppendEntries(ref lvl.blockCache, lvl.blockCacheLock); + lvl.BlockDB.WriteEntries(); Server.s.Log("Saved BlockDB changes for:" + lvl.name, true); } diff --git a/MCGalaxy/Player/Player.Handlers.cs b/MCGalaxy/Player/Player.Handlers.cs index 5c7dca8b4..e0cdb1e26 100644 --- a/MCGalaxy/Player/Player.Handlers.cs +++ b/MCGalaxy/Player/Player.Handlers.cs @@ -125,11 +125,15 @@ namespace MCGalaxy { byte heldBlock = GetActualHeldBlock(out heldExt); int index = level.PosToInt(x, y, z); if (doDelete) { - if (DeleteBlock(old, x, y, z, block, extBlock)) - level.AddToBlockDB(this, index, old, oldExt, 0, 0, flags); + if (DeleteBlock(old, x, y, z, block, extBlock)) { + level.BlockDB.Add(this, x, y, z, flags, + old, oldExt, 0, 0); + } } else { - if (PlaceBlock(old, x, y, z, block, extBlock)) - level.AddToBlockDB(this, index, old, oldExt, heldBlock, heldExt, flags); + if (PlaceBlock(old, x, y, z, block, extBlock)) { + level.BlockDB.Add(this, x, y, z, flags, + old, oldExt, heldBlock, heldExt); + } } }