From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Sat, 1 Feb 2025 16:57:01 +0300 Subject: [PATCH] Optimize explosions diff --git a/net/minecraft/world/level/ServerExplosion.java b/net/minecraft/world/level/ServerExplosion.java index 278761647a6095581f8d8ff4f94ccc28b6e9c8a7..6d1a73c319e19dbc17122abb508aff462c4a56f4 100644 --- a/net/minecraft/world/level/ServerExplosion.java +++ b/net/minecraft/world/level/ServerExplosion.java @@ -377,6 +377,11 @@ public class ServerExplosion implements Explosion { } private List calculateExplodedPositions() { + // DivineMC start - Optimize explosions + if (org.bxteam.divinemc.DivineConfig.enableFasterTntOptimization && !level.isClientSide && !(getIndirectSourceEntity() instanceof net.minecraft.world.entity.monster.breeze.Breeze)) { + return doExplosionA(this); + } + // DivineMC end - Optimize explosions // Paper start - collision optimisations final ObjectArrayList ret = new ObjectArrayList<>(); @@ -475,6 +480,157 @@ public class ServerExplosion implements Explosion { // Paper end - collision optimisations } + // DivineMC start - Optimize explosions + private static final it.unimi.dsi.fastutil.objects.Object2DoubleOpenHashMap> densityCache = new it.unimi.dsi.fastutil.objects.Object2DoubleOpenHashMap<>(); + private static final it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap stateCache = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(); + private static final it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap fluidCache = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(); + private static final BlockPos.MutableBlockPos posMutable = new BlockPos.MutableBlockPos(0, 0, 0); + private static final it.unimi.dsi.fastutil.objects.ObjectOpenHashSet affectedBlockPositionsSet = new it.unimi.dsi.fastutil.objects.ObjectOpenHashSet<>(); + private static boolean firstRay; + private static boolean rayCalcDone; + + public static @org.jetbrains.annotations.NotNull List doExplosionA(ServerExplosion e) { + List toBlow; + + if (!org.bxteam.divinemc.DivineConfig.explosionNoBlockDamage && e.damageSource != null) { + rayCalcDone = false; + firstRay = true; + getAffectedPositionsOnPlaneY(e, 0, 0, 15, 0, 15); // bottom + getAffectedPositionsOnPlaneY(e, 15, 0, 15, 0, 15); // top + getAffectedPositionsOnPlaneX(e, 0, 1, 14, 0, 15); // west + getAffectedPositionsOnPlaneX(e, 15, 1, 14, 0, 15); // east + getAffectedPositionsOnPlaneZ(e, 0, 1, 14, 1, 14); // north + getAffectedPositionsOnPlaneZ(e, 15, 1, 14, 1, 14); // south + stateCache.clear(); + fluidCache.clear(); + + toBlow = new ArrayList<>(affectedBlockPositionsSet); + affectedBlockPositionsSet.clear(); + } else { + toBlow = java.util.Collections.emptyList(); + } + densityCache.clear(); + + return toBlow; + } + + private static void getAffectedPositionsOnPlaneX(Explosion e, int x, int yStart, int yEnd, int zStart, int zEnd) { + if (!rayCalcDone) { + final double xRel = (double) x / 15.0D * 2.0D - 1.0D; + + for (int z = zStart; z <= zEnd; ++z) { + double zRel = (double) z / 15.0D * 2.0D - 1.0D; + + for (int y = yStart; y <= yEnd; ++y) { + double yRel = (double) y / 15.0D * 2.0D - 1.0D; + + if (checkAffectedPosition((ServerExplosion) e, xRel, yRel, zRel)) { + return; + } + } + } + } + } + + private static void getAffectedPositionsOnPlaneY(Explosion e, int y, int xStart, int xEnd, int zStart, int zEnd) { + if (!rayCalcDone) { + final double yRel = (double) y / 15.0D * 2.0D - 1.0D; + + for (int z = zStart; z <= zEnd; ++z) { + double zRel = (double) z / 15.0D * 2.0D - 1.0D; + + for (int x = xStart; x <= xEnd; ++x) { + double xRel = (double) x / 15.0D * 2.0D - 1.0D; + + if (checkAffectedPosition((ServerExplosion) e, xRel, yRel, zRel)) { + return; + } + } + } + } + } + + private static void getAffectedPositionsOnPlaneZ(Explosion e, int z, int xStart, int xEnd, int yStart, int yEnd) { + if (!rayCalcDone) { + final double zRel = (double) z / 15.0D * 2.0D - 1.0D; + + for (int x = xStart; x <= xEnd; ++x) { + double xRel = (double) x / 15.0D * 2.0D - 1.0D; + + for (int y = yStart; y <= yEnd; ++y) { + double yRel = (double) y / 15.0D * 2.0D - 1.0D; + + if (checkAffectedPosition((ServerExplosion) e, xRel, yRel, zRel)) { + return; + } + } + } + } + } + + private static boolean checkAffectedPosition(ServerExplosion e, double xRel, double yRel, double zRel) { + double len = Math.sqrt(xRel * xRel + yRel * yRel + zRel * zRel); + double xInc = (xRel / len) * 0.3; + double yInc = (yRel / len) * 0.3; + double zInc = (zRel / len) * 0.3; + float rand = e.level().random.nextFloat(); + float sizeRand = (org.bxteam.divinemc.DivineConfig.tntRandomRange >= 0 ? (float) org.bxteam.divinemc.DivineConfig.tntRandomRange : rand); + float size = e.radius() * (0.7F + sizeRand * 0.6F); + Vec3 vec3 = e.center(); + double posX = vec3.x; + double posY = vec3.y; + double posZ = vec3.z; + + for (float f1 = 0.3F; size > 0.0F; size -= 0.22500001F) { + posMutable.set(posX, posY, posZ); + + // Don't query already cached positions again from the world + BlockState state = stateCache.get(posMutable); + FluidState fluid = fluidCache.get(posMutable); + BlockPos posImmutable = null; + + if (state == null) { + posImmutable = posMutable.immutable(); + state = e.level().getBlockState(posImmutable); + stateCache.put(posImmutable, state); + fluid = e.level().getFluidState(posImmutable); + fluidCache.put(posImmutable, fluid); + } + + if (!state.isAir()) { + float resistance = Math.max(state.getBlock().getExplosionResistance(), fluid.getExplosionResistance()); + + if (e.source != null) { + resistance = e.source.getBlockExplosionResistance(e, e.level(), posMutable, state, fluid, resistance); + } + + size -= (resistance + 0.3F) * 0.3F; + } + + if (size > 0.0F) { + if ((e.source == null || e.source.shouldBlockExplode(e, e.level(), posMutable, state, size))) + affectedBlockPositionsSet.add(posImmutable != null ? posImmutable : posMutable.immutable()); + } else if (firstRay) { + rayCalcDone = true; + return true; + } + + firstRay = false; + + posX += xInc; + posY += yInc; + posZ += zInc; + } + + return false; + } + + private Optional noBlockCalcsWithNoBLockDamage(final ExplosionDamageCalculator instance, final Explosion explosion, final BlockGetter blockGetter, final BlockPos blockPos, final BlockState blockState, final FluidState fluidState) { + if (org.bxteam.divinemc.DivineConfig.explosionNoBlockDamage) return Optional.of(Blocks.BEDROCK.getExplosionResistance()); + return instance.getBlockExplosionResistance(explosion, blockGetter, blockPos, blockState, fluidState); + } + // DivineMC end - Optimize explosions + private void hurtEntities() { float f = this.radius * 2.0F; int floor = Mth.floor(this.center.x - f - 1.0); @@ -567,6 +723,11 @@ public class ServerExplosion implements Explosion { } private void interactWithBlocks(List blocks) { + // DivineMC start - Optimize explosions + if (org.bxteam.divinemc.DivineConfig.explosionNoBlockDamage) { + blocks.clear(); + } + // DivineMC end - Optimize explosions List list = new ArrayList<>(); Util.shuffle(blocks, this.level.random);