use of net.minecraft.world.chunk.ChunkSection in project lithium-fabric by CaffeineMC.
the class LandPathNodeMakerMixin method getNodeTypeFromNeighbors.
/**
* @reason Use optimized implementation which avoids scanning blocks for dangers where possible
* @author JellySquid
*/
@Overwrite
public static PathNodeType getNodeTypeFromNeighbors(BlockView world, BlockPos.Mutable pos, PathNodeType type) {
int x = pos.getX();
int y = pos.getY();
int z = pos.getZ();
ChunkSection section = null;
// reads to just one chunk and avoid hits against the server chunk manager.
if (world instanceof CollisionView && WorldHelper.areNeighborsWithinSameChunk(pos)) {
// if the cached chunk section was initialized will early-exit.
if (!world.isOutOfHeightLimit(y)) {
// This cast is always safe and is necessary to obtain direct references to chunk sections.
Chunk chunk = (Chunk) ((CollisionView) world).getChunkAsView(Pos.ChunkCoord.fromBlockCoord(x), Pos.ChunkCoord.fromBlockCoord(z));
// An empty chunk or section will never pose any danger sources, which will be caught later.
if (chunk != null) {
section = chunk.getSectionArray()[Pos.SectionYIndex.fromBlockCoord(world, y)];
}
}
// against this chunk section will always fail, allowing us to fast-exit.
if (section == null || PathNodeCache.isSectionSafeAsNeighbor(section)) {
return type;
}
}
int xStart = x - 1;
int yStart = y - 1;
int zStart = z - 1;
int xEnd = x + 1;
int yEnd = y + 1;
int zEnd = z + 1;
// Vanilla iteration order is XYZ
for (int adjX = xStart; adjX <= xEnd; adjX++) {
for (int adjY = yStart; adjY <= yEnd; adjY++) {
for (int adjZ = zStart; adjZ <= zEnd; adjZ++) {
// Skip the vertical column of the origin block
if (adjX == x && adjZ == z) {
continue;
}
BlockState state;
// retrieval by calling upon the cached chunk directly.
if (section != null) {
state = section.getBlockState(adjX & 15, adjY & 15, adjZ & 15);
} else {
state = world.getBlockState(pos.set(adjX, adjY, adjZ));
}
// Ensure that the block isn't air first to avoid expensive hash table accesses
if (state.isAir()) {
continue;
}
PathNodeType neighborType = PathNodeCache.getNeighborPathNodeType(state);
if (neighborType != PathNodeType.OPEN) {
return neighborType;
}
}
}
}
return type;
}
use of net.minecraft.world.chunk.ChunkSection in project lithium-fabric by CaffeineMC.
the class EntityMixin method tryShortcutFluidPushing.
@Inject(method = "updateMovementInFluid(Lnet/minecraft/tag/TagKey;D)Z", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/Entity;isPushedByFluids()Z", shift = At.Shift.BEFORE), cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD)
public void tryShortcutFluidPushing(TagKey<Fluid> tag, double speed, CallbackInfoReturnable<Boolean> cir, Box box, int x1, int x2, int y1, int y2, int z1, int z2, double zero) {
TrackedBlockStatePredicate blockStateFlag;
if (tag == FluidTags.WATER) {
blockStateFlag = BlockStateFlags.WATER;
} else if (tag == FluidTags.LAVA) {
blockStateFlag = BlockStateFlags.LAVA;
} else {
return;
}
int chunkX1 = x1 >> 4;
int chunkZ1 = z1 >> 4;
int chunkX2 = ((x2 - 1) >> 4);
int chunkZ2 = ((z2 - 1) >> 4);
int chunkYIndex1 = Math.max(Pos.SectionYIndex.fromBlockCoord(this.world, y1), Pos.SectionYIndex.getMinYSectionIndex(this.world));
int chunkYIndex2 = Math.min(Pos.SectionYIndex.fromBlockCoord(this.world, y2 - 1), Pos.SectionYIndex.getMaxYSectionIndexInclusive(this.world));
for (int chunkX = chunkX1; chunkX <= chunkX2; chunkX++) {
for (int chunkZ = chunkZ1; chunkZ <= chunkZ2; chunkZ++) {
Chunk chunk = this.world.getChunk(chunkX, chunkZ);
for (int chunkYIndex = chunkYIndex1; chunkYIndex <= chunkYIndex2; chunkYIndex++) {
ChunkSection section = chunk.getSectionArray()[chunkYIndex];
if (((BlockCountingSection) section).anyMatch(blockStateFlag)) {
// fluid found, cannot skip code
return;
}
}
}
}
// side effects of not finding a fluid:
this.fluidHeight.put(tag, 0.0);
cir.setReturnValue(false);
}
use of net.minecraft.world.chunk.ChunkSection in project lithium-fabric by CaffeineMC.
the class WorldMixin method getBlockState.
/**
* @reason Reduce method size to help the JVM inline, Avoid excess height limit checks
* @author 2No2Name
*/
@Overwrite
public BlockState getBlockState(BlockPos pos) {
WorldChunk worldChunk = this.getChunk(ChunkSectionPos.getSectionCoord(pos.getX()), ChunkSectionPos.getSectionCoord(pos.getZ()));
ChunkSection[] sections = worldChunk.getSectionArray();
int x = pos.getX();
int y = pos.getY();
int z = pos.getZ();
int chunkY = this.getSectionIndex(y);
if (chunkY < 0 || chunkY >= sections.length) {
return OUTSIDE_WORLD_BLOCK;
}
ChunkSection section = sections[chunkY];
if (section == null || section.isEmpty()) {
return INSIDE_WORLD_DEFAULT_BLOCK;
}
return section.getBlockState(x & 15, y & 15, z & 15);
// This code path is slower than with the extra world height limit check. Tradeoff in favor of the default path.
}
use of net.minecraft.world.chunk.ChunkSection in project lithium-fabric by CaffeineMC.
the class ExplosionMixin method traverseBlock.
/**
* 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
* @param blockZ The z-coordinate of the block the ray is inside of
* @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 (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;
}
return 0.0F;
}
int chunkX = Pos.ChunkCoord.fromBlockCoord(blockX);
int chunkZ = Pos.ChunkCoord.fromBlockCoord(blockZ);
// Avoid calling into the chunk manager as much as possible through managing chunks locally
if (this.prevChunkX != chunkX || this.prevChunkZ != chunkZ) {
this.prevChunk = this.world.getChunk(chunkX, chunkZ);
this.prevChunkX = chunkX;
this.prevChunkZ = chunkZ;
}
final Chunk chunk = this.prevChunk;
BlockState blockState = Blocks.AIR.getDefaultState();
float totalResistance = 0.0F;
Optional<Float> 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()[Pos.SectionYIndex.fromBlockCoord(chunk, blockY)];
// 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
// 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;
}
use of net.minecraft.world.chunk.ChunkSection in project Spelunker by Leximon.
the class PlayerEntityMixin method moveEndInject.
@Inject(method = "tick", at = @At("HEAD"))
private void moveEndInject(CallbackInfo ci) {
if (!hasStatusEffect(SpelunkerMod.STATUS_EFFECT_SPELUNKER)) {
if (!spelunkerEffectChunks.isEmpty())
spelunkerEffectChunks.clear();
forceOreChunkUpdate = true;
return;
}
if (SpelunkerConfig.serverValidating && world.isClient())
return;
int cx = ChunkSectionPos.getSectionCoord(getX());
int cy = ChunkSectionPos.getSectionCoord(getY());
int cz = ChunkSectionPos.getSectionCoord(getZ());
// update if player crosses chunk border
if (cx != lastCx || cy != lastCy || cz != lastCz || forceOreChunkUpdate) {
forceOreChunkUpdate = false;
HashMap<Vec3i, ChunkSection> newChunks = SpelunkerEffectManager.getSurroundingChunkSections(world, getPos());
// calc difference and find ores
HashSet<Vec3i> remove = new HashSet<>();
spelunkerEffectChunks.removeIf(p -> {
if (!newChunks.containsKey(p)) {
remove.add(p);
return true;
}
return false;
});
ArrayList<ChunkOres> add = new ArrayList<>();
for (Map.Entry<Vec3i, ChunkSection> section : newChunks.entrySet()) {
Vec3i pos = section.getKey();
if (!spelunkerEffectChunks.contains(pos)) {
add.add(SpelunkerEffectManager.findOresInChunk(world, pos));
spelunkerEffectChunks.add(pos);
}
}
// handle new and removed chunk sections
if (world.isClient()) {
SpelunkerModClient.spelunkerEffectRenderer.updateChunks(world, remove, add);
} else if (SpelunkerConfig.serverValidating) {
PacketByteBuf buf = SpelunkerEffectManager.writePacket(world, true, remove, add);
ServerPlayNetworking.send((ServerPlayerEntity) (Object) this, SpelunkerMod.PACKET_ORE_CHUNKS, buf);
}
}
lastCx = cx;
lastCy = cy;
lastCz = cz;
}
Aggregations