/// <summary> /// Destroy the block /// </summary> /// <param name="entity">entity who destroyed the block</param> /// <param name="block">block that has been destroyed</param> public virtual void Destroy(IEntityBase entity, IStructBlock iBlock) { StructBlock block = (StructBlock)iBlock; BlockDestroyEventArgs eventArgs = RaiseDestroyEvent(entity, block); if (eventArgs.EventCanceled) { return; } PlaySoundOnDestroy(entity, block); UpdateWorld(block, true); // Check if the entity is a player if ((entity != null) && (entity is Player)) { // Check if the player is not in creative mode // Don't drop any items if the player is in creative mode if (((Player)entity).GameMode == GameMode.Normal) { DropItems(entity as EntityBase, block); } } NotifyNearbyBlocks((EntityBase)entity, block); }
protected override void OnStop() { UniversalCoords currentBlockCoords = UniversalCoords.FromAbsWorld(Position); byte? blockId = World.GetBlockId(currentBlockCoords); if (blockId == null) return; if (BlockHelper.Instance.IsAir((byte)blockId)) { var item = ItemHelper.GetInstance(BlockId); item.Count = 1; World.Server.DropItem(World, currentBlockCoords, item); } else { UniversalCoords aboveBlockCoords = UniversalCoords.FromWorld(currentBlockCoords.WorldX, currentBlockCoords.WorldY + 1, currentBlockCoords.WorldZ); StructBlock aboveBlock = new StructBlock(aboveBlockCoords, BlockId, 0, World); BlockHelper.Instance.CreateBlockInstance(BlockId).Spawn(aboveBlock); foreach (LivingEntity living in World.Server.GetNearbyLivings(World, aboveBlockCoords)) { if (Math.Abs(living.Position.X - aboveBlockCoords.WorldX) < 2 && Math.Abs(living.Position.Z - aboveBlockCoords.WorldZ) < 2 && Math.Abs(living.Position.Y + living.Height - aboveBlockCoords.WorldY) < 2) living.CheckSuffocation(); } } base.OnStop(); }
/// <summary> /// Destroy the block /// </summary> /// <param name="entity">entity who destroyed the block</param> /// <param name="block">block that has been destroyed</param> public virtual void Destroy(IEntityBase entity, IStructBlock iBlock) { StructBlock block = (StructBlock)iBlock; BlockDestroyEventArgs eventArgs = RaiseDestroyEvent(entity, block); if (eventArgs.EventCanceled) return; PlaySoundOnDestroy(entity, block); UpdateWorld(block, true); // Check if the entity is a player if ((entity != null) && (entity.GetType() == typeof(Player))) { // Check if the player is in creative mode if (((Player)entity).GameMode == System.Convert.ToByte(1)) { // Don't drop any items as the player is in creative mode goto skipDrop; } } DropItems(entity as EntityBase, block); skipDrop: DamageItem(entity); NotifyNearbyBlocks((EntityBase)entity, block); }
/// <summary> /// Checks if the block can be placed next to the target one /// </summary> /// <param name="who">the entity who places the block</param> /// <param name="block">the block being placed</param> /// <param name="targetBlock">the block being targeted (aimed)</param> /// <param name="targetSide">the side of the target block</param> /// <returns>true if the block can be placed, false otherwise</returns> protected virtual bool CanBePlacedOn(EntityBase who, StructBlock block, StructBlock targetBlock, BlockFace targetSide) { if (!BlockHelper.Instance.IsSolid(targetBlock.Type)) return false; byte? originalBlock = block.World.GetBlockId(block.Coords); if ( originalBlock == null || (originalBlock != (byte)BlockData.Blocks.Air && originalBlock != (byte)BlockData.Blocks.Water && originalBlock != (byte)BlockData.Blocks.Still_Water && originalBlock != (byte)BlockData.Blocks.Lava && originalBlock != (byte)BlockData.Blocks.Still_Lava)) return false; if (!BlockHelper.Instance.IsAir(block.Type) && !BlockHelper.Instance.IsLiquid(block.Type)) { foreach ( EntityBase entity in block.World.Server.GetNearbyEntitiesInternal(block.World, block.Coords)) { LivingEntity living = entity as LivingEntity; if (living == null) continue; if (living.BoundingBox.IntersectsWith(GetCollisionBoundingBox(block))) return false; } } return true; }
/// <summary> /// Updates world data upon block destruction /// </summary> /// <param name="block">block that has been destroyed</param> protected virtual void UpdateWorld(StructBlock block, bool isDestroyed = false) { byte newType = (isDestroyed ? (byte)BlockData.Blocks.Air : block.Type); byte newMeta = (isDestroyed ? (byte)0 : block.MetaData); block.World.SetBlockAndData(block.Coords, newType, newMeta); RecalculateChunkValues(block); }
/// <summary> /// Notifies the nearby block that the current block has been destroyed /// May be used by recipient block to start the physic simulation etc /// </summary> /// <param name="entity">entity who destroyed the block</param> /// <param name="block">block that has been destroyed</param> protected virtual void NotifyNearbyBlocks(EntityBase entity, StructBlock block, bool destroyed = true) { List<UniversalCoords> blocks = new List<UniversalCoords>(6); if (block.Coords.WorldY < 127) blocks.Add(UniversalCoords.FromWorld(block.Coords.WorldX, block.Coords.WorldY + 1, block.Coords.WorldZ)); if (block.Coords.WorldY > 0) blocks.Add(UniversalCoords.FromWorld(block.Coords.WorldX, block.Coords.WorldY - 1, block.Coords.WorldZ)); blocks.Add(UniversalCoords.FromWorld(block.Coords.WorldX - 1, block.Coords.WorldY, block.Coords.WorldZ)); blocks.Add(UniversalCoords.FromWorld(block.Coords.WorldX + 1, block.Coords.WorldY, block.Coords.WorldZ)); blocks.Add(UniversalCoords.FromWorld(block.Coords.WorldX, block.Coords.WorldY, block.Coords.WorldZ - 1)); blocks.Add(UniversalCoords.FromWorld(block.Coords.WorldX, block.Coords.WorldY, block.Coords.WorldZ + 1)); byte blockId = 0; byte blockMeta = 0; foreach (var coords in blocks) { Chunk chunk = block.World.GetChunk(coords) as Chunk; if (chunk == null) break; blockId = (byte)chunk.GetType(coords); blockMeta = chunk.GetData(coords); if (destroyed) BlockHelper.Instance.CreateBlockInstance(blockId).NotifyDestroy(entity, block, new StructBlock(coords, blockId, blockMeta, block.World)); else BlockHelper.Instance.CreateBlockInstance(blockId).NotifyPlace(entity, block, new StructBlock(coords, blockId, blockMeta, block.World)); } }
public virtual void RecalculateChunkValues(StructBlock block) { Chunk chunk = GetBlockChunk(block); if (chunk == null) { return; } byte blockX, blockY, blockZ; blockX = (byte)block.Coords.BlockX; blockY = (byte)block.Coords.BlockY; blockZ = (byte)block.Coords.BlockZ; byte oldHeight = chunk.HeightMap[blockX, blockZ]; if (blockY + 1 >= chunk.HeightMap[blockX, blockZ]) { chunk.RecalculateHeight(block.Coords); } #if PROFILE Stopwatch watch = new Stopwatch(); watch.Start(); #endif //chunk.SpreadLightFromBlock(blockX, blockY, blockZ, chunk.GetBlockLight(blockX, blockY, blockZ), oldHeight); #if PROFILE watch.Stop(); block.World.Logger.Log(LogLevel.Info, "Block skylight recalc: {0}ms", watch.ElapsedMilliseconds); #endif block.World.Update(block.Coords, false); }
/// <summary> /// Gets the collision bounding box for the provided location. /// </summary> /// <returns> /// The collision bounding box. /// </returns> /// <param name='coords'> /// Coords. /// </param> public BoundingBox GetCollisionBoundingBox(StructBlock block) { UniversalCoords coords = block.Coords; return(new BoundingBox(coords.WorldX + BlockBoundsOffset.Minimum.X, coords.WorldY + BlockBoundsOffset.Minimum.Y, coords.WorldZ + BlockBoundsOffset.Minimum.Z, coords.WorldX + BlockBoundsOffset.Maximum.X, coords.WorldY + BlockBoundsOffset.Maximum.Y, coords.WorldZ + BlockBoundsOffset.Maximum.Z)); }
public override void Place(IEntityBase entity, IStructBlock iBlock, IStructBlock targetIBlock, BlockFace face) { StructBlock block = (StructBlock)iBlock; LivingEntity living = entity as LivingEntity; if (living == null) { return; } switch (living.FacingDirection(4)) { case "N": block.MetaData = (byte)MetaData.Door.Northwest; break; case "W": block.MetaData = (byte)MetaData.Door.Southwest; break; case "S": block.MetaData = (byte)MetaData.Door.Southeast; break; case "E": block.MetaData = (byte)MetaData.Door.Northeast; break; default: return; } base.Place(entity, block, targetIBlock, face); }
protected override void NotifyDestroy(EntityBase entity, StructBlock sourceBlock, StructBlock targetBlock) { if ((targetBlock.Coords.WorldY - sourceBlock.Coords.WorldY) == 1 && targetBlock.Coords.WorldX == sourceBlock.Coords.WorldX && targetBlock.Coords.WorldZ == sourceBlock.Coords.WorldZ) Destroy(targetBlock); base.NotifyDestroy(entity, sourceBlock, targetBlock); }
protected override void UpdateWorld(StructBlock block, bool isDestroyed = false) { if (isDestroyed) { ContainerFactory.Destroy((WorldManager)block.World, block.Coords); } base.UpdateWorld(block, isDestroyed); }
/// <summary> /// Raises the block placement event /// </summary> /// <param name="entity">entity who placed the block</param> /// <param name="block">block that has been placed</param> /// <returns>resulting event args</returns> protected virtual bool RaisePlaceEvent(IEntityBase entity, StructBlock block) { BlockPlaceEventArgs e = new BlockPlaceEventArgs(this, entity); block.World.Server.PluginManager.CallEvent(Event.BlockPlace, e); // Destruction made not by the living can not be interrupted? if (entity == null) return true; return !e.EventCanceled; }
public RayTraceHitBlock RayTraceIntersection(StructBlock block, Vector3 start, Vector3 end) { BoundingBox boundingBox = GetCollisionBoundingBox(block); RayTraceHit rayTraceHit = boundingBox.RayTraceIntersection(start, end); if (rayTraceHit != null) return new RayTraceHitBlock(block.Coords, rayTraceHit.FaceHit, rayTraceHit.Hit); return null; }
protected override bool CanBePlacedOn(EntityBase who, StructBlock block, StructBlock targetBlock, BlockFace targetSide) { if (block.Coords.WorldY > 125) return false; UniversalCoords blockAbove = UniversalCoords.FromWorld(block.Coords.WorldX, block.Coords.WorldY + 1, block.Coords.WorldZ); if (block.World.GetBlockId(blockAbove) != (byte)BlockData.Blocks.Air) return false; return base.CanBePlacedOn(who, block, targetBlock, targetSide); }
protected override void NotifyDestroy(EntityBase entity, StructBlock sourceBlock, StructBlock targetBlock) { if ((targetBlock.Coords.WorldY - sourceBlock.Coords.WorldY) == 1 && targetBlock.Coords.WorldX == sourceBlock.Coords.WorldX && targetBlock.Coords.WorldZ == sourceBlock.Coords.WorldZ) { Destroy(targetBlock); } base.NotifyDestroy(entity, sourceBlock, targetBlock); }
protected override bool CanBePlacedOn(EntityBase who, StructBlock block, StructBlock targetBlock, BlockFace targetSide) { Chunk chunk = GetBlockChunk(block); Chunk targetChunk = GetBlockChunk(targetBlock); if (chunk == null || targetChunk == null) return false; if (targetSide == BlockFace.Down) return false; return base.CanBePlacedOn(who, block, targetBlock, targetSide); }
public override void Place(IEntityBase entity, IStructBlock iBlock, IStructBlock targetIBlock, BlockFace face) { StructBlock block = (StructBlock)iBlock; StructBlock targetBlock = (StructBlock)targetIBlock; LivingEntity living = (entity as LivingEntity); if (living == null) { return; } block.MetaData = GetDirection(living, block, targetBlock, face); base.Place(entity, block, targetBlock, face); }
protected override void UpdateWorld(StructBlock block, bool isDestroyed = false) { base.UpdateWorld(block, isDestroyed); if (isDestroyed) return; if ((block.MetaData & 8) != 0 && block.Coords.WorldY < 127) { UniversalCoords upperBlock = UniversalCoords.FromWorld(block.Coords.WorldX, block.Coords.WorldY + 1, block.Coords.WorldZ); StructBlock upperHalf = new StructBlock(upperBlock, (byte)Type, (byte)(block.MetaData | 8), block.World); BlockHelper.Instance.CreateBlockInstance((byte)Type).Spawn(upperHalf); } }
protected override bool CanBePlacedOn(EntityBase who, StructBlock block, StructBlock targetBlock, BlockFace targetSide) { if (block.Coords.WorldY > 125) { return(false); } UniversalCoords blockAbove = UniversalCoords.FromWorld(block.Coords.WorldX, block.Coords.WorldY + 1, block.Coords.WorldZ); if (block.World.GetBlockId(blockAbove) != (byte)BlockData.Blocks.Air) { return(false); } return(base.CanBePlacedOn(who, block, targetBlock, targetSide)); }
/// <summary> /// Invoked to drop the loot after block destruction /// </summary> /// <param name="entity">entity that destroyed the block</param> /// <param name="block">block that has been destroyed</param> protected virtual void DropItems(EntityBase entity, StructBlock block, List<ItemStack> overridedLoot = null) { List<ItemStack> toDrop; if (overridedLoot != null && overridedLoot.Count > 0) toDrop = overridedLoot; else if (LootTable != null && LootTable.Count > 0) toDrop = LootTable; else return; foreach (var lootEntry in toDrop) { if (lootEntry.Count > 0) block.World.Server.DropItem(block.World, block.Coords, lootEntry); } }
protected override void UpdateWorld(StructBlock block, bool isDestroyed = false) { base.UpdateWorld(block, isDestroyed); if (isDestroyed) { return; } if ((block.MetaData & 8) != 0 && block.Coords.WorldY < 127) { UniversalCoords upperBlock = UniversalCoords.FromWorld(block.Coords.WorldX, block.Coords.WorldY + 1, block.Coords.WorldZ); StructBlock upperHalf = new StructBlock(upperBlock, (byte)Type, (byte)(block.MetaData | 8), block.World); BlockHelper.Instance.CreateBlockInstance((byte)Type).Spawn(upperHalf); } }
protected virtual byte GetDirection(LivingEntity living, StructBlock block, StructBlock targetBlock, BlockFace face) { byte direction = 0; switch (face) { case BlockFace.East: direction = (byte)MetaData.Container.East; break; case BlockFace.West: direction = (byte)MetaData.Container.West; break; case BlockFace.North: direction = (byte)MetaData.Container.North; break; case BlockFace.South: direction = (byte)MetaData.Container.South; break; default: switch (living.FacingDirection(4)) // Built on floor, set by facing dir { case "N": direction = (byte)MetaData.Container.North; break; case "W": direction = (byte)MetaData.Container.West; break; case "S": direction = (byte)MetaData.Container.South; break; case "E": direction = (byte)MetaData.Container.East; break; default: return(0); } break; } return(direction); }
protected override bool CanBePlacedOn(EntityBase who, StructBlock block, StructBlock targetBlock, BlockFace targetSide) { Chunk chunk = GetBlockChunk(block); Chunk targetChunk = GetBlockChunk(targetBlock); if (chunk == null || targetChunk == null) { return(false); } if (targetSide == BlockFace.Down) { return(false); } return(base.CanBePlacedOn(who, block, targetBlock, targetSide)); }
/// <summary> /// Plays the sound on block destruction /// </summary> /// <param name="entity">entity that destroyed the block</param> /// <param name="block">block that has been destroyed</param> protected virtual void PlaySoundOnDestroy(IEntityBase entity, StructBlock block) { foreach (Client c in block.World.Server.GetNearbyPlayersInternal(block.World, block.Coords)) { if (c.Owner == entity) continue; c.SendPacket(new SoundOrParticleEffectPacket { EffectID = SoundOrParticleEffectPacket.SoundOrParticleEffect.PARTICLE_BLOCK_BREAK, X = block.Coords.WorldX, Y = block.Coords.WorldY, Z = block.Coords.WorldZ, SoundData = block.Type }); } }
/// <summary> /// Places the block /// </summary> /// <param name="entity">entity who placed the block</param> /// <param name="block">block that is being placed</param> /// <param name="targetBlock">block that is being targeted (aimed)</param> /// <param name="face">side of the target block</param> public virtual void Place(IEntityBase ientity, IStructBlock iBlock, IStructBlock targetIBlock, BlockFace face) { StructBlock block = (StructBlock) iBlock; StructBlock targetBlock = (StructBlock) targetIBlock; EntityBase entity = (EntityBase) ientity; if (!CanBePlacedOn(entity, block, targetBlock, face) || !RaisePlaceEvent(entity, block)) { // Revert the change since the client has already graphically placed the block if(entity is Player) { Player player = entity as Player; player.Server.SendPacketToNearbyPlayers(player.World, player.Position, new BlockChangePacket{Data = targetBlock.MetaData, Type = targetBlock.Type, X = targetBlock.Coords.WorldX, Y = (sbyte)targetBlock.Coords.WorldY, Z = targetBlock.Coords.WorldZ}); } return; } UpdateWorld(block); RemoveItem(entity); NotifyNearbyBlocks(entity, block, false); }
protected virtual byte GetDirection(LivingEntity living, StructBlock block, StructBlock targetBlock, BlockFace face) { byte direction = 0; switch (face) { case BlockFace.East: direction = (byte)MetaData.Container.East; break; case BlockFace.West: direction = (byte)MetaData.Container.West; break; case BlockFace.North: direction = (byte)MetaData.Container.North; break; case BlockFace.South: direction = (byte)MetaData.Container.South; break; default: switch (living.FacingDirection(4)) // Built on floor, set by facing dir { case "N": direction = (byte)MetaData.Container.North; break; case "W": direction = (byte)MetaData.Container.West; break; case "S": direction = (byte)MetaData.Container.South; break; case "E": direction = (byte)MetaData.Container.East; break; default: return 0; } break; } return direction; }
/// <summary> /// Invoked to drop the loot after block destruction /// </summary> /// <param name="block">block that has been destroyed</param> protected virtual void DropItems(StructBlock block, List<ItemStack> overridedLoot = null) { DropItems(null, block, overridedLoot); }
/// <summary> /// Spawns the block in the world (not placed by the player) /// </summary> /// <param name="block">block that is being spawned</param> public virtual void Spawn(StructBlock block) { UpdateWorld(block); NotifyNearbyBlocks(null, block, false); }
/// <summary> /// Removes the block from the world. Don't drop anything. /// </summary> /// <param name="block">block that is being removed</param> public virtual void Remove(StructBlock block) { UpdateWorld(block, true); NotifyNearbyBlocks(null, block); }
protected virtual void NotifyPlace(EntityBase entity, StructBlock sourceBlock, StructBlock targetBlock) { }
/// <summary> /// Raises the block destruction event /// </summary> /// <param name="entity">entity who destroyed the block</param> /// <param name="block">block that has been destroyed</param> /// <returns>resulting event args</returns> protected virtual BlockDestroyEventArgs RaiseDestroyEvent(IEntityBase entity, StructBlock block) { BlockDestroyEventArgs e = new BlockDestroyEventArgs(this, entity); block.World.Server.PluginManager.CallEvent(Event.BlockDestroy, e); return e; }
public virtual void Fertilize(EntityBase entity, StructBlock block) { }
public Chunk GetBlockChunk(StructBlock block) { return block.World.GetChunk(block.Coords) as Chunk; }
/// <summary> /// Invoked to drop the loot after block destruction /// </summary> /// <param name="block">block that has been destroyed</param> protected virtual void DropItems(StructBlock block, List <ItemInventory> overridedLoot = null) { DropItems(null, block, overridedLoot); }
protected override void UpdateWorld(StructBlock block, bool isDestroyed = false) { if (isDestroyed) ContainerFactory.Destroy((WorldManager)block.World, block.Coords); base.UpdateWorld(block, isDestroyed); }
/// <summary> /// Raises the block destruction event /// </summary> /// <param name="entity">entity who destroyed the block</param> /// <param name="block">block that has been destroyed</param> /// <returns>resulting event args</returns> protected virtual BlockDestroyEventArgs RaiseDestroyEvent(IEntityBase entity, StructBlock block) { BlockDestroyEventArgs e = new BlockDestroyEventArgs(this, entity); block.World.Server.PluginManager.CallEvent(Event.BlockDestroy, e); return(e); }
/// <summary> /// Gets the collision bounding box for the provided location. /// </summary> /// <returns> /// The collision bounding box. /// </returns> /// <param name='coords'> /// Coords. /// </param> public BoundingBox GetCollisionBoundingBox(StructBlock block) { UniversalCoords coords = block.Coords; return new BoundingBox(coords.WorldX + BlockBoundsOffset.Minimum.X, coords.WorldY + BlockBoundsOffset.Minimum.Y, coords.WorldZ + BlockBoundsOffset.Minimum.Z, coords.WorldX + BlockBoundsOffset.Maximum.X, coords.WorldY + BlockBoundsOffset.Maximum.Y, coords.WorldZ + BlockBoundsOffset.Maximum.Z); }
/// <summary> /// Plays the sound on block destruction /// </summary> /// <param name="entity">entity that destroyed the block</param> /// <param name="block">block that has been destroyed</param> protected virtual void PlaySoundOnDestroy(IEntityBase entity, StructBlock block) { foreach (Client c in block.World.Server.GetNearbyPlayersInternal(block.World, block.Coords)) { if (c.Owner == entity) continue; c.SendPacket(new SoundEffectPacket { EffectID = SoundEffectPacket.SoundEffect.BLOCK_BREAK, X = block.Coords.WorldX, Y = block.Coords.WorldY, Z = block.Coords.WorldZ, SoundData = block.Type }); } }
public virtual void RecalculateChunkValues(StructBlock block) { Chunk chunk = GetBlockChunk(block); if (chunk == null) return; byte blockX, blockY, blockZ; blockX = (byte)block.Coords.BlockX; blockY = (byte)block.Coords.BlockY; blockZ = (byte)block.Coords.BlockZ; byte oldHeight = chunk.HeightMap[blockX, blockZ]; if (blockY + 1 >= chunk.HeightMap[blockX, blockZ]) chunk.RecalculateHeight(block.Coords); #if PROFILE Stopwatch watch = new Stopwatch(); watch.Start(); #endif //chunk.SpreadLightFromBlock(blockX, blockY, blockZ, chunk.GetBlockLight(blockX, blockY, blockZ), oldHeight); #if PROFILE watch.Stop(); block.World.Logger.Log(LogLevel.Info, "Block skylight recalc: {0}ms", watch.ElapsedMilliseconds); #endif block.World.Update(block.Coords, false); }
public virtual bool IsOpen(StructBlock block) { // TODO: correctly implement block state for doors return false; }
public Chunk GetBlockChunk(StructBlock block) { return(block.World.GetChunk(block.Coords) as Chunk); }
public virtual bool IsOpen(StructBlock block) { // TODO: correctly implement block state for doors return(false); }