-
Notifications
You must be signed in to change notification settings - Fork 225
Anvil API
The Anvil API is for modifying MCA files (<world>/region
). If used properly, it can be the fastest method to modify the world, however it is considerably more complicated than the other approaches.
I would only recommend using this if the world is unloaded, or you are checking at least 1024 chunks.
If a world is loaded, the MCAQUeue must wrap the implementation FaweQueue. The default queue will assist the MCAQUeue in modifying world files that are in use.
FaweQueue defaultQueue = SetQueue.IMP.getNewQueue(folder, true, false);
MCAQueue mcaQueue = new MCAQueue(defaultQueue);
If the world is unloaded, we just need to provide the world name, directory and tell it if it has sky light.
String world = "world"; // The name of the world
File folder = new File(world + File.separater + "region");
boolean hasSky = true; // If the world has sky
MCAQueue mcaQueue = new MCAQueue(world, folder, hasSky);
// Set a block at a position
mcaQueue.setBlock(x, y, z, FaweCache.getBlock(BlockID.Stone, 0));
mcaQueue.flushQueue();
Change the queue used by an EditSession when constructing it with the EditSessionBuilder#queue(mcaQueue)
Change the queue used by an AsyncWorld in the constructor new AsyncWorld(world, queue)
A MCAFilter lets you modify large areas very quickly by making use of multiple cores and using a structure that reduces lookup costs. The world is filtered from the least expensive to modify, to the most (Path, File, MCAFile, MCAChunk, BaseBlock). I.e. it is much quicker to replace an entire file or chunk than it is to modify individual blocks.
To use an existing filter, see here. You can see them being used in the AnvilCommands class
// If the world is loaded (use RegionWrapper.Global() for the entire world)
MCAFilter result = mcaQueue.filterCopy(filter, region);
// OR If the world is unloaded
// MCAFilter result = mcaQueue.filterRegion(filter, region);
// OR If the world is unloaded AND you want to filter the entire world
// MCAFilter result = mcaQueue.filterWorld(filter, region);
Blocks can be copied/pasted from another MCAFile.
Note: If you just want to replace the entire world, it would be faster to use a filter to replace the entire .mca
files.
mcaQueue.pasteRegion(mcaQueueFrom, regionFrom, Vector offset);
See HeightMapMCAGenerator
Or for more control, the MCAWriter
File dir = new File("TestWorld/region");
// Create a new generator from a heightmap
// Note: If you don't want to use an image, use the other constructor
BufferedImage heightMap = ImageIO.read(new URL("https://i.imgur.com/plFXYiI.png"));
// Our new generator
HeightMapMCAGenerator gen = new HeightMapMCAGenerator(heightMap, dir);
// Add some cliffs
BufferedImage cliffHeightMap = ImageIO.read(new URL("https://i.imgur.com/wx5oiA7.png"));
boolean onlyWhite = false; // Only use the white parts of the heightmap
gen.setColumn(cliffHeightMap, new BaseBlock(BlockID.STONE), onlyWhite);
// Add some tallgrass
gen.setOverlay(new BlockMask(gen, new BaseBlock(BlockID.GRASS)), new BaseBlock(BlockID.LONG_GRASS));
// Add some caves
gen.addCaves();
// Add some ores
gen.addDefaultOres(new BlockMask(gen, new BaseBlock(BlockID.STONE)));
// Add some trees
World world = WorldEdit.getInstance().getServer().getWorlds().get(0);
WorldData worldData = world.getWorldData();
File treeFolder = new File("trees");
ClipboardHolder[] trees = ClipboardFormat.SCHEMATIC.loadAllFromDirectory(treeFolder, worldData);
Mask flat = new AngleMask(gen, 0, 0); // Only flat terrain
boolean randomRotate = true;
gen.addSchems(flat, worldData, trees, 50, randomRotate);
// You can also get/set specific blocks
// Note: Individual block changes are slower than the methods above
gen.setBlock(0, 255, 0, new BaseBlock(BlockID.SPONGE)); // Set a specific block
System.out.println(gen.getLazyBlock(0, 255, 0)); // Get a specific block
// Done, let's generate the world!
gen.generate();
String worldName = "world";
File root = new File(worldName + File.separator + "region");
MCAQueue queue = new MCAQueue(worldName, root, true);
MCAFilterCounter counter = queue.filterWorld(new MCAFilterCounter() {
@Override
public void applyBlock(int x, int y, int z, BaseBlock block, MutableLong ignore) {
if (block.getId() == 5) { // Change the id if it's 5
block.setId(7);
}
}
});
// See: FaweBlockMatcher.fromBlocks(...) which returns true if a block matches
// See: FaweBlockMatcher.setBlocks(...) which will modify a provided block
MCAQueue queue = new MCAQueue(worldName, root, true);
final int radius = 4000;
final int radiusSquared = radius * radius;
queue.filterWorld(new MCAFilter() {
@Override
public MCAFile applyFile(MCAFile mca) {
int distanceX = Math.abs((mca.getX() << 9) + 256) - 256;
int distanceZ = Math.abs((mca.getZ() << 9) + 256) - 256;
int distanceSquared = distanceX * distanceX + distanceZ * distanceZ;
if (distanceSquared > radiusSquared) {
// Delete this file since it's outside the radius
mca.close(ForkJoinPool.commonPool());
mca.getFile().delete();
return null;
} else if (distanceSquared + 512 < radiusSquared) {
// Don't filter this MCAFile since it's well within the radius
return null;
} else {
return mca;
}
}
@Override
public boolean appliesChunk(int cx, int cz) {
int distanceX = Math.abs((cx << 4) + 8) - 8;
int distanceZ = Math.abs((cz << 4) + 8) - 8;
int distanceSquared = distanceX * distanceX + distanceZ * distanceZ;
if (distanceSquared > radiusSquared) {
// Chunk is outside the radius
return true;
} else {
// We don't care about chunks inside the radius
return false;
}
}
@Override
public MCAChunk applyChunk(MCAChunk chunk) {
chunk.setDeleted(true);
// We don't want to filter blocks
return null;
}
});
String worldName = "world";
boolean hasSky = true;
File root = new File(worldName + File.separator + "region");
MCAWorld world = new MCAWorld(worldName, root, hasSky);
EditSession editSession = new EditSessionBuilder(world)
.checkMemory(false)
.allowedRegionsEverywhere()
.fastmode(true)
.changeSetNull()
.limitUnlimited()
.build();
// Do stuff here with the editSession (non generated sections of the world cannot be modified)
This wiki is outdated, move to https://github.com/IntellectualSites/FastAsyncWorldEdit-Documentation/
This Wiki is for Legacy Versions (1.8 - 1.12.2). Check here for 1.13+ versions: https://github.com/IntellectualSites/FastAsyncWorldEdit-Documentation/