WorldScanner
com.jsmacrosce.jsmacros.client.api.classes.worldscanner.WorldScanner
Scans chunks and block-coordinate regions for blocks matching optional block and state filters.
Filter results are cached per block state and reused by later scans on the same scanner. Scans skip chunks unavailable to the client and do not request them from the server.
There are three kinds of search and they differ in the units they take. The chunk searches take a centre in chunk coordinates, the area searches take block coordinates, and the reach searches take a point and a distance. A chunk coordinate is the block coordinate divided by sixteen, and the parameter names say which of the two a method is expecting.
// reuse a scanner so matching states already evaluated are not tested again
const scanner = World.getWorldScanner(
JavaWrapper.methodToJava(function (block) {
return block.getId() === "minecraft:diamond_ore";
}),
null
);
if (scanner !== null) {
// every position in the nine chunks around the player
const found = scanner.scanAroundPlayer(1);
Chat.log(`${found.size()} diamond ore, from ${scanner.getCachedAmount()} states tested`);
// the same scanner, asking for counts rather than positions
const counts = scanner.getBlocksInChunks(0, 0, 0, true);
Chat.log(`${counts.size()} kinds of block in the chunk at the origin`);
}Constructors
new WorldScanner
new WorldScanner(Level world, Function<BlockHelper, Boolean> blockFilter, Function<BlockStateHelper, Boolean> stateFilter)#world. Non-null block and state filters are both applied; the block filter runs first, and either may be null to omit that test. With both null, every encountered state matches. Scans may use parallel streams unless a wrapped script filter's context is not multithreaded; this choice is made when the scanner is constructed. // naming the parameter type is what tells the wrapper what it is being
// handed. The two are stages: a block is kept when the block filter and
// the state filter both accept it
const scanner = World.getWorldScanner(
JavaWrapper.methodToJava(function (block: BlockHelper) {
return block.getId() !== "minecraft:dirt";
}),
JavaWrapper.methodToJava(function (state: BlockStateHelper) {
return state.isSolid();
})
);
if (scanner !== null) {
Chat.log(`${scanner.scanAroundPlayer(2).size()} blocks matched`);
}Parameters:
world: the world to scanblockFilter: a filter method for the blocks, ornullto keep all of themstateFilter: a filter method for the block states, ornullto keep all of those
Methods
getBlocksInChunk
ignoreState uses the block string, while false uses the state string including its properties. Counts cover the chunk's full height. Chunks not available to the client are skipped. // a count of the ores in one chunk. The centre here is a chunk
// coordinate, not a block one, so 0 is the chunk at the origin rather
// than the block at 0, 0
const scanner = World.getWorldScanner(
JavaWrapper.methodToJava(function (block: BlockHelper) {
return block.getId().endsWith("_ore");
}),
null
);
if (scanner !== null) {
const counts = scanner.getBlocksInChunk(0, 0, true);
for (const key of counts.keySet()) {
Chat.log(`${key}: ${counts.get(key)}`);
}
}Parameters:
chunkX: the x coordinate of the chunk to scanchunkZ: the z coordinate of the chunk to scanignoreState: whether multiple states should be combined to a single block
getBlocksInChunks
getBlocksInChunks(int centerX, int centerZ, int chunkRange, boolean ignoreState): Map<String, Integer>#centerX - chunkRange through centerX + chunkRange and likewise for Z. Keys follow getBlocksInChunk(int, int, boolean); counts from all available chunks are added together, and unavailable chunks are skipped. // a count of the ores in the nine chunks around a chunk. The key
// comes from the block itself and has nothing to do with how the
// filter was built, so the filter's form is not what is shown here
const scanner = World.getWorldScanner(
JavaWrapper.methodToJava(function (block: BlockHelper) {
return block.getId().endsWith("_ore");
}),
null
);
if (scanner !== null) {
const counts = scanner.getBlocksInChunks(0, 0, 1, true);
Chat.log(`${counts.size()} kinds of ore in the nine chunks`);
}Parameters:
centerX: the x coordinate of the center chunk to scan aroundcenterZ: the z coordinate of the center chunk to scan aroundchunkRange: non-negative radius in chunks; zero scans only the center chunkignoreState: whether multiple states should be combined to a single block
getCachedAmount
getCachedAmount(): int#getChunkRange
2 * chunkrange + 1; positions are ordered by ascending X, then ascending Z. // the nine chunks around a chunk, as chunk positions rather than
// block ones, which is what the scan methods take
const scanner = World.getWorldScanner(
JavaWrapper.methodToJava(function (block: BlockHelper) { return true; }),
null
);
if (scanner !== null) {
const chunks = scanner.getChunkRange(0, 0, 1);
Chat.log(`${chunks.size()} chunks`);
}Parameters:
centerX: the x coordinate of the center chunk to scan aroundcenterZ: the z coordinate of the center chunk to scan aroundchunkrange: the range to scan around the center chunk
2 * chunkrange + 1 squared entriesscanAroundPlayer
2 * chunkRange + 1; returns an empty list when there is no player. Unavailable chunks are skipped.Parameters:
chunkRange: the range to scan around the center chunk
scanChunkRange
2 * chunkrange + 1; unavailable chunks are skipped.Parameters:
centerX: the x coordinate of the center chunk to scan aroundcenterZ: the z coordinate of the center chunk to scan aroundchunkrange: the range to scan around the center chunk
scanClosestReachable
// the nearest block of one kind the player could reach, or null when
// there is none, which is why the result is checked rather than read
const scanner = World.getWorldScanner(
JavaWrapper.methodToJava(function (block: BlockHelper) {
return block.getId() === "minecraft:chest";
}),
null
);
if (scanner !== null) {
const nearest = scanner.scanClosestReachable();
if (nearest !== null) {
Chat.log(`nearest chest at ${nearest.getX()}, ${nearest.getY()}, ${nearest.getZ()}`);
} else {
Chat.log("no chest in reach");
}
}null if there is none or there is no playerstrict false, reach and ranking use unit block boxes rather than block shapes. // the nearest by bounding box rather than by shape, which is the
// looser of the two and so can name a block out of touch
const scanner = World.getWorldScanner(
JavaWrapper.methodToJava(function (block: BlockHelper) {
return block.getId() === "minecraft:torch";
}),
null
);
if (scanner !== null) {
const nearest = scanner.scanClosestReachable(false);
if (nearest !== null) {
Chat.log(`nearest torch at ${nearest.getX()}, ${nearest.getY()}, ${nearest.getZ()}`);
}
}Parameters:
strict: whether reach should also be checked against the block's shape
null if there is none or there is no playerreach of pos; obstructions are not considered. Reach is measured to unit block boxes, and with strict true the block's shape must also be within reach. Candidates are ranked by distance from pos shifted by (-0.5, -0.5, -0.5) to their block positions. // the full form, from a fixed point with a reach of the script's own
// choosing and the shape check turned off
const scanner = World.getWorldScanner(
JavaWrapper.methodToJava(function (block: BlockHelper) {
return block.getId() === "minecraft:chest";
}),
null
);
if (scanner !== null) {
const from = PositionCommon.createPos(0.5, 64, 0.5);
const nearest = scanner.scanClosestReachable(from, 6.0, false);
if (nearest !== null) {
Chat.log(`nearest chest at ${nearest.getX()}, ${nearest.getY()}, ${nearest.getZ()}`);
}
}Parameters:
pos: the point to search fromreach: maximum distance in blocks fromposstrict: whether to require the block's shape to be within reach
reach of pos, or null if there is nonescanCubeArea
pos, including both ends on each axis. Its side length is 2 * range + 1; the Y bounds are clamped to world height, and a cube entirely outside that height is empty. // the 3x3x3 cube around a block position, both ends counted
const scanner = World.getWorldScanner(
JavaWrapper.methodToJava(function (block: BlockHelper) {
return block.getId() === "minecraft:chest";
}),
null
);
if (scanner !== null) {
const centre = PositionCommon.createBlockPos(100, 64, 100);
const found = scanner.scanCubeArea(centre, 1);
Chat.log(`${found.size()} chests in the cube`);
}Parameters:
pos: the centre of the cuberange: how many blocks out from the centre to go on each axis
2 * range + 1; the y range is clamped to the world height.Parameters:
x: the x coordinate of the centre of the cubey: the y coordinate of the centre of the cubez: the z coordinate of the centre of the cuberange: how many blocks out from the centre to go on each axis
Parameters:
pos1: first pos, inclusivepos2: second pos, exclusive
Parameters:
x1: first x coordinate, inclusivey1: first y coordinate, inclusivez1: first z coordinate, inclusivex2: second x coordinate, exclusivey2: second y coordinate, exclusivez2: second z coordinate, exclusive
scanCubeAreaInclusive
Parameters:
pos1: first pos, inclusivepos2: second pos, inclusive
Parameters:
x1: first x coordinate, inclusivey1: first y coordinate, inclusivez1: first z coordinate, inclusivex2: second x coordinate, inclusivey2: second y coordinate, inclusivez2: second z coordinate, inclusive
scanReachable
strict true, the block's shape must be within reach; otherwise its unit block box is tested instead.Parameters:
strict: whether to require the block's shape to be within reach; false tests its unit block box
pos using the player's block-interaction reach (4.5 when there is no player) and the strict shape check. Obstructions are not considered.Parameters:
pos: the point to search from
pospos using the supplied reach and strict shape check. Obstructions are not considered; unlike scanReachable(Pos3D), this overload does not obtain reach from the player.Parameters:
pos: the point to search fromreach: how far out fromposto go
reach of pospos using reach; obstructions are not considered. Distance is measured to each unit block box, and when strict is true the block's shape must also be within reach. A negative reach throws IllegalArgumentException.Parameters:
pos: the point to search fromreach: the maximum distance in blocksstrict: whether to require the block's shape to be within reach; false tests its unit block box
scanSphereArea
radius of (pos.x - 0.5, pos.y - 0.5, pos.z - 0.5). Distance is measured to each candidate's integer block position, not its center; the y range is clamped to world height.Parameters:
pos: suppliesx,y, andz; distance uses each coordinate minus0.5radius: how far out to go
radius of (x - 0.5, y - 0.5, z - 0.5). Distance is measured to each candidate's integer block position, not its center; the y range is clamped to world height. This uses the same distance convention as scanSphereArea(Pos3D, double). // the same sphere written as three numbers and a radius
const scanner = World.getWorldScanner(
JavaWrapper.methodToJava(function (block: BlockHelper) {
return block.getId() === "minecraft:coal_ore";
}),
null
);
if (scanner !== null) {
const found = scanner.scanSphereArea(0.5, 64, 0.5, 20);
Chat.log(`${found.size()} coal ore within 20 blocks`);
}Parameters:
x: x coordinate; the distance origin usesx - 0.5y: y coordinate; the distance origin usesy - 0.5z: z coordinate; the distance origin usesz - 0.5radius: how far out to go