Skip to content

Instantly share code, notes, and snippets.

@TelepathicGrunt
Created November 16, 2023 03:26
Show Gist options
  • Save TelepathicGrunt/d79487f35fa5ff04f5c1394f7a626c3e to your computer and use it in GitHub Desktop.
Save TelepathicGrunt/d79487f35fa5ff04f5c1394f7a626c3e to your computer and use it in GitHub Desktop.
public static List<BlockPos> matchingBlocksOfKindInRange(Level level, BlockPos centerPos, int radius, Predicate<BlockState> predicate) {
List<BlockPos> validPos = new ObjectArrayList<>();
// Figure out how many chunk radius we need to search outward to encompass the radius properly
ChunkPos maxChunkPos = new ChunkPos(
SectionPos.blockToSectionCoord(centerPos.getX() + radius),
SectionPos.blockToSectionCoord(centerPos.getZ() + radius)
);
ChunkPos minChunkPos = new ChunkPos(
SectionPos.blockToSectionCoord(centerPos.getX() - radius),
SectionPos.blockToSectionCoord(centerPos.getZ() - radius)
);
// Get all the chunks in range
for (int xOffset = minChunkPos.x; xOffset <= maxChunkPos.x; xOffset++) {
for (int zOffset = minChunkPos.z; zOffset <= maxChunkPos.z; zOffset++) {
ChunkAccess chunk = level.getChunk(xOffset, zOffset);
// Find and store all matches
scanChunkForMatchInRange(predicate, validPos, chunk, centerPos, radius);
}
}
return validPos;
}
private static void scanChunkForMatchInRange(Predicate<BlockState> predicate, List<BlockPos> validPos, ChunkAccess chunk, BlockPos originalPos, int radius) {
BlockPos.MutableBlockPos mutableSectionWorldOrigin = new BlockPos.MutableBlockPos();
BlockPos.MutableBlockPos mutableSectionWorldBlockPos = new BlockPos.MutableBlockPos();
int radiusSq = radius * radius;
// Iterate over all sections in chunk. Note, sections can be negative if world extends to negative.
for (int i = chunk.getMinSection(); i < chunk.getMaxSection(); ++i) {
int sectionWorldY = SectionPos.sectionToBlockCoord(i);
// Make sure this section is in range of the radius we want to check.
if (sectionWorldY + 15 < originalPos.getY() - radius || sectionWorldY > originalPos.getY() + radius) {
continue;
}
LevelChunkSection levelChunkSection = chunk.getSection(chunk.getSectionIndexFromSectionY(i));
// Check if chunk section has match
if (levelChunkSection.maybeHas(predicate)) {
// Set to origin corner of chunk section
mutableSectionWorldOrigin.set(
SectionPos.sectionToBlockCoord(chunk.getPos().x),
sectionWorldY,
SectionPos.sectionToBlockCoord(chunk.getPos().z));
for(int yOffset = 0; yOffset < 16; yOffset++) {
for(int zOffset = 0; zOffset < 16; zOffset++) {
for(int xOffset = 0; xOffset < 16; xOffset++) {
// Go to spot in section in terms of world position.
mutableSectionWorldBlockPos.set(mutableSectionWorldOrigin).move(xOffset, yOffset, zOffset);
// Make sure spot is in radius
int xDiff = originalPos.getX() - mutableSectionWorldBlockPos.getX();
int yDiff = originalPos.getY() - mutableSectionWorldBlockPos.getY();
int zDiff = originalPos.getZ() - mutableSectionWorldBlockPos.getZ();
if ((xDiff * xDiff + yDiff * yDiff + zDiff * zDiff) <= radiusSq) {
// Test block and add position found.
BlockState blockState = levelChunkSection.getBlockState(xOffset, yOffset, zOffset);
if (predicate.test(blockState)) {
validPos.add(mutableSectionWorldBlockPos.immutable());
}
}
}
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment