fix explosions for real this time
This commit is contained in:
parent
11db0e57cb
commit
aaad753263
36 changed files with 338 additions and 495 deletions
|
@ -24,9 +24,9 @@ public class CommandExplode extends Command {
|
|||
|
||||
public void exec(CommandEnvironment env, Executor exec, Vec3 pos, WorldServer world, int radius, boolean ticked, boolean fire, boolean noblocks, boolean altsound) {
|
||||
if(ticked)
|
||||
world.newExplosion(pos.xCoord, pos.yCoord, pos.zCoord, radius);
|
||||
world.explodeTicked(null, pos.xCoord, pos.yCoord, pos.zCoord, radius);
|
||||
else
|
||||
world.newExplosion(null, pos.xCoord, pos.yCoord, pos.zCoord, radius, fire, !noblocks, altsound);
|
||||
world.explode(null, null, pos.xCoord, pos.yCoord, pos.zCoord, radius, fire, !noblocks, altsound);
|
||||
exec.log("Explosion bei %d, %d, %d in %s erzeugt", ExtMath.floord(pos.xCoord), ExtMath.floord(pos.yCoord), ExtMath.floord(pos.zCoord), world.dimension.getDisplay());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,10 +27,13 @@ import common.collect.Maps;
|
|||
import common.collect.Sets;
|
||||
import common.dimension.DimType;
|
||||
import common.dimension.Dimension;
|
||||
import common.effect.Effect;
|
||||
import common.enchantment.Enchantment;
|
||||
import common.entity.DamageSource;
|
||||
import common.entity.Entity;
|
||||
import common.entity.EntityTrackerEntry;
|
||||
import common.entity.effect.EntityLightning;
|
||||
import common.entity.item.EntityExplosion;
|
||||
import common.entity.npc.EntityNPC;
|
||||
import common.entity.types.EntityLiving;
|
||||
import common.init.Blocks;
|
||||
|
@ -40,6 +43,7 @@ import common.log.Log;
|
|||
import common.network.IPlayer;
|
||||
import common.network.Packet;
|
||||
import common.packet.SPacketEntityStatus;
|
||||
import common.packet.SPacketEntityVelocity;
|
||||
import common.packet.SPacketExplosion;
|
||||
import common.packet.SPacketEffect;
|
||||
import common.packet.SPacketSoundEffect;
|
||||
|
@ -67,7 +71,6 @@ import common.vars.Vars;
|
|||
import common.village.Village;
|
||||
import common.world.BlockArray;
|
||||
import common.world.Chunk;
|
||||
import common.world.Explosion;
|
||||
import common.world.AWorldServer;
|
||||
import common.world.LightType;
|
||||
import common.world.State;
|
||||
|
@ -111,6 +114,31 @@ import server.worldgen.tree.WorldGenTaiga2;
|
|||
|
||||
public final class WorldServer extends AWorldServer {
|
||||
private static final int[][] XZ_DIRS = new int[][] {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
|
||||
private static final int[][] TABLES = new int[1024][];
|
||||
|
||||
private static int[] shuffle(int size) {
|
||||
int[] table = new int[size];
|
||||
Random rand = new Random(8236737136521L);
|
||||
for(int z = 0; z < size; z++) {
|
||||
table[z] = z;
|
||||
}
|
||||
for(int z = 0; z < size; z++) {
|
||||
int r = rand.zrange(size);
|
||||
int n = table[z];
|
||||
table[z] = table[r];
|
||||
table[r] = n;
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
private static int[] getTable(int size) {
|
||||
if(size < 0 || size >= TABLES.length)
|
||||
return null;
|
||||
int[] table = TABLES[size];
|
||||
if(table == null)
|
||||
TABLES[size] = table = shuffle(size);
|
||||
return table;
|
||||
}
|
||||
|
||||
private final Server server;
|
||||
private final File chunkDir;
|
||||
|
@ -906,24 +934,152 @@ public final class WorldServer extends AWorldServer {
|
|||
public void setEntityState(Entity entityIn, byte state) {
|
||||
this.sendToAllTrackingAndSelf(entityIn, new SPacketEntityStatus(entityIn, state));
|
||||
}
|
||||
|
||||
private boolean destroyBlock(BlockPos pos, float power, EntityLiving source) {
|
||||
State state = this.getState(pos);
|
||||
Block block = state.getBlock();
|
||||
if(block != Blocks.air && (block.getMaterial().isLiquid() || power - (block.getResistance() / 5.0F + 0.3F) * 0.3F > 0.0F)) {
|
||||
if(block.canExplosionDrop() && this.rand.floatv() <= 1.0F / (power * power))
|
||||
block.drop(this, pos, state, 0);
|
||||
this.setState(pos, Blocks.air.getState(), power < 40.0F ? 2 : 10);
|
||||
block.onDestroyedExplosion(this, pos, source, state);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private Set<EntityNPC> damageEntities(Entity exploder, EntityLiving source, double posX, double posY, double posZ, float radius) {
|
||||
float dmgRadius = radius * 2.0F;
|
||||
int x1 = ExtMath.floord(posX - (double)dmgRadius - 1.0D);
|
||||
int x2 = ExtMath.floord(posX + (double)dmgRadius + 1.0D);
|
||||
int y1 = ExtMath.floord(posY - (double)dmgRadius - 1.0D);
|
||||
int y2 = ExtMath.floord(posY + (double)dmgRadius + 1.0D);
|
||||
int z1 = ExtMath.floord(posZ - (double)dmgRadius - 1.0D);
|
||||
int z2 = ExtMath.floord(posZ + (double)dmgRadius + 1.0D);
|
||||
List<Entity> list = this.getEntitiesWithinAABBExcludingEntity(exploder, new BoundingBox((double)x1, (double)y1, (double)z1, (double)x2, (double)y2, (double)z2));
|
||||
Vec3 vec3 = new Vec3(posX, posY, posZ);
|
||||
Set<EntityNPC> velocity = Sets.newHashSet();
|
||||
for (int pos = 0; pos < list.size(); pos++)
|
||||
{
|
||||
Entity entity = (Entity)list.get(pos);
|
||||
if (!entity.isImmuneToExplosions())
|
||||
{
|
||||
double dist = entity.getDistance(posX, posY, posZ) / (double)dmgRadius;
|
||||
if (dist <= 1.0D)
|
||||
{
|
||||
double dx = entity.posX - posX;
|
||||
double dy = entity.posY + (double)entity.getEyeHeight() - posY;
|
||||
double dz = entity.posZ - posZ;
|
||||
double dt = (double)ExtMath.sqrtd(dx * dx + dy * dy + dz * dz);
|
||||
if (dt != 0.0D)
|
||||
{
|
||||
dx = dx / dt;
|
||||
dy = dy / dt;
|
||||
dz = dz / dt;
|
||||
double density = (double)this.getBlockDensity(vec3, entity.getEntityBoundingBox());
|
||||
double damage = (1.0D - dist) * density;
|
||||
if(Vars.damageExplosion)
|
||||
entity.attackEntityFrom(DamageSource.causeExplosionDamage(source), ((int)((damage * damage + damage) / 2.0D * 8.0D * (double)dmgRadius + 1.0D)));
|
||||
if(!(entity instanceof EntityLiving living) || !living.hasEffect(Effect.STABILITY)) {
|
||||
double velo = Enchantment.getKnockbackFactor(entity, damage);
|
||||
entity.motionX += dx * velo;
|
||||
entity.motionY += dy * velo;
|
||||
entity.motionZ += dz * velo;
|
||||
if(entity.isPlayer())
|
||||
velocity.add((EntityNPC)entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return velocity;
|
||||
}
|
||||
|
||||
public Explosion newExplosion(Entity entityIn, double x, double y, double z, float strength, boolean isFlaming, boolean isSmoking, boolean altSound) {
|
||||
Explosion explosion = new Explosion(this, entityIn, x, y, z, strength, isFlaming, isSmoking);
|
||||
explosion.doExplosionA();
|
||||
explosion.doExplosionB(false, altSound);
|
||||
public void explode(EntityLiving source, Entity exploder, double posX, double posY, double posZ, float radius, boolean fire, boolean destroy, boolean altSound) {
|
||||
Set<BlockPos> set = Sets.<BlockPos>newHashSet();
|
||||
int d = ((int)radius) + 1;
|
||||
double falloff = radius * 0.125d;
|
||||
falloff = falloff > 4.0d ? 4.0d : falloff;
|
||||
for (int x = -d; x <= d; ++x)
|
||||
{
|
||||
for (int y = -d; y <= d; ++y)
|
||||
{
|
||||
for (int z = -d; z <= d; ++z)
|
||||
{
|
||||
double dist = (double)ExtMath.sqrtd(((double)x) * ((double)x) + ((double)y) * ((double)y) + ((double)z) * ((double)z));
|
||||
if(dist < radius - falloff ||
|
||||
(dist < radius && this.rand.doublev() + ((dist - (radius - falloff)) / falloff) < 1.0d)) {
|
||||
BlockPos pos = new BlockPos(posX + x, posY + y, posZ + z);
|
||||
if(this.destroyBlock(pos, radius, source))
|
||||
set.add(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
List<BlockPos> blocks = Lists.<BlockPos>newArrayList(set);
|
||||
set.clear();
|
||||
|
||||
Set<EntityNPC> velocity = this.damageEntities(exploder, source, posX, posY, posZ, radius);
|
||||
|
||||
if(!isSmoking) {
|
||||
explosion.clearAffectedBlockPositions();
|
||||
this.sendSound(altSound ? SoundEvent.EXPLODE_ALT : SoundEvent.EXPLODE, posX, posY, posZ, 4.0F);
|
||||
|
||||
if (fire)
|
||||
{
|
||||
for (BlockPos pos : blocks)
|
||||
{
|
||||
if(this.getState(pos).getBlock() == Blocks.air && this.getState(pos.down()).getBlock().isFullBlock() && this.rand.zrange(3) == 0)
|
||||
this.setState(pos, Blocks.fire.getState());
|
||||
}
|
||||
}
|
||||
|
||||
for(EntityNPC player : this.players) {
|
||||
if(player.getDistanceSq(posX, posY, posZ) < 4096.0D)
|
||||
player.connection.sendPacket(new SPacketExplosion(posX, posY, posZ, destroy ? blocks : null, radius >= 2.0f && destroy));
|
||||
if(velocity.contains(player))
|
||||
player.connection.sendPacket(new SPacketEntityVelocity(player));
|
||||
}
|
||||
|
||||
for(EntityNPC entityplayer : this.players) {
|
||||
if(entityplayer.getDistanceSq(x, y, z) < 4096.0D) {
|
||||
entityplayer.connection.sendPacket(new SPacketExplosion(x, y, z, strength, explosion.getAffectedBlockPositions(),
|
||||
(Vec3)explosion.getPlayerKnockbackMap().get(entityplayer), altSound));
|
||||
}
|
||||
}
|
||||
|
||||
public int explodePartial(EntityLiving source, Entity exploder, double posX, double posY, double posZ, double radius, double minDist, int iter, int max)
|
||||
{
|
||||
int d = ((int)radius) + 1;
|
||||
int div = d * 2 + 1;
|
||||
int[] table = getTable(div);
|
||||
if(table == null)
|
||||
return 0;
|
||||
double falloff = radius * 0.125d;
|
||||
falloff = falloff > 4.0d ? 4.0d : falloff;
|
||||
int lmt = div * div * div;
|
||||
int cnt = 0;
|
||||
for(; iter < lmt && cnt < max; iter++)
|
||||
{
|
||||
int x = table[(iter / div) % div] - d;
|
||||
int y = table[iter % div] - d;
|
||||
int z = table[(iter / div) / div] - d;
|
||||
double dist = (double)ExtMath.sqrtd(((double)x) * ((double)x) + ((double)y) * ((double)y) + ((double)z) * ((double)z));
|
||||
if(dist > minDist && (dist < radius - falloff ||
|
||||
(dist < radius && this.rand.doublev() + ((dist - (radius - falloff)) / falloff) < 1.0d))) {
|
||||
BlockPos pos = new BlockPos(posX + x, posY + y, posZ + z);
|
||||
if(this.destroyBlock(pos, (float)radius, null) && this.rand.chance(1000)) {
|
||||
this.sendSound(SoundEvent.EXPLODE, posX + x, posY + y, posZ + z, 4.0F);
|
||||
this.spawnParticles(ParticleType.EXPLOSION_HUGE, posX + x, posY + y, posZ + z);
|
||||
}
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
Set<EntityNPC> velocity = this.damageEntities(exploder, source, posX, posY, posZ, (float)radius);
|
||||
|
||||
for(EntityNPC player : this.players) {
|
||||
if(velocity.contains(player))
|
||||
player.connection.sendPacket(new SPacketEntityVelocity(player));
|
||||
}
|
||||
|
||||
return iter >= lmt ? 0 : iter;
|
||||
}
|
||||
|
||||
return explosion;
|
||||
public void explodeTicked(EntityLiving source, double x, double y, double z, int radius) {
|
||||
this.spawnEntityInWorld(new EntityExplosion(this, x, y, z, radius, source));
|
||||
}
|
||||
|
||||
public void resetWeather() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue