diff --git a/maps.yml b/maps.yml index 2c560f7c9d..57eda7fdda 100644 --- a/maps.yml +++ b/maps.yml @@ -15,6 +15,8 @@ members: "org/bukkit/event/entity/EntityRegainHealthEvent _INVALID_setAmount (I)V": setAmount "org/bukkit/entity/Minecart _INVALID_getDamage ()I": getDamage "org/bukkit/entity/Minecart _INVALID_setDamage (I)V": setDamage + "org/bukkit/entity/Projectile _INVALID_getShooter ()Lorg/bukkit/entity/LivingEntity;": getShooter + "org/bukkit/entity/Projectile _INVALID_setShooter (Lorg/bukkit/entity/LivingEntity;)V": setShooter flags: "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftLivingEntity getHealth ()I": 0x1001 "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftEnderDragonPart getHealth ()I": 0x1001 @@ -32,3 +34,11 @@ flags: "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftLivingEntity setLastDamage (I)V": 0x1001 "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftMinecart setDamage (I)V": 0x1001 "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftMinecart getDamage ()I": 0x1001 + "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftProjectile getShooter ()Lorg/bukkit/entity/LivingEntity;": 0x1001 + "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftProjectile setShooter (Lorg/bukkit/entity/LivingEntity;)V": 0x1001 + "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftArrow getShooter ()Lorg/bukkit/entity/LivingEntity;": 0x1001 + "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftArrow setShooter (Lorg/bukkit/entity/LivingEntity;)V": 0x1001 + "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftFireball getShooter ()Lorg/bukkit/entity/LivingEntity;": 0x1001 + "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftFireball setShooter (Lorg/bukkit/entity/LivingEntity;)V": 0x1001 + "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftFish getShooter ()Lorg/bukkit/entity/LivingEntity;": 0x1001 + "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftFish setShooter (Lorg/bukkit/entity/LivingEntity;)V": 0x1001 diff --git a/src/main/java/net/minecraft/server/DispenseBehaviorFireball.java b/src/main/java/net/minecraft/server/DispenseBehaviorFireball.java index 56ff612256..0fd9487bd3 100644 --- a/src/main/java/net/minecraft/server/DispenseBehaviorFireball.java +++ b/src/main/java/net/minecraft/server/DispenseBehaviorFireball.java @@ -49,7 +49,10 @@ final class DispenseBehaviorFireball extends DispenseBehaviorItem { } } - world.addEntity(new EntitySmallFireball(world, d0, d1, d2, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ())); + EntitySmallFireball entitysmallfireball = new EntitySmallFireball(world, d0, d1, d2, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ()); + entitysmallfireball.projectileSource = new org.bukkit.craftbukkit.projectiles.CraftBlockProjectileSource((TileEntityDispenser) isourceblock.getTileEntity()); + + world.addEntity(entitysmallfireball); // itemstack.a(1); // Handled during event processing // CraftBukkit end diff --git a/src/main/java/net/minecraft/server/DispenseBehaviorProjectile.java b/src/main/java/net/minecraft/server/DispenseBehaviorProjectile.java index 0a51bafdbf..49de3f4189 100644 --- a/src/main/java/net/minecraft/server/DispenseBehaviorProjectile.java +++ b/src/main/java/net/minecraft/server/DispenseBehaviorProjectile.java @@ -42,6 +42,7 @@ public abstract class DispenseBehaviorProjectile extends DispenseBehaviorItem { } iprojectile.shoot(event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ(), this.b(), this.a()); + ((Entity) iprojectile).projectileSource = new org.bukkit.craftbukkit.projectiles.CraftBlockProjectileSource((TileEntityDispenser) isourceblock.getTileEntity()); // CraftBukkit end world.addEntity((Entity) iprojectile); diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java index dc0abc5974..f74d937ef4 100644 --- a/src/main/java/net/minecraft/server/Entity.java +++ b/src/main/java/net/minecraft/server/Entity.java @@ -109,6 +109,7 @@ public abstract class Entity { public UUID uniqueID; // CraftBukkit - protected -> public public EnumEntitySize at; public boolean valid; // CraftBukkit + public org.bukkit.projectiles.ProjectileSource projectileSource; // CraftBukkit - For projectiles only public int getId() { return this.id; diff --git a/src/main/java/net/minecraft/server/EntityArrow.java b/src/main/java/net/minecraft/server/EntityArrow.java index efa05ba251..51c3173f33 100644 --- a/src/main/java/net/minecraft/server/EntityArrow.java +++ b/src/main/java/net/minecraft/server/EntityArrow.java @@ -3,6 +3,7 @@ package net.minecraft.server; import java.util.List; // CraftBukkit start +import org.bukkit.entity.LivingEntity; import org.bukkit.event.entity.EntityCombustByEntityEvent; import org.bukkit.event.player.PlayerPickupItemEvent; // CraftBukkit end @@ -41,6 +42,7 @@ public class EntityArrow extends Entity implements IProjectile { super(world); this.k = 10.0D; this.shooter = entityliving; + this.projectileSource = (LivingEntity) entityliving.getBukkitEntity(); // CraftBukkit if (entityliving instanceof EntityHuman) { this.fromPlayer = 1; } @@ -69,6 +71,7 @@ public class EntityArrow extends Entity implements IProjectile { super(world); this.k = 10.0D; this.shooter = entityliving; + this.projectileSource = (LivingEntity) entityliving.getBukkitEntity(); // CraftBukkit if (entityliving instanceof EntityHuman) { this.fromPlayer = 1; } diff --git a/src/main/java/net/minecraft/server/EntityFireball.java b/src/main/java/net/minecraft/server/EntityFireball.java index 82da554b7b..939de5dd3c 100644 --- a/src/main/java/net/minecraft/server/EntityFireball.java +++ b/src/main/java/net/minecraft/server/EntityFireball.java @@ -42,6 +42,7 @@ public abstract class EntityFireball extends Entity { public EntityFireball(World world, EntityLiving entityliving, double d0, double d1, double d2) { super(world); this.shooter = entityliving; + this.projectileSource = (org.bukkit.entity.LivingEntity) entityliving.getBukkitEntity(); // CraftBukkit this.a(1.0F, 1.0F); this.setPositionRotation(entityliving.locX, entityliving.locY, entityliving.locZ, entityliving.yaw, entityliving.pitch); this.setPosition(this.locX, this.locY, this.locZ); diff --git a/src/main/java/net/minecraft/server/EntityProjectile.java b/src/main/java/net/minecraft/server/EntityProjectile.java index 10c242c1b7..329aecd855 100644 --- a/src/main/java/net/minecraft/server/EntityProjectile.java +++ b/src/main/java/net/minecraft/server/EntityProjectile.java @@ -25,6 +25,7 @@ public abstract class EntityProjectile extends Entity implements IProjectile { public EntityProjectile(World world, EntityLiving entityliving) { super(world); this.shooter = entityliving; + this.projectileSource = (org.bukkit.entity.LivingEntity) entityliving.getBukkitEntity(); // CraftBukkit this.a(0.25F, 0.25F); this.setPositionRotation(entityliving.locX, entityliving.locY + (double) entityliving.getHeadHeight(), entityliving.locZ, entityliving.yaw, entityliving.pitch); this.locX -= (double) (MathHelper.cos(this.yaw / 180.0F * 3.1415927F) * 0.16F); diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftDispenser.java b/src/main/java/org/bukkit/craftbukkit/block/CraftDispenser.java index 1e39bd3af0..762a8e6dcd 100644 --- a/src/main/java/org/bukkit/craftbukkit/block/CraftDispenser.java +++ b/src/main/java/org/bukkit/craftbukkit/block/CraftDispenser.java @@ -3,12 +3,15 @@ package org.bukkit.craftbukkit.block; import net.minecraft.server.BlockDispenser; import net.minecraft.server.Blocks; import net.minecraft.server.TileEntityDispenser; + import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.Dispenser; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.inventory.CraftInventory; +import org.bukkit.craftbukkit.projectiles.CraftBlockProjectileSource; import org.bukkit.inventory.Inventory; +import org.bukkit.projectiles.BlockProjectileSource; public class CraftDispenser extends CraftBlockState implements Dispenser { private final CraftWorld world; @@ -25,6 +28,16 @@ public class CraftDispenser extends CraftBlockState implements Dispenser { return new CraftInventory(dispenser); } + public BlockProjectileSource getBlockProjectileSource() { + Block block = getBlock(); + + if (block.getType() != Material.DISPENSER) { + return null; + } + + return new CraftBlockProjectileSource(dispenser); + } + public boolean dispense() { Block block = getBlock(); diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java index 3f1bcd2590..4c319a7fb8 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java @@ -7,6 +7,7 @@ import org.bukkit.craftbukkit.CraftServer; import org.bukkit.entity.Arrow; import org.bukkit.entity.EntityType; import org.bukkit.entity.LivingEntity; +import org.bukkit.projectiles.ProjectileSource; public class CraftArrow extends AbstractProjectile implements Arrow { @@ -14,20 +15,6 @@ public class CraftArrow extends AbstractProjectile implements Arrow { super(server, entity); } - public LivingEntity getShooter() { - if (getHandle().shooter != null) { - return (LivingEntity) getHandle().shooter.getBukkitEntity(); - } - - return null; - } - - public void setShooter(LivingEntity shooter) { - if (shooter instanceof CraftLivingEntity) { - getHandle().shooter = ((CraftLivingEntity) shooter).getHandle(); - } - } - public void setKnockbackStrength(int knockbackStrength) { Validate.isTrue(knockbackStrength >= 0, "Knockback cannot be negative"); getHandle().a(knockbackStrength); @@ -45,6 +32,19 @@ public class CraftArrow extends AbstractProjectile implements Arrow { getHandle().a(critical); } + public ProjectileSource getShooter() { + return getHandle().projectileSource; + } + + public void setShooter(ProjectileSource shooter) { + if (shooter instanceof LivingEntity) { + getHandle().shooter = ((CraftLivingEntity) shooter).getHandle(); + } else { + getHandle().shooter = null; + } + getHandle().projectileSource = shooter; + } + @Override public EntityArrow getHandle() { return (EntityArrow) entity; @@ -58,4 +58,17 @@ public class CraftArrow extends AbstractProjectile implements Arrow { public EntityType getType() { return EntityType.ARROW; } + + @Deprecated + public LivingEntity _INVALID_getShooter() { + if (getHandle().shooter == null) { + return null; + } + return (LivingEntity) getHandle().shooter.getBukkitEntity(); + } + + @Deprecated + public void _INVALID_setShooter(LivingEntity shooter) { + getHandle().shooter = ((CraftLivingEntity) shooter).getHandle(); + } } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFireball.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFireball.java index 6ebe28d3f4..3a9871762c 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFireball.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFireball.java @@ -7,6 +7,7 @@ import org.bukkit.craftbukkit.CraftServer; import org.bukkit.entity.EntityType; import org.bukkit.entity.Fireball; import org.bukkit.entity.LivingEntity; +import org.bukkit.projectiles.ProjectileSource; import org.bukkit.util.Vector; public class CraftFireball extends AbstractProjectile implements Fireball { @@ -30,18 +31,17 @@ public class CraftFireball extends AbstractProjectile implements Fireball { getHandle().bukkitYield = yield; } - public LivingEntity getShooter() { - if (getHandle().shooter != null) { - return (LivingEntity) getHandle().shooter.getBukkitEntity(); - } - - return null; + public ProjectileSource getShooter() { + return getHandle().projectileSource; } - public void setShooter(LivingEntity shooter) { + public void setShooter(ProjectileSource shooter) { if (shooter instanceof CraftLivingEntity) { - getHandle().shooter = (EntityLiving) ((CraftLivingEntity) shooter).entity; + getHandle().shooter = ((CraftLivingEntity) shooter).getHandle(); + } else { + getHandle().shooter = null; } + getHandle().projectileSource = shooter; } public Vector getDirection() { @@ -65,4 +65,17 @@ public class CraftFireball extends AbstractProjectile implements Fireball { public EntityType getType() { return EntityType.UNKNOWN; } + + @Deprecated + public void _INVALID_setShooter(LivingEntity shooter) { + setShooter(shooter); + } + + @Deprecated + public LivingEntity _INVALID_getShooter() { + if (getHandle().shooter != null) { + return (LivingEntity) getHandle().shooter.getBukkitEntity(); + } + return null; + } } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFish.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFish.java index b6575e967f..edb30e7c68 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFish.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFish.java @@ -9,6 +9,7 @@ import org.bukkit.craftbukkit.CraftServer; import org.bukkit.entity.EntityType; import org.bukkit.entity.Fish; import org.bukkit.entity.LivingEntity; +import org.bukkit.projectiles.ProjectileSource; public class CraftFish extends AbstractProjectile implements Fish { private double biteChance = -1; @@ -17,7 +18,7 @@ public class CraftFish extends AbstractProjectile implements Fish { super(server, entity); } - public LivingEntity getShooter() { + public ProjectileSource getShooter() { if (getHandle().owner != null) { return getHandle().owner.getBukkitEntity(); } @@ -25,7 +26,7 @@ public class CraftFish extends AbstractProjectile implements Fish { return null; } - public void setShooter(LivingEntity shooter) { + public void setShooter(ProjectileSource shooter) { if (shooter instanceof CraftHumanEntity) { getHandle().owner = (EntityHuman) ((CraftHumanEntity) shooter).entity; } @@ -61,4 +62,14 @@ public class CraftFish extends AbstractProjectile implements Fish { Validate.isTrue(chance >= 0 && chance <= 1, "The bite chance must be between 0 and 1."); this.biteChance = chance; } + + @Deprecated + public LivingEntity _INVALID_getShooter() { + return (LivingEntity) getShooter(); + } + + @Deprecated + public void _INVALID_setShooter(LivingEntity shooter) { + setShooter(shooter); + } } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java index 3f45837c50..9cdb0c1822 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java @@ -13,6 +13,7 @@ import net.minecraft.server.EntityEnderDragon; import net.minecraft.server.EntityEnderPearl; import net.minecraft.server.EntityFishingHook; import net.minecraft.server.EntityHuman; +import net.minecraft.server.EntityFireball; import net.minecraft.server.EntityInsentient; import net.minecraft.server.EntityLargeFireball; import net.minecraft.server.EntityLiving; @@ -293,8 +294,12 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { return effects; } - @SuppressWarnings("unchecked") public T launchProjectile(Class projectile) { + return launchProjectile(projectile, null); + } + + @SuppressWarnings("unchecked") + public T launchProjectile(Class projectile, Vector velocity) { net.minecraft.server.World world = ((CraftWorld) getWorld()).getHandle(); net.minecraft.server.Entity launch = null; @@ -324,11 +329,16 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { launch = new EntityLargeFireball(world, getHandle(), direction.getX(), direction.getY(), direction.getZ()); } + ((EntityFireball) launch).projectileSource = this; launch.setPositionRotation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); } Validate.notNull(launch, "Projectile not supported"); + if (velocity != null) { + ((T) launch.getBukkitEntity()).setVelocity(velocity); + } + world.addEntity(launch); return (T) launch.getBukkitEntity(); } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftProjectile.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftProjectile.java index b60d97b107..2f29f2fc72 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftProjectile.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftProjectile.java @@ -2,30 +2,32 @@ package org.bukkit.craftbukkit.entity; import net.minecraft.server.EntityLiving; import net.minecraft.server.EntityProjectile; + import org.bukkit.craftbukkit.CraftServer; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Projectile; +import org.bukkit.projectiles.ProjectileSource; public abstract class CraftProjectile extends AbstractProjectile implements Projectile { public CraftProjectile(CraftServer server, net.minecraft.server.Entity entity) { super(server, entity); } - public LivingEntity getShooter() { - if (getHandle().getShooter() != null) { - return (LivingEntity) getHandle().getShooter().getBukkitEntity(); - } - - return null; + public ProjectileSource getShooter() { + return getHandle().projectileSource; } - public void setShooter(LivingEntity shooter) { + public void setShooter(ProjectileSource shooter) { if (shooter instanceof CraftLivingEntity) { getHandle().shooter = (EntityLiving) ((CraftLivingEntity) shooter).entity; if (shooter instanceof CraftHumanEntity) { getHandle().shooterName = ((CraftHumanEntity) shooter).getName(); } + } else { + getHandle().shooter = null; + getHandle().shooterName = null; } + getHandle().projectileSource = shooter; } @Override @@ -37,4 +39,24 @@ public abstract class CraftProjectile extends AbstractProjectile implements Proj public String toString() { return "CraftProjectile"; } + + + @Deprecated + public LivingEntity _INVALID_getShooter() { + if (getHandle().shooter == null) { + return null; + } + return (LivingEntity) getHandle().shooter.getBukkitEntity(); + } + + @Deprecated + public void _INVALID_setShooter(LivingEntity shooter) { + if (shooter == null) { + return; + } + getHandle().shooter = ((CraftLivingEntity) shooter).getHandle(); + if (shooter instanceof CraftHumanEntity) { + getHandle().shooterName = ((CraftHumanEntity) shooter).getName(); + } + } } diff --git a/src/main/java/org/bukkit/craftbukkit/projectiles/CraftBlockProjectileSource.java b/src/main/java/org/bukkit/craftbukkit/projectiles/CraftBlockProjectileSource.java new file mode 100644 index 0000000000..f3550458e9 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/projectiles/CraftBlockProjectileSource.java @@ -0,0 +1,142 @@ +package org.bukkit.craftbukkit.projectiles; + +import java.util.Random; + +import org.apache.commons.lang.Validate; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.entity.Arrow; +import org.bukkit.entity.Egg; +import org.bukkit.entity.EnderPearl; +import org.bukkit.entity.Fireball; +import org.bukkit.entity.Projectile; +import org.bukkit.entity.SmallFireball; +import org.bukkit.entity.Snowball; +import org.bukkit.entity.ThrownExpBottle; +import org.bukkit.entity.ThrownPotion; +import org.bukkit.entity.WitherSkull; +import org.bukkit.inventory.ItemStack; +import org.bukkit.projectiles.BlockProjectileSource; +import org.bukkit.util.Vector; + +import net.minecraft.server.BlockDispenser; +import net.minecraft.server.EntityArrow; +import net.minecraft.server.EntityEgg; +import net.minecraft.server.EntityEnderPearl; +import net.minecraft.server.EntityFireball; +import net.minecraft.server.EntityLargeFireball; +import net.minecraft.server.EntityPotion; +import net.minecraft.server.EntityProjectile; +import net.minecraft.server.EntitySmallFireball; +import net.minecraft.server.EntitySnowball; +import net.minecraft.server.EntityThrownExpBottle; +import net.minecraft.server.EntityWitherSkull; +import net.minecraft.server.EnumFacing; +import net.minecraft.server.IPosition; +import net.minecraft.server.IProjectile; +import net.minecraft.server.MathHelper; +import net.minecraft.server.SourceBlock; +import net.minecraft.server.TileEntityDispenser; + +public class CraftBlockProjectileSource implements BlockProjectileSource { + private final TileEntityDispenser dispenserBlock; + + public CraftBlockProjectileSource(TileEntityDispenser dispenserBlock) { + this.dispenserBlock = dispenserBlock; + } + + @Override + public Block getBlock() { + return dispenserBlock.getWorld().getWorld().getBlockAt(dispenserBlock.x, dispenserBlock.y, dispenserBlock.z); + } + + @Override + public T launchProjectile(Class projectile) { + return launchProjectile(projectile, null); + } + + @Override + public T launchProjectile(Class projectile, Vector velocity) { + Validate.isTrue(getBlock().getType() == Material.DISPENSER, "Block is no longer dispenser"); + // Copied from BlockDispenser.dispense() + SourceBlock isourceblock = new SourceBlock(dispenserBlock.getWorld(), dispenserBlock.x, dispenserBlock.y, dispenserBlock.z); + // Copied from DispenseBehaviorProjectile + IPosition iposition = BlockDispenser.a(isourceblock); + EnumFacing enumfacing = BlockDispenser.b(isourceblock.h()); + net.minecraft.server.World world = dispenserBlock.getWorld(); + net.minecraft.server.Entity launch = null; + + if (Snowball.class.isAssignableFrom(projectile)) { + launch = new EntitySnowball(world, iposition.getX(), iposition.getY(), iposition.getZ()); + } else if (Egg.class.isAssignableFrom(projectile)) { + launch = new EntityEgg(world, iposition.getX(), iposition.getY(), iposition.getZ()); + } else if (EnderPearl.class.isAssignableFrom(projectile)) { + launch = new EntityEnderPearl(world); + launch.setPosition(iposition.getX(), iposition.getY(), iposition.getZ()); + } else if (ThrownExpBottle.class.isAssignableFrom(projectile)) { + launch = new EntityThrownExpBottle(world, iposition.getX(), iposition.getY(), iposition.getZ()); + } else if (ThrownPotion.class.isAssignableFrom(projectile)) { + launch = new EntityPotion(world, iposition.getX(), iposition.getY(), iposition.getZ(), CraftItemStack.asNMSCopy(new ItemStack(Material.POTION, 1))); + } else if (Arrow.class.isAssignableFrom(projectile)) { + launch = new EntityArrow(world, iposition.getX(), iposition.getY(), iposition.getZ()); + ((EntityArrow) launch).fromPlayer = 1; + ((EntityArrow) launch).projectileSource = this; + } else if (Fireball.class.isAssignableFrom(projectile)) { + double d0 = iposition.getX() + (double) ((float) enumfacing.c() * 0.3F); + double d1 = iposition.getY() + (double) ((float) enumfacing.c() * 0.3F); + double d2 = iposition.getZ() + (double) ((float) enumfacing.e() * 0.3F); + Random random = world.random; + double d3 = random.nextGaussian() * 0.05D + (double) enumfacing.c(); + double d4 = random.nextGaussian() * 0.05D + (double) enumfacing.d(); + double d5 = random.nextGaussian() * 0.05D + (double) enumfacing.e(); + + if (SmallFireball.class.isAssignableFrom(projectile)) { + launch = new EntitySmallFireball(world, d0, d1, d2, d3, d4, d5); + } else if (WitherSkull.class.isAssignableFrom(projectile)) { + launch = new EntityWitherSkull(world); + launch.setPosition(d0, d1, d2); + double d6 = (double) MathHelper.sqrt(d3 * d3 + d4 * d4 + d5 * d5); + + ((EntityFireball) launch).dirX = d3 / d6 * 0.1D; + ((EntityFireball) launch).dirY = d4 / d6 * 0.1D; + ((EntityFireball) launch).dirZ = d5 / d6 * 0.1D; + } else { + launch = new EntityLargeFireball(world); + launch.setPosition(d0, d1, d2); + double d6 = (double) MathHelper.sqrt(d3 * d3 + d4 * d4 + d5 * d5); + + ((EntityFireball) launch).dirX = d3 / d6 * 0.1D; + ((EntityFireball) launch).dirY = d4 / d6 * 0.1D; + ((EntityFireball) launch).dirZ = d5 / d6 * 0.1D; + } + + ((EntityFireball) launch).projectileSource = this; + } + + Validate.notNull(launch, "Projectile not supported"); + + if (launch instanceof IProjectile) { + if (launch instanceof EntityProjectile) { + ((EntityProjectile) launch).projectileSource = this; + } + // Values from DispenseBehaviorProjectile + float a = 6.0F; + float b = 1.1F; + if (launch instanceof EntityPotion || launch instanceof ThrownExpBottle) { + // Values from respective DispenseBehavior classes + a *= 0.5F; + b *= 1.25F; + } + // Copied from DispenseBehaviorProjectile + ((IProjectile) launch).shoot((double) enumfacing.c(), (double) ((float) enumfacing.d() + 0.1F), (double) enumfacing.e(), b, a); + } + + if (velocity != null) { + ((T) launch.getBukkitEntity()).setVelocity(velocity); + } + + world.addEntity(launch); + return (T) launch.getBukkitEntity(); + } +}