Add replaceall command

/replaceall <world> [from] <to>
This commit is contained in:
Jesse Boyd 2016-08-25 12:54:12 +10:00
parent 151cbf5679
commit 0f480b87bc
10 changed files with 208 additions and 32 deletions

View File

@ -23,7 +23,7 @@ ext {
git = org.ajoberstar.grgit.Grgit.open(file(".git"))
revision = "-${git.head().abbreviatedId}"
parents = git.head().parentIds;
index = -45; // Offset to mach CI
index = -43; // Offset to mach CI
for (;parents != null && !parents.isEmpty();index++) {
commit = git.getResolve().toCommit(parents.get(0));
parents = commit.getParentIds();

View File

@ -36,6 +36,7 @@ import com.sk89q.worldedit.command.tool.brush.GravityBrush;
import com.sk89q.worldedit.event.extent.EditSessionEvent;
import com.sk89q.worldedit.extension.platform.CommandManager;
import com.sk89q.worldedit.extension.platform.PlatformManager;
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
import com.sk89q.worldedit.extent.clipboard.io.SchematicReader;
@ -263,7 +264,7 @@ public class Fawe {
String versionString = scanner.next().trim();
scanner.close();
this.version = new FaweVersion(versionString);
Settings.DATE = new Date(version.year, version.month, version.day).toGMTString();
Settings.DATE = new Date(100 + version.year, version.month, version.day).toGMTString();
Settings.BUILD = "http://ci.athion.net/job/FastAsyncWorldEdit/" + version.build;
Settings.COMMIT = "https://github.com/boy0001/FastAsyncWorldedit/commit/" + Integer.toHexString(version.hash);
} catch (Throwable ignore) {}
@ -351,6 +352,7 @@ public class Fawe {
CuboidRegion.inject(); // Optimizations
// Extents
BlockTransformExtent.inject(); // Fix for cache not being mutable
AbstractDelegateExtent.inject(); // Optimizations
// Vector
Vector.inject(); // Optimizations
// Operations

View File

@ -5,6 +5,7 @@ import com.boydti.fawe.config.BBC;
import com.boydti.fawe.jnbt.anvil.MCAChunk;
import com.boydti.fawe.jnbt.anvil.MCAFilter;
import com.boydti.fawe.jnbt.anvil.MCAQueue;
import com.boydti.fawe.object.mask.FaweBlockMatcher;
import com.boydti.fawe.object.number.LongAdder;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandPermissions;
@ -35,6 +36,41 @@ public class AnvilCommands {
this.worldEdit = worldEdit;
}
@Command(
aliases = { "/replaceall", "/rea", "/repall" },
usage = "<folder> [from-block] <to-block>",
desc = "Replace all blocks in the selection with another",
flags = "d",
min = 2,
max = 4
)
@CommandPermissions("worldedit.region.replace")
public void replaceAll(Player player, EditSession editSession, String folder, @Optional String from, String to, @Switch('d') boolean useData) throws WorldEditException {
final FaweBlockMatcher matchFrom;
if (from == null) {
matchFrom = FaweBlockMatcher.NOT_AIR;
} else {
if (from.contains(":")) {
useData = true; //override d flag, if they specified data they want it
}
matchFrom = FaweBlockMatcher.fromBlocks(worldEdit.getBlocks(player, from, true), useData);
}
final FaweBlockMatcher matchTo = FaweBlockMatcher.setBlocks(worldEdit.getBlocks(player, to, true));
BaseBlock tmp = new BaseBlock(35, 14);
File root = new File(folder + File.separator + "region");
MCAQueue queue = new MCAQueue(folder, root, true);
final LongAdder count = new LongAdder();
queue.filterWorld(new MCAFilter() {
@Override
public void applyBlock(int x, int y, int z, BaseBlock block) {
if (matchFrom.apply(block) && matchTo.apply(block)) {
count.add(1);
}
}
});
BBC.VISITOR_BLOCK.send(player, count.longValue());
}
@Command(
aliases = { "/countall" },
usage = "<folder> [hasSky] <id>",
@ -44,9 +80,9 @@ public class AnvilCommands {
max = 3
)
@CommandPermissions("worldedit.anvil.countallstone")
public void countAll(Player player, EditSession editSession, String folder, @Optional("true") boolean hasSky, String arg, @Switch('d') boolean useData) throws WorldEditException {
public void countAll(Player player, EditSession editSession, String folder, String arg, @Switch('d') boolean useData) throws WorldEditException {
File root = new File(folder + File.separator + "region");
MCAQueue queue = new MCAQueue(folder, root, hasSky);
MCAQueue queue = new MCAQueue(folder, root, true);
final LongAdder count = new LongAdder();
if (arg.contains(":")) {
useData = true; //override d flag, if they specified data they want it

View File

@ -31,7 +31,7 @@ public class Reload extends FaweCommand {
MainUtil.sendMessage(player, "No version information available.");
return false;
}
MainUtil.sendMessage(player, "Version Date: " + new Date(version.year, version.month, version.day).toLocaleString());
MainUtil.sendMessage(player, "Version Date: " + new Date(100 + version.year, version.month, version.day).toLocaleString());
MainUtil.sendMessage(player, "Version Commit: " + Integer.toHexString(version.hash));
MainUtil.sendMessage(player, "Version Build: #" + version.build);
return true;

View File

@ -193,11 +193,10 @@ public class Settings extends Config {
}
}
@Comment("Experimental options")
@Comment("Experimental options, use at your own risk")
public static class EXPERIMENTAL {
@Comment({
"Directly modify the region files:",
" - May corrupt world if in use"
"Directly modify the region files.",
})
public static boolean ANVIL_QUEUE_MODE = false;
@Comment({

View File

@ -316,7 +316,6 @@ public class MCAChunk extends FaweChunk<Void> {
}
public int getSkyLight(int x, int y, int z) {
modified = true;
int layer = y >> 4;
byte[] skyLayer = skyLight[layer];
if (skyLayer == null) {
@ -327,7 +326,6 @@ public class MCAChunk extends FaweChunk<Void> {
}
public int getBlockLight(int x, int y, int z) {
modified = true;
int layer = y >> 4;
byte[] blockLayer = blockLight[layer];
if (blockLayer == null) {

View File

@ -15,7 +15,6 @@ import com.sk89q.jnbt.NBTInputStream;
import com.sk89q.jnbt.NBTOutputStream;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
@ -67,7 +66,7 @@ public class MCAFile {
fieldBuf2.setAccessible(true);
fieldBuf3 = NBTInputStream.class.getDeclaredField("buf");
fieldBuf3.setAccessible(true);
fieldBuf4 = ByteArrayOutputStream.class.getDeclaredField("buf");
fieldBuf4 = FastByteArrayOutputStream.class.getDeclaredField("array");
fieldBuf4.setAccessible(true);
fieldBuf5 = DeflaterOutputStream.class.getDeclaredField("buf");
fieldBuf5.setAccessible(true);
@ -102,6 +101,7 @@ public class MCAFile {
}
NBTInputStream nis = getChunkIS(offset);
MCAChunk chunk = new MCAChunk(nis, queue, cx, cz, size);
nis.close();
int pair = MathMan.pair((short) (cx & 31), (short) (cz & 31));
chunks.put(pair, chunk);
return chunk;
@ -207,6 +207,7 @@ public class MCAFile {
NBTStreamer ns = new NBTStreamer(is);
addReaders.run(ns);
ns.readFully();
is.close();
}
/**
@ -248,6 +249,7 @@ public class MCAFile {
NBTOutputStream nos = new NBTOutputStream(bos);
nos.writeNamedTag("", tag);
bos.flush();
bos.close();
byte[] result = baos.toByteArray();
return result;
}
@ -267,13 +269,14 @@ public class MCAFile {
private void writeHeader(int cx, int cz, int offsetMedium, int sizeByte) throws IOException {
int i = ((cx & 31) << 2) + ((cz & 31) << 7);
raf.seek(i);
raf.write((offsetMedium >>> 16) & 0xFF);
raf.write((offsetMedium >>> 8) & 0xFF);
raf.write((offsetMedium >>> 0) & 0xFF);
raf.write((offsetMedium >> 16));
raf.write((offsetMedium >> 8));
raf.write((offsetMedium >> 0));
raf.write(sizeByte);
}
public void close() {
flush();
try {
raf.close();
} catch (IOException e) {
@ -336,7 +339,6 @@ public class MCAFile {
}
}
if (newBytes == null) {
System.out.println("Deleting: " + cx + "," + cz);
// Don't write
continue;
}
@ -353,16 +355,16 @@ public class MCAFile {
byte[] nextBytes = getChunkCompressedBytes(nextOffset2);
relocate.put(pair, nextBytes);
}
System.out.println("Relocating " + nextCX + "," + nextCZ);
// System.out.println("Relocating " + nextCX + "," + nextCZ);
int nextSize = MathMan.unpairY(nextLoc) << 12;
end += nextSize;
nextOffset2 += nextSize;
}
System.out.println("Writing: " + cx + "," + cz);
// System.out.println("Writing: " + cx + "," + cz);
writeSafe(start, newBytes);
if (offset != start || end != start + size) {
System.out.println("Header: " + cx + "," + cz + " | " + offset + "," + start + " | " + end + "," + (start + size) + " | " + size + " | " + start);
writeHeader(cx, cz, offset >> 12, newSize);
if (offset != start || end != start + size || oldSize != newSize) {
// System.out.println("Header: " + cx + "," + cz + " | " + offset + "," + start + " | " + end + "," + (start + size) + " | " + size + " | " + start);
writeHeader(cx, cz, start >> 12, newSize);
}
start += newSize << 12;
}

View File

@ -1,6 +1,5 @@
package com.boydti.fawe.jnbt.anvil;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.example.CharFaweChunk;
import com.boydti.fawe.example.NMSMappedFaweQueue;
import com.boydti.fawe.object.FaweChunk;
@ -43,7 +42,7 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
public void filterWorld(final MCAFilter filter) {
File folder = getSaveFolder();
for (File file : folder.listFiles()) {
for (final File file : folder.listFiles()) {
try {
String name = file.getName();
String[] split = name.split("\\.");
@ -56,6 +55,9 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
Runnable run = new Runnable() {
@Override
public void run() {
// May not do anything, but seems to lead to smaller lag spikes
System.gc();
System.gc();
final MutableMCABackedBaseBlock mutableBlock = new MutableMCABackedBaseBlock();
final int cbx = mcaX << 5;
final int cbz = mcaZ << 5;
@ -77,15 +79,11 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
if (chunk.doesSectionExist(layer)) {
mutableBlock.setArrays(layer);
int yStart = layer << 4;
int index = 0;
for (int y = yStart; y < yStart + 16; y++) {
short[][] cacheY = FaweCache.CACHE_J[y];
for (int z = bz; z < bz + 16; z++) {
int rz = z & 15;
short[] cacheYZ = cacheY[rz];
for (int x = 0; x < 16; x++) {
int rx = x & 15;
short index = cacheYZ[rx];
mutableBlock.setIndex(rx, y, rz, index);
for (int x = bx; x < bx + 16; x++,index++) {
mutableBlock.setIndex(x & 15, y, z & 15, index);
filter.applyBlock(x, y, z, mutableBlock);
}
}
@ -98,13 +96,18 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
}
} catch (Throwable e) {
System.out.println("Failed to load: r." + mcaX + "." + mcaZ + ".mca -> (local) " + rcx + "," + rcz);
e.printStackTrace();
}
}
}
});
finalFile.close();
System.gc();
System.gc();
}
};
TaskManager.IMP.getPublicForkJoinPool().submit(run);
// TaskManager.IMP.getPublicForkJoinPool().submit(run);
run.run();
}
}
} catch (Throwable ignore) {}

View File

@ -27,8 +27,8 @@ public class MutableMCABackedBaseBlock extends BaseBlock {
}
public void setArrays(int layer) {
data = chunk.data[layer];
ids = chunk.ids[layer];
data = chunk.data[layer];
}
public void setIndex(int x, int y, int z, int index) {

View File

@ -0,0 +1,136 @@
package com.boydti.fawe.object.mask;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.object.PseudoRandom;
import com.sk89q.worldedit.blocks.BaseBlock;
import java.util.Set;
public abstract class FaweBlockMatcher {
public abstract boolean apply(BaseBlock block);
public static FaweBlockMatcher ALWAYS_TRUE = new FaweBlockMatcher() {
@Override
public boolean apply(BaseBlock block) {
return true;
}
};
public static FaweBlockMatcher NOT_AIR = new FaweBlockMatcher() {
@Override
public boolean apply(BaseBlock block) {
return block.getId() != 0;
}
};
public static FaweBlockMatcher setBlock(BaseBlock block) {
final int id = block.getId();
final int data = block.getData();
if (data == 0) {
return new FaweBlockMatcher() {
@Override
public boolean apply(BaseBlock oldBlock) {
int currentId = oldBlock.getId();
oldBlock.setId(id);
if (FaweCache.hasData(currentId)) {
oldBlock.setData(0);
}
if (FaweCache.hasNBT(id) && oldBlock.hasNbtData()) {
oldBlock.setNbtData(null);
}
return true;
}
};
}
return new FaweBlockMatcher() {
@Override
public boolean apply(BaseBlock oldBlock) {
int currentId = oldBlock.getId();
oldBlock.setId(id);
oldBlock.setData(data);
if (FaweCache.hasNBT(id) && oldBlock.hasNbtData()) {
oldBlock.setNbtData(null);
}
return true;
}
};
}
public static FaweBlockMatcher setBlocks(Set<BaseBlock> blocks) {
if (blocks.size() == 1) {
return setBlock(blocks.iterator().next());
}
final BaseBlock[] array = blocks.toArray(new BaseBlock[blocks.size()]);
final PseudoRandom random = new PseudoRandom(System.nanoTime());
final int size = array.length;
return new FaweBlockMatcher() {
@Override
public boolean apply(BaseBlock block) {
BaseBlock replace = array[random.random(size)];
int currentId = block.getId();
block.setId(replace.getId());
if (FaweCache.hasNBT(currentId)) {
block.setNbtData(null);
}
if (FaweCache.hasData(currentId) || replace.getData() != 0) {
block.setData(replace.getData());
}
return true;
}
};
}
public static FaweBlockMatcher fromBlock(BaseBlock block, boolean checkData) {
final int id = block.getId();
final int data = block.getData();
if (checkData && FaweCache.hasData(id)) {
return new FaweBlockMatcher() {
@Override
public boolean apply(BaseBlock block) {
return (block.getId() == id && block.getData() == data);
}
};
} else {
return new FaweBlockMatcher() {
@Override
public boolean apply(BaseBlock block) {
return (block.getId() == id);
}
};
}
}
public static FaweBlockMatcher fromBlocks(Set<BaseBlock> searchBlocks, boolean checkData) {
if (searchBlocks.size() == 1) {
return fromBlock(searchBlocks.iterator().next(), checkData);
}
final boolean[] allowedId = new boolean[FaweCache.getId(Character.MAX_VALUE)];
for (BaseBlock block : searchBlocks) {
allowedId[block.getId()] = true;
}
final boolean[] allowed = new boolean[Character.MAX_VALUE];
for (BaseBlock block : searchBlocks) {
allowed[FaweCache.getCombined(block)] = true;
}
if (checkData) {
return new FaweBlockMatcher() {
@Override
public boolean apply(BaseBlock block) {
int id = block.getId();
if (allowedId[id]) {
if (FaweCache.hasData(id)) {
return allowed[(id << 4) + block.getData()];
}
return true;
}
return false;
}
};
}
return new FaweBlockMatcher() {
@Override
public boolean apply(BaseBlock block) {
return allowedId[block.getId()];
}
};
}
}