From 9cefe7602b66fb78c9e37ce4b80e19743534a360 Mon Sep 17 00:00:00 2001 From: Sen Date: Tue, 1 Jul 2025 17:43:31 +0200 Subject: [PATCH] make ticked explosions less laggy --- .../common/entity/item/EntityExplosion.java | 20 ++++-- common/src/main/java/common/vars/Vars.java | 2 + .../src/main/java/common/world/Explosion.java | 70 ++++++++++++++----- 3 files changed, 66 insertions(+), 26 deletions(-) diff --git a/common/src/main/java/common/entity/item/EntityExplosion.java b/common/src/main/java/common/entity/item/EntityExplosion.java index f457c712..18e5a34c 100755 --- a/common/src/main/java/common/entity/item/EntityExplosion.java +++ b/common/src/main/java/common/entity/item/EntityExplosion.java @@ -3,6 +3,7 @@ package common.entity.item; import common.entity.Entity; import common.entity.EntityType; import common.tags.TagObject; +import common.vars.Vars; import common.world.Explosion; import common.world.World; @@ -10,13 +11,13 @@ public class EntityExplosion extends Entity { private int progress; private int radius; + private int iteration; public EntityExplosion(World worldIn) { super(worldIn); this.preventSpawning = true; this.setSize(0.1F, 0.1F); -// this.setInvisible(true); } public EntityExplosion(World worldIn, double x, double y, double z) @@ -49,29 +50,34 @@ public class EntityExplosion extends Entity this.prevY = this.posY; this.prevZ = this.posZ; this.motionX = this.motionY = this.motionZ = 0.0D; - if(this.progress++ >= this.radius) { + if(this.worldObj.client) + return; + if(this.progress >= this.radius) { this.setDead(); + return; } - else if(!this.worldObj.client) { - this.explode(this.progress - 1); - } + if(this.explode(this.progress - 1)) + ++this.progress; } - private void explode(double min) + private boolean explode(double min) { - Explosion.doExplosionAlgo3(this.worldObj, this.posX, this.posY + (double)(this.height / 2.0F), this.posZ, this.rand, min + 6.0d, min); + this.iteration = Explosion.doExplosionAlgo3(this.worldObj, this.posX, this.posY, this.posZ, this.rand, min + 6.0d, min, this.iteration, Vars.maxExplosionIters); + return this.iteration == 0; } protected void writeEntity(TagObject tagCompound) { tagCompound.setInt("Progress", this.progress); tagCompound.setInt("Radius", this.radius); + tagCompound.setInt("Iteration", this.iteration); } protected void readEntity(TagObject tagCompund) { this.progress = tagCompund.getInt("Progress"); this.radius = tagCompund.getInt("Radius"); + this.iteration = tagCompund.getInt("Iteration"); } public float getEyeHeight() diff --git a/common/src/main/java/common/vars/Vars.java b/common/src/main/java/common/vars/Vars.java index a704e680..205ef9db 100755 --- a/common/src/main/java/common/vars/Vars.java +++ b/common/src/main/java/common/vars/Vars.java @@ -253,6 +253,8 @@ public abstract class Vars { public static int eggTimer = 6000; @Var(name = "spawnMoreZombies") public static int spawnMoreZombie = 25; + @Var(name = "explosionBlocksPerTick", min = 100, max = 100000) + public static int maxExplosionIters = 1024; @Var(name = "knockback") public static float knockback = 1.0f; diff --git a/common/src/main/java/common/world/Explosion.java b/common/src/main/java/common/world/Explosion.java index 032cd7ea..f2aa0fe1 100755 --- a/common/src/main/java/common/world/Explosion.java +++ b/common/src/main/java/common/world/Explosion.java @@ -26,6 +26,32 @@ import common.vars.Vars; public class Explosion { + 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; + } + /** whether or not the explosion sets fire to blocks around it */ private final boolean isFlaming; @@ -151,32 +177,36 @@ public class Explosion } } - public static void doExplosionAlgo3(World worldObj, double explosionX, double explosionY, double explosionZ, Random rand, double explosionSize, double minDist) + public static int doExplosionAlgo3(World worldObj, double explosionX, double explosionY, double explosionZ, Random rand, double explosionSize, double minDist, int iter, int max) { int d = ((int)explosionSize) + 1; + int div = d * 2 + 1; + int[] table = getTable(div); + if(table == null) + return 0; double falloff = explosionSize * 0.125d; falloff = falloff > 4.0d ? 4.0d : falloff; - for (int x = -d; x <= d; ++x) + int lmt = div * div * div; + int cnt = 0; + for(; iter < lmt && cnt < max; iter++) { - 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 > minDist && (dist < explosionSize - falloff || - (dist < explosionSize && rand.doublev() + ((dist - (explosionSize - falloff)) / falloff) < 1.0d))) { - BlockPos blockpos = new BlockPos(explosionX + x, explosionY + y, explosionZ + z); - State iblockstate = worldObj.getState(blockpos); - if(iblockstate.getBlock() != Blocks.air && iblockstate.getBlock().getExplosionResistance(null) < 60000.0f) { - worldObj.setState(blockpos, Blocks.air.getState(), 3); - if(rand.chance(1000)) { - worldObj.playSound(SoundEvent.EXPLODE, explosionX + x, explosionY + y, explosionZ + z, 4.0F); - ((AWorldServer)worldObj).spawnParticle(ParticleType.EXPLOSION_HUGE, explosionX + x, explosionY + y, explosionZ + z, 0, rand.gaussian() * 0.02D, rand.gaussian() * 0.02D, rand.gaussian() * 0.02D, 1.0, 0); - } - } + 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 < explosionSize - falloff || + (dist < explosionSize && rand.doublev() + ((dist - (explosionSize - falloff)) / falloff) < 1.0d))) { + BlockPos blockpos = new BlockPos(explosionX + x, explosionY + y, explosionZ + z); + State iblockstate = worldObj.getState(blockpos); + if(iblockstate.getBlock() != Blocks.air && iblockstate.getBlock().getExplosionResistance(null) < 60000.0f) { + worldObj.setState(blockpos, Blocks.air.getState(), 3); + if(rand.chance(1000)) { + worldObj.playSound(SoundEvent.EXPLODE, explosionX + x, explosionY + y, explosionZ + z, 4.0F); + ((AWorldServer)worldObj).spawnParticle(ParticleType.EXPLOSION_HUGE, explosionX + x, explosionY + y, explosionZ + z, 0, rand.gaussian() * 0.02D, rand.gaussian() * 0.02D, rand.gaussian() * 0.02D, 1.0, 0); } } - } + cnt++; + } } if(worldObj.client || Vars.damageExplosion) { @@ -195,6 +225,8 @@ public class Explosion } } } + + return iter >= lmt ? 0 : iter; } /**