mirror of
https://github.com/boy0001/FastAsyncWorldedit.git
synced 2024-11-28 05:35:37 +01:00
Add replaceall command
/replaceall <world> [from] <to>
This commit is contained in:
parent
151cbf5679
commit
0f480b87bc
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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({
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) {}
|
||||
|
@ -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) {
|
||||
|
@ -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()];
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user