Paper/src/main/java/net/minecraft/server/Explosion.java

306 Zeilen
12 KiB
Java

2011-01-03 12:24:25 +01:00
package net.minecraft.server;
2011-01-29 22:50:29 +01:00
import java.util.ArrayList;
2012-07-29 09:33:13 +02:00
import java.util.HashMap;
2011-01-29 22:50:29 +01:00
import java.util.HashSet;
2012-07-29 09:33:13 +02:00
import java.util.Iterator;
2011-01-29 22:50:29 +01:00
import java.util.List;
2012-07-29 09:33:13 +02:00
import java.util.Map;
2011-01-29 22:50:29 +01:00
import java.util.Random;
// CraftBukkit start
import org.bukkit.Bukkit;
import org.bukkit.event.entity.EntityDamageByBlockEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityExplodeEvent;
2011-01-21 17:39:58 +01:00
import org.bukkit.Location;
// CraftBukkit end
2011-01-03 12:24:25 +01:00
public class Explosion {
2011-01-29 22:50:29 +01:00
public boolean a = false;
public boolean b = true;
private int i = 16;
private Random j = new Random();
private World world;
public double posX;
public double posY;
public double posZ;
public Entity source;
public float size;
2012-07-29 09:33:13 +02:00
public List blocks = new ArrayList();
private Map l = new HashMap();
2011-02-23 13:56:36 +01:00
public boolean wasCanceled = false; // CraftBukkit
2011-01-29 22:50:29 +01:00
public Explosion(World world, Entity entity, double d0, double d1, double d2, float f) {
this.world = world;
this.source = entity;
this.size = (float) Math.max(f, 0.0); // CraftBukkit - clamp bad values
this.posX = d0;
this.posY = d1;
this.posZ = d2;
2011-01-03 12:24:25 +01:00
}
public void a() {
// CraftBukkit start
if (this.size < 0.1F) {
return;
}
// CraftBukkit end
2012-07-29 09:33:13 +02:00
float f = this.size;
2012-07-29 09:33:13 +02:00
HashSet hashset = new HashSet();
2011-01-29 22:50:29 +01:00
int i;
int j;
int k;
double d0;
double d1;
double d2;
for (i = 0; i < this.i; ++i) {
for (j = 0; j < this.i; ++j) {
for (k = 0; k < this.i; ++k) {
if (i == 0 || i == this.i - 1 || j == 0 || j == this.i - 1 || k == 0 || k == this.i - 1) {
double d3 = (double) ((float) i / ((float) this.i - 1.0F) * 2.0F - 1.0F);
double d4 = (double) ((float) j / ((float) this.i - 1.0F) * 2.0F - 1.0F);
double d5 = (double) ((float) k / ((float) this.i - 1.0F) * 2.0F - 1.0F);
2011-01-29 22:50:29 +01:00
double d6 = Math.sqrt(d3 * d3 + d4 * d4 + d5 * d5);
d3 /= d6;
d4 /= d6;
d5 /= d6;
float f1 = this.size * (0.7F + this.world.random.nextFloat() * 0.6F);
2011-01-29 22:50:29 +01:00
d0 = this.posX;
d1 = this.posY;
d2 = this.posZ;
2011-01-29 22:50:29 +01:00
for (float f2 = 0.3F; f1 > 0.0F; f1 -= f2 * 0.75F) {
int l = MathHelper.floor(d0);
int i1 = MathHelper.floor(d1);
int j1 = MathHelper.floor(d2);
int k1 = this.world.getTypeId(l, i1, j1);
2011-01-29 22:50:29 +01:00
if (k1 > 0) {
Block block = Block.byId[k1];
float f3 = this.source != null ? this.source.a(this, block, l, i1, j1) : block.a(this.source);
f1 -= (f3 + 0.3F) * f2;
2011-01-29 22:50:29 +01:00
}
2012-07-29 09:33:13 +02:00
if (f1 > 0.0F && i1 < 256 && i1 >= 0) { // CraftBukkit - don't wrap explosions
hashset.add(new ChunkPosition(l, i1, j1));
2011-01-29 22:50:29 +01:00
}
d0 += d3 * (double) f2;
d1 += d4 * (double) f2;
d2 += d5 * (double) f2;
2011-01-03 12:24:25 +01:00
}
2011-01-29 22:50:29 +01:00
}
2011-01-03 12:24:25 +01:00
}
}
}
2012-07-29 09:33:13 +02:00
this.blocks.addAll(hashset);
this.size *= 2.0F;
i = MathHelper.floor(this.posX - (double) this.size - 1.0D);
j = MathHelper.floor(this.posX + (double) this.size + 1.0D);
k = MathHelper.floor(this.posY - (double) this.size - 1.0D);
int l1 = MathHelper.floor(this.posY + (double) this.size + 1.0D);
int i2 = MathHelper.floor(this.posZ - (double) this.size - 1.0D);
int j2 = MathHelper.floor(this.posZ + (double) this.size + 1.0D);
2012-07-29 09:33:13 +02:00
List list = this.world.getEntities(this.source, AxisAlignedBB.a().a((double) i, (double) k, (double) i2, (double) j, (double) l1, (double) j2));
Vec3D vec3d = this.world.getVec3DPool().create(this.posX, this.posY, this.posZ);
2011-01-29 22:50:29 +01:00
for (int k2 = 0; k2 < list.size(); ++k2) {
Entity entity = (Entity) list.get(k2);
2012-07-29 09:33:13 +02:00
double d7 = entity.f(this.posX, this.posY, this.posZ) / (double) this.size;
2011-01-29 22:50:29 +01:00
if (d7 <= 1.0D) {
2012-07-29 09:33:13 +02:00
d0 = entity.locX - this.posX;
d1 = entity.locY + (double) entity.getHeadHeight() - this.posY;
d2 = entity.locZ - this.posZ;
double d8 = (double) MathHelper.sqrt(d0 * d0 + d1 * d1 + d2 * d2);
if (d8 != 0.0D) {
d0 /= d8;
d1 /= d8;
d2 /= d8;
2012-07-29 09:33:13 +02:00
double d9 = (double) this.world.a(vec3d, entity.boundingBox);
double d10 = (1.0D - d7) * d9;
// CraftBukkit start - explosion damage hook
org.bukkit.entity.Entity damagee = (entity == null) ? null : entity.getBukkitEntity();
int damageDone = (int) ((d10 * d10 + d10) / 2.0D * 8.0D * (double) this.size + 1.0D);
if (damagee == null) {
// nothing was hurt
} else if (this.source == null) { // Block explosion (without an entity source; bed etc.)
EntityDamageByBlockEvent event = new EntityDamageByBlockEvent(null, damagee, EntityDamageEvent.DamageCause.BLOCK_EXPLOSION, damageDone);
Bukkit.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
damagee.setLastDamageCause(event);
entity.damageEntity(DamageSource.EXPLOSION, event.getDamage());
entity.motX += d0 * d10;
entity.motY += d1 * d10;
entity.motZ += d2 * d10;
if (entity instanceof EntityHuman) {
this.l.put((EntityHuman) entity, this.world.getVec3DPool().create(d0 * d10, d1 * d10, d2 * d10));
2012-07-29 09:33:13 +02:00
}
}
} else {
2012-07-29 09:33:13 +02:00
final org.bukkit.entity.Entity damager = this.source.getBukkitEntity();
final EntityDamageEvent.DamageCause damageCause;
if (damager instanceof org.bukkit.entity.TNTPrimed) {
damageCause = EntityDamageEvent.DamageCause.BLOCK_EXPLOSION;
} else {
damageCause = EntityDamageEvent.DamageCause.ENTITY_EXPLOSION;
}
EntityDamageByEntityEvent event = new EntityDamageByEntityEvent(damager, damagee, damageCause, damageDone);
Bukkit.getPluginManager().callEvent(event);
2011-01-29 22:50:29 +01:00
2012-07-29 09:33:13 +02:00
if (!event.isCancelled()) {
entity.getBukkitEntity().setLastDamageCause(event);
entity.damageEntity(DamageSource.EXPLOSION, event.getDamage());
2012-07-29 09:33:13 +02:00
entity.motX += d0 * d10;
entity.motY += d1 * d10;
entity.motZ += d2 * d10;
if (entity instanceof EntityHuman) {
this.l.put((EntityHuman) entity, this.world.getVec3DPool().create(d0 * d10, d1 * d10, d2 * d10));
2012-07-29 09:33:13 +02:00
}
}
}
2012-07-29 09:33:13 +02:00
// CraftBukkit end
2011-01-03 12:24:25 +01:00
}
}
}
this.size = f;
2011-01-03 12:24:25 +01:00
}
2011-04-20 22:47:26 +02:00
public void a(boolean flag) {
this.world.makeSound(this.posX, this.posY, this.posZ, "random.explode", 4.0F, (1.0F + (this.world.random.nextFloat() - this.world.random.nextFloat()) * 0.2F) * 0.7F);
if (this.size >= 2.0F && this.b) {
this.world.addParticle("hugeexplosion", this.posX, this.posY, this.posZ, 1.0D, 0.0D, 0.0D);
} else {
this.world.addParticle("largeexplode", this.posX, this.posY, this.posZ, 1.0D, 0.0D, 0.0D);
}
2011-01-29 22:50:29 +01:00
Iterator iterator;
2011-11-20 09:01:14 +01:00
ChunkPosition chunkposition;
2012-07-29 09:33:13 +02:00
int i;
2011-11-20 09:01:14 +01:00
int j;
int k;
int l;
2012-07-29 09:33:13 +02:00
if (this.b) {
// CraftBukkit start
org.bukkit.World bworld = this.world.getWorld();
org.bukkit.entity.Entity explode = this.source == null ? null : this.source.getBukkitEntity();
Location location = new Location(bworld, this.posX, this.posY, this.posZ);
List<org.bukkit.block.Block> blockList = new ArrayList<org.bukkit.block.Block>();
for (int i1 = this.blocks.size() - 1; i1 >= 0; i1--) {
ChunkPosition cpos = (ChunkPosition) this.blocks.get(i1);
org.bukkit.block.Block block = bworld.getBlockAt(cpos.x, cpos.y, cpos.z);
if (block.getType() != org.bukkit.Material.AIR) {
blockList.add(block);
}
}
EntityExplodeEvent event = new EntityExplodeEvent(explode, location, blockList, 0.3F);
this.world.getServer().getPluginManager().callEvent(event);
this.blocks.clear();
for (org.bukkit.block.Block block : event.blockList()) {
ChunkPosition coords = new ChunkPosition(block.getX(), block.getY(), block.getZ());
blocks.add(coords);
}
if (event.isCancelled()) {
this.wasCanceled = true;
return;
}
// CraftBukkit end
2011-01-03 12:24:25 +01:00
iterator = this.blocks.iterator();
while (iterator.hasNext()) {
chunkposition = (ChunkPosition) iterator.next();
i = chunkposition.x;
j = chunkposition.y;
k = chunkposition.z;
l = this.world.getTypeId(i, j, k);
if (flag) {
double d0 = (double) ((float) i + this.world.random.nextFloat());
double d1 = (double) ((float) j + this.world.random.nextFloat());
double d2 = (double) ((float) k + this.world.random.nextFloat());
double d3 = d0 - this.posX;
double d4 = d1 - this.posY;
double d5 = d2 - this.posZ;
double d6 = (double) MathHelper.sqrt(d3 * d3 + d4 * d4 + d5 * d5);
d3 /= d6;
d4 /= d6;
d5 /= d6;
double d7 = 0.5D / (d6 / (double) this.size + 0.1D);
d7 *= (double) (this.world.random.nextFloat() * this.world.random.nextFloat() + 0.3F);
d3 *= d7;
d4 *= d7;
d5 *= d7;
this.world.addParticle("explode", (d0 + this.posX * 1.0D) / 2.0D, (d1 + this.posY * 1.0D) / 2.0D, (d2 + this.posZ * 1.0D) / 2.0D, d3, d4, d5);
this.world.addParticle("smoke", d0, d1, d2, d3, d4, d5);
2012-07-29 09:33:13 +02:00
}
// CraftBukkit - stop explosions from putting out fire
if (l > 0 && l != Block.FIRE.id) {
// CraftBukkit start - special case skulls, add yield
int data = this.world.getData(i, j, k);
if (l == Block.SKULL.id) {
data = Block.SKULL.getDropData(this.world, i, j, k);
}
Block.byId[l].dropNaturally(this.world, i, j, k, data, event.getYield(), 0);
// CraftBukkit end
if (this.world.setRawTypeIdAndData(i, j, k, 0, 0, this.world.isStatic)) {
this.world.applyPhysics(i, j, k, 0);
}
Block.byId[l].wasExploded(this.world, i, j, k);
}
2011-01-03 12:24:25 +01:00
}
}
2011-11-20 09:01:14 +01:00
if (this.a) {
2012-07-29 09:33:13 +02:00
iterator = this.blocks.iterator();
while (iterator.hasNext()) {
chunkposition = (ChunkPosition) iterator.next();
i = chunkposition.x;
j = chunkposition.y;
k = chunkposition.z;
l = this.world.getTypeId(i, j, k);
int i1 = this.world.getTypeId(i, j - 1, k);
if (l == 0 && Block.q[i1] && this.j.nextInt(3) == 0) {
2012-07-29 09:33:13 +02:00
this.world.setTypeId(i, j, k, Block.FIRE.id);
2011-11-20 09:01:14 +01:00
}
}
}
2011-01-03 12:24:25 +01:00
}
2012-07-29 09:33:13 +02:00
public Map b() {
return this.l;
2012-07-29 09:33:13 +02:00
}
2011-01-03 12:24:25 +01:00
}