diff --git a/patches/server/0020-Optimised-Explosions.patch b/patches/server/0020-Optimised-Explosions.patch index 660ce14..ad9f13a 100644 --- a/patches/server/0020-Optimised-Explosions.patch +++ b/patches/server/0020-Optimised-Explosions.patch @@ -142,12 +142,13 @@ index 0000000000000000000000000000000000000000..3f6f34cc617efaad420485a7f613cfca +} diff --git a/src/main/java/me/samsuik/sakura/explosion/SakuraExplosion.java b/src/main/java/me/samsuik/sakura/explosion/SakuraExplosion.java new file mode 100644 -index 0000000000000000000000000000000000000000..4f9880d35347dd008aa2ee6e67f35301ff37a4c0 +index 0000000000000000000000000000000000000000..8a8b4169c8928459f6b51150bd8e67d0a309ca08 --- /dev/null +++ b/src/main/java/me/samsuik/sakura/explosion/SakuraExplosion.java -@@ -0,0 +1,391 @@ +@@ -0,0 +1,403 @@ +package me.samsuik.sakura.explosion; + ++import me.samsuik.sakura.entity.EntityState; +import net.minecraft.core.BlockPos; +import net.minecraft.core.particles.ParticleOptions; +import net.minecraft.server.level.ServerLevel; @@ -155,6 +156,7 @@ index 0000000000000000000000000000000000000000..4f9880d35347dd008aa2ee6e67f35301 +import net.minecraft.util.Mth; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.Entity; ++import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.boss.EnderDragonPart; +import net.minecraft.world.entity.boss.enderdragon.EnderDragon; @@ -201,40 +203,39 @@ index 0000000000000000000000000000000000000000..4f9880d35347dd008aa2ee6e67f35301 + @Override + public void explode() { + if (this.radius < 0.1F) { -+ for (int i = 1; i < source.getStacked() && !wasCanceled; ++i) { -+ this.finalizeExplosion(false); ++ for (int i = 1; i < source.getStacked(); ++i) { ++ getToBlow().clear(); ++ ((ServerLevel) level).notifyPlayersOfExplosion(x, y, z, radius, this); ++ finalizeExplosion(false); + } + + return; + } -+ -+ PrimedTnt origin = (PrimedTnt) source; -+ List positions = new ArrayList<>(origin.getStacked()); -+ -+ // This is a temporary entity that will be used for movement. -+ PrimedTnt tnt = new PrimedTnt(level, 0, 0, 0, null); -+ AABB bounds = new AABB(x, y, z, x, y, z); -+ -+ origin.entityState().apply(tnt); + -+ Vec3 lastMovement = tnt.getDeltaMovement(); ++ List positions = new ArrayList<>(source.getStacked()); + ExplosionBlockCache[] blockCache = createBlockCache(); ++ ++ EntityState entityState = null; ++ AABB bounds = new AABB(x, y, z, x, y, z); ++ Vec3 lastMovement = source.entityState().momentum(); + int wrapped = 0; + -+ for (int i = 0; i < origin.getStacked() && !wasCanceled; ++i) { ++ for (int i = 0; i < source.getStacked() && !wasCanceled; ++i) { + if (i > 0) { -+ updatePosition(origin, tnt); ++ calculateNextPosition(entityState); ++ getToBlow().clear(); + } + -+ // block at explosion position -+ int blockX = Mth.floor(x); -+ int blockY = Mth.floor(y); -+ int blockZ = Mth.floor(z); ++ // keep track of positions and bounds + Vec3 position = new Vec3(x, y, z); ++ positions.add(position); ++ bounds = bounds.minmax(new AABB(position, position)); + + // search for blocks if necessary + if (wrapped < 7 + 12) { -+ getToBlow().clear(); ++ int blockX = Mth.floor(x); ++ int blockY = Mth.floor(y); ++ int blockZ = Mth.floor(z); + + long key = BlockPos.asLong(blockX, blockY, blockZ); + ExplosionBlockCache center = getOrCacheExplosionBlock(blockX, blockY, blockZ, key, true); @@ -244,28 +245,30 @@ index 0000000000000000000000000000000000000000..4f9880d35347dd008aa2ee6e67f35301 + } + } + -+ // keep track of positions and bounds -+ positions.add(position); -+ bounds = bounds.minmax(new AABB(position, position)); -+ -+ Vec3 movement = tnt.getDeltaMovement(); -+ ++ // Check if the explosion has wrapped around with swinging on each axis + if (wrapped < 7) { -+ // Check if the explosion has wrapped around with swinging on each axis ++ Vec3 movement = source.entityState().momentum(); + if (movement.x == lastMovement.x || movement.x * lastMovement.x < 0) wrapped |= 1; + if (movement.y == lastMovement.y || movement.y * lastMovement.y < 0) wrapped |= 1 << 1; + if (movement.z == lastMovement.z || movement.z * lastMovement.z < 0) wrapped |= 1 << 2; -+ } else if (getToBlow().isEmpty() && level.sakuraConfig().cannons.explosion.avoidRedundantBlockSearches) { -+ wrapped++; -+ } else { -+ wrapped = 7; ++ lastMovement = movement; + } + -+ lastMovement = tnt.getDeltaMovement(); ++ boolean isFinalExplosion = i + 1 >= source.getStacked(); ++ ++ // Possible optimisation here is making our own finalize explosion for this special case. ++ // If this is after the explosion event we can take better advantage of protection plugins. ++ if (isFinalExplosion || !getToBlow().isEmpty()) { ++ locateAndImpactEntities(positions, bounds, blockCache); ++ bounds = new AABB(position, position); ++ positions.clear(); ++ } + -+ if (i + 1 < origin.getStacked()) { ++ if (!isFinalExplosion) { + BlockPos.MutableBlockPos mbp = new BlockPos.MutableBlockPos(); -+ impactEntityIdle(tnt, new Entity[0], position, 1, radius * 2.0f, mbp, blockCache); ++ ++ // Calculate next source velocity ++ entityState = calculateNextVelocity(position, mbp, blockCache); + + // The purpose of this is to make sure papers blockCache doesn't become + // outdated by flushing the map and removing stale entries from the recent @@ -273,41 +276,50 @@ index 0000000000000000000000000000000000000000..4f9880d35347dd008aa2ee6e67f35301 + // movement and then start moving without blocks this may break stuff to + // fix it see the note above or add a boolean to mark the cache as dirty + // outside this loop and then invalidate before the final impact entities. -+ if (!getToBlow().isEmpty() && tnt.getDeltaMovement().lengthSqr() <= 64.0) { ++ if (!getToBlow().isEmpty()) { + invalidateBlockCache(blockCache); + } + -+ // could it be viable to have a configuration option to only -+ // call finalize explosion when blocks are found -+ // may affect plugins that need exact explosion positions ++ // Could be viable in the future to have a configuration option to reduce explosion events + super.finalizeExplosion(false); + ((ServerLevel) level).notifyPlayersOfExplosion(x, y, z, radius, this); -+ } else { -+ locateAndImpactEntities(positions, bounds, blockCache); ++ ++ // Update wrapped, this is for tracking swinging and if blocks are found ++ if (getToBlow().isEmpty() && level.sakuraConfig().cannons.explosion.avoidRedundantBlockSearches) { ++ wrapped++; ++ } else { ++ wrapped = 7; ++ } + } + } + + clearBlockCache(); + } + -+ private void updatePosition(PrimedTnt origin, PrimedTnt tnt) { -+ boolean originMoved = !origin.position().equals(tnt.position()); ++ private void calculateNextPosition(EntityState entityState) { ++ if (source instanceof PrimedTnt tnt) { ++ tnt.setFuse(100); ++ } + -+ origin.setFuse(100); -+ tnt.storeEntityState(); -+ tnt.entityState().apply(origin); ++ boolean moved = !source.entityState().position().equals(source.position()); ++ entityState.apply(source); ++ source.storeEntityState(); + -+ // We have to check delta movement otherwise this optimisation can break reversing tnt. -+ // If origin was shot upwards to a block then falls in the explosion tick it will swing -+ // and origin and tnt will be in the same position every other tnt while swinging. -+ if (!getToBlow().isEmpty() || tnt.getDeltaMovement().lengthSqr() <= 64.0 || originMoved) { -+ origin.tick(); ++ if (!getToBlow().isEmpty() || source.getDeltaMovement().lengthSqr() <= 65.16525625 || moved) { ++ source.tick(); + } + + // update explosion position -+ x = origin.getX(); -+ y = origin.getY(0.0625); -+ z = origin.getZ(); ++ x = source.getX(); ++ y = source.getY(); ++ z = source.getZ(); ++ } ++ ++ private EntityState calculateNextVelocity(Vec3 position, BlockPos.MutableBlockPos mbp, ExplosionBlockCache[] blockCache) { ++ PrimedTnt tnt = new PrimedTnt(EntityType.TNT, level); ++ source.entityState().apply(tnt); ++ impactEntityIdle(tnt, new Entity[0], position, 1, radius * 2.0f, mbp, blockCache); ++ return EntityState.of(tnt); + } + + private void locateAndImpactEntities(List positions, AABB bb, ExplosionBlockCache[] blockCache) { diff --git a/patches/server/0040-Configure-cannon-physics-by-version.patch b/patches/server/0040-Configure-cannon-physics-by-version.patch index 2935a8e..cc16cde 100644 --- a/patches/server/0040-Configure-cannon-physics-by-version.patch +++ b/patches/server/0040-Configure-cannon-physics-by-version.patch @@ -36,10 +36,19 @@ index ae2eede559bd9fe7e500ce180f2ac102a95d3856..7ced5ae768cbea9ee0a7bab2365fbaef if (xSmaller && z != 0.0) { z = performAABBCollisionsZ(axisalignedbb, z, aabbs); diff --git a/src/main/java/me/samsuik/sakura/explosion/SakuraExplosion.java b/src/main/java/me/samsuik/sakura/explosion/SakuraExplosion.java -index 4f9880d35347dd008aa2ee6e67f35301ff37a4c0..79d5cd8f90fda2390a64c2d1e0cfca6b66ad83ac 100644 +index 8a8b4169c8928459f6b51150bd8e67d0a309ca08..a291516ec7bdb9d8b840f41ca52e6bbaf8e2e08a 100644 --- a/src/main/java/me/samsuik/sakura/explosion/SakuraExplosion.java +++ b/src/main/java/me/samsuik/sakura/explosion/SakuraExplosion.java -@@ -244,10 +244,17 @@ public class SakuraExplosion extends Explosion { +@@ -163,7 +163,7 @@ public class SakuraExplosion extends Explosion { + + // update explosion position + x = source.getX(); +- y = source.getY(); ++ y = physics.before(1_10_0) ? source.getY() + (double) 0.49f : source.getY(0.0625D); + z = source.getZ(); + } + +@@ -256,10 +256,17 @@ public class SakuraExplosion extends Explosion { if (distanceFromBottom > 1.0) continue; double x = entity.getX() - pos.x; @@ -58,7 +67,7 @@ index 4f9880d35347dd008aa2ee6e67f35301ff37a4c0..79d5cd8f90fda2390a64c2d1e0cfca6b if (distance == 0.0D) continue; x /= distance; -@@ -292,10 +299,17 @@ public class SakuraExplosion extends Explosion { +@@ -304,10 +311,17 @@ public class SakuraExplosion extends Explosion { if (distanceFromBottom <= 1.0) { double x = entity.getX() - pos.x;