Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cache blockstates and blast resistance for explosions #282

Open
wants to merge 2 commits into
base: 1.17.x/dev
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.fluid.FluidState;
import net.minecraft.fluid.Fluids;
import net.minecraft.util.Pair;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3i;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.ChunkSection;
Expand All @@ -24,6 +25,8 @@

import java.util.*;

import static net.minecraft.util.math.MathHelper.floor;

/**
* Optimizations for Explosions: Reduce allocations and getChunk/getBlockState calls
* Original implementation by
Expand Down Expand Up @@ -62,6 +65,9 @@ public abstract class ExplosionMixin {
// The cached mutable block position used during block traversal.
private final BlockPos.Mutable cachedPos = new BlockPos.Mutable();

//cached block and blast resistance
private final HashMap<BlockPos,Pair<Float,BlockState>> blockAndBlastResCache=new HashMap<>();

// The chunk coordinate of the most recently stepped through block.
private int prevChunkX = Integer.MIN_VALUE;
private int prevChunkZ = Integer.MIN_VALUE;
Expand All @@ -77,6 +83,7 @@ public abstract class ExplosionMixin {

private int minY, maxY;


@Inject(
method = "<init>(Lnet/minecraft/world/World;Lnet/minecraft/entity/Entity;Lnet/minecraft/entity/damage/DamageSource;Lnet/minecraft/world/explosion/ExplosionBehavior;DDDFZLnet/minecraft/world/explosion/Explosion$DestructionType;)V",
at = @At("TAIL")
Expand Down Expand Up @@ -149,7 +156,6 @@ public boolean collectBlocks(List<BlockPos> affectedBlocks, Collection<BlockPos>
}
}
}

// We can now iterate back over the set of positions we modified and re-build BlockPos objects from them
// This will only allocate as many objects as there are in the set, where otherwise we would allocate them
// each step of a every ray.
Expand Down Expand Up @@ -186,9 +192,9 @@ private void performRayCast(Random random, double vecX, double vecY, double vecZ

// Step through the ray until it is finally stopped
while (strength > 0.0F) {
int blockX = MathHelper.floor(stepX);
int blockY = MathHelper.floor(stepY);
int blockZ = MathHelper.floor(stepZ);
int blockX = floor(stepX);
int blockY = floor(stepY);
int blockZ = floor(stepZ);

float resistance;

Expand Down Expand Up @@ -232,15 +238,38 @@ private void performRayCast(Random random, double vecX, double vecY, double vecZ
*/
private float traverseBlock(float strength, int blockX, int blockY, int blockZ, LongOpenHashSet touched) {
BlockPos pos = this.cachedPos.set(blockX, blockY, blockZ);

Pair<Float,BlockState> blockAndBlastRes = this.blockAndBlastResCache.get(pos);
//test if the block is cached
if(blockAndBlastRes==null) {
//compute values and cache
blockAndBlastRes = getBlockAndBlastRes(blockX,blockY,blockZ);
this.blockAndBlastResCache.put(pos,blockAndBlastRes);
}
// Check if this ray is still strong enough to break blocks if not out of bound, and if so, add this position to the set
// of positions to destroy
if(blockAndBlastRes.getRight()!=null)
{
float reducedStrength = strength - blockAndBlastRes.getLeft();
if (reducedStrength > 0.0F && (this.explodeAirBlocks || !blockAndBlastRes.getRight().isAir())) {
if (this.behavior.canDestroyBlock((Explosion) (Object) this, this.world, pos, blockAndBlastRes.getRight(), reducedStrength)) {
touched.add(pos.asLong());
}
}
}
return blockAndBlastRes.getLeft();
}
private Pair<Float,BlockState> getBlockAndBlastRes(int blockX, int blockY, int blockZ) {
Pair<Float,BlockState> result= new Pair(0.0,null);
BlockPos pos = this.cachedPos.set(blockX, blockY, blockZ);
// Early-exit if the y-coordinate is out of bounds.
if (this.world.isOutOfHeightLimit(blockY)) {
Optional<Float> blastResistance = this.behavior.getBlastResistance((Explosion) (Object) this, this.world, pos, Blocks.AIR.getDefaultState(), Fluids.EMPTY.getDefaultState());
//noinspection OptionalIsPresent
if (blastResistance.isPresent()) {
return (blastResistance.get() + 0.3F) * 0.3F;
result.setLeft((blastResistance.get() + 0.3F) * 0.3F);
return result;
}
return 0.0F;
return result;
}


Expand Down Expand Up @@ -293,17 +322,8 @@ private float traverseBlock(float strength, int blockX, int blockY, int blockZ,
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
float reducedStrength = strength - totalResistance;
if (reducedStrength > 0.0F && (this.explodeAirBlocks || !blockState.isAir())) {
if (this.behavior.canDestroyBlock((Explosion) (Object) this, this.world, pos, blockState, reducedStrength)) {
touched.add(pos.asLong());
}
}

return totalResistance;
result.setLeft(totalResistance);
result.setRight(blockState);
return result;
}

}