package com.vinlanx.explosionoverhaul; import com.vinlanx.explosionoverhaul.api.IExplosionPower; import com.vinlanx.explosionoverhaul.mixinhelper.ExplosionAccessor; import java.util.HashSet; import java.util.List; import java.util.Set; import net.minecraft.core.BlockPos; import net.minecraft.core.particles.ParticleTypes; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.Explosion; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; public class ServerExplosionHandler { public static void handleExplosion(ServerLevel level, Explosion explosion, List affectedBlocks) { if (!((Boolean)Config.COMMON.enableCraterDestruction.get()).booleanValue()) { affectedBlocks.clear(); return; } float power = 4.0f; if (explosion instanceof IExplosionPower explosionPower) { power = Math.max(1.0f, explosionPower.getPower()); } Vec3 center = explosion instanceof ExplosionAccessor accessor ? accessor.explosionoverhaul$getCenter() : Vec3.ZERO; int radius = Math.max(5, Math.min(18, Math.round(power * 2.0f * ((Double)Config.COMMON.craterSizeMultiplier.get()).floatValue()))); ExplosionOverhaul.LOGGER.info("Explosion Overhaul handling explosion at {} with power {} and radius {}", center, power, radius); Set existing = new HashSet<>(affectedBlocks); BlockPos origin = BlockPos.containing(center); double radiusSq = radius * radius; int directBlocksChanged = 0; for (BlockPos pos : BlockPos.betweenClosed(origin.offset(-radius, -radius, -radius), origin.offset(radius, radius, radius))) { double distanceSq = pos.distToCenterSqr(center); if (distanceSq > radiusSq) { continue; } BlockState state = level.getBlockState(pos); if (state.isAir() || state.getDestroySpeed(level, pos) < 0.0f) { continue; } BlockPos immutable = pos.immutable(); if (existing.add(immutable)) { affectedBlocks.add(immutable); } if (directBlocksChanged < 2500) { level.setBlock(immutable, Blocks.AIR.defaultBlockState(), 3); ++directBlocksChanged; } } level.sendParticles(ParticleTypes.EXPLOSION_EMITTER, center.x(), center.y(), center.z(), Math.max(2, radius / 3), 0.5, 0.5, 0.5, 0.0); level.sendParticles(ParticleTypes.LARGE_SMOKE, center.x(), center.y(), center.z(), radius * 8, radius * 0.35, radius * 0.25, radius * 0.35, 0.08); level.sendParticles(ParticleTypes.FLAME, center.x(), center.y(), center.z(), radius * 4, radius * 0.25, radius * 0.2, radius * 0.25, 0.05); } public static void register() { } public record CameraShakeProfile(float intensity, int durationTicks, float pushIntensity) { } }