From b393c9a06cd3fe23e19b3ad5f56165227bd726dd Mon Sep 17 00:00:00 2001 From: 2No2Name <2No2Name@web.de> Date: Tue, 4 Aug 2020 02:01:50 +0200 Subject: [PATCH 1/5] fix: explosions being different from vanilla --- .../mods/lithium/common/util/TypeCast.java | 17 ++++++++ .../world/explosions/ExplosionMixin.java | 41 +++++++++++-------- 2 files changed, 42 insertions(+), 16 deletions(-) create mode 100644 src/main/java/me/jellysquid/mods/lithium/common/util/TypeCast.java diff --git a/src/main/java/me/jellysquid/mods/lithium/common/util/TypeCast.java b/src/main/java/me/jellysquid/mods/lithium/common/util/TypeCast.java new file mode 100644 index 000000000..0a8b3e393 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/lithium/common/util/TypeCast.java @@ -0,0 +1,17 @@ +package me.jellysquid.mods.lithium.common.util; + +import net.minecraft.world.explosion.Explosion; + +/** + * Class to work around being unable to cast SomeClassMixin to SomeClass inside SomeClassMixin. + * Add methods for ohter types when needed. + * + * Hopefully(!) the casts can be inlined and completely eliminated (casting SomeClass to SomeClass never doing anything). + * + * @author 2No2Name + */ +public class TypeCast { + public static Explosion toExplosion(Object returnValue) { + return (Explosion) returnValue; + } +} 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..b6355523e 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 @@ -2,6 +2,7 @@ import it.unimi.dsi.fastutil.longs.LongIterator; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; +import me.jellysquid.mods.lithium.common.util.TypeCast; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.enchantment.ProtectionEnchantment; @@ -11,6 +12,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 +21,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 +31,7 @@ import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Random; @Mixin(Explosion.class) @@ -72,6 +76,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 +162,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 +188,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 +207,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(TypeCast.toExplosion(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,7 +233,7 @@ 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; + float totalResistance = 0.0F; // If the chunk is missing or out of bounds, assume that it is air if (chunk != null) { @@ -240,24 +253,20 @@ private float traverseBlock(float strength, int blockX, int blockY, int blockZ, // 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); - } + // Get the explosion resistance like vanilla + Optional blastResistance = this.behavior.getBlastResistance(TypeCast.toExplosion(this), this.world, pos, blockState, fluidState); + // Calculate how much this block will resist an explosion's ray + totalResistance = blastResistance.map(aFloat -> (aFloat + 0.3F) * 0.3F).orElse(0.0F); - // Calculate how much this block space will resist an explosion's ray - totalResistance = (resistance + 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(TypeCast.toExplosion(this), this.world, pos, blockState, reducedStrength)) { touched.add(pos.asLong()); } } From b2235ba619478e8c8337b7195b31646d66ec1bc0 Mon Sep 17 00:00:00 2001 From: 2No2Name <2No2Name@web.de> Date: Tue, 4 Aug 2020 20:53:27 +0200 Subject: [PATCH 2/5] use traditional if statement over Optional.map --- .../mods/lithium/mixin/world/explosions/ExplosionMixin.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 b6355523e..c9bb54c68 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 @@ -256,8 +256,9 @@ private float traverseBlock(float strength, int blockX, int blockY, int blockZ, // Get the explosion resistance like vanilla Optional blastResistance = this.behavior.getBlastResistance(TypeCast.toExplosion(this), this.world, pos, blockState, fluidState); // Calculate how much this block will resist an explosion's ray - totalResistance = blastResistance.map(aFloat -> (aFloat + 0.3F) * 0.3F).orElse(0.0F); - + if (blastResistance.isPresent()) { + totalResistance = (blastResistance.get() + 0.3F) * 0.3F; + } } } } From 3b46651c1872293295dec00afada4ac6c384e22b Mon Sep 17 00:00:00 2001 From: 2No2Name <2No2Name@web.de> Date: Tue, 4 Aug 2020 21:26:38 +0200 Subject: [PATCH 3/5] Inline typecast --- .../mods/lithium/common/util/TypeCast.java | 17 ----------------- .../mixin/world/explosions/ExplosionMixin.java | 9 ++++----- 2 files changed, 4 insertions(+), 22 deletions(-) delete mode 100644 src/main/java/me/jellysquid/mods/lithium/common/util/TypeCast.java diff --git a/src/main/java/me/jellysquid/mods/lithium/common/util/TypeCast.java b/src/main/java/me/jellysquid/mods/lithium/common/util/TypeCast.java deleted file mode 100644 index 0a8b3e393..000000000 --- a/src/main/java/me/jellysquid/mods/lithium/common/util/TypeCast.java +++ /dev/null @@ -1,17 +0,0 @@ -package me.jellysquid.mods.lithium.common.util; - -import net.minecraft.world.explosion.Explosion; - -/** - * Class to work around being unable to cast SomeClassMixin to SomeClass inside SomeClassMixin. - * Add methods for ohter types when needed. - * - * Hopefully(!) the casts can be inlined and completely eliminated (casting SomeClass to SomeClass never doing anything). - * - * @author 2No2Name - */ -public class TypeCast { - public static Explosion toExplosion(Object returnValue) { - return (Explosion) returnValue; - } -} 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 c9bb54c68..65d61efef 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 @@ -2,7 +2,6 @@ import it.unimi.dsi.fastutil.longs.LongIterator; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; -import me.jellysquid.mods.lithium.common.util.TypeCast; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.enchantment.ProtectionEnchantment; @@ -199,7 +198,7 @@ private void performRayCast(Random random, double vecX, double vecY, double vecZ } /** - * Called for every step made by a ray being cast by an explosion. + * Called for every step made by a ray being cast by an explosion. fai * @param strength The strength of the ray during this step * @param blockX The x-coordinate of the block the ray is inside of * @param blockY The y-coordinate of the block the ray is inside of @@ -211,7 +210,7 @@ private float traverseBlock(float strength, int blockX, int blockY, int blockZ, // Early-exit if the y-coordinate is out of bounds. if (World.isHeightInvalid(blockY)) { - Optional blastResistance = this.behavior.getBlastResistance(TypeCast.toExplosion(this), this.world, pos, Blocks.AIR.getDefaultState(), Fluids.EMPTY.getDefaultState()); + 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; } @@ -254,7 +253,7 @@ private float traverseBlock(float strength, int blockX, int blockY, int blockZ, FluidState fluidState = blockState.getFluidState(); // Get the explosion resistance like vanilla - Optional blastResistance = this.behavior.getBlastResistance(TypeCast.toExplosion(this), this.world, pos, blockState, fluidState); + Optional blastResistance = this.behavior.getBlastResistance((Explosion) (Object) this, this.world, pos, blockState, fluidState); // Calculate how much this block will resist an explosion's ray if (blastResistance.isPresent()) { totalResistance = (blastResistance.get() + 0.3F) * 0.3F; @@ -267,7 +266,7 @@ private float traverseBlock(float strength, int blockX, int blockY, int blockZ, // of positions to destroy float reducedStrength = strength - totalResistance; if (reducedStrength > 0.0F) { - if (this.behavior.canDestroyBlock(TypeCast.toExplosion(this), this.world, pos, blockState, reducedStrength)) { + if (this.behavior.canDestroyBlock((Explosion) (Object) this, this.world, pos, blockState, reducedStrength)) { touched.add(pos.asLong()); } } From 8945a31d277a0f2b837e53d830b2feffc934c3b5 Mon Sep 17 00:00:00 2001 From: 2No2Name <2No2Name@web.de> Date: Wed, 5 Aug 2020 19:51:16 +0200 Subject: [PATCH 4/5] Handle air in all cases in ExplosionMixin --- .../world/explosions/ExplosionMixin.java | 54 ++++++++++--------- 1 file changed, 30 insertions(+), 24 deletions(-) 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 65d61efef..371b801eb 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 @@ -233,33 +233,39 @@ private float traverseBlock(float strength, int blockX, int blockY, int blockZ, 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(); - - // Get the explosion resistance like vanilla - Optional blastResistance = this.behavior.getBlastResistance((Explosion) (Object) this, this.world, pos, blockState, fluidState); - // Calculate how much this block will resist an explosion's ray - if (blastResistance.isPresent()) { - totalResistance = (blastResistance.get() + 0.3F) * 0.3F; + 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; } } } + 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 From 626067379973c54ce19ceb00cb9a3e33219a9391 Mon Sep 17 00:00:00 2001 From: 2No2Name <2No2Name@web.de> Date: Wed, 5 Aug 2020 19:54:04 +0200 Subject: [PATCH 5/5] Undo random characters in comment --- .../mods/lithium/mixin/world/explosions/ExplosionMixin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 371b801eb..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 @@ -198,7 +198,7 @@ private void performRayCast(Random random, double vecX, double vecY, double vecZ } /** - * Called for every step made by a ray being cast by an explosion. fai + * Called for every step made by a ray being cast by an explosion. * @param strength The strength of the ray during this step * @param blockX The x-coordinate of the block the ray is inside of * @param blockY The y-coordinate of the block the ray is inside of