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 1 commit
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
@@ -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;
@@ -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
@@ -62,6 +65,10 @@ public abstract class ExplosionMixin {
// The cached mutable block position used during block traversal.
private final BlockPos.Mutable cachedPos = new BlockPos.Mutable();

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

@maityyy maityyy Oct 7, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unpacking can degrade performance here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

about the pair?idk,it seems better than 2 hashmap for me

Copy link
Contributor

@maityyy maityyy Oct 7, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's better to replace Pair<BlockState, Float> with this

public record BlockStateResistance(BlockState state, float resistance)
private final HashMap<BlockPos, BlockStateResistance> map = new HashMap<>();

Copy link
Author

@pwouik pwouik Oct 7, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried,it look cleaner, but it crash at runtime, mixin seems to not really like that

 net.minecraft.util.crash.CrashException: Ticking entity
	at net.minecraft.server.MinecraftServer.tickWorlds(MinecraftServer.java:895) ~[[email protected]+build.40-v2.jar:?]
	at net.minecraft.server.MinecraftServer.tick(MinecraftServer.java:831) ~[[email protected]+build.40-v2.jar:?]
	at net.minecraft.server.integrated.IntegratedServer.tick(IntegratedServer.java:96) ~[[email protected]+build.40-v2.jar:?]
	at net.minecraft.server.MinecraftServer.handler$zgl000$modifiedRunLoop(MinecraftServer.java:2890) ~[[email protected]+build.40-v2.jar:?]
	at net.minecraft.server.MinecraftServer.runServer(MinecraftServer.java:676) ~[[email protected]+build.40-v2.jar:?]
	at net.minecraft.server.MinecraftServer.method_29739(MinecraftServer.java:270) ~[[email protected]+build.40-v2.jar:?]
	at java.lang.Thread.run(Thread.java:831) [?:?]
Caused by: org.spongepowered.asm.mixin.transformer.throwables.IllegalClassLoadError: me.jellysquid.mods.lithium.mixin.world.explosions.BlockStateResistance is in a defined mixin package me.jellysquid.mods.lithium.mixin.* owned by lithium.mixins.json and cannot be referenced directly
	at org.spongepowered.asm.mixin.transformer.MixinProcessor.applyMixins(MixinProcessor.java:330) ~[sponge-mixin-0.9.4+mixin.0.8.2.jar:0.9.4+mixin.0.8.2]
	at org.spongepowered.asm.mixin.transformer.MixinTransformer.transformClass(MixinTransformer.java:208) ~[sponge-mixin-0.9.4+mixin.0.8.2.jar:0.9.4+mixin.0.8.2]
	at org.spongepowered.asm.mixin.transformer.MixinTransformer.transformClassBytes(MixinTransformer.java:178) ~[sponge-mixin-0.9.4+mixin.0.8.2.jar:0.9.4+mixin.0.8.2]
	at org.spongepowered.asm.mixin.transformer.FabricMixinTransformerProxy.transformClassBytes(FabricMixinTransformerProxy.java:23) ~[fabric-loader-0.11.6.jar:0.9.4+mixin.0.8.2]
	at net.fabricmc.loader.launch.knot.KnotClassDelegate.getPostMixinClassByteArray(KnotClassDelegate.java:162) ~[fabric-loader-0.11.6.jar:?]
	at net.fabricmc.loader.launch.knot.KnotClassLoader.loadClass(KnotClassLoader.java:154) ~[fabric-loader-0.11.6.jar:?]
	at java.lang.ClassLoader.loadClass(ClassLoader.java:519) ~[?:?]
	at net.minecraft.world.explosion.Explosion.getBlockAndBlastRes(Explosion.java:1329) ~[[email protected]+build.40-v2.jar:?]
	at net.minecraft.world.explosion.Explosion.traverseBlock(Explosion.java:1251) ~[[email protected]+build.40-v2.jar:?]
	at net.minecraft.world.explosion.Explosion.performRayCast(Explosion.java:1215) ~[[email protected]+build.40-v2.jar:?]
	at net.minecraft.world.explosion.Explosion.redirect$zfb000$collectBlocks(Explosion.java:1160) ~[[email protected]+build.40-v2.jar:?]
	at net.minecraft.world.explosion.Explosion.collectBlocksAndDamageEntities(Explosion.java:192) ~[[email protected]+build.40-v2.jar:?]
	at net.minecraft.server.world.ServerWorld.createExplosion(ServerWorld.java:907) ~[[email protected]+build.40-v2.jar:?]
	at net.minecraft.world.World.createExplosion(World.java:495) ~[[email protected]+build.40-v2.jar:?]
	at net.minecraft.entity.TntEntity.explode(TntEntity.java:100) ~[[email protected]+build.40-v2.jar:?]
	at net.minecraft.entity.TntEntity.tick(TntEntity.java:88) ~[[email protected]+build.40-v2.jar:?]
	at net.minecraft.server.world.ServerWorld.tickEntity(ServerWorld.java:655) ~[[email protected]+build.40-v2.jar:?]
	at net.minecraft.world.World.tickEntity(World.java:483) ~[[email protected]+build.40-v2.jar:?]
	at net.minecraft.server.world.ServerWorld.method_31420(ServerWorld.java:417) ~[[email protected]+build.40-v2.jar:?]
	at net.minecraft.world.EntityList.forEach(EntityList.java:54) ~[[email protected]+build.40-v2.jar:?]
	at net.minecraft.server.world.ServerWorld.tick(ServerWorld.java:392) ~[[email protected]+build.40-v2.jar:?]
	at net.minecraft.server.MinecraftServer.tickWorlds(MinecraftServer.java:891) ~[[email protected]+build.40-v2.jar:?]
	... 6 more```

Copy link
Contributor

@maityyy maityyy Oct 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try to create a class in common package


// The chunk coordinate of the most recently stepped through block.
private int prevChunkX = Integer.MIN_VALUE;
private int prevChunkZ = Integer.MIN_VALUE;
@@ -77,11 +84,13 @@ 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")
)
private void init(World world, Entity entity, DamageSource damageSource, ExplosionBehavior explosionBehavior, double d, double e, double f, float g, boolean bl, Explosion.DestructionType destructionType, CallbackInfo ci) {
this.posOrigin=new BlockPos(floor(d),floor(e),floor(f));
this.minY = this.world.getBottomY();
this.maxY = this.world.getTopY();

@@ -149,7 +158,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.
@@ -186,9 +194,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;

@@ -232,15 +240,41 @@ 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);

int relX=pos.getX()-this.posOrigin.getX();
int relY=pos.getY()-this.posOrigin.getY();
int relZ=pos.getZ()-this.posOrigin.getZ();
Pair<Float,BlockState> blockAndBlastRes = this.blockAndBlastResCache.get(new Vec3i(relX,relY,relZ));
//test if the block is cached
if(blockAndBlastRes==null) {
//compute values and cache
blockAndBlastRes = getBlockAndBlastRes(blockX,blockY,blockZ);
this.blockAndBlastResCache.put(new Vec3i(relX,relY,relZ),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;
}


@@ -293,17 +327,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;
}

}