public bool DoPhysicsBlockchange(int b, BlockID block, bool overRide = false, PhysicsArgs data = default(PhysicsArgs), bool addUndo = true) { if (blocks == null || b < 0 || b >= blocks.Length) { return(false); } BlockID old = blocks[b]; #if TEN_BIT_BLOCKS BlockID extended = Block.ExtendedBase[old]; if (extended > 0) { old = (BlockID)(extended | GetExtTile(b)); } #else if (old == Block.custom_block) { old = (BlockID)(Block.Extended | GetExtTile(b)); } #endif try { if (!overRide) { if (Props[old].OPBlock || (Props[block].OPBlock && data.Raw != 0)) { return(false); } } if (old == Block.Sponge && physics > 0 && block != Block.Sponge) { OtherPhysics.DoSpongeRemoved(this, b, false); } if (old == Block.LavaSponge && physics > 0 && block != Block.LavaSponge) { OtherPhysics.DoSpongeRemoved(this, b, true); } if (addUndo) { UndoPos uP = default(UndoPos); uP.Index = b; uP.SetData(old, block); if (UndoBuffer.Count < Server.Config.PhysicsUndo) { UndoBuffer.Add(uP); } else { if (currentUndo >= Server.Config.PhysicsUndo) { currentUndo = 0; } UndoBuffer[currentUndo] = uP; } currentUndo++; } Changed = true; if (block >= Block.Extended) { #if TEN_BIT_BLOCKS blocks[b] = Block.ExtendedClass[block >> Block.ExtendedShift]; #else blocks[b] = Block.custom_block; #endif ushort x, y, z; IntToPos(b, out x, out y, out z); FastSetExtTile(x, y, z, (BlockRaw)block); } else { blocks[b] = (BlockRaw)block; if (old >= Block.Extended) { ushort x, y, z; IntToPos(b, out x, out y, out z); FastRevertExtTile(x, y, z); } } if (physics > 0 && (ActivatesPhysics(block) || data.Raw != 0)) { AddCheck(b, false, data); } // Save bandwidth not sending identical looking blocks, like air/op_air changes. return(!Block.VisuallyEquals(old, block)); } catch { return(false); } }
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(); }
/// <summary> Retrieves the default physics block handler for the given block. </summary> internal static HandlePhysics GetPhysicsHandler(BlockID block, BlockProps[] props) { switch (block) { case Block.Door_Log_air: return(DoorPhysics.Do); case Block.Door_TNT_air: return(DoorPhysics.Do); case Block.Door_Green_air: return(DoorPhysics.Do); case Block.SnakeTail: return(SnakePhysics.DoTail); case Block.Snake: return(SnakePhysics.Do); case Block.RocketHead: return(RocketPhysics.Do); case Block.Fireworks: return(FireworkPhysics.Do); case Block.ZombieBody: return(ZombiePhysics.Do); case Block.ZombieHead: return(ZombiePhysics.DoHead); case Block.Creeper: return(ZombiePhysics.Do); case Block.Water: return(SimpleLiquidPhysics.DoWater); case Block.Deadly_ActiveWater: return(SimpleLiquidPhysics.DoWater); case Block.Lava: return(SimpleLiquidPhysics.DoLava); case Block.Deadly_ActiveLava: return(SimpleLiquidPhysics.DoLava); case Block.WaterDown: return(ExtLiquidPhysics.DoWaterfall); case Block.LavaDown: return(ExtLiquidPhysics.DoLavafall); case Block.WaterFaucet: return((Level lvl, ref PhysInfo C) => ExtLiquidPhysics.DoFaucet(lvl, ref C, Block.WaterDown)); case Block.LavaFaucet: return((Level lvl, ref PhysInfo C) => ExtLiquidPhysics.DoFaucet(lvl, ref C, Block.LavaDown)); case Block.FiniteWater: return(FinitePhysics.DoWaterOrLava); case Block.FiniteLava: return(FinitePhysics.DoWaterOrLava); case Block.FiniteFaucet: return(FinitePhysics.DoFaucet); case Block.Magma: return(ExtLiquidPhysics.DoMagma); case Block.Geyser: return(ExtLiquidPhysics.DoGeyser); case Block.FastLava: return(SimpleLiquidPhysics.DoFastLava); case Block.Deadly_FastLava: return(SimpleLiquidPhysics.DoFastLava); case Block.Air: return(AirPhysics.DoAir); case Block.Leaves: return(LeafPhysics.DoLeaf); case Block.Sapling: return(OtherPhysics.DoShrub); case Block.Fire: return(FirePhysics.Do); case Block.LavaFire: return(FirePhysics.Do); case Block.Sand: return(OtherPhysics.DoFalling); case Block.Gravel: return(OtherPhysics.DoFalling); case Block.FloatWood: return(OtherPhysics.DoFloatwood); case Block.Sponge: return((Level lvl, ref PhysInfo C) => OtherPhysics.DoSponge(lvl, ref C, false)); case Block.LavaSponge: return((Level lvl, ref PhysInfo C) => OtherPhysics.DoSponge(lvl, ref C, true)); // Special blocks that are not saved case Block.Air_Flood: return((Level lvl, ref PhysInfo C) => AirPhysics.DoFlood(lvl, ref C, AirFlood.Full, Block.Air_Flood)); case Block.Air_FloodLayer: return((Level lvl, ref PhysInfo C) => AirPhysics.DoFlood(lvl, ref C, AirFlood.Layer, Block.Air_FloodLayer)); case Block.Air_FloodDown: return((Level lvl, ref PhysInfo C) => AirPhysics.DoFlood(lvl, ref C, AirFlood.Down, Block.Air_FloodDown)); case Block.Air_FloodUp: return((Level lvl, ref PhysInfo C) => AirPhysics.DoFlood(lvl, ref C, AirFlood.Up, Block.Air_FloodUp)); case Block.TNT_Small: return(TntPhysics.DoSmallTnt); case Block.TNT_Big: return(TntPhysics.DoBigTnt); case Block.TNT_Nuke: return(TntPhysics.DoNukeTnt); case Block.TNT_Explosion: return(TntPhysics.DoTntExplosion); case Block.Train: return(TrainPhysics.Do); } HandlePhysics animalAI = AnimalAIHandler(props[block].AnimalAI); if (animalAI != null) { return(animalAI); } if (props[block].oDoorBlock != Block.Invalid) { return(DoorPhysics.oDoor); } if (props[block].GrassBlock != Block.Invalid) { return(OtherPhysics.DoDirtGrow); } if (props[block].DirtBlock != Block.Invalid) { return(OtherPhysics.DoGrassDie); } // TODO: should this be checking WaterKills/LavaKills // Adv physics updating anything placed next to water or lava if ((block >= Block.Red && block <= Block.RedMushroom) || block == Block.Wood || block == Block.Log || block == Block.Bookshelf) { return(OtherPhysics.DoOther); } return(null); }
/// <summary> Performs a user like block change, but **DOES NOT** update the BlockDB. </summary> /// <remarks> The return code can be used to avoid sending redundant block changes. </remarks> /// <remarks> Does NOT send the changed block to any players - use BroadcastChange. </remarks> public ChangeResult TryChangeBlock(Player p, ushort x, ushort y, ushort z, BlockID block, bool drawn = false) { string errorLocation = "start"; try { BlockID old = GetBlock(x, y, z); if (old == Block.Invalid) { return(ChangeResult.Unchanged); } errorLocation = "Permission checking"; if (!CheckAffect(p, x, y, z, old, block)) { return(ChangeResult.Unchanged); } if (old == block) { return(ChangeResult.Unchanged); } if (old == Block.Sponge && physics > 0 && block != Block.Sponge) { OtherPhysics.DoSpongeRemoved(this, PosToInt(x, y, z), false); } if (old == Block.LavaSponge && physics > 0 && block != Block.LavaSponge) { OtherPhysics.DoSpongeRemoved(this, PosToInt(x, y, z), true); } p.TotalModified++; if (drawn) { p.TotalDrawn++; } else if (block == Block.Air) { p.TotalDeleted++; } else { p.TotalPlaced++; } errorLocation = "Setting tile"; if (block >= Block.Extended) { #if TEN_BIT_BLOCKS SetTile(x, y, z, Block.ExtendedClass[block >> Block.ExtendedShift]); #else SetTile(x, y, z, Block.custom_block); #endif FastSetExtTile(x, y, z, (BlockRaw)block); } else { SetTile(x, y, z, (BlockRaw)block); if (old >= Block.Extended) { FastRevertExtTile(x, y, z); } } errorLocation = "Adding physics"; if (physics > 0 && ActivatesPhysics(block)) { AddCheck(PosToInt(x, y, z)); } Changed = true; ChangedSinceBackup = true; return(Block.VisuallyEquals(old, block) ? ChangeResult.VisuallySame : ChangeResult.Modified); } catch (Exception e) { Logger.LogError(e); Chat.MessageOps(p.name + " triggered a non-fatal error on " + ColoredName + ", &Sat location: " + errorLocation); Logger.Log(LogType.Warning, "{0} triggered a non-fatal error on {1}, &Sat location: {2}", p.name, ColoredName, errorLocation); return(0); } }
internal static void SetupCorePhysicsHandlers() { physicsHandlers[Block.birdblack] = BirdPhysics.Do; physicsHandlers[Block.birdwhite] = BirdPhysics.Do; physicsHandlers[Block.birdlava] = BirdPhysics.Do; physicsHandlers[Block.birdwater] = BirdPhysics.Do; physicsHandlers[Block.birdred] = (Level lvl, ref Check C) => HunterPhysics.DoKiller(lvl, ref C, Block.air); physicsHandlers[Block.birdblue] = (Level lvl, ref Check C) => HunterPhysics.DoKiller(lvl, ref C, Block.air); physicsHandlers[Block.birdkill] = (Level lvl, ref Check C) => HunterPhysics.DoKiller(lvl, ref C, Block.air); physicsHandlers[Block.snaketail] = SnakePhysics.DoTail; physicsHandlers[Block.snake] = SnakePhysics.Do; physicsHandlers[Block.rockethead] = RocketPhysics.Do; physicsHandlers[Block.firework] = FireworkPhysics.Do; physicsHandlers[Block.zombiebody] = ZombiePhysics.Do; physicsHandlers[Block.zombiehead] = ZombiePhysics.DoHead; physicsHandlers[Block.creeper] = ZombiePhysics.Do; physicsHandlers[Block.fishbetta] = (Level lvl, ref Check C) => HunterPhysics.DoKiller(lvl, ref C, Block.water); physicsHandlers[Block.fishshark] = (Level lvl, ref Check C) => HunterPhysics.DoKiller(lvl, ref C, Block.water); physicsHandlers[Block.fishlavashark] = (Level lvl, ref Check C) => HunterPhysics.DoKiller(lvl, ref C, Block.lava); physicsHandlers[Block.fishgold] = (Level lvl, ref Check C) => HunterPhysics.DoFlee(lvl, ref C, Block.water); physicsHandlers[Block.fishsalmon] = (Level lvl, ref Check C) => HunterPhysics.DoFlee(lvl, ref C, Block.water); physicsHandlers[Block.fishsponge] = (Level lvl, ref Check C) => HunterPhysics.DoFlee(lvl, ref C, Block.water); physicsHandlers[Block.water] = SimpleLiquidPhysics.DoWater; physicsHandlers[Block.activedeathwater] = SimpleLiquidPhysics.DoWater; physicsHandlers[Block.lava] = SimpleLiquidPhysics.DoLava; physicsHandlers[Block.activedeathlava] = SimpleLiquidPhysics.DoLava; physicsHandlers[Block.WaterDown] = ExtLiquidPhysics.DoWaterfall; physicsHandlers[Block.LavaDown] = ExtLiquidPhysics.DoLavafall; physicsHandlers[Block.WaterFaucet] = (Level lvl, ref Check C) => ExtLiquidPhysics.DoFaucet(lvl, ref C, Block.WaterDown); physicsHandlers[Block.LavaFaucet] = (Level lvl, ref Check C) => ExtLiquidPhysics.DoFaucet(lvl, ref C, Block.LavaDown); physicsHandlers[Block.finiteWater] = FinitePhysics.DoWaterOrLava; physicsHandlers[Block.finiteLava] = FinitePhysics.DoWaterOrLava; physicsHandlers[Block.finiteFaucet] = FinitePhysics.DoFaucet; physicsHandlers[Block.magma] = ExtLiquidPhysics.DoMagma; physicsHandlers[Block.geyser] = ExtLiquidPhysics.DoGeyser; physicsHandlers[Block.lava_fast] = SimpleLiquidPhysics.DoFastLava; physicsHandlers[Block.fastdeathlava] = SimpleLiquidPhysics.DoFastLava; physicsHandlers[Block.air] = AirPhysics.DoAir; physicsHandlers[Block.dirt] = OtherPhysics.DoDirt; physicsHandlers[Block.leaf] = LeafPhysics.DoLeaf; physicsHandlers[Block.shrub] = OtherPhysics.DoShrub; physicsHandlers[Block.fire] = FirePhysics.Do; physicsHandlers[Block.lava_fire] = FirePhysics.Do; physicsHandlers[Block.sand] = OtherPhysics.DoFalling; physicsHandlers[Block.gravel] = OtherPhysics.DoFalling; physicsHandlers[Block.cobblestoneslab] = OtherPhysics.DoStairs; physicsHandlers[Block.staircasestep] = OtherPhysics.DoStairs; physicsHandlers[Block.wood_float] = OtherPhysics.DoFloatwood; physicsHandlers[Block.sponge] = (Level lvl, ref Check C) => OtherPhysics.DoSponge(lvl, ref C, false); physicsHandlers[Block.lava_sponge] = (Level lvl, ref Check C) => OtherPhysics.DoSponge(lvl, ref C, true); //Special blocks that are not saved physicsHandlers[Block.air_flood] = (Level lvl, ref Check C) => AirPhysics.DoFlood(lvl, ref C, AirFlood.Full, Block.air_flood); physicsHandlers[Block.air_flood_layer] = (Level lvl, ref Check C) => AirPhysics.DoFlood(lvl, ref C, AirFlood.Layer, Block.air_flood_layer); physicsHandlers[Block.air_flood_down] = (Level lvl, ref Check C) => AirPhysics.DoFlood(lvl, ref C, AirFlood.Down, Block.air_flood_down); physicsHandlers[Block.air_flood_up] = (Level lvl, ref Check C) => AirPhysics.DoFlood(lvl, ref C, AirFlood.Up, Block.air_flood_up); physicsHandlers[Block.smalltnt] = TntPhysics.DoSmallTnt; physicsHandlers[Block.bigtnt] = (Level lvl, ref Check C) => TntPhysics.DoLargeTnt(lvl, ref C, 1); physicsHandlers[Block.nuketnt] = (Level lvl, ref Check C) => TntPhysics.DoLargeTnt(lvl, ref C, 4); physicsHandlers[Block.tntexplosion] = TntPhysics.DoTntExplosion; physicsHandlers[Block.train] = TrainPhysics.Do; for (int i = 0; i < 256; i++) { //Adv physics updating anything placed next to water or lava if ((i >= Block.red && i <= Block.redmushroom) || i == Block.wood || i == Block.trunk || i == Block.bookcase) { physicsHandlers[i] = OtherPhysics.DoOther; continue; } if (Block.Props[i].ODoorId != Block.Invalid) { physicsHandlers[i] = DoorPhysics.oDoor; physicsDoorsHandlers[i] = DoorPhysics.oDoor; } } }
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(); }
internal bool DoPhysicsBlockchange(int b, ExtBlock block, bool overRide = false, PhysicsArgs data = default(PhysicsArgs), bool addUndo = true) { if (blocks == null || b < 0 || b >= blocks.Length) { return(false); } ExtBlock old; old.BlockID = blocks[b]; old.ExtID = old.BlockID == Block.custom_block ? GetExtTile(b) : Block.Air; try { if (!overRide) { if (Props[old.Index].OPBlock || (Props[block.Index].OPBlock && data.Raw != 0)) { return(false); } } if (old.BlockID == Block.Sponge && physics > 0 && block.BlockID != Block.Sponge) { OtherPhysics.DoSpongeRemoved(this, b, false); } if (old.BlockID == Block.LavaSponge && physics > 0 && block.BlockID != Block.LavaSponge) { OtherPhysics.DoSpongeRemoved(this, b, true); } if (addUndo) { UndoPos uP = default(UndoPos); uP.index = b; uP.SetData(old, block); if (UndoBuffer.Count < ServerConfig.PhysicsUndo) { UndoBuffer.Add(uP); } else { if (currentUndo >= ServerConfig.PhysicsUndo) { currentUndo = 0; } UndoBuffer[currentUndo] = uP; } currentUndo++; } blocks[b] = block.BlockID; Changed = true; if (block.BlockID == Block.custom_block) { ushort x, y, z; IntToPos(b, out x, out y, out z); SetExtTileNoCheck(x, y, z, block.ExtID); } else if (old.BlockID == Block.custom_block) { ushort x, y, z; IntToPos(b, out x, out y, out z); RevertExtTileNoCheck(x, y, z); } if (physics > 0 && (ActivatesPhysics(block) || data.Raw != 0)) { AddCheck(b, false, data); } // Save bandwidth sending identical looking blocks, like air/op_air changes. return(!old.VisuallyEquals(block)); } catch { blocks[b] = block.BlockID; return(false); } }
/// <summary> Returns: <br/> /// 0 - block change was not performed <br/> /// 1 - old block was same as new block visually (e.g. white to door_white)<br/> /// 2 - old block was different to new block visually </summary> /// <remarks> The return code can be used to avoid sending redundant block changes. </remarks> public int DoBlockchange(Player p, ushort x, ushort y, ushort z, ExtBlock block, bool drawn = false) { string errorLocation = "start"; try { if (x >= Width || y >= Height || z >= Length) { return(0); } ExtBlock old = GetBlock(x, y, z); errorLocation = "Permission checking"; if (!CheckAffectPermissions(p, x, y, z, old, block)) { p.RevertBlock(x, y, z); return(0); } if (old == block) { return(0); } if (old.BlockID == Block.Sponge && physics > 0 && block.BlockID != Block.Sponge) { OtherPhysics.DoSpongeRemoved(this, PosToInt(x, y, z), false); } if (old.BlockID == Block.LavaSponge && physics > 0 && block.BlockID != Block.LavaSponge) { OtherPhysics.DoSpongeRemoved(this, PosToInt(x, y, z), true); } p.SessionModified++; p.TotalModified++; if (drawn) { p.TotalDrawn++; } else if (block.BlockID == Block.Air) { p.TotalDeleted++; } else { p.TotalPlaced++; } errorLocation = "Setting tile"; SetTile(x, y, z, block.BlockID); if (old.BlockID == Block.custom_block && block.BlockID != Block.custom_block) { RevertExtTileNoCheck(x, y, z); } if (block.BlockID == Block.custom_block) { SetExtTileNoCheck(x, y, z, block.ExtID); } errorLocation = "Adding physics"; if (p.PlayingTntWars && block.BlockID == Block.TNT_Small) { AddTntCheck(PosToInt(x, y, z), p); } if (physics > 0 && ActivatesPhysics(block)) { AddCheck(PosToInt(x, y, z)); } Changed = true; backedup = false; return(old.VisuallyEquals(block) ? 1 : 2); } catch (Exception e) { Logger.LogError(e); Chat.MessageOps(p.name + " triggered a non-fatal error on " + ColoredName + ", %Sat location: " + errorLocation); Logger.Log(LogType.Warning, "{0} triggered a non-fatal error on {1}, %Sat location: {2}", p.name, ColoredName, errorLocation); return(0); } }
internal bool DoPhysicsBlockchange(int b, byte block, bool overRide = false, PhysicsArgs data = default(PhysicsArgs), byte extBlock = 0, bool addUndo = true) { if (b < 0 || b >= blocks.Length || blocks == null) { return(false); } byte old = blocks[b]; byte oldExt = old == Block.custom_block ? GetExtTile(b) : (byte)0; try { if (!overRide) { if (Block.Props[old].OPBlock || (Block.Props[block].OPBlock && data.Raw != 0)) { return(false); } } if (b == Block.sponge && physics > 0 && block != Block.sponge) { OtherPhysics.DoSpongeRemoved(this, b); } if (b == Block.lava_sponge && physics > 0 && block != Block.lava_sponge) { OtherPhysics.DoSpongeRemoved(this, b, true); } if (addUndo) { UndoPos uP = default(UndoPos); uP.index = b; uP.SetData(old, oldExt, block, extBlock); if (UndoBuffer.Count < Server.physUndo) { UndoBuffer.Add(uP); } else { if (currentUndo >= Server.physUndo) { currentUndo = 0; } UndoBuffer[currentUndo] = uP; } currentUndo++; } blocks[b] = block; changed = true; if (block == Block.custom_block) { ushort x, y, z; IntToPos(b, out x, out y, out z); SetExtTileNoCheck(x, y, z, extBlock); } else if (old == Block.custom_block) { ushort x, y, z; IntToPos(b, out x, out y, out z); RevertExtTileNoCheck(x, y, z); } if (physics > 0 && (ActivatesPhysics(block, extBlock) || data.Raw != 0)) { AddCheck(b, false, data); } // Save bandwidth sending identical looking blocks, like air/op_air changes. bool diffBlock = Block.Convert(old) != Block.Convert(block); if (!diffBlock && old == Block.custom_block) { diffBlock = oldExt != extBlock; } return(diffBlock); } catch { blocks[b] = block; return(false); } }
public bool DoBlockchange(Player p, ushort x, ushort y, ushort z, byte block, byte extBlock = 0, bool drawn = false) { string errorLocation = "start"; retry: try { //if (x < 0 || y < 0 || z < 0) return; if (x >= Width || y >= Height || z >= Length) { return(false); } byte old = GetTile(x, y, z), extOld = 0; if (old == Block.custom_block) { extOld = GetExtTile(x, y, z); } errorLocation = "Permission checking"; if (!CheckAffectPermissions(p, x, y, z, old, block, extBlock)) { p.RevertBlock(x, y, z); return(false); } if (old == Block.sponge && physics > 0 && block != Block.sponge) { OtherPhysics.DoSpongeRemoved(this, PosToInt(x, y, z)); } if (old == Block.lava_sponge && physics > 0 && block != Block.lava_sponge) { OtherPhysics.DoSpongeRemoved(this, PosToInt(x, y, z), true); } errorLocation = "Undo buffer filling"; Player.UndoPos Pos; Pos.x = x; Pos.y = y; Pos.z = z; Pos.mapName = name; Pos.type = old; Pos.extType = extOld; Pos.newtype = block; Pos.newExtType = extBlock; Pos.timeDelta = (int)DateTime.UtcNow.Subtract(Server.StartTime).TotalSeconds; p.UndoBuffer.Add(this, Pos); errorLocation = "Setting tile"; p.IncrementBlockStats(block, drawn); SetTile(x, y, z, block); if (old == Block.custom_block && block != Block.custom_block) { RevertExtTileNoCheck(x, y, z); } if (block == Block.custom_block) { SetExtTileNoCheck(x, y, z, extBlock); } errorLocation = "Adding physics"; if (p.PlayingTntWars && block == Block.smalltnt) { AddTntCheck(PosToInt(x, y, z), p); } if (physics > 0 && ActivatesPhysics(block, extBlock)) { AddCheck(PosToInt(x, y, z)); } changed = true; backedup = false; bool diffBlock = old == Block.custom_block ? extOld != extBlock : Block.Convert(old) != Block.Convert(block); return(diffBlock); } catch (OutOfMemoryException) { Player.Message(p, "Undo buffer too big! Cleared!"); p.UndoBuffer.Clear(); p.RemoveInvalidUndos(); goto retry; } catch (Exception e) { Server.ErrorLog(e); Chat.MessageOps(p.name + " triggered a non-fatal error on " + ColoredName); Chat.MessageOps("Error location: " + errorLocation); Server.s.Log(p.name + " triggered a non-fatal error on " + ColoredName); Server.s.Log("Error location: " + errorLocation); return(false); } }
internal bool DoBlockchange(Player p, ushort x, ushort y, ushort z, byte type, byte extType = 0) { string errorLocation = "start"; retry: try { //if (x < 0 || y < 0 || z < 0) return; if (x >= Width || y >= Height || z >= Length) { return(false); } byte b = GetTile(x, y, z), extB = 0; if (b == Block.custom_block) { extB = GetExtTile(x, y, z); } errorLocation = "Permission checking"; if (!CheckAffectPermissions(p, x, y, z, b, type, extType)) { p.RevertBlock(x, y, z); return(false); } if (b == Block.sponge && physics > 0 && type != Block.sponge) { OtherPhysics.DoSpongeRemoved(this, PosToInt(x, y, z)); } if (b == Block.lava_sponge && physics > 0 && type != Block.lava_sponge) { OtherPhysics.DoSpongeRemoved(this, PosToInt(x, y, z), true); } errorLocation = "Undo buffer filling"; Player.UndoPos Pos; Pos.x = x; Pos.y = y; Pos.z = z; Pos.mapName = name; Pos.type = b; Pos.extType = extB; Pos.newtype = type; Pos.newExtType = extType; Pos.timeDelta = (int)DateTime.UtcNow.Subtract(Server.StartTime).TotalSeconds; p.UndoBuffer.Add(this, Pos); errorLocation = "Setting tile"; p.loginBlocks++; p.overallBlocks++; SetTile(x, y, z, type); if (b == Block.custom_block && type != Block.custom_block) { RevertExtTileNoCheck(x, y, z); } if (type == Block.custom_block) { SetExtTileNoCheck(x, y, z, extType); } errorLocation = "Adding physics"; if (p.PlayingTntWars && type == Block.smalltnt) { AddTntCheck(PosToInt(x, y, z), p); } if (physics > 0 && Block.Physics(type)) { AddCheck(PosToInt(x, y, z)); } changed = true; backedup = false; bool diffBlock = b == Block.custom_block ? extB != extType : Block.Convert(b) != Block.Convert(type); return(diffBlock); } catch (OutOfMemoryException) { Player.SendMessage(p, "Undo buffer too big! Cleared!"); p.UndoBuffer.Clear(); p.RemoveInvalidUndos(); goto retry; } catch (Exception e) { Server.ErrorLog(e); Chat.GlobalMessageOps(p.name + " triggered a non-fatal error on " + name); Chat.GlobalMessageOps("Error location: " + errorLocation); Server.s.Log(p.name + " triggered a non-fatal error on " + name); Server.s.Log("Error location: " + errorLocation); return(false); } }