mirror of
https://github.com/ClassiCube/MCGalaxy.git
synced 2025-09-23 20:53:40 -04:00
DB: Fix BlockDB with /resizelvl
This commit is contained in:
parent
88bfba87c2
commit
62410fc34a
@ -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<int, string> names,
|
||||
ushort x, ushort y, ushort z) {
|
||||
int index = p.level.PosToInt(x, y, z);
|
||||
FastList<BlockDBEntry> entries = p.level.blockCache;
|
||||
BlockDB blockDB = p.level.BlockDB;
|
||||
int index = x + blockDB.Dims.X * (z + blockDB.Dims.Z * y);
|
||||
FastList<BlockDBEntry> entries = blockDB.Cache;
|
||||
|
||||
for (int i = 0; i < entries.Count; i++) {
|
||||
if (entries.Items[i].Index != index) continue;
|
||||
|
@ -24,7 +24,9 @@ namespace MCGalaxy.DB {
|
||||
|
||||
public unsafe sealed class BlockDB {
|
||||
|
||||
public ushort Width, Height, Length;
|
||||
/// <summary> Dimensions used to pack coordinates into an index. </summary>
|
||||
/// <remarks> May be different from actual level's dimensions, such as when the level has been resized. </remarks>
|
||||
public Vec3U16 Dims;
|
||||
|
||||
/// <summary> The map/level name associated with this BlockDB. </summary>
|
||||
public string MapName;
|
||||
@ -38,25 +40,69 @@ namespace MCGalaxy.DB {
|
||||
/// <summary> The path of this BlockDB's temp backing file on disc for resizing. </summary>
|
||||
public string TempPath { get { return "blockdb/" + MapName + ".temp"; } }
|
||||
|
||||
/// <summary> Used to synchronise adding to Cache by multiple threads. </summary>
|
||||
internal readonly object CacheLock = new object();
|
||||
|
||||
/// <summary> In-memory list of recent BlockDB changes. </summary>
|
||||
public FastList<BlockDBEntry> Cache = new FastList<BlockDBEntry>();
|
||||
|
||||
/// <summary> Whether changes are actually added to the BlockDB. </summary>
|
||||
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<BlockDBEntry> 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<BlockDBEntry>();
|
||||
lock (CacheLock)
|
||||
Cache = new FastList<BlockDBEntry>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -77,7 +123,7 @@ namespace MCGalaxy.DB {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary> Finds all block changes by the given player. </summary>
|
||||
public void FindChangesBy(int id, Action<BlockDBEntry> output, out Vec3U16 dims) {
|
||||
dims = default(Vec3U16);
|
||||
@ -115,18 +161,18 @@ namespace MCGalaxy.DB {
|
||||
/// <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>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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++;
|
||||
|
@ -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
|
||||
|
@ -87,8 +87,7 @@ namespace MCGalaxy {
|
||||
public List<UndoPos> UndoBuffer = new List<UndoPos>();
|
||||
public List<Zone> ZoneList;
|
||||
public bool backedup;
|
||||
internal readonly object blockCacheLock = new object();
|
||||
public FastList<BlockDBEntry> blockCache = new FastList<BlockDBEntry>();
|
||||
|
||||
[ConfigBool("UseBlockDB", "Other", null, true)]
|
||||
public bool UseBlockDB = true;
|
||||
public BlockDB BlockDB;
|
||||
|
@ -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++) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user