diff --git a/src/main/java/me/jellysquid/mods/lithium/mixin/world/explosions/ExplosionMixin.java b/src/main/java/me/jellysquid/mods/lithium/mixin/world/explosions/ExplosionMixin.java index 06e6a41a5..c328d29b6 100644 --- a/src/main/java/me/jellysquid/mods/lithium/mixin/world/explosions/ExplosionMixin.java +++ b/src/main/java/me/jellysquid/mods/lithium/mixin/world/explosions/ExplosionMixin.java @@ -11,6 +11,7 @@ import net.minecraft.entity.damage.DamageSource; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.fluid.FluidState; +import net.minecraft.fluid.Fluids; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Box; import net.minecraft.util.math.MathHelper; @@ -19,6 +20,7 @@ import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.ChunkSection; import net.minecraft.world.explosion.Explosion; +import net.minecraft.world.explosion.ExplosionBehavior; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -28,6 +30,7 @@ import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Random; @Mixin(Explosion.class) @@ -72,6 +75,9 @@ public static float getExposure(Vec3d self, Entity entity) { @Final private Map affectedPlayers; + @Shadow + @Final + private ExplosionBehavior behavior; // The cached mutable block position used during block traversal. private final BlockPos.Mutable cachedPos = new BlockPos.Mutable(); @@ -155,7 +161,7 @@ private void performRayCast(Random random, double vecX, double vecY, double vecZ int prevY = Integer.MIN_VALUE; int prevZ = Integer.MIN_VALUE; - float prevResistance = 0.0f; + float prevResistance = 0.0F; // Step through the ray until it is finally stopped while (strength > 0.0F) { @@ -181,8 +187,9 @@ private void performRayCast(Random random, double vecX, double vecY, double vecZ resistance = prevResistance; } + strength -= resistance; // Apply a constant fall-off - strength -= resistance + 0.225F; + strength -= 0.22500001F; stepX += normX * 0.3D; stepY += normY * 0.3D; @@ -199,12 +206,17 @@ private void performRayCast(Random random, double vecX, double vecY, double vecZ * @return The resistance of the current block space to the ray */ private float traverseBlock(float strength, int blockX, int blockY, int blockZ, LongOpenHashSet touched) { + BlockPos pos = this.cachedPos.set(blockX, blockY, blockZ); + // Early-exit if the y-coordinate is out of bounds. if (World.isHeightInvalid(blockY)) { - return 0.0f; + Optional blastResistance = this.behavior.getBlastResistance((Explosion) (Object) this, this.world, pos, Blocks.AIR.getDefaultState(), Fluids.EMPTY.getDefaultState()); + if (blastResistance.isPresent()) { + return (blastResistance.get() + 0.3F) * 0.3F; + } + return 0.0F; } - BlockPos pos = this.cachedPos.set(blockX, blockY, blockZ); int chunkX = blockX >> 4; int chunkZ = blockZ >> 4; @@ -220,44 +232,47 @@ private float traverseBlock(float strength, int blockX, int blockY, int blockZ, final Chunk chunk = this.prevChunk; BlockState blockState = Blocks.AIR.getDefaultState(); - float totalResistance = 0.0f; - - // If the chunk is missing or out of bounds, assume that it is air - if (chunk != null) { - // We operate directly on chunk sections to avoid interacting with BlockPos and to squeeze out as much - // performance as possible here - ChunkSection section = chunk.getSectionArray()[blockY >> 4]; - - // If the section doesn't exist or it's empty, assume that the block is air - if (section != null && !section.isEmpty()) { - // Retrieve the block state from the chunk section directly to avoid associated overhead - blockState = section.getBlockState(blockX & 15, blockY & 15, blockZ & 15); - - // If the block state is air, it cannot have fluid or any kind of resistance, so just leave - if (blockState.getBlock() != Blocks.AIR) { - // Rather than query the fluid state from the container as we just did with the block state, we can - // simply ask the block state we retrieved what fluid it has. This is exactly what the call would - // do anyways, except that it would have to retrieve the block state a second time, adding overhead. - FluidState fluidState = blockState.getFluidState(); - - // Pick the highest resistance value between the block and fluid - float resistance = Math.max(blockState.getBlock().getBlastResistance(), fluidState.getBlastResistance()); - - // If this explosion was caused by an entity, allow for it to modify the resistance of this position - if (this.entity != null) { - resistance = this.entity.getEffectiveExplosionResistance((Explosion) (Object) this, this.world, pos, blockState, fluidState, resistance); + float totalResistance = 0.0F; + Optional blastResistance; + + labelGetBlastResistance: + { + // If the chunk is missing or out of bounds, assume that it is air + if (chunk != null) { + // We operate directly on chunk sections to avoid interacting with BlockPos and to squeeze out as much + // performance as possible here + ChunkSection section = chunk.getSectionArray()[blockY >> 4]; + + // If the section doesn't exist or it's empty, assume that the block is air + if (section != null && !section.isEmpty()) { + // Retrieve the block state from the chunk section directly to avoid associated overhead + blockState = section.getBlockState(blockX & 15, blockY & 15, blockZ & 15); + + // If the block state is air, it cannot have fluid or any kind of resistance, so just leave + if (blockState.getBlock() != Blocks.AIR) { + // Rather than query the fluid state from the container as we just did with the block state, we can + // simply ask the block state we retrieved what fluid it has. This is exactly what the call would + // do anyways, except that it would have to retrieve the block state a second time, adding overhead. + FluidState fluidState = blockState.getFluidState(); + + // Get the explosion resistance like vanilla + blastResistance = this.behavior.getBlastResistance((Explosion) (Object) this, this.world, pos, blockState, fluidState); + break labelGetBlastResistance; } - - // Calculate how much this block space will resist an explosion's ray - totalResistance = (resistance + 0.3F) * 0.3F; } } + blastResistance = this.behavior.getBlastResistance((Explosion) (Object) this, this.world, pos, Blocks.AIR.getDefaultState(), Fluids.EMPTY.getDefaultState()); + } + // Calculate how much this block will resist an explosion's ray + if (blastResistance.isPresent()) { + totalResistance = (blastResistance.get() + 0.3F) * 0.3F; } // Check if this ray is still strong enough to break blocks, and if so, add this position to the set // of positions to destroy - if ((strength - totalResistance) > 0.0F) { - if ((this.entity == null) || this.entity.canExplosionDestroyBlock((Explosion) (Object) this, this.world, pos, blockState, strength)) { + float reducedStrength = strength - totalResistance; + if (reducedStrength > 0.0F) { + if (this.behavior.canDestroyBlock((Explosion) (Object) this, this.world, pos, blockState, reducedStrength)) { touched.add(pos.asLong()); } }