public void Output(DrawOpBlock b) { if (b.Block == Block.Invalid) { return; } Level lvl = op.Level; Player p = op.Player; if (b.X >= lvl.Width || b.Y >= lvl.Height || b.Z >= lvl.Length) { return; } int index = b.X + lvl.Width * (b.Z + b.Y * lvl.Length); BlockID old = lvl.blocks[index]; #if TEN_BIT_BLOCKS BlockID extended = Block.ExtendedBase[old]; if (extended > 0) { old = (BlockID)(extended | lvl.FastGetExtTile(b.X, b.Y, b.Z)); } #else if (old == Block.custom_block) { old = (BlockID)(Block.Extended | lvl.FastGetExtTile(b.X, b.Y, b.Z)); } #endif if (old == Block.Invalid) { return; } // Check to make sure the block is actually different and that can be used if (old == b.Block || !p.group.Blocks[old] || !p.group.Blocks[b.Block]) { return; } // Check if player can affect block at coords in world AccessController denied = lvl.CanAffect(p, b.X, b.Y, b.Z); if (denied != null) { if (p.lastAccessStatus < DateTime.UtcNow) { denied.CheckDetailed(p); p.lastAccessStatus = DateTime.UtcNow.AddSeconds(2); } return; } // Set the block (inlined) lvl.Changed = true; if (b.Block >= Block.Extended) { #if TEN_BIT_BLOCKS lvl.blocks[index] = Block.ExtendedClass[b.Block >> Block.ExtendedShift]; #else lvl.blocks[index] = Block.custom_block; #endif lvl.FastSetExtTile(b.X, b.Y, b.Z, (BlockRaw)b.Block); } else { lvl.blocks[index] = (BlockRaw)b.Block; if (old >= Block.Extended) { lvl.FastRevertExtTile(b.X, b.Y, b.Z); } } lvl.BlockDB.Cache.Add(p, b.X, b.Y, b.Z, op.Flags, old, b.Block); p.SessionModified++; p.TotalModified++; p.TotalDrawn++; // increment block stats inline // Potentially buffer the block change if (op.TotalModified == reloadThreshold) { if (!p.Ignores.DrawOutput) { p.Message("Changed over {0} blocks, preparing to reload map..", reloadThreshold); } lvl.blockqueue.ClearAll(); } else if (op.TotalModified < reloadThreshold) { if (!Block.VisuallyEquals(old, b.Block)) { lvl.blockqueue.Add(p, index, b.Block); } if (lvl.physics > 0) { if (old == Block.Sponge && b.Block != Block.Sponge) { OtherPhysics.DoSpongeRemoved(lvl, index, false); } if (old == Block.LavaSponge && b.Block != Block.LavaSponge) { OtherPhysics.DoSpongeRemoved(lvl, index, true); } if (lvl.ActivatesPhysics(b.Block)) { lvl.AddCheck(index); } } } op.TotalModified++; // Attempt to prevent BlockDB in-memory cache from growing too large (> 1,000,000 entries) int count = lvl.BlockDB.Cache.Count; if (count == 0 || (count % 1000000) != 0) { return; } // if drawop has a read lock on BlockDB (e.g. undo/redo), we must release it here bool hasReadLock = false; if (op.BlockDBReadLock != null) { op.BlockDBReadLock.Dispose(); hasReadLock = true; } using (IDisposable wLock = lvl.BlockDB.Locker.AccquireWrite(100)) { if (wLock != null) { lvl.BlockDB.FlushCache(); } } if (!hasReadLock) { return; } op.BlockDBReadLock = lvl.BlockDB.Locker.AccquireRead(); }
public void Output(DrawOpBlock b) { if (b.Block.BlockID == Block.Invalid) { return; } Level lvl = op.Level; Player p = op.Player; if (b.X >= lvl.Width || b.Y >= lvl.Height || b.Z >= lvl.Length) { return; } int index = b.X + lvl.Width * (b.Z + b.Y * lvl.Length); ExtBlock old; old.BlockID = lvl.blocks[index]; old.ExtID = 0; if (old.BlockID == Block.custom_block) { old.ExtID = lvl.GetExtTileNoCheck(b.X, b.Y, b.Z); } if (old.BlockID == Block.Invalid) { return; } // Check to make sure the block is actually different and that we can change it if (old == b.Block || !lvl.CheckAffectPermissions(p, b.X, b.Y, b.Z, old, b.Block)) { return; } // Set the block (inlined) lvl.blocks[index] = b.Block.BlockID; lvl.Changed = true; if (old.BlockID == Block.custom_block && b.Block.BlockID != Block.custom_block) { lvl.RevertExtTileNoCheck(b.X, b.Y, b.Z); } if (b.Block.BlockID == Block.custom_block) { lvl.SetExtTileNoCheck(b.X, b.Y, b.Z, b.Block.ExtID); } if (p != null) { lvl.BlockDB.Cache.Add(p, b.X, b.Y, b.Z, op.Flags, old, b.Block); p.SessionModified++; p.TotalModified++; p.TotalDrawn++; // increment block stats inline } // Potentially buffer the block change if (op.TotalModified == reloadThreshold) { if (p == null || !p.Ignores.DrawOutput) { Player.Message(p, "Changed over {0} blocks, preparing to reload map..", reloadThreshold); } lock (lvl.queueLock) lvl.blockqueue.Clear(); } else if (op.TotalModified < reloadThreshold) { if (!old.VisuallyEquals(b.Block)) { BlockQueue.Addblock(p, index, b.Block); } if (lvl.physics > 0) { if (old.BlockID == Block.Sponge && b.Block.BlockID != Block.Sponge) { OtherPhysics.DoSpongeRemoved(lvl, index, false); } if (old.BlockID == Block.LavaSponge && b.Block.BlockID != Block.LavaSponge) { OtherPhysics.DoSpongeRemoved(lvl, index, true); } if (lvl.ActivatesPhysics(b.Block)) { lvl.AddCheck(index); } } } op.TotalModified++; // Attempt to prevent the BlockDB from growing too large (> 1,000,000 entries) int count = lvl.BlockDB.Cache.Count; if (count == 0 || (count % 1000000) != 0) { return; } // if drawop has a read lock on BlockDB (e.g. undo/redo), we must release it here bool hasReadLock = false; if (op.BlockDBReadLock != null) { op.BlockDBReadLock.Dispose(); hasReadLock = true; } using (IDisposable wLock = lvl.BlockDB.Locker.AccquireWrite(100)) { if (wLock != null) { lvl.BlockDB.WriteEntries(); } } if (!hasReadLock) { return; } op.BlockDBReadLock = lvl.BlockDB.Locker.AccquireRead(); }